From 431aa3274ca322e143c3dbc856ae1ac894f5d15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Tue, 5 Dec 2017 00:26:29 +0100 Subject: [PATCH] wined3d: Implement SV_ClipDistance. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- dlls/wined3d/glsl_shader.c | 63 ++++++++++++++++++++++++++++------ dlls/wined3d/shader.c | 36 ++++++++++++++++++- dlls/wined3d/wined3d_private.h | 41 +++++++++++----------- 3 files changed, 108 insertions(+), 32 deletions(-) diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 5d08c00175e..b89b7aa3d53 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 c4eed76d78f..7d59f8b9a04 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 01f0e1695b8..363118c6248 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 */ + DWORD uav_read_mask : 8; /* MAX_UNORDERED_ACCESS_VIEWS, 8 */ + DWORD uav_counter_mask : 8; /* 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 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;