From 1eca380886b5028e027f1380c04f221ac94ed47d Mon Sep 17 00:00:00 2001 From: wwylele Date: Thu, 17 Aug 2017 10:46:59 +0300 Subject: [PATCH 1/4] gl_rasterizer: add clipping plane z<=0 defined in PICA --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 3 +++ src/video_core/renderer_opengl/gl_shader_gen.cpp | 2 ++ src/video_core/renderer_opengl/gl_state.cpp | 13 +++++++++++++ src/video_core/renderer_opengl/gl_state.h | 3 +++ 4 files changed, 21 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 1c6c15a58b..aa95ef21da 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -28,6 +28,9 @@ MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { + // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0 + state.clip_distance[0] = true; + // Create sampler objects for (size_t i = 0; i < texture_samplers.size(); ++i) { texture_samplers[i].Create(); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index ae67aab052..0dae4b91ea 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -1196,6 +1196,8 @@ void main() { normquat = vert_normquat; view = vert_view; gl_Position = vec4(vert_position.x, vert_position.y, -vert_position.z, vert_position.w); + gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0 + // TODO (wwylele): calculate gl_ClipDistance[1] from user-defined clipping plane } )"; diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index bc9d34b840..06a905766f 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -68,6 +68,8 @@ OpenGLState::OpenGLState() { draw.vertex_buffer = 0; draw.uniform_buffer = 0; draw.shader_program = 0; + + clip_distance = {}; } void OpenGLState::Apply() const { @@ -261,6 +263,17 @@ void OpenGLState::Apply() const { glUseProgram(draw.shader_program); } + // Clip distance + for (size_t i = 0; i < clip_distance.size(); ++i) { + if (clip_distance[i] != cur_state.clip_distance[i]) { + if (clip_distance[i]) { + glEnable(GL_CLIP_DISTANCE0 + i); + } else { + glDisable(GL_CLIP_DISTANCE0 + i); + } + } + } + cur_state = *this; } diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 745a74479a..437fe34c47 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -4,6 +4,7 @@ #pragma once +#include #include namespace TextureUnits { @@ -123,6 +124,8 @@ public: GLuint shader_program; // GL_CURRENT_PROGRAM } draw; + std::array clip_distance; // GL_CLIP_DISTANCE + OpenGLState(); /// Get the currently active OpenGL state From 5a4af616c67a4d7968c71b419795777c3601341b Mon Sep 17 00:00:00 2001 From: wwylele Date: Thu, 17 Aug 2017 10:56:15 +0300 Subject: [PATCH 2/4] gl_shader_gen: simplify and clarify the depth transformation between vertex shader and fragment shader --- src/video_core/renderer_opengl/gl_shader_gen.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 0dae4b91ea..015e69da97 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -1112,7 +1112,10 @@ vec4 secondary_fragment_color = vec4(0.0); "gl_FragCoord.y < scissor_y2)) discard;\n"; } - out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; + // After perspective divide, OpenGL transform z_over_w from [-1, 1] to [near, far]. Here we use + // default near = 0 and far = 1, and undo the transformation to get the original z_over_w, then + // do our own transformation according to PICA specification. + out += "float z_over_w = 2.0 * gl_FragCoord.z - 1.0;\n"; out += "float depth = z_over_w * depth_scale + depth_offset;\n"; if (state.depthmap_enable == RasterizerRegs::DepthBuffering::WBuffering) { out += "depth /= gl_FragCoord.w;\n"; @@ -1195,7 +1198,7 @@ void main() { texcoord0_w = vert_texcoord0_w; normquat = vert_normquat; view = vert_view; - gl_Position = vec4(vert_position.x, vert_position.y, -vert_position.z, vert_position.w); + gl_Position = vert_position; gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0 // TODO (wwylele): calculate gl_ClipDistance[1] from user-defined clipping plane } From 72b26ac32f74457d017e4eb96d83e2a66e713a5a Mon Sep 17 00:00:00 2001 From: wwylele Date: Thu, 17 Aug 2017 10:57:31 +0300 Subject: [PATCH 3/4] swrasterizer/clipper: remove tested TODO hwtested. Current implementation is the correct behavior --- src/video_core/swrasterizer/clipper.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/video_core/swrasterizer/clipper.cpp b/src/video_core/swrasterizer/clipper.cpp index 7537689b7f..cdbc715026 100644 --- a/src/video_core/swrasterizer/clipper.cpp +++ b/src/video_core/swrasterizer/clipper.cpp @@ -125,10 +125,6 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu {Math::MakeVec(f0, f0, f0, -f1), Math::Vec4(f0, f0, f0, EPSILON)}, // w = EPSILON }}; - // TODO: If one vertex lies outside one of the depth clipping planes, some platforms (e.g. Wii) - // drop the whole primitive instead of clipping the primitive properly. We should test if - // this happens on the 3DS, too. - // Simple implementation of the Sutherland-Hodgman clipping algorithm. // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here) for (auto edge : clipping_edges) { From 63b6e802cdffc1464b4a1fe3f5171d71146e8e9a Mon Sep 17 00:00:00 2001 From: wwylele Date: Thu, 17 Aug 2017 11:02:19 +0300 Subject: [PATCH 4/4] swrasterizer: remove invalid TODO This function is called in clipping, before the pespective divide, and is not used in later rasterization. Thus it doesn't need perspective correction. --- src/video_core/swrasterizer/rasterizer.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/video_core/swrasterizer/rasterizer.h b/src/video_core/swrasterizer/rasterizer.h index 2f08775813..66cd6cfd49 100644 --- a/src/video_core/swrasterizer/rasterizer.h +++ b/src/video_core/swrasterizer/rasterizer.h @@ -19,10 +19,9 @@ struct Vertex : Shader::OutputVertex { // Linear interpolation // factor: 0=this, 1=vtx + // Note: This function cannot be called after perspective divide void Lerp(float24 factor, const Vertex& vtx) { pos = pos * factor + vtx.pos * (float24::FromFloat32(1) - factor); - - // TODO: Should perform perspective correct interpolation here... quat = quat * factor + vtx.quat * (float24::FromFloat32(1) - factor); color = color * factor + vtx.color * (float24::FromFloat32(1) - factor); tc0 = tc0 * factor + vtx.tc0 * (float24::FromFloat32(1) - factor); @@ -30,12 +29,11 @@ struct Vertex : Shader::OutputVertex { tc0_w = tc0_w * factor + vtx.tc0_w * (float24::FromFloat32(1) - factor); view = view * factor + vtx.view * (float24::FromFloat32(1) - factor); tc2 = tc2 * factor + vtx.tc2 * (float24::FromFloat32(1) - factor); - - screenpos = screenpos * factor + vtx.screenpos * (float24::FromFloat32(1) - factor); } // Linear interpolation // factor: 0=v0, 1=v1 + // Note: This function cannot be called after perspective divide static Vertex Lerp(float24 factor, const Vertex& v0, const Vertex& v1) { Vertex ret = v0; ret.Lerp(factor, v1);