Просмотр исходного кода

gl_rasterizer: Enable clip distances when set in register and in shader

ReinUsesLisp 7 лет назад
Родитель
Сommit
2908d30274

+ 1 - 0
src/video_core/engines/maxwell_3d.h

@@ -42,6 +42,7 @@ public:
         static constexpr std::size_t NumVertexArrays = 32;
         static constexpr std::size_t NumVertexAttributes = 32;
         static constexpr std::size_t NumTextureSamplers = 32;
+        static constexpr std::size_t NumClipDistances = 8;
         static constexpr std::size_t MaxShaderProgram = 6;
         static constexpr std::size_t MaxShaderStage = 5;
         // Maximum number of const buffers per shader stage.

+ 24 - 11
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -295,6 +295,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
     // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
     u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
     u32 current_texture_bindpoint = 0;
+    std::array<bool, Maxwell::NumClipDistances> clip_distances{};
 
     for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
         const auto& shader_config = gpu.regs.shader_config[index];
@@ -355,12 +356,22 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
         current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
                                                   primitive_mode, current_texture_bindpoint);
 
+        // Workaround for Intel drivers.
+        // When a clip distance is enabled but not set in the shader it crops parts of the screen
+        // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
+        // clip distances only when it's written by a shader stage.
+        for (std::size_t i = 0; i < Maxwell::NumClipDistances; ++i) {
+            clip_distances[i] |= shader->GetShaderEntries().clip_distances[i];
+        }
+
         // When VertexA is enabled, we have dual vertex shaders
         if (program == Maxwell::ShaderProgram::VertexA) {
             // VertexB was combined with VertexA, so we skip the VertexB iteration
             index++;
         }
     }
+
+    SyncClipEnabled(clip_distances);
 }
 
 std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
@@ -642,7 +653,6 @@ void RasterizerOpenGL::DrawArrays() {
     SyncCullMode();
     SyncPrimitiveRestart();
     SyncScissorTest(state);
-    SyncClipEnabled();
     // Alpha Testing is synced on shaders.
     SyncTransformFeedback();
     SyncPointState();
@@ -1019,20 +1029,23 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
     state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
 }
 
-void RasterizerOpenGL::SyncClipEnabled() {
+void RasterizerOpenGL::SyncClipEnabled(
+    const std::array<bool, Maxwell::Regs::NumClipDistances>& clip_mask) {
+
     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
-    state.clip_distance[0] = regs.clip_distance_enabled.c0 != 0;
-    state.clip_distance[1] = regs.clip_distance_enabled.c1 != 0;
-    state.clip_distance[2] = regs.clip_distance_enabled.c2 != 0;
-    state.clip_distance[3] = regs.clip_distance_enabled.c3 != 0;
-    state.clip_distance[4] = regs.clip_distance_enabled.c4 != 0;
-    state.clip_distance[5] = regs.clip_distance_enabled.c5 != 0;
-    state.clip_distance[6] = regs.clip_distance_enabled.c6 != 0;
-    state.clip_distance[7] = regs.clip_distance_enabled.c7 != 0;
+    const std::array<bool, Maxwell::Regs::NumClipDistances> reg_state{
+        regs.clip_distance_enabled.c0 != 0, regs.clip_distance_enabled.c1 != 0,
+        regs.clip_distance_enabled.c2 != 0, regs.clip_distance_enabled.c3 != 0,
+        regs.clip_distance_enabled.c4 != 0, regs.clip_distance_enabled.c5 != 0,
+        regs.clip_distance_enabled.c6 != 0, regs.clip_distance_enabled.c7 != 0};
+
+    for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) {
+        state.clip_distance[i] = reg_state[i] && clip_mask[i];
+    }
 }
 
 void RasterizerOpenGL::SyncClipCoef() {
-    UNREACHABLE();
+    UNIMPLEMENTED();
 }
 
 void RasterizerOpenGL::SyncCullMode() {

+ 2 - 1
src/video_core/renderer_opengl/gl_rasterizer.h

@@ -142,7 +142,8 @@ private:
     void SyncViewport(OpenGLState& current_state);
 
     /// Syncs the clip enabled status to match the guest state
-    void SyncClipEnabled();
+    void SyncClipEnabled(
+        const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& clip_mask);
 
     /// Syncs the clip coefficients to match the guest state
     void SyncClipCoef();

+ 9 - 1
src/video_core/renderer_opengl/gl_shader_decompiler.cpp

@@ -525,6 +525,7 @@ public:
                 ((header.vtg.clip_distances >> index) & 1) == 0,
                 "Shader is setting gl_ClipDistance{} without enabling it in the header", index);
 
+            clip_distances[index] = true;
             fixed_pipeline_output_attributes_used.insert(attribute);
             shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';');
             break;
@@ -602,6 +603,11 @@ public:
         return used_samplers;
     }
 
+    /// Returns an array of the used clip distances.
+    const std::array<bool, Maxwell::NumClipDistances>& GetClipDistances() const {
+        return clip_distances;
+    }
+
     /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
     /// necessary.
     std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
@@ -975,6 +981,7 @@ private:
     const std::string& suffix;
     const Tegra::Shader::Header& header;
     std::unordered_set<Attribute::Index> fixed_pipeline_output_attributes_used;
+    std::array<bool, Maxwell::NumClipDistances> clip_distances{};
     u64 local_memory_size;
 };
 
@@ -997,7 +1004,8 @@ public:
 
     /// Returns entries in the shader that are useful for external functions
     ShaderEntries GetEntries() const {
-        return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length};
+        return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), regs.GetClipDistances(),
+                shader_length};
     }
 
 private:

+ 1 - 0
src/video_core/renderer_opengl/gl_shader_gen.h

@@ -163,6 +163,7 @@ private:
 struct ShaderEntries {
     std::vector<ConstBufferEntry> const_buffer_entries;
     std::vector<SamplerEntry> texture_samplers;
+    std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> clip_distances;
     std::size_t shader_length;
 };