From: Józef Kucia jkucia@codeweavers.com
Based on a patch by Andrew Wesie.
In Direct3D, SV_VertexID generally starts from zero. In OpenGL, gl_VertexID starts from "first" parameter passed to glDrawArrays(), or from "baseVertex" parameter for indexed draw calls. The GL_ARB_shader_draw_parameters extension doesn't help us much because gl_BaseVertexARB is zero for non-indexed draw calls [1]. If gl_BaseVertexARB would be equal to "first" for non-indexed draw calls, we could simply use gl_VertexID - gl_BaseVertexARB.
After this commit, SV_VertexID is still wrong for indirect draw calls because we cannot easily access the "first" field from struct DrawArraysIndirectCommand in a vertex shader.
[1] - The ARB_shader_draw_parameters spec says that "In the case where the command has no <baseVertex> parameter, the value of <gl_BaseVertexARB> is zero."
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/wined3d/cs.c | 9 ++++++++- dlls/wined3d/glsl_shader.c | 29 +++++++++++++++++++---------- dlls/wined3d/wined3d_private.h | 1 + 3 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index ca79b7117142..c7c0c0bddb81 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -845,6 +845,7 @@ static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data) const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info; const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info; const struct wined3d_shader *geometry_shader; + struct wined3d_device *device = cs->device; int base_vertex_idx, load_base_vertex_idx; struct wined3d_state *state = &cs->state; const struct wined3d_cs_draw *op = data; @@ -867,7 +868,13 @@ static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data) else load_base_vertex_idx = 0;
- state->base_vertex_index = base_vertex_idx; + if (state->base_vertex_index != base_vertex_idx) + { + state->base_vertex_index = base_vertex_idx; + for (i = 0; i < device->context_count; ++i) + device->contexts[i]->constant_update_mask |= WINED3D_SHADER_CONST_BASE_VERTEX_ID; + } + if (state->load_base_vertex_index != load_base_vertex_idx) { state->load_base_vertex_index = load_base_vertex_idx; diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 545e1bff9f52..ad59e97e3fc5 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -155,6 +155,7 @@ struct glsl_vs_program GLint uniform_i_locations[WINED3D_MAX_CONSTS_I]; GLint uniform_b_locations[WINED3D_MAX_CONSTS_B]; GLint pos_fixup_location; + GLint base_vertex_id_location;
GLint modelview_matrix_location[MAX_VERTEX_BLENDS]; GLint projection_matrix_location; @@ -1775,22 +1776,21 @@ static void shader_glsl_load_color_key_constant(const struct glsl_ps_program *ps static void shader_glsl_load_constants(void *shader_priv, struct wined3d_context *context, const struct wined3d_state *state) { - const struct glsl_context_data *ctx_data = context->shader_backend_data; const struct wined3d_shader *vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX]; const struct wined3d_shader *pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL]; + const struct glsl_context_data *ctx_data = context->shader_backend_data; + struct glsl_shader_prog_link *prog = ctx_data->glsl_program; const struct wined3d_gl_info *gl_info = context->gl_info; - struct shader_glsl_priv *priv = shader_priv; float position_fixup[4 * WINED3D_MAX_VIEWPORTS]; + struct shader_glsl_priv *priv = shader_priv; + unsigned int constant_version; DWORD update_mask; - - struct glsl_shader_prog_link *prog = ctx_data->glsl_program; - UINT constant_version; int i;
- if (!prog) { - /* No GLSL program set - nothing to do. */ + /* No GLSL program set - nothing to do. */ + if (!prog) return; - } + constant_version = prog->constant_version; update_mask = context->constant_update_mask & prog->constant_update_mask;
@@ -1829,6 +1829,12 @@ static void shader_glsl_load_constants(void *shader_priv, struct wined3d_context checkGLcall("glUniform4fv"); }
+ if (update_mask & WINED3D_SHADER_CONST_BASE_VERTEX_ID) + { + GL_EXTCALL(glUniform1i(prog->vs.base_vertex_id_location, state->base_vertex_index)); + checkGLcall("base vertex id"); + } + if (update_mask & WINED3D_SHADER_CONST_FFP_MODELVIEW) { struct wined3d_matrix mat; @@ -2359,8 +2365,8 @@ static void shader_glsl_declare_generic_vertex_attribute(struct wined3d_string_b
if (e->sysval_semantic == WINED3D_SV_VERTEX_ID) { - shader_addline(buffer, "vec4 vs_in%u = vec4(intBitsToFloat(gl_VertexID), 0.0, 0.0, 0.0);\n", - index); + shader_addline(buffer, "uniform int base_vertex_id;\n"); + shader_addline(buffer, "vec4 vs_in%u = vec4(intBitsToFloat(gl_VertexID - base_vertex_id), 0.0, 0.0, 0.0);\n", index); return; } if (e->sysval_semantic == WINED3D_SV_INSTANCE_ID) @@ -10123,6 +10129,7 @@ static void shader_glsl_init_vs_uniform_locations(const struct wined3d_gl_info * }
vs->pos_fixup_location = GL_EXTCALL(glGetUniformLocation(program_id, "pos_fixup")); + vs->base_vertex_id_location = GL_EXTCALL(glGetUniformLocation(program_id, "base_vertex_id"));
for (i = 0; i < MAX_VERTEX_BLENDS; ++i) { @@ -10694,6 +10701,8 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_B; if (entry->vs.pos_fixup_location != -1) entry->constant_update_mask |= WINED3D_SHADER_CONST_POS_FIXUP; + if (entry->vs.base_vertex_id_location != -1) + entry->constant_update_mask |= WINED3D_SHADER_CONST_BASE_VERTEX_ID;
shader_glsl_load_program_resources(context, priv, program_id, vshader); } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index f908ff717324..4e80cc75acfa 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -445,6 +445,7 @@ enum wined3d_shader_resource_type #define WINED3D_SHADER_CONST_FFP_LIGHTS 0x00080000 #define WINED3D_SHADER_CONST_FFP_PS 0x00100000 #define WINED3D_SHADER_CONST_FFP_COLOR_KEY 0x00200000 +#define WINED3D_SHADER_CONST_BASE_VERTEX_ID 0x00400000
enum wined3d_shader_register_type {