From 49f4c68e29a9eed401b8e0f3f33a03fbe0d47667 Mon Sep 17 00:00:00 2001 From: "H. Verbeet" Date: Sat, 19 Aug 2006 17:23:20 +0200 Subject: [PATCH] wined3d: Lookup GLSL float uniform locations only once per program. --- 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 84b26456bc5..75c8a6d4bc7 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(IWineD3DDevice *iface, IWineD3DBaseShader* shader 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(IWineD3DDevice *iface) { 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(IWineD3DDevice *iface) { /* 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(IWineD3DDevice *iface) { /* 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(IWineD3DDevice *iface) { 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(IWineD3DDevice* iface) { 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 360efddd2b3..5eb71f1ed17 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -1791,20 +1791,21 @@ inline static void drawPrimitiveDrawStrided( } /* 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 d222610f022..3c1d9ad2111 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; iwineD3DDevice->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 ea77ecdb6a2..6dde42972fb 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 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_InitStartupStateBlock(IWineD3DStat } 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 0010062c710..bfa75102a5d 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 SHADER_OPCODE_ARG*); struct glsl_shader_prog_link { struct list entry; GLhandleARB programId; + GLhandleARB *vuniformF_locations; + GLhandleARB *puniformF_locations; IWineD3DVertexShader* vertexShader; IWineD3DPixelShader* pixelShader; };