[PATCH 1/7] wined3d: Implement SV_ClipDistance.

Józef Kucia jkucia at codeweavers.com
Mon Dec 4 17:26:29 CST 2017


In D3D10+ all clip distances declared in a shader are always enabled.
In other words, enablement of clip distances is a property of a shader.

Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---

>From wined3d API standpoint, the RS_CLIPPLANEENABLE state is ignored
when SM4+ shaders are active. We shouldn't touch the RS_CLIPPLANEENABLE
state when SM4+ shaders are in use.

Fixes https://bugs.winehq.org/show_bug.cgi?id=43932

---
 dlls/wined3d/glsl_shader.c     | 63 ++++++++++++++++++++++++++++++++++--------
 dlls/wined3d/shader.c          | 36 +++++++++++++++++++++++-
 dlls/wined3d/wined3d_private.h | 43 ++++++++++++++--------------
 3 files changed, 109 insertions(+), 33 deletions(-)

diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 5d08c00175eb..b89b7aa3d53c 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -241,7 +241,10 @@ struct glsl_shader_prog_link
     struct glsl_cs_program cs;
     GLuint id;
     DWORD constant_update_mask;
-    UINT constant_version;
+    unsigned int constant_version;
+    DWORD shader_controlled_clip_distances : 1;
+    DWORD clip_distance_mask : 8; /* MAX_CLIP_DISTANCES, 8 */
+    DWORD padding : 23;
 };
 
 struct glsl_program_key
@@ -6923,6 +6926,26 @@ static void shader_glsl_setup_sm4_shader_output(struct shader_glsl_priv *priv,
     }
 }
 
+static void shader_glsl_generate_clip_or_cull_distances(struct wined3d_string_buffer *buffer,
+        const struct wined3d_shader_signature_element *element, DWORD clip_or_cull_distance_mask)
+{
+    unsigned int i, clip_or_cull_index;
+    char reg_mask[6];
+
+    /* Assign consecutive indices starting from 0. */
+    clip_or_cull_index = element->semantic_idx ? wined3d_popcount(clip_or_cull_distance_mask & 0xf) : 0;
+    for (i = 0; i < 4; ++i)
+    {
+        if (!(element->mask & (WINED3DSP_WRITEMASK_0 << i)))
+            continue;
+
+        shader_glsl_write_mask_to_str(WINED3DSP_WRITEMASK_0 << i, reg_mask);
+        shader_addline(buffer, "gl_ClipDistance[%u] = outputs[%u]%s;\n",
+                clip_or_cull_index, element->register_idx, reg_mask);
+        ++clip_or_cull_index;
+    }
+}
+
 static void shader_glsl_setup_sm3_rasterizer_input(struct shader_glsl_priv *priv,
         const struct wined3d_gl_info *gl_info, const DWORD *map,
         const struct wined3d_shader_signature *input_signature,
@@ -6932,7 +6955,7 @@ static void shader_glsl_setup_sm3_rasterizer_input(struct shader_glsl_priv *priv
 {
     struct wined3d_string_buffer *buffer = &priv->shader_buffer;
     const char *semantic_name;
-    UINT semantic_idx;
+    unsigned int semantic_idx;
     char reg_mask[6];
     unsigned int i;
 
@@ -6966,6 +6989,10 @@ static void shader_glsl_setup_sm3_rasterizer_input(struct shader_glsl_priv *priv
             shader_addline(buffer, "gl_Layer = floatBitsToInt(outputs[%u])%s;\n",
                     output->register_idx, reg_mask);
         }
+        else if (output->sysval_semantic == WINED3D_SV_CLIP_DISTANCE)
+        {
+            shader_glsl_generate_clip_or_cull_distances(buffer, output, reg_maps_out->clip_distance_mask);
+        }
         else if (output->sysval_semantic)
         {
             FIXME("Unhandled sysval semantic %#x.\n", output->sysval_semantic);
@@ -9852,6 +9879,7 @@ static HRESULT shader_glsl_compile_compute_shader(struct shader_glsl_priv *priv,
     entry->ps.id = 0;
     entry->cs.id = shader_id;
     entry->constant_version = 0;
+    entry->shader_controlled_clip_distances = 0;
     entry->ps.np2_fixup_info = NULL;
     add_glsl_program_entry(priv, entry);
 
@@ -9926,11 +9954,12 @@ static void set_glsl_compute_shader_program(const struct wined3d_context *contex
 static void set_glsl_shader_program(const struct wined3d_context *context, const struct wined3d_state *state,
         struct shader_glsl_priv *priv, struct glsl_context_data *ctx_data)
 {
-    const struct wined3d_gl_info *gl_info = context->gl_info;
     const struct wined3d_d3d_info *d3d_info = context->d3d_info;
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    const struct wined3d_shader *pre_rasterization_shader;
     const struct ps_np2fixup_info *np2fixup_info = NULL;
-    struct glsl_shader_prog_link *entry = NULL;
     struct wined3d_shader *hshader, *dshader, *gshader;
+    struct glsl_shader_prog_link *entry = NULL;
     struct wined3d_shader *vshader = NULL;
     struct wined3d_shader *pshader = NULL;
     GLuint reorder_shader_id = 0;
@@ -10068,6 +10097,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
     entry->ps.id = ps_id;
     entry->cs.id = 0;
     entry->constant_version = 0;
+    entry->shader_controlled_clip_distances = 0;
     entry->ps.np2_fixup_info = np2fixup_info;
     /* Add the hash table entry */
     add_glsl_program_entry(priv, entry);
@@ -10194,7 +10224,15 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
     shader_glsl_init_gs_uniform_locations(gl_info, priv, program_id, &entry->gs);
     shader_glsl_init_ps_uniform_locations(gl_info, priv, program_id, &entry->ps,
             pshader ? pshader->limits->constant_float : 0);
-    checkGLcall("Find glsl program uniform locations");
+    checkGLcall("find glsl program uniform locations");
+
+    pre_rasterization_shader = gshader ? gshader : dshader ? dshader : vshader;
+    if (pre_rasterization_shader && pre_rasterization_shader->reg_maps.shader_version.major >= 4)
+    {
+        unsigned int clip_distance_count = wined3d_popcount(pre_rasterization_shader->reg_maps.clip_distance_mask);
+        entry->shader_controlled_clip_distances = 1;
+        entry->clip_distance_mask = (1u << clip_distance_count) - 1;
+    }
 
     if (needs_legacy_glsl_syntax(gl_info))
     {
@@ -10350,6 +10388,7 @@ static void shader_glsl_select(void *shader_priv, struct wined3d_context *contex
     struct glsl_context_data *ctx_data = context->shader_backend_data;
     const struct wined3d_gl_info *gl_info = context->gl_info;
     struct shader_glsl_priv *priv = shader_priv;
+    struct glsl_shader_prog_link *glsl_program;
     GLenum current_vertex_color_clamp;
     GLuint program_id, prev_id;
 
@@ -10357,13 +10396,15 @@ static void shader_glsl_select(void *shader_priv, struct wined3d_context *contex
     priv->fragment_pipe->enable_extension(gl_info, !use_ps(state));
 
     prev_id = ctx_data->glsl_program ? ctx_data->glsl_program->id : 0;
-
     set_glsl_shader_program(context, state, priv, ctx_data);
+    glsl_program = ctx_data->glsl_program;
 
-    if (ctx_data->glsl_program)
+    if (glsl_program)
     {
-        program_id = ctx_data->glsl_program->id;
-        current_vertex_color_clamp = ctx_data->glsl_program->vs.vertex_color_clamp;
+        program_id = glsl_program->id;
+        current_vertex_color_clamp = glsl_program->vs.vertex_color_clamp;
+        if (glsl_program->shader_controlled_clip_distances)
+            context_enable_clip_distances(context, glsl_program->clip_distance_mask);
     }
     else
     {
@@ -10392,8 +10433,8 @@ static void shader_glsl_select(void *shader_priv, struct wined3d_context *contex
         GL_EXTCALL(glUseProgram(program_id));
         checkGLcall("glUseProgram");
 
-        if (program_id)
-            context->constant_update_mask |= ctx_data->glsl_program->constant_update_mask;
+        if (glsl_program)
+            context->constant_update_mask |= glsl_program->constant_update_mask;
     }
 
     context->shader_update_mask |= (1u << WINED3D_SHADER_TYPE_COMPUTE);
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index c4eed76d78f0..7d59f8b9a042 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -952,6 +952,31 @@ static HRESULT shader_record_shader_phase(struct wined3d_shader *shader,
     return WINED3D_OK;
 }
 
+static HRESULT shader_calculate_clip_or_cull_distance_mask(
+        const struct wined3d_shader_signature_element *e, DWORD *mask)
+{
+    unsigned int i;
+
+    *mask = 0;
+
+    /* Cull and clip distances are packed in 4 component registers. 0 and 1 are
+     * the only allowed semantic indices.
+     */
+    if (e->semantic_idx >= MAX_CLIP_DISTANCES / 4)
+    {
+        WARN("Invalid clip/cull distance index %u.\n", e->semantic_idx);
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    for (i = 0; i < 4; ++i)
+    {
+        if (e->mask & (WINED3DSP_WRITEMASK_0 << i))
+            *mask |= 1u << (4 * e->semantic_idx + i);
+    }
+
+    return WINED3D_OK;
+}
+
 static void wined3d_insert_interpolation_mode(DWORD *packed_interpolation_mode,
         unsigned int register_idx, enum wined3d_shader_interpolation_mode mode)
 {
@@ -1754,7 +1779,16 @@ static HRESULT shader_get_registers_used(struct wined3d_shader *shader, const st
     {
         for (i = 0; i < output_signature->element_count; ++i)
         {
-            reg_maps->output_registers |= 1u << output_signature->elements[i].register_idx;
+            const struct wined3d_shader_signature_element *e = &output_signature->elements[i];
+            DWORD mask;
+
+            reg_maps->output_registers |= 1u << e->register_idx;
+            if (e->sysval_semantic == WINED3D_SV_CLIP_DISTANCE)
+            {
+                if (FAILED(hr = shader_calculate_clip_or_cull_distance_mask(e, &mask)))
+                    return hr;
+                reg_maps->clip_distance_mask |= mask;
+            }
         }
     }
     else if (reg_maps->output_registers)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index da06ba159f79..b8f0b4d194e0 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1006,31 +1006,32 @@ struct wined3d_shader_reg_maps
     BYTE bumpmat;                                   /* MAX_TEXTURES, 8 */
     BYTE luminanceparams;                           /* MAX_TEXTURES, 8 */
     struct wined3d_shader_resource_info uav_resource_info[MAX_UNORDERED_ACCESS_VIEWS];
-    DWORD uav_read_mask;                            /* MAX_UNORDERED_ACCESS_VIEWS, 8 */
-    DWORD uav_counter_mask;                         /* MAX_UNORDERED_ACCESS_VIEWS, 8 */
-
-    WORD usesnrm        : 1;
-    WORD vpos           : 1;
-    WORD usesdsx        : 1;
-    WORD usesdsy        : 1;
-    WORD usestexldd     : 1;
-    WORD usesmova       : 1;
-    WORD usesfacing     : 1;
-    WORD usesrelconstF  : 1;
-    WORD fog            : 1;
-    WORD usestexldl     : 1;
-    WORD usesifc        : 1;
-    WORD usescall       : 1;
-    WORD usespow        : 1;
-    WORD point_size     : 1;
-    WORD vocp           : 1;
-    WORD padding        : 1;
+    DWORD uav_read_mask : 8;                        /* MAX_UNORDERED_ACCESS_VIEWS, 8 */
+    DWORD uav_counter_mask : 8;                     /* MAX_UNORDERED_ACCESS_VIEWS, 8 */
+
+    DWORD clip_distance_mask : 8;                   /* MAX_CLIP_DISTANCES, 8 */
+    DWORD usesnrm        : 1;
+    DWORD vpos           : 1;
+    DWORD usesdsx        : 1;
+    DWORD usesdsy        : 1;
+    DWORD usestexldd     : 1;
+    DWORD usesmova       : 1;
+    DWORD usesfacing     : 1;
+    DWORD usesrelconstF  : 1;
+    DWORD fog            : 1;
+    DWORD usestexldl     : 1;
+    DWORD usesifc        : 1;
+    DWORD usescall       : 1;
+    DWORD usespow        : 1;
+    DWORD point_size     : 1;
+    DWORD vocp           : 1;
+    DWORD padding        : 25;
 
     DWORD rt_mask; /* Used render targets, 32 max. */
 
     /* Whether or not loops are used in this shader, and nesting depth */
-    unsigned loop_depth;
-    UINT min_rel_offset, max_rel_offset;
+    unsigned int loop_depth;
+    unsigned int min_rel_offset, max_rel_offset;
 
     struct wined3d_shader_tgsm *tgsm;
     SIZE_T tgsm_capacity;
-- 
2.13.6




More information about the wine-devel mailing list