[4/4] wined3d: Improve float constant loading a bit

H. Verbeet hverbeet at gmail.com
Sat Aug 19 10:24:02 CDT 2006


The current way of loading float constants is quite expensive. This
patch makes wined3d use a list of constants that are set, instead of
looping through all constants and checking if they're set. This also
moves the TRACEs and checkGLcalls out of the loop. This should improve
performance somewhat for applications that use shaders.

Changelog:
  - Use a list to keep track of what constants are set
  - Move TRACEs and checkGLcall calls out of the main constant loading loop
-------------- next part --------------
 dlls/wined3d/arb_program_shader.c |   78 +++++++++++++++++++--------------
 dlls/wined3d/device.c             |   14 +++++-
 dlls/wined3d/glsl_shader.c        |   87 +++++++++++++++++++++++++------------
 dlls/wined3d/stateblock.c         |   13 ++++++
 dlls/wined3d/wined3d_private.h    |    7 +++
 5 files changed, 135 insertions(+), 64 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index 7aa6691..7a3fb70 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -8,6 +8,7 @@
  * Copyright 2005 Oliver Stieber
  * Copyright 2006 Ivan Gyurdiev
  * 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
@@ -41,48 +42,57 @@ #define GLINFO_LOCATION      (*gl_info)
 
 /** 
  * Loads floating point constants into the currently set ARB_vertex/fragment_program.
- * When @constants_set == NULL, it will load all the constants.
+ * When constant_list == NULL, it will load all the constants.
  *  
  * @target_type should be either GL_VERTEX_PROGRAM_ARB (for vertex shaders)
  *  or GL_FRAGMENT_PROGRAM_ARB (for pixel shaders)
  */
-void shader_arb_load_constantsF(
-    IWineD3DBaseShaderImpl* This,
-    WineD3D_GL_Info *gl_info,
-    GLuint target_type,
-    unsigned max_constants,
-    float* constants,
-    BOOL* constants_set) {
-
+static void shader_arb_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info, GLuint target_type,
+        unsigned int max_constants, float* constants, struct list *constant_list) {
+    constant_entry *constant;
+    local_constant* lconst;
     int i;
-    struct list* ptr;
-    
-    for (i=0; i<max_constants; ++i) {
-        if (NULL == constants_set || constants_set[i]) {
-            TRACE("Loading constants %i: %f, %f, %f, %f\n", i,
-                  constants[i * 4 + 0], constants[i * 4 + 1],
-                  constants[i * 4 + 2], constants[i * 4 + 3]);
-
-            GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, &constants[i * 4]));
-            checkGLcall("glProgramEnvParameter4fvARB");
+
+    if (!constant_list) {
+        if (TRACE_ON(d3d_shader)) {
+            for (i = 0; i < max_constants; ++i) {
+                TRACE("Loading constants %i: %f, %f, %f, %f\n", i,
+                        constants[i * 4 + 0], constants[i * 4 + 1],
+                        constants[i * 4 + 2], constants[i * 4 + 3]);
+            }
+        }
+        for (i = 0; i < max_constants; ++i) {
+            GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4)));
+        }
+        checkGLcall("glProgramEnvParameter4fvARB()");
+    } else {
+        if (TRACE_ON(d3d_shader)) {
+            LIST_FOR_EACH_ENTRY(constant, constant_list, constant_entry, entry) {
+                i = constant->idx;
+                TRACE("Loading constants %i: %f, %f, %f, %f\n", i,
+                        constants[i * 4 + 0], constants[i * 4 + 1],
+                        constants[i * 4 + 2], constants[i * 4 + 3]);
+            }
         }
+        LIST_FOR_EACH_ENTRY(constant, constant_list, constant_entry, entry) {
+            i = constant->idx;
+            GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4)));
+        }
+        checkGLcall("glProgramEnvParameter4fvARB()");
     }
 
     /* Load immediate constants */
-    ptr = list_head(&This->baseShader.constantsF);
-    while (ptr) {
-
-        local_constant* lconst = LIST_ENTRY(ptr, struct local_constant, entry);
-        unsigned int idx = lconst->idx;
-        GLfloat* values = (GLfloat*) lconst->value;
-
-        TRACE("Loading local constants %i: %f, %f, %f, %f\n", idx,
-            values[0], values[1], values[2], values[3]);
-
-        GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, idx, values));
-        checkGLcall("glProgramEnvParameter4fvARB");
-        ptr = list_next(&This->baseShader.constantsF, ptr);
+    if (TRACE_ON(d3d_shader)) {
+        LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
+            GLfloat* values = (GLfloat*)lconst->value;
+            TRACE("Loading local constants %i: %f, %f, %f, %f\n", lconst->idx,
+                    values[0], values[1], values[2], values[3]);
+        }
+    }
+    LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
+        GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, lconst->idx, (GLfloat*)lconst->value));
     }
+    checkGLcall("glProgramEnvParameter4fvARB()");
 }
 
 /**
@@ -116,7 +126,7 @@ void shader_arb_load_constants(
         shader_arb_load_constantsF(vshader, gl_info, GL_VERTEX_PROGRAM_ARB,
                                    GL_LIMITS(vshader_constantsF),
                                    stateBlock->vertexShaderConstantF,
-                                   stateBlock->set.vertexShaderConstantsF);
+                                   &stateBlock->set_vconstantsF);
     }
 
     if (usePixelShader) {
@@ -127,7 +137,7 @@ void shader_arb_load_constants(
         shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB, 
                                    GL_LIMITS(pshader_constantsF),
                                    stateBlock->pixelShaderConstantF,
-                                   stateBlock->set.pixelShaderConstantsF);
+                                   &stateBlock->set_pconstantsF);
     }
 }
 
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 5f39a42..49f2cf1 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4882,8 +4882,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl
            srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
 
     for (i = start; i < cnt + start; ++i) {
+        if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
+            constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
+            ptr->idx = i;
+            list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
+            This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
+        }
         This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
-        This->updateStateBlock->set.vertexShaderConstantsF[i]     = TRUE;
     }
 
     return WINED3D_OK;
@@ -5064,8 +5069,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl
            srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
 
     for (i = start; i < cnt + start; ++i) {
+        if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
+            constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
+            ptr->idx = i;
+            list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
+            This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
+        }
         This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
-        This->updateStateBlock->set.pixelShaderConstantsF[i]     = TRUE;
     }
 
     return WINED3D_OK;
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 3c1d9ad..2ff147c 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -76,49 +76,77 @@ 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.
+ * When constant_list == NULL, it will load all the constants.
  */
-void shader_glsl_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info,
+static void shader_glsl_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info,
         unsigned int max_constants, float* constants, GLhandleARB *constant_locations,
-        BOOL* constants_set) {
+        struct list *constant_list) {
+    local_constant* lconst;
     GLhandleARB tmp_loc;
     int i;
-    struct list* ptr;
-
-    for (i=0; i<max_constants; ++i) {
-        if (NULL == constants_set || constants_set[i]) {
-
-            TRACE("Loading constants %i: %f, %f, %f, %f\n", i,
-                  constants[i * 4 + 0], constants[i * 4 + 1],
-                  constants[i * 4 + 2], constants[i * 4 + 3]);
 
+    if (!constant_list) {
+        if (TRACE_ON(d3d_shader)) {
+            for (i = 0; i < max_constants; ++i) {
+                tmp_loc = constant_locations[i];
+                if (tmp_loc != -1) {
+                    TRACE("Loading constants %i: %f, %f, %f, %f\n", i,
+                            constants[i * 4 + 0], constants[i * 4 + 1],
+                            constants[i * 4 + 2], constants[i * 4 + 3]);
+                }
+            }
+        }
+        for (i = 0; i < max_constants; ++i) {
+            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)));
+            }
+        }
+        checkGLcall("glUniform4fvARB()");
+    } else {
+        constant_entry *constant;
+        if (TRACE_ON(d3d_shader)) {
+            LIST_FOR_EACH_ENTRY(constant, constant_list, constant_entry, entry) {
+                i = constant->idx;
+                tmp_loc = constant_locations[i];
+                if (tmp_loc != -1) {
+                    TRACE("Loading constants %i: %f, %f, %f, %f\n", i,
+                            constants[i * 4 + 0], constants[i * 4 + 1],
+                            constants[i * 4 + 2], constants[i * 4 + 3]);
+                }
+            }
+        }
+        LIST_FOR_EACH_ENTRY(constant, constant_list, constant_entry, entry) {
+            i = constant->idx;
             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]));
-                checkGLcall("glUniform4fvARB");
+                GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, constants + (i * 4)));
             }
         }
+        checkGLcall("glUniform4fvARB()");
     }
 
     /* Load immediate constants */
-    ptr = list_head(&This->baseShader.constantsF);
-    while (ptr) {
-        local_constant* lconst = LIST_ENTRY(ptr, struct local_constant, entry);
-        unsigned int idx = lconst->idx;
-        GLfloat* values = (GLfloat*) lconst->value;
-
-        TRACE("Loading local constants %i: %f, %f, %f, %f\n", idx,
-            values[0], values[1], values[2], values[3]);
-
-        tmp_loc = constant_locations[idx];
+    if (TRACE_ON(d3d_shader)) {
+        LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
+            tmp_loc = constant_locations[lconst->idx];
+            if (tmp_loc != -1) {
+                GLfloat* values = (GLfloat*)lconst->value;
+                TRACE("Loading local constants %i: %f, %f, %f, %f\n", lconst->idx,
+                        values[0], values[1], values[2], values[3]);
+            }
+        }
+    }
+    LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
+        tmp_loc = constant_locations[lconst->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));
-            checkGLcall("glUniform4fvARB");
+            GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, (GLfloat*)lconst->value));
         }
-        ptr = list_next(&This->baseShader.constantsF, ptr);
     }
+    checkGLcall("glUniform4fvARB()");
 }
 
 /** 
@@ -248,6 +276,7 @@ void shader_glsl_load_constants(
     IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface;
     WineD3D_GL_Info *gl_info = &((IWineD3DImpl*)stateBlock->wineD3DDevice->wineD3D)->gl_info;
     GLhandleARB *constant_locations;
+    struct list *constant_list;
     GLhandleARB programId;
     
     if (!stateBlock->glsl_program) {
@@ -264,6 +293,7 @@ void shader_glsl_load_constants(
             (IWineD3DVertexDeclarationImpl*) vshader_impl->vertexDeclaration;
 
         constant_locations = stateBlock->glsl_program->vuniformF_locations;
+        constant_list = &stateBlock->set_vconstantsF;
 
         if (NULL != vertexDeclaration && NULL != vertexDeclaration->constants) {
             /* Load DirectX 8 float constants/uniforms for vertex shader */
@@ -273,7 +303,7 @@ void shader_glsl_load_constants(
 
         /* Load DirectX 9 float constants/uniforms for vertex shader */
         shader_glsl_load_constantsF(vshader, gl_info, GL_LIMITS(vshader_constantsF),
-                stateBlock->vertexShaderConstantF, constant_locations, stateBlock->set.vertexShaderConstantsF);
+                stateBlock->vertexShaderConstantF, constant_locations, constant_list);
 
         /* Load DirectX 9 integer constants/uniforms for vertex shader */
         shader_glsl_load_constantsI(vshader, gl_info, programId, MAX_CONST_I,
@@ -291,13 +321,14 @@ void shader_glsl_load_constants(
         IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader;
 
         constant_locations = stateBlock->glsl_program->puniformF_locations;
+        constant_list = &stateBlock->set_pconstantsF;
 
         /* 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, GL_LIMITS(pshader_constantsF),
-                stateBlock->pixelShaderConstantF, constant_locations, stateBlock->set.pixelShaderConstantsF);
+                stateBlock->pixelShaderConstantF, constant_locations, constant_list);
 
         /* 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 6dde429..823bc7a 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -53,6 +53,9 @@ #define WINED3D_MEMCHECK(_object) if (NU
     object->changed.vertexShaderConstantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BOOL) * GL_LIMITS(vshader_constantsF));
     WINED3D_MEMCHECK(object->changed.vertexShaderConstantsF);
 
+    list_init(&object->set_vconstantsF);
+    list_init(&object->set_pconstantsF);
+
 #undef WINED3D_MEMCHECK
 
     return WINED3D_OK;
@@ -225,6 +228,8 @@ static ULONG  WINAPI IWineD3DStateBlockI
     TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
 
     if (!refCount) {
+        constant_entry *constant, *constant2;
+
         /* type 0 represents the primary stateblock, so free all the resources */
         if (This->blockType == WINED3DSBT_INIT) {
             int counter;
@@ -274,6 +279,14 @@ static ULONG  WINAPI IWineD3DStateBlockI
         HeapFree(GetProcessHeap(), 0, This->set.pixelShaderConstantsF);
         HeapFree(GetProcessHeap(), 0, This->changed.pixelShaderConstantsF);
 
+        LIST_FOR_EACH_ENTRY_SAFE(constant, constant2, &This->set_vconstantsF, constant_entry, entry) {
+            HeapFree(GetProcessHeap(), 0, constant);
+        }
+
+        LIST_FOR_EACH_ENTRY_SAFE(constant, constant2, &This->set_pconstantsF, constant_entry, entry) {
+            HeapFree(GetProcessHeap(), 0, constant);
+        }
+
         HeapFree(GetProcessHeap(), 0, This);
     }
     return refCount;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index bfa7510..5d7af02 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1040,6 +1040,11 @@ typedef struct SAVEDSTATES {
         BOOL                     *vertexShaderConstantsF;
 } SAVEDSTATES;
 
+typedef struct {
+    struct list entry;
+    int idx;
+} constant_entry;
+
 struct IWineD3DStateBlockImpl
 {
     /* IUnknown fields */
@@ -1054,6 +1059,8 @@ struct IWineD3DStateBlockImpl
     /* Array indicating whether things have been set or changed */
     SAVEDSTATES               changed;
     SAVEDSTATES               set;
+    struct list               set_vconstantsF;
+    struct list               set_pconstantsF;
 
     /* Drawing - Vertex Shader or FVF related */
     DWORD                     fvf;


More information about the wine-patches mailing list