diff options
| author | 2017-09-16 10:23:00 +0200 | |
|---|---|---|
| committer | 2017-09-16 10:23:00 +0200 | |
| commit | 699c92099140f6017c66433805d2e9a592f91169 (patch) | |
| tree | 8ff5b734c055dc47c4231d817863f9bd3dcde111 /src | |
| parent | Merge pull request #2842 from Subv/switchable_page_table (diff) | |
| parent | SwRasterizer/Clipper: flip the sign convention to match PICA and OpenGL (diff) | |
| download | yuzu-699c92099140f6017c66433805d2e9a592f91169.tar.gz yuzu-699c92099140f6017c66433805d2e9a592f91169.tar.xz yuzu-699c92099140f6017c66433805d2e9a592f91169.zip | |
Merge pull request #2900 from wwylele/clip-2
PICA: implement custom clip plane
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/regs_rasterizer.h | 14 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 28 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 80 | ||||
| -rw-r--r-- | src/video_core/swrasterizer/clipper.cpp | 31 |
5 files changed, 116 insertions, 46 deletions
diff --git a/src/video_core/regs_rasterizer.h b/src/video_core/regs_rasterizer.h index 2874fd127..4fef00d76 100644 --- a/src/video_core/regs_rasterizer.h +++ b/src/video_core/regs_rasterizer.h | |||
| @@ -5,10 +5,10 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | |||
| 9 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 10 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 11 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "video_core/pica_types.h" | ||
| 12 | 12 | ||
| 13 | namespace Pica { | 13 | namespace Pica { |
| 14 | 14 | ||
| @@ -31,7 +31,17 @@ struct RasterizerRegs { | |||
| 31 | 31 | ||
| 32 | BitField<0, 24, u32> viewport_size_y; | 32 | BitField<0, 24, u32> viewport_size_y; |
| 33 | 33 | ||
| 34 | INSERT_PADDING_WORDS(0x9); | 34 | INSERT_PADDING_WORDS(0x3); |
| 35 | |||
| 36 | BitField<0, 1, u32> clip_enable; | ||
| 37 | BitField<0, 24, u32> clip_coef[4]; // float24 | ||
| 38 | |||
| 39 | Math::Vec4<float24> GetClipCoef() const { | ||
| 40 | return {float24::FromRaw(clip_coef[0]), float24::FromRaw(clip_coef[1]), | ||
| 41 | float24::FromRaw(clip_coef[2]), float24::FromRaw(clip_coef[3])}; | ||
| 42 | } | ||
| 43 | |||
| 44 | INSERT_PADDING_WORDS(0x1); | ||
| 35 | 45 | ||
| 36 | BitField<0, 24, u32> viewport_depth_range; // float24 | 46 | BitField<0, 24, u32> viewport_depth_range; // float24 |
| 37 | BitField<0, 24, u32> viewport_depth_near_plane; // float24 | 47 | BitField<0, 24, u32> viewport_depth_near_plane; // float24 |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index aa95ef21d..7b0cd1b66 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -169,6 +169,8 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { | |||
| 169 | glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, proctex_diff_lut_buffer.handle); | 169 | glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, proctex_diff_lut_buffer.handle); |
| 170 | 170 | ||
| 171 | // Sync fixed function OpenGL state | 171 | // Sync fixed function OpenGL state |
| 172 | SyncClipEnabled(); | ||
| 173 | SyncClipCoef(); | ||
| 172 | SyncCullMode(); | 174 | SyncCullMode(); |
| 173 | SyncBlendEnabled(); | 175 | SyncBlendEnabled(); |
| 174 | SyncBlendFuncs(); | 176 | SyncBlendFuncs(); |
| @@ -401,6 +403,18 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 401 | SyncCullMode(); | 403 | SyncCullMode(); |
| 402 | break; | 404 | break; |
| 403 | 405 | ||
| 406 | // Clipping plane | ||
| 407 | case PICA_REG_INDEX(rasterizer.clip_enable): | ||
| 408 | SyncClipEnabled(); | ||
| 409 | break; | ||
| 410 | |||
| 411 | case PICA_REG_INDEX_WORKAROUND(rasterizer.clip_coef[0], 0x48): | ||
| 412 | case PICA_REG_INDEX_WORKAROUND(rasterizer.clip_coef[1], 0x49): | ||
| 413 | case PICA_REG_INDEX_WORKAROUND(rasterizer.clip_coef[2], 0x4a): | ||
| 414 | case PICA_REG_INDEX_WORKAROUND(rasterizer.clip_coef[3], 0x4b): | ||
| 415 | SyncClipCoef(); | ||
| 416 | break; | ||
| 417 | |||
| 404 | // Depth modifiers | 418 | // Depth modifiers |
| 405 | case PICA_REG_INDEX(rasterizer.viewport_depth_range): | 419 | case PICA_REG_INDEX(rasterizer.viewport_depth_range): |
| 406 | SyncDepthScale(); | 420 | SyncDepthScale(); |
| @@ -1280,6 +1294,20 @@ void RasterizerOpenGL::SetShader() { | |||
| 1280 | } | 1294 | } |
| 1281 | } | 1295 | } |
| 1282 | 1296 | ||
| 1297 | void RasterizerOpenGL::SyncClipEnabled() { | ||
| 1298 | state.clip_distance[1] = Pica::g_state.regs.rasterizer.clip_enable != 0; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | void RasterizerOpenGL::SyncClipCoef() { | ||
| 1302 | const auto raw_clip_coef = Pica::g_state.regs.rasterizer.GetClipCoef(); | ||
| 1303 | const GLvec4 new_clip_coef = {raw_clip_coef.x.ToFloat32(), raw_clip_coef.y.ToFloat32(), | ||
| 1304 | raw_clip_coef.z.ToFloat32(), raw_clip_coef.w.ToFloat32()}; | ||
| 1305 | if (new_clip_coef != uniform_block_data.data.clip_coef) { | ||
| 1306 | uniform_block_data.data.clip_coef = new_clip_coef; | ||
| 1307 | uniform_block_data.dirty = true; | ||
| 1308 | } | ||
| 1309 | } | ||
| 1310 | |||
| 1283 | void RasterizerOpenGL::SyncCullMode() { | 1311 | void RasterizerOpenGL::SyncCullMode() { |
| 1284 | const auto& regs = Pica::g_state.regs; | 1312 | const auto& regs = Pica::g_state.regs; |
| 1285 | 1313 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 78e218efe..46c62961c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -151,14 +151,21 @@ private: | |||
| 151 | LightSrc light_src[8]; | 151 | LightSrc light_src[8]; |
| 152 | alignas(16) GLvec4 const_color[6]; // A vec4 color for each of the six tev stages | 152 | alignas(16) GLvec4 const_color[6]; // A vec4 color for each of the six tev stages |
| 153 | alignas(16) GLvec4 tev_combiner_buffer_color; | 153 | alignas(16) GLvec4 tev_combiner_buffer_color; |
| 154 | alignas(16) GLvec4 clip_coef; | ||
| 154 | }; | 155 | }; |
| 155 | 156 | ||
| 156 | static_assert( | 157 | static_assert( |
| 157 | sizeof(UniformData) == 0x460, | 158 | sizeof(UniformData) == 0x470, |
| 158 | "The size of the UniformData structure has changed, update the structure in the shader"); | 159 | "The size of the UniformData structure has changed, update the structure in the shader"); |
| 159 | static_assert(sizeof(UniformData) < 16384, | 160 | static_assert(sizeof(UniformData) < 16384, |
| 160 | "UniformData structure must be less than 16kb as per the OpenGL spec"); | 161 | "UniformData structure must be less than 16kb as per the OpenGL spec"); |
| 161 | 162 | ||
| 163 | /// Syncs the clip enabled status to match the PICA register | ||
| 164 | void SyncClipEnabled(); | ||
| 165 | |||
| 166 | /// Syncs the clip coefficients to match the PICA register | ||
| 167 | void SyncClipCoef(); | ||
| 168 | |||
| 162 | /// Sets the OpenGL shader in accordance with the current PICA register state | 169 | /// Sets the OpenGL shader in accordance with the current PICA register state |
| 163 | void SetShader(); | 170 | void SetShader(); |
| 164 | 171 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index c536e61e1..9fe183944 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -25,6 +25,42 @@ using TevStageConfig = TexturingRegs::TevStageConfig; | |||
| 25 | 25 | ||
| 26 | namespace GLShader { | 26 | namespace GLShader { |
| 27 | 27 | ||
| 28 | static const std::string UniformBlockDef = R"( | ||
| 29 | #define NUM_TEV_STAGES 6 | ||
| 30 | #define NUM_LIGHTS 8 | ||
| 31 | |||
| 32 | struct LightSrc { | ||
| 33 | vec3 specular_0; | ||
| 34 | vec3 specular_1; | ||
| 35 | vec3 diffuse; | ||
| 36 | vec3 ambient; | ||
| 37 | vec3 position; | ||
| 38 | vec3 spot_direction; | ||
| 39 | float dist_atten_bias; | ||
| 40 | float dist_atten_scale; | ||
| 41 | }; | ||
| 42 | |||
| 43 | layout (std140) uniform shader_data { | ||
| 44 | vec2 framebuffer_scale; | ||
| 45 | int alphatest_ref; | ||
| 46 | float depth_scale; | ||
| 47 | float depth_offset; | ||
| 48 | int scissor_x1; | ||
| 49 | int scissor_y1; | ||
| 50 | int scissor_x2; | ||
| 51 | int scissor_y2; | ||
| 52 | vec3 fog_color; | ||
| 53 | vec2 proctex_noise_f; | ||
| 54 | vec2 proctex_noise_a; | ||
| 55 | vec2 proctex_noise_p; | ||
| 56 | vec3 lighting_global_ambient; | ||
| 57 | LightSrc light_src[NUM_LIGHTS]; | ||
| 58 | vec4 const_color[NUM_TEV_STAGES]; | ||
| 59 | vec4 tev_combiner_buffer_color; | ||
| 60 | vec4 clip_coef; | ||
| 61 | }; | ||
| 62 | )"; | ||
| 63 | |||
| 28 | PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) { | 64 | PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) { |
| 29 | PicaShaderConfig res; | 65 | PicaShaderConfig res; |
| 30 | 66 | ||
| @@ -1010,8 +1046,6 @@ std::string GenerateFragmentShader(const PicaShaderConfig& config) { | |||
| 1010 | 1046 | ||
| 1011 | std::string out = R"( | 1047 | std::string out = R"( |
| 1012 | #version 330 core | 1048 | #version 330 core |
| 1013 | #define NUM_TEV_STAGES 6 | ||
| 1014 | #define NUM_LIGHTS 8 | ||
| 1015 | 1049 | ||
| 1016 | in vec4 primary_color; | 1050 | in vec4 primary_color; |
| 1017 | in vec2 texcoord[3]; | 1051 | in vec2 texcoord[3]; |
| @@ -1023,36 +1057,6 @@ in vec4 gl_FragCoord; | |||
| 1023 | 1057 | ||
| 1024 | out vec4 color; | 1058 | out vec4 color; |
| 1025 | 1059 | ||
| 1026 | struct LightSrc { | ||
| 1027 | vec3 specular_0; | ||
| 1028 | vec3 specular_1; | ||
| 1029 | vec3 diffuse; | ||
| 1030 | vec3 ambient; | ||
| 1031 | vec3 position; | ||
| 1032 | vec3 spot_direction; | ||
| 1033 | float dist_atten_bias; | ||
| 1034 | float dist_atten_scale; | ||
| 1035 | }; | ||
| 1036 | |||
| 1037 | layout (std140) uniform shader_data { | ||
| 1038 | vec2 framebuffer_scale; | ||
| 1039 | int alphatest_ref; | ||
| 1040 | float depth_scale; | ||
| 1041 | float depth_offset; | ||
| 1042 | int scissor_x1; | ||
| 1043 | int scissor_y1; | ||
| 1044 | int scissor_x2; | ||
| 1045 | int scissor_y2; | ||
| 1046 | vec3 fog_color; | ||
| 1047 | vec2 proctex_noise_f; | ||
| 1048 | vec2 proctex_noise_a; | ||
| 1049 | vec2 proctex_noise_p; | ||
| 1050 | vec3 lighting_global_ambient; | ||
| 1051 | LightSrc light_src[NUM_LIGHTS]; | ||
| 1052 | vec4 const_color[NUM_TEV_STAGES]; | ||
| 1053 | vec4 tev_combiner_buffer_color; | ||
| 1054 | }; | ||
| 1055 | |||
| 1056 | uniform sampler2D tex[3]; | 1060 | uniform sampler2D tex[3]; |
| 1057 | uniform samplerBuffer lighting_lut; | 1061 | uniform samplerBuffer lighting_lut; |
| 1058 | uniform samplerBuffer fog_lut; | 1062 | uniform samplerBuffer fog_lut; |
| @@ -1061,7 +1065,11 @@ uniform samplerBuffer proctex_color_map; | |||
| 1061 | uniform samplerBuffer proctex_alpha_map; | 1065 | uniform samplerBuffer proctex_alpha_map; |
| 1062 | uniform samplerBuffer proctex_lut; | 1066 | uniform samplerBuffer proctex_lut; |
| 1063 | uniform samplerBuffer proctex_diff_lut; | 1067 | uniform samplerBuffer proctex_diff_lut; |
| 1068 | )"; | ||
| 1069 | |||
| 1070 | out += UniformBlockDef; | ||
| 1064 | 1071 | ||
| 1072 | out += R"( | ||
| 1065 | // Rotate the vector v by the quaternion q | 1073 | // Rotate the vector v by the quaternion q |
| 1066 | vec3 quaternion_rotate(vec4 q, vec3 v) { | 1074 | vec3 quaternion_rotate(vec4 q, vec3 v) { |
| 1067 | return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); | 1075 | return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); |
| @@ -1197,6 +1205,12 @@ out float texcoord0_w; | |||
| 1197 | out vec4 normquat; | 1205 | out vec4 normquat; |
| 1198 | out vec3 view; | 1206 | out vec3 view; |
| 1199 | 1207 | ||
| 1208 | )"; | ||
| 1209 | |||
| 1210 | out += UniformBlockDef; | ||
| 1211 | |||
| 1212 | out += R"( | ||
| 1213 | |||
| 1200 | void main() { | 1214 | void main() { |
| 1201 | primary_color = vert_color; | 1215 | primary_color = vert_color; |
| 1202 | texcoord[0] = vert_texcoord0; | 1216 | texcoord[0] = vert_texcoord0; |
| @@ -1207,7 +1221,7 @@ void main() { | |||
| 1207 | view = vert_view; | 1221 | view = vert_view; |
| 1208 | gl_Position = vert_position; | 1222 | gl_Position = vert_position; |
| 1209 | gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0 | 1223 | gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0 |
| 1210 | // TODO (wwylele): calculate gl_ClipDistance[1] from user-defined clipping plane | 1224 | gl_ClipDistance[1] = dot(clip_coef, vert_position); |
| 1211 | } | 1225 | } |
| 1212 | )"; | 1226 | )"; |
| 1213 | 1227 | ||
diff --git a/src/video_core/swrasterizer/clipper.cpp b/src/video_core/swrasterizer/clipper.cpp index cdbc71502..a52129eb7 100644 --- a/src/video_core/swrasterizer/clipper.cpp +++ b/src/video_core/swrasterizer/clipper.cpp | |||
| @@ -31,7 +31,7 @@ public: | |||
| 31 | : coeffs(coeffs), bias(bias) {} | 31 | : coeffs(coeffs), bias(bias) {} |
| 32 | 32 | ||
| 33 | bool IsInside(const Vertex& vertex) const { | 33 | bool IsInside(const Vertex& vertex) const { |
| 34 | return Math::Dot(vertex.pos + bias, coeffs) <= float24::FromFloat32(0); | 34 | return Math::Dot(vertex.pos + bias, coeffs) >= float24::FromFloat32(0); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | bool IsOutSide(const Vertex& vertex) const { | 37 | bool IsOutSide(const Vertex& vertex) const { |
| @@ -116,19 +116,18 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu | |||
| 116 | static const float24 f0 = float24::FromFloat32(0.0); | 116 | static const float24 f0 = float24::FromFloat32(0.0); |
| 117 | static const float24 f1 = float24::FromFloat32(1.0); | 117 | static const float24 f1 = float24::FromFloat32(1.0); |
| 118 | static const std::array<ClippingEdge, 7> clipping_edges = {{ | 118 | static const std::array<ClippingEdge, 7> clipping_edges = {{ |
| 119 | {Math::MakeVec(f1, f0, f0, -f1)}, // x = +w | 119 | {Math::MakeVec(-f1, f0, f0, f1)}, // x = +w |
| 120 | {Math::MakeVec(-f1, f0, f0, -f1)}, // x = -w | 120 | {Math::MakeVec(f1, f0, f0, f1)}, // x = -w |
| 121 | {Math::MakeVec(f0, f1, f0, -f1)}, // y = +w | 121 | {Math::MakeVec(f0, -f1, f0, f1)}, // y = +w |
| 122 | {Math::MakeVec(f0, -f1, f0, -f1)}, // y = -w | 122 | {Math::MakeVec(f0, f1, f0, f1)}, // y = -w |
| 123 | {Math::MakeVec(f0, f0, f1, f0)}, // z = 0 | 123 | {Math::MakeVec(f0, f0, -f1, f0)}, // z = 0 |
| 124 | {Math::MakeVec(f0, f0, -f1, -f1)}, // z = -w | 124 | {Math::MakeVec(f0, f0, f1, f1)}, // z = -w |
| 125 | {Math::MakeVec(f0, f0, f0, -f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON | 125 | {Math::MakeVec(f0, f0, f0, f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON |
| 126 | }}; | 126 | }}; |
| 127 | 127 | ||
| 128 | // Simple implementation of the Sutherland-Hodgman clipping algorithm. | 128 | // Simple implementation of the Sutherland-Hodgman clipping algorithm. |
| 129 | // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here) | 129 | // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here) |
| 130 | for (auto edge : clipping_edges) { | 130 | auto Clip = [&](const ClippingEdge& edge) { |
| 131 | |||
| 132 | std::swap(input_list, output_list); | 131 | std::swap(input_list, output_list); |
| 133 | output_list->clear(); | 132 | output_list->clear(); |
| 134 | 133 | ||
| @@ -147,12 +146,24 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu | |||
| 147 | } | 146 | } |
| 148 | reference_vertex = &vertex; | 147 | reference_vertex = &vertex; |
| 149 | } | 148 | } |
| 149 | }; | ||
| 150 | |||
| 151 | for (auto edge : clipping_edges) { | ||
| 152 | Clip(edge); | ||
| 150 | 153 | ||
| 151 | // Need to have at least a full triangle to continue... | 154 | // Need to have at least a full triangle to continue... |
| 152 | if (output_list->size() < 3) | 155 | if (output_list->size() < 3) |
| 153 | return; | 156 | return; |
| 154 | } | 157 | } |
| 155 | 158 | ||
| 159 | if (g_state.regs.rasterizer.clip_enable) { | ||
| 160 | ClippingEdge custom_edge{g_state.regs.rasterizer.GetClipCoef()}; | ||
| 161 | Clip(custom_edge); | ||
| 162 | |||
| 163 | if (output_list->size() < 3) | ||
| 164 | return; | ||
| 165 | } | ||
| 166 | |||
| 156 | InitScreenCoordinates((*output_list)[0]); | 167 | InitScreenCoordinates((*output_list)[0]); |
| 157 | InitScreenCoordinates((*output_list)[1]); | 168 | InitScreenCoordinates((*output_list)[1]); |
| 158 | 169 | ||