[3/4] wined3d: Lookup GLSL float uniform locations only once per
program
H. Verbeet
hverbeet at gmail.com
Sat Aug 19 10:23:20 CDT 2006
Currently GLSL uniform locations are looked up every time a constant
is loaded. Since this happens quite a lot, the lookup is rather
expensive. This patch should increase performance a bit for
applications that use shaders, when GLSL is enabled.
Changelog:
- Lookup GLSL float uniform locations only once per program
-------------- next part --------------
dlls/wined3d/device.c | 29 ++++++++++++++++++++----
dlls/wined3d/drawprim.c | 11 +++++----
dlls/wined3d/glsl_shader.c | 49 +++++++++++++++++-----------------------
dlls/wined3d/stateblock.c | 6 ++---
dlls/wined3d/wined3d_private.h | 4 ++-
5 files changed, 57 insertions(+), 42 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 3abd963..5f39a42 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -7,6 +7,7 @@
* Copyright 2004 Christian Costa
* Copyright 2005 Oliver Stieber
* Copyright 2006 Stefan D?singer for CodeWeavers
+ * Copyright 2006 Henri Verbeet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -246,9 +247,9 @@ static void attach_glsl_shader(IWineD3DD
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
- if (This->stateBlock->shaderPrgId != 0 && shaderObj != 0) {
- TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->shaderPrgId);
- GL_EXTCALL(glAttachObjectARB(This->stateBlock->shaderPrgId, shaderObj));
+ if (This->stateBlock->glsl_program && shaderObj != 0) {
+ TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
+ GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
checkGLcall("glAttachObjectARB");
}
}
@@ -278,6 +279,8 @@ void set_glsl_shader_program(IWineD3DDev
struct glsl_shader_prog_link *newLink = NULL;
struct list *ptr = NULL;
GLhandleARB programId = 0;
+ int i;
+ char glsl_name[8];
ptr = list_head( &This->glsl_shader_progs );
while (ptr) {
@@ -287,7 +290,7 @@ void set_glsl_shader_program(IWineD3DDev
/* Existing Program found, use it */
TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
curLink->programId);
- This->stateBlock->shaderPrgId = curLink->programId;
+ This->stateBlock->glsl_program = curLink;
return;
}
/* This isn't the entry we need - try the next one */
@@ -297,11 +300,11 @@ void set_glsl_shader_program(IWineD3DDev
/* If we get to this point, then no matching program exists, so we create one */
programId = GL_EXTCALL(glCreateProgramObjectARB());
TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
- This->stateBlock->shaderPrgId = programId;
/* Allocate a new link for the list of programs */
newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
newLink->programId = programId;
+ This->stateBlock->glsl_program = newLink;
/* Attach GLSL vshader */
if (NULL != vshader && wined3d_settings.vs_selected_mode == SHADER_GLSL) {
@@ -341,6 +344,18 @@ void set_glsl_shader_program(IWineD3DDev
GL_EXTCALL(glLinkProgramARB(programId));
print_glsl_info_log(&GLINFO_LOCATION, programId);
list_add_head( &This->glsl_shader_progs, &newLink->entry);
+
+ newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
+ for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
+ snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
+ newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
+ }
+ newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
+ for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
+ snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
+ newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
+ }
+
return;
}
@@ -401,6 +416,10 @@ static void delete_glsl_shader_list(IWin
delete_glsl_shader_program(iface, curLink->programId);
+ /* Free the uniform locations */
+ HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
+ HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
+
/* Free the memory for this list item */
HeapFree(GetProcessHeap(), 0, curLink);
}
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 360efdd..5eb71f1 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -1791,20 +1791,21 @@ #undef BUFFER_OR_DATA
}
/* If GLSL is used for either pixel or vertex shaders, make a GLSL program
- * Otherwise set 0, which restores fixed function */
+ * Otherwise set NULL, to restore fixed function */
if ((wined3d_settings.vs_selected_mode == SHADER_GLSL && useVertexShaderFunction) ||
(wined3d_settings.ps_selected_mode == SHADER_GLSL && usePixelShaderFunction))
set_glsl_shader_program(iface);
else
- This->stateBlock->shaderPrgId = 0;
+ This->stateBlock->glsl_program = NULL;
/* If GLSL is used now, or might have been used before, (re)set the program */
if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
wined3d_settings.ps_selected_mode == SHADER_GLSL) {
- if (This->stateBlock->shaderPrgId)
- TRACE_(d3d_shader)("Using GLSL program %u\n", This->stateBlock->shaderPrgId);
- GL_EXTCALL(glUseProgramObjectARB(This->stateBlock->shaderPrgId));
+ GLhandleARB progId = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->programId : 0;
+ if (progId)
+ TRACE_(d3d_shader)("Using GLSL program %u\n", progId);
+ GL_EXTCALL(glUseProgramObjectARB(progId));
checkGLcall("glUseProgramObjectARB");
}
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index d222610..3c1d9ad 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -2,6 +2,7 @@
* GLSL pixel and vertex shader implementation
*
* Copyright 2006 Jason Green
+ * Copyright 2006 Henri Verbeet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -55,7 +56,7 @@ void shader_glsl_load_psamplers(
IWineD3DStateBlock* iface) {
IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface;
- GLhandleARB programId = stateBlock->shaderPrgId;
+ GLhandleARB programId = stateBlock->glsl_program->programId;
GLhandleARB name_loc;
int i;
char sampler_name[20];
@@ -77,19 +78,11 @@ void shader_glsl_load_psamplers(
* Loads floating point constants (aka uniforms) into the currently set GLSL program.
* When @constants_set == NULL, it will load all the constants.
*/
-void shader_glsl_load_constantsF(
- IWineD3DBaseShaderImpl* This,
- WineD3D_GL_Info *gl_info,
- GLhandleARB programId,
- unsigned max_constants,
- float* constants,
- BOOL* constants_set) {
-
+void shader_glsl_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info,
+ unsigned int max_constants, float* constants, GLhandleARB *constant_locations,
+ BOOL* constants_set) {
GLhandleARB tmp_loc;
int i;
- char tmp_name[8];
- char is_pshader = shader_is_pshader_version(This->baseShader.hex_version);
- const char* prefix = is_pshader? "PC":"VC";
struct list* ptr;
for (i=0; i<max_constants; ++i) {
@@ -99,10 +92,7 @@ void shader_glsl_load_constantsF(
constants[i * 4 + 0], constants[i * 4 + 1],
constants[i * 4 + 2], constants[i * 4 + 3]);
- /* TODO: Benchmark and see if it would be beneficial to store the
- * locations of the constants to avoid looking up each time */
- snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, i);
- tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name));
+ tmp_loc = constant_locations[i];
if (tmp_loc != -1) {
/* We found this uniform name in the program - go ahead and send the data */
GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, &constants[i * 4]));
@@ -121,8 +111,7 @@ void shader_glsl_load_constantsF(
TRACE("Loading local constants %i: %f, %f, %f, %f\n", idx,
values[0], values[1], values[2], values[3]);
- snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, idx);
- tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name));
+ tmp_loc = constant_locations[idx];
if (tmp_loc != -1) {
/* We found this uniform name in the program - go ahead and send the data */
GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, values));
@@ -258,12 +247,14 @@ void shader_glsl_load_constants(
IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface;
WineD3D_GL_Info *gl_info = &((IWineD3DImpl*)stateBlock->wineD3DDevice->wineD3D)->gl_info;
- GLhandleARB programId = stateBlock->shaderPrgId;
+ GLhandleARB *constant_locations;
+ GLhandleARB programId;
- if (programId == 0) {
+ if (!stateBlock->glsl_program) {
/* No GLSL program set - nothing to do. */
return;
}
+ programId = stateBlock->glsl_program->programId;
if (useVertexShader) {
IWineD3DBaseShaderImpl* vshader = (IWineD3DBaseShaderImpl*) stateBlock->vertexShader;
@@ -272,16 +263,17 @@ void shader_glsl_load_constants(
IWineD3DVertexDeclarationImpl* vertexDeclaration =
(IWineD3DVertexDeclarationImpl*) vshader_impl->vertexDeclaration;
+ constant_locations = stateBlock->glsl_program->vuniformF_locations;
+
if (NULL != vertexDeclaration && NULL != vertexDeclaration->constants) {
/* Load DirectX 8 float constants/uniforms for vertex shader */
- shader_glsl_load_constantsF(vshader, gl_info, programId, GL_LIMITS(vshader_constantsF),
- vertexDeclaration->constants, NULL);
+ shader_glsl_load_constantsF(vshader, gl_info, GL_LIMITS(vshader_constantsF),
+ vertexDeclaration->constants, constant_locations, NULL);
}
/* Load DirectX 9 float constants/uniforms for vertex shader */
- shader_glsl_load_constantsF(vshader, gl_info, programId, GL_LIMITS(vshader_constantsF),
- stateBlock->vertexShaderConstantF,
- stateBlock->set.vertexShaderConstantsF);
+ shader_glsl_load_constantsF(vshader, gl_info, GL_LIMITS(vshader_constantsF),
+ stateBlock->vertexShaderConstantF, constant_locations, stateBlock->set.vertexShaderConstantsF);
/* Load DirectX 9 integer constants/uniforms for vertex shader */
shader_glsl_load_constantsI(vshader, gl_info, programId, MAX_CONST_I,
@@ -298,13 +290,14 @@ void shader_glsl_load_constants(
IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader;
+ constant_locations = stateBlock->glsl_program->puniformF_locations;
+
/* Load pixel shader samplers */
shader_glsl_load_psamplers(gl_info, iface);
/* Load DirectX 9 float constants/uniforms for pixel shader */
- shader_glsl_load_constantsF(pshader, gl_info, programId, GL_LIMITS(pshader_constantsF),
- stateBlock->pixelShaderConstantF,
- stateBlock->set.pixelShaderConstantsF);
+ shader_glsl_load_constantsF(pshader, gl_info, GL_LIMITS(pshader_constantsF),
+ stateBlock->pixelShaderConstantF, constant_locations, stateBlock->set.pixelShaderConstantsF);
/* Load DirectX 9 integer constants/uniforms for pixel shader */
shader_glsl_load_constantsI(pshader, gl_info, programId, MAX_CONST_I,
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index ea77ecd..6dde429 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -166,7 +166,7 @@ void stateblock_copy(
Dest->pixelShader = This->pixelShader;
Dest->vertex_blend = This->vertex_blend;
Dest->tween_factor = This->tween_factor;
- Dest->shaderPrgId = This->shaderPrgId;
+ Dest->glsl_program = This->glsl_program;
/* Fixed size arrays */
memcpy(Dest->vertexShaderConstantB, This->vertexShaderConstantB, sizeof(BOOL) * MAX_CONST_B);
@@ -1067,9 +1067,9 @@ #endif
}
This->wineD3DDevice->currentPalette = 0;
- /* Set default GLSL program ID to 0. We won't actually create one
+ /* Set default GLSL program to NULL. We won't actually create one
* until the app sets a vertex or pixel shader */
- This->shaderPrgId = 0;
+ This->glsl_program = NULL;
TRACE("-----------------------> Device defaults now set up...\n");
return WINED3D_OK;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 0010062..bfa7510 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1120,7 +1120,7 @@ struct IWineD3DStateBlockImpl
DWORD samplerState[MAX_SAMPLERS][WINED3D_HIGHEST_SAMPLER_STATE + 1];
/* Current GLSL Shader Program */
- GLhandleARB shaderPrgId;
+ struct glsl_shader_prog_link *glsl_program;
};
extern void stateblock_savedstates_set(
@@ -1304,6 +1304,8 @@ typedef void (*SHADER_HANDLER) (struct S
struct glsl_shader_prog_link {
struct list entry;
GLhandleARB programId;
+ GLhandleARB *vuniformF_locations;
+ GLhandleARB *puniformF_locations;
IWineD3DVertexShader* vertexShader;
IWineD3DPixelShader* pixelShader;
};
More information about the wine-patches
mailing list