From 80bca9bc9ce95cbcff894f516eefe497b5096a4c Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Mon, 4 Aug 2014 12:17:23 +0200 Subject: [PATCH] wined3d: Add constant buffer support to the GLSL shader backend. --- dlls/wined3d/context.c | 11 +++++- dlls/wined3d/cs.c | 2 ++ dlls/wined3d/directx.c | 31 +++++++++++++++++ dlls/wined3d/glsl_shader.c | 40 +++++++++++++++++++++- dlls/wined3d/state.c | 62 +++++++++++++++++++++++++++++++++- dlls/wined3d/utils.c | 2 ++ dlls/wined3d/wined3d_gl.h | 12 +++++++ dlls/wined3d/wined3d_private.h | 8 ++++- 8 files changed, 164 insertions(+), 4 deletions(-) diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index 70b9b31de71..af33f49a06a 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -2948,7 +2948,7 @@ BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_de const struct wined3d_state *state = &device->state; const struct StateEntry *state_table = context->state_table; const struct wined3d_fb_state *fb = state->fb; - unsigned int i; + unsigned int i, j; WORD map; if (!context_validate_rt_config(context->gl_info->limits.buffers, @@ -2985,6 +2985,15 @@ BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_de buffer_get_sysmem(state->index_buffer, context); } + for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i) + { + for (j = 0; j < WINED3D_MAX_CBS; ++j) + { + if (state->cb[i][j]) + buffer_internal_preload(state->cb[i][j], context, state); + } + } + for (i = 0; i < context->numDirtyEntries; ++i) { DWORD rep = context->dirtyArray[i]; diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 9288b949d81..684ac9f79b0 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -569,6 +569,8 @@ static void wined3d_cs_exec_set_constant_buffer(struct wined3d_cs *cs, const voi InterlockedIncrement(&op->buffer->resource.bind_count); if (prev) InterlockedDecrement(&prev->resource.bind_count); + + device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(op->type)); } void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_shader_type type, diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index be63db4a224..dd425f95505 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -145,6 +145,7 @@ static const struct wined3d_extension_map gl_extension_map[] = {"GL_ARB_texture_rectangle", ARB_TEXTURE_RECTANGLE }, {"GL_ARB_texture_rg", ARB_TEXTURE_RG }, {"GL_ARB_timer_query", ARB_TIMER_QUERY }, + {"GL_ARB_uniform_buffer_object", ARB_UNIFORM_BUFFER_OBJECT }, {"GL_ARB_vertex_array_bgra", ARB_VERTEX_ARRAY_BGRA }, {"GL_ARB_vertex_blend", ARB_VERTEX_BLEND }, {"GL_ARB_vertex_buffer_object", ARB_VERTEX_BUFFER_OBJECT }, @@ -2417,6 +2418,9 @@ static void wined3d_adapter_init_limits(struct wined3d_gl_info *gl_info) gl_info->limits.buffers = 1; gl_info->limits.textures = 1; gl_info->limits.texture_coords = 1; + gl_info->limits.vertex_uniform_blocks = 0; + gl_info->limits.geometry_uniform_blocks = 0; + gl_info->limits.fragment_uniform_blocks = 0; gl_info->limits.fragment_samplers = 1; gl_info->limits.vertex_samplers = 0; gl_info->limits.combined_samplers = gl_info->limits.fragment_samplers + gl_info->limits.vertex_samplers; @@ -2593,6 +2597,19 @@ static void wined3d_adapter_init_limits(struct wined3d_gl_info *gl_info) gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &gl_max); gl_info->limits.glsl_vs_float_constants = gl_max / 4; TRACE("Max ARB_VERTEX_SHADER float constants: %u.\n", gl_info->limits.glsl_vs_float_constants); + + if (gl_info->supported[ARB_UNIFORM_BUFFER_OBJECT]) + { + gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &gl_max); + gl_info->limits.vertex_uniform_blocks = min(gl_max, WINED3D_MAX_CBS); + TRACE("Max vertex uniform blocks: %u (%d).\n", gl_info->limits.vertex_uniform_blocks, gl_max); + } + } + if (gl_info->supported[ARB_GEOMETRY_SHADER4] && gl_info->supported[ARB_UNIFORM_BUFFER_OBJECT]) + { + gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_BLOCKS, &gl_max); + gl_info->limits.geometry_uniform_blocks = min(gl_max, WINED3D_MAX_CBS); + TRACE("Max geometry uniform blocks: %u (%d).\n", gl_info->limits.geometry_uniform_blocks, gl_max); } if (gl_info->supported[ARB_FRAGMENT_SHADER]) { @@ -2602,6 +2619,20 @@ static void wined3d_adapter_init_limits(struct wined3d_gl_info *gl_info) gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &gl_max); gl_info->limits.glsl_varyings = gl_max; TRACE("Max GLSL varyings: %u (%u 4 component varyings).\n", gl_max, gl_max / 4); + + if (gl_info->supported[ARB_UNIFORM_BUFFER_OBJECT]) + { + gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &gl_max); + gl_info->limits.fragment_uniform_blocks = min(gl_max, WINED3D_MAX_CBS); + TRACE("Max fragment uniform blocks: %u (%d).\n", gl_info->limits.fragment_uniform_blocks, gl_max); + } + } + if (gl_info->supported[ARB_UNIFORM_BUFFER_OBJECT]) + { + gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, &gl_max); + TRACE("Max combined uniform blocks: %d.\n", gl_max); + gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &gl_max); + TRACE("Max uniform buffer bindings: %d.\n", gl_max); } if (gl_info->supported[NV_LIGHT_MAX_EXPONENT]) diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 515e815eb33..1097d87af28 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -1083,7 +1083,8 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont for (i = 0; i < WINED3D_MAX_CBS; ++i) { if (reg_maps->cb_sizes[i]) - shader_addline(buffer, "uniform vec4 %s_cb%u[%u];\n", prefix, i, reg_maps->cb_sizes[i]); + shader_addline(buffer, "layout(std140) uniform block_%s_cb%u { vec4 %s_cb%u[%u]; };\n", + prefix, i, prefix, i, reg_maps->cb_sizes[i]); } /* Declare texture samplers */ @@ -4488,6 +4489,8 @@ static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context * nvidia drivers write a warning if we don't do so. */ if (gl_info->supported[ARB_TEXTURE_RECTANGLE]) shader_addline(buffer, "#extension GL_ARB_texture_rectangle : enable\n"); + if (gl_info->supported[ARB_UNIFORM_BUFFER_OBJECT]) + shader_addline(buffer, "#extension GL_ARB_uniform_buffer_object : enable\n"); if (gl_info->supported[EXT_GPU_SHADER4]) shader_addline(buffer, "#extension GL_EXT_gpu_shader4 : enable\n"); @@ -4541,6 +4544,8 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context if (gl_info->supported[ARB_SHADER_BIT_ENCODING]) shader_addline(buffer, "#extension GL_ARB_shader_bit_encoding : enable\n"); + if (gl_info->supported[ARB_UNIFORM_BUFFER_OBJECT]) + shader_addline(buffer, "#extension GL_ARB_uniform_buffer_object : enable\n"); if (gl_info->supported[EXT_GPU_SHADER4]) shader_addline(buffer, "#extension GL_EXT_gpu_shader4 : enable\n"); @@ -4614,6 +4619,8 @@ static GLhandleARB shader_glsl_generate_geometry_shader(const struct wined3d_con shader_addline(buffer, "#extension GL_ARB_geometry_shader4 : enable\n"); if (gl_info->supported[ARB_SHADER_BIT_ENCODING]) shader_addline(buffer, "#extension GL_ARB_shader_bit_encoding : enable\n"); + if (gl_info->supported[ARB_UNIFORM_BUFFER_OBJECT]) + shader_addline(buffer, "#extension GL_ARB_uniform_buffer_object : enable\n"); if (gl_info->supported[EXT_GPU_SHADER4]) shader_addline(buffer, "#extension GL_EXT_gpu_shader4 : enable\n"); @@ -5755,6 +5762,26 @@ static void shader_glsl_init_ps_uniform_locations(const struct wined3d_gl_info * ps->ycorrection_location = GL_EXTCALL(glGetUniformLocationARB(program_id, "ycorrection")); } +static void shader_glsl_init_uniform_block_bindings(const struct wined3d_gl_info *gl_info, GLhandleARB program_id, + const struct wined3d_shader_reg_maps *reg_maps, unsigned int base, unsigned int count) +{ + const char *prefix = shader_glsl_get_prefix(reg_maps->shader_version.type); + GLuint block_idx; + unsigned int i; + char name[16]; + + for (i = 0; i < count; ++i) + { + if (!reg_maps->cb_sizes[i]) + continue; + + snprintf(name, sizeof(name), "block_%s_cb%u", prefix, i); + block_idx = GL_EXTCALL(glGetUniformBlockIndex(program_id, name)); + GL_EXTCALL(glUniformBlockBinding(program_id, block_idx, base + i)); + } + checkGLcall("glUniformBlockBinding"); +} + /* Context activation is done by the caller. */ 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) @@ -5985,8 +6012,15 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const if (vshader->reg_maps.boolean_constants) entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_B; entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_POS_FIXUP; + + shader_glsl_init_uniform_block_bindings(gl_info, programId, &vshader->reg_maps, + 0, gl_info->limits.vertex_uniform_blocks); } + if (gshader) + shader_glsl_init_uniform_block_bindings(gl_info, programId, &gshader->reg_maps, + gl_info->limits.vertex_uniform_blocks, gl_info->limits.geometry_uniform_blocks); + if (ps_id) { if (pshader) @@ -5998,6 +6032,10 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_B; if (entry->ps.ycorrection_location != -1) entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_Y_CORR; + + shader_glsl_init_uniform_block_bindings(gl_info, programId, &pshader->reg_maps, + gl_info->limits.vertex_uniform_blocks + gl_info->limits.geometry_uniform_blocks, + gl_info->limits.fragment_uniform_blocks); } else { diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index 36c4e71db5d..c7d1a105d7d 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -4896,7 +4896,64 @@ void state_srgbwrite(struct wined3d_context *context, const struct wined3d_state gl_info->gl_ops.gl.p_glDisable(GL_FRAMEBUFFER_SRGB); } -const struct StateEntryTemplate misc_state_template[] = { +static void state_cb(const struct wined3d_gl_info *gl_info, const struct wined3d_state *state, + enum wined3d_shader_type type, unsigned int base, unsigned int count) +{ + struct wined3d_buffer *buffer; + unsigned int i; + + for (i = 0; i < count; ++i) + { + buffer = state->cb[type][i]; + GL_EXTCALL(glBindBufferBase(GL_UNIFORM_BUFFER, base + i, buffer ? buffer->buffer_object : 0)); + } + checkGLcall("glBindBufferBase"); +} + +static void state_cb_vs(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) +{ + const struct wined3d_gl_limits *limits = &context->gl_info->limits; + + TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); + + state_cb(context->gl_info, state, WINED3D_SHADER_TYPE_VERTEX, 0, limits->vertex_uniform_blocks); +} + +static void state_cb_gs(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) +{ + const struct wined3d_gl_limits *limits = &context->gl_info->limits; + + TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); + + state_cb(context->gl_info, state, WINED3D_SHADER_TYPE_GEOMETRY, + limits->vertex_uniform_blocks, limits->geometry_uniform_blocks); +} + +static void state_cb_ps(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) +{ + const struct wined3d_gl_limits *limits = &context->gl_info->limits; + + TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); + + state_cb(context->gl_info, state, WINED3D_SHADER_TYPE_PIXEL, + limits->vertex_uniform_blocks + limits->geometry_uniform_blocks, limits->fragment_uniform_blocks); +} + +static void state_cb_warn(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) +{ + TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); + + WARN("Constant buffers (%s) no supported.\n", debug_d3dstate(state_id)); +} + +const struct StateEntryTemplate misc_state_template[] = +{ + { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX), { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX), state_cb_vs, }, ARB_UNIFORM_BUFFER_OBJECT }, + { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX), { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX), state_cb_warn, }, WINED3D_GL_EXT_NONE }, + { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),{ STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),state_cb_gs, }, ARB_UNIFORM_BUFFER_OBJECT }, + { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),{ STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),state_cb_warn, }, WINED3D_GL_EXT_NONE }, + { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL), { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL), state_cb_ps, }, ARB_UNIFORM_BUFFER_OBJECT }, + { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL), { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL), state_cb_warn, }, WINED3D_GL_EXT_NONE }, { STATE_RENDER(WINED3D_RS_SRCBLEND), { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE), NULL }, WINED3D_GL_EXT_NONE }, { STATE_RENDER(WINED3D_RS_DESTBLEND), { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE), NULL }, WINED3D_GL_EXT_NONE }, { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE), { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE), state_blend }, WINED3D_GL_EXT_NONE }, @@ -5825,6 +5882,9 @@ static void validate_state_table(struct StateEntry *state_table) STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), STATE_SHADER(WINED3D_SHADER_TYPE_GEOMETRY), STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), + STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX), + STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY), + STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL), STATE_VIEWPORT, STATE_LIGHT_TYPE, STATE_SCISSORRECT, diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index afc77fcb857..286638affe5 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -2684,6 +2684,8 @@ const char *debug_d3dstate(DWORD state) return wine_dbg_sprintf("STATE_SAMPLER(%#x)", state - STATE_SAMPLER(0)); if (STATE_IS_SHADER(state)) return wine_dbg_sprintf("STATE_SHADER(%s)", debug_shader_type(state - STATE_SHADER(0))); + if (STATE_IS_CONSTANT_BUFFER(state)) + return wine_dbg_sprintf("STATE_CONSTANT_BUFFER(%s)", debug_shader_type(state - STATE_CONSTANT_BUFFER(0))); if (STATE_IS_TRANSFORM(state)) return wine_dbg_sprintf("STATE_TRANSFORM(%s)", debug_d3dtstype(state - STATE_TRANSFORM(0))); if (STATE_IS_STREAMSRC(state)) diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h index acfbe3cebfd..b02905e5734 100644 --- a/dlls/wined3d/wined3d_gl.h +++ b/dlls/wined3d/wined3d_gl.h @@ -90,6 +90,7 @@ enum wined3d_gl_extension ARB_TEXTURE_RECTANGLE, ARB_TEXTURE_RG, ARB_TIMER_QUERY, + ARB_UNIFORM_BUFFER_OBJECT, ARB_VERTEX_ARRAY_BGRA, ARB_VERTEX_BLEND, ARB_VERTEX_BUFFER_OBJECT, @@ -325,6 +326,17 @@ enum wined3d_gl_extension /* GL_ARB_timer_query */ \ USE_GL_FUNC(glQueryCounter) \ USE_GL_FUNC(glGetQueryObjectui64v) \ + /* GL_ARB_uniform_buffer_object */ \ + USE_GL_FUNC(glBindBufferBase) \ + USE_GL_FUNC(glBindBufferRange) \ + USE_GL_FUNC(glGetActiveUniformBlockName) \ + USE_GL_FUNC(glGetActiveUniformBlockiv) \ + USE_GL_FUNC(glGetActiveUniformName) \ + USE_GL_FUNC(glGetActiveUniformsiv) \ + USE_GL_FUNC(glGetIntegeri_v) \ + USE_GL_FUNC(glGetUniformBlockIndex) \ + USE_GL_FUNC(glGetUniformIndices) \ + USE_GL_FUNC(glUniformBlockBinding) \ /* GL_ARB_vertex_blend */ \ USE_GL_FUNC(glVertexBlendARB) \ USE_GL_FUNC(glWeightPointerARB) \ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 1d199256778..7e17dcdbb06 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -961,7 +961,10 @@ DWORD get_flexible_vertex_size(DWORD d3dvtVertexType) DECLSPEC_HIDDEN; #define STATE_SHADER(a) (STATE_SAMPLER(MAX_COMBINED_SAMPLERS) + (a)) #define STATE_IS_SHADER(a) ((a) >= STATE_SHADER(0) && (a) < STATE_SHADER(WINED3D_SHADER_TYPE_COUNT)) -#define STATE_TRANSFORM(a) (STATE_SHADER(WINED3D_SHADER_TYPE_COUNT) + (a) - 1) +#define STATE_CONSTANT_BUFFER(a) (STATE_SHADER(WINED3D_SHADER_TYPE_COUNT) + (a)) +#define STATE_IS_CONSTANT_BUFFER(a) ((a) >= STATE_CONSTANT_BUFFER(0) && (a) < STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COUNT)) + +#define STATE_TRANSFORM(a) (STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COUNT) + (a) - 1) #define STATE_IS_TRANSFORM(a) ((a) >= STATE_TRANSFORM(1) && (a) <= STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(255))) #define STATE_STREAMSRC (STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(255)) + 1) @@ -1576,6 +1579,9 @@ struct wined3d_gl_limits UINT lights; UINT textures; UINT texture_coords; + UINT vertex_uniform_blocks; + UINT geometry_uniform_blocks; + UINT fragment_uniform_blocks; UINT fragment_samplers; UINT vertex_samplers; UINT combined_samplers;