WineD3D patches for review and discussion - not to be applied as-is.

Jason Green jave27 at gmail.com
Fri May 26 01:17:41 CDT 2006


All of these apply to the latest Git tree, and should come after my
last patch submission to wine-patches, but it shouldn't matter.  I'm
just looking for a little more feedback on these before I submit.
This should lay the groundwork to begin implementing GLSL opcode
generation.  I've hacked around with some of them, and this will
succesfully generate a GLSL shader program if the opcodes are
implemented properly.

Please let me know if any of my ideas here are fundamentally flawed.
We've worked a bunch of it out on IRC, but this should be a nicer
version to look at than my stuff at pastebin.  :-)

None of this code changes anything for the end-result
ARB_vertex/fragment_program.  It only generates GLSL if you have this
regkey:

HKLU\Software\Wine\Direct3D\UseGLSL = "enabled"
-------------- next part --------------
>From nobody Mon Sep 17 00:00:00 2001
From: Jason Green <jave27 at gmail.com>
Date: Fri, 26 May 2006 01:04:37 -0400
To: wine-patches <wine-patches at winehq.org>
Subject: [PATCH 1/5] Add ability to generate GLSL shader objects for vertex and pixel shaders.

- Also modifies the baseshader declarations, and a few minor trace/formatting cleanups.

---

 dlls/wined3d/baseshader.c   |   26 ++++++++++++++++++++++----
 dlls/wined3d/pixelshader.c  |   25 +++++++++++++++++++++++--
 dlls/wined3d/vertexshader.c |   31 +++++++++++++++++++++++++++++--
 3 files changed, 74 insertions(+), 8 deletions(-)

77c5f0e5fc62b66943b762730d927ee2553ef842
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index 4e30421..cba12f5 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -549,8 +549,28 @@ void generate_glsl_declarations(
     shader_reg_maps* reg_maps,
     SHADER_BUFFER* buffer) {
 
+    IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
+    int i;
+
     FIXME("GLSL not fully implemented yet.\n");
 
+    /* Declare the constants (aka uniforms) */
+    shader_addline(buffer, "uniform vec4 C[%u];\n", This->baseShader.limits.constant_float);
+
+    /* Declare address variables */
+    for (i = 0; i < This->baseShader.limits.address; i++) {
+        if (reg_maps->address & (1 << i))
+            shader_addline(buffer, "ivec4 A%ld;\n", i);
+    }
+
+    /* Declare temporary variables */
+    for(i = 0; i < This->baseShader.limits.temporary; i++) {
+        if (reg_maps->temporary & (1 << i))
+            shader_addline(buffer, "vec4 R%lu;\n", i);
+    }
+
+    /* Start the main program */
+    shader_addline(buffer, "void main() {\n");
 }
 
 /** Shared code in order to generate the bulk of the shader string.
@@ -585,7 +605,6 @@ void generate_base_shader(
     /* Pre-declare registers */
     if (wined3d_settings.shader_mode == SHADER_GLSL) {
         generate_glsl_declarations(iface, &reg_maps, buffer);
-        shader_addline(buffer, "void main() {\n");
     } else {
         generate_arb_declarations(iface, &reg_maps, buffer);
     }
@@ -680,8 +699,7 @@ void generate_base_shader(
 /** Prints the GLSL info log which will contain error messages if they exist */
 void print_glsl_info_log(
     WineD3D_GL_Info *gl_info,
-    GLhandleARB obj)
-{
+    GLhandleARB obj) {
     int infologLength = 0;
     char *infoLog;
 
@@ -693,7 +711,7 @@ void print_glsl_info_log(
     {
         infoLog = (char *)HeapAlloc(GetProcessHeap(), 0, infologLength);
         GL_EXTCALL(glGetInfoLogARB(obj, infologLength, NULL, infoLog));
-        FIXME("Error received from GLSL shader #%u: %s", obj, debugstr_a(infoLog));
+        FIXME("Error received from GLSL shader #%u: %s\n", obj, debugstr_a(infoLog));
         HeapFree(GetProcessHeap(), 0, infoLog);
     }
 }
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index be4fbb8..5720ea0 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -1298,8 +1298,29 @@ #endif
     buffer.bsize = 0;
     buffer.lineNo = 0;
 
-    /* TODO: Optionally, generate the GLSL shader instead */
-    if (GL_SUPPORT(ARB_VERTEX_PROGRAM)) {
+    if (wined3d_settings.shader_mode == SHADER_GLSL) {
+
+        /* Create the hw GLSL shader object and assign it as the baseShader.prgId */
+        GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB));
+        int success_flag = 0;
+
+        /* Generate the bulk of the shader code */
+        generate_base_shader( (IWineD3DBaseShader*) This, &buffer, pFunction);
+
+        shader_addline(&buffer, "}\n\0");
+
+        TRACE("Compiling shader object %u\n", shader_obj);
+        GL_EXTCALL(glShaderSourceARB(shader_obj, 1, (const char**)&buffer.buffer, NULL));
+        GL_EXTCALL(glCompileShaderARB(shader_obj));
+        GL_EXTCALL(glGetObjectParameterivARB(shader_obj,
+                   GL_OBJECT_COMPILE_STATUS_ARB, &success_flag));
+        if (success_flag == FALSE) /* Print any compile errors in our shader */
+            print_glsl_info_log(&GLINFO_LOCATION, shader_obj);
+
+        /* Store the shader object */
+        This->baseShader.prgId = shader_obj;
+
+    } else if (wined3d_settings.shader_mode == SHADER_ARB) {
         /*  Create the hw ARB shader */
         shader_addline(&buffer, "!!ARBfp1.0\n");
 
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index cb8d973..03f0ce0 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -1063,8 +1063,35 @@ #endif
     buffer.bsize = 0;
     buffer.lineNo = 0;
 
-    /* TODO: Optionally, generate the GLSL shader instead */
-    if (GL_SUPPORT(ARB_VERTEX_PROGRAM)) {
+    if (wined3d_settings.shader_mode == SHADER_GLSL) {
+
+        /* Create the hw GLSL shader program and assign it as the baseShader.prgId */
+        GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB));
+        int i;
+        int success_flag = 0;
+
+        /* Declare all named attributes (TODO: Add this to the reg_maps and only declare those that are needed)*/
+        for (i = 0; i < 16; ++i)
+            shader_addline(&buffer, "attribute vec4 attrib%i;\n", i);
+
+        /* Generate the bulk of the shader code */
+        generate_base_shader( (IWineD3DBaseShader*) This, &buffer, pFunction);
+
+        shader_addline(&buffer, "}\n\0");
+
+        TRACE("Compiling shader object %u\n", shader_obj);
+        GL_EXTCALL(glShaderSourceARB(shader_obj, 1, (const char**)&buffer.buffer, NULL));
+        GL_EXTCALL(glCompileShaderARB(shader_obj));
+        GL_EXTCALL(glGetObjectParameterivARB(shader_obj,
+                   GL_OBJECT_COMPILE_STATUS_ARB, &success_flag));
+        if (success_flag == FALSE) /* Print any compile errors in our shader */
+            print_glsl_info_log(&GLINFO_LOCATION, shader_obj);
+
+       /* Store the shader object */
+        This->baseShader.prgId = shader_obj;
+
+    } else if (wined3d_settings.shader_mode == SHADER_ARB) {
+
         /*  Create the hw ARB shader */
         shader_addline(&buffer, "!!ARBvp1.0\n");
 
-- 
1.3.3







-------------- next part --------------
>From nobody Mon Sep 17 00:00:00 2001
From: Jason Green <jave27 at gmail.com>
Date: Fri, 26 May 2006 01:46:29 -0400
To: wine-patches <wine-patches at winehq.org>
Subject: [PATCH 5/5] Add ability to store the GLSL Shader Program Object on the stateblock

- When the app calls SetPixelShader or SetVertexShader, those functions will now either:
 - Create a new Program object and attach themselves to it,
 - or attach themselves to the existing object
- Then, they will link into that object.
- They will Detach old objects if necessary.

---

 dlls/wined3d/device.c          |   82 ++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/stateblock.c      |   14 +++++++
 dlls/wined3d/wined3d_private.h |    3 +
 3 files changed, 99 insertions(+), 0 deletions(-)

c7bdccd97e7bd53a5b49bbce454c7628016b820b
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index eff9504..ff2b8c9 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -27,9 +27,11 @@ #include "config.h"
 #ifdef HAVE_FLOAT_H
 # include <float.h>
 #endif
+#include <stdio.h>
 #include "wined3d_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
+WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
 
 /* x11drv GDI escapes */
@@ -4341,6 +4343,51 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetVer
         IWineD3DVertexShader_Release(oldShader);
     }
 
+    /* If we're using GLSL, we need to possibly create a Shader Program at this point,
+     * unless one is already set, then we need to attach the vertex shader object to it */
+    if (NULL != pShader && wined3d_settings.shader_mode == SHADER_GLSL
+        && oldShader != pShader) {
+
+        GLhandleARB programId = This->updateStateBlock->shaderPrgId;
+        GLhandleARB shaderObj = ((IWineD3DVertexShaderImpl*)pShader)->baseShader.prgId;
+        int success_flag = 0;
+
+        if (programId == 0) {
+            /* No shader program is set, create a new program */
+            programId = GL_EXTCALL(glCreateProgramObjectARB());
+            TRACE_(d3d_shader)("Creating new shader program %u\n", programId);
+
+	    /* Store this programId on the stateblock */
+           This->updateStateBlock->shaderPrgId = programId;
+        } else if (oldShader != NULL) {
+            /* Detach the old shader object */
+            TRACE_(d3d_shader)("Detaching shader object %u from program %u\n",
+                ((IWineD3DVertexShaderImpl*)oldShader)->baseShader.prgId, programId);
+            GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
+            checkGLcall("glDetachObjectARB");
+        }
+
+        TRACE_(d3d_shader)("Attaching shader object %u to program %u\n", shaderObj, programId);
+        GL_EXTCALL(glAttachObjectARB(programId, shaderObj));
+        checkGLcall("glAttachObjectARB");
+        GL_EXTCALL(glLinkProgramARB(programId));
+        GL_EXTCALL(glGetObjectParameterivARB(programId,
+                   GL_OBJECT_LINK_STATUS_ARB, &success_flag));
+        if (!success_flag) {
+            /* Print any linking errors in our shader */
+            print_glsl_info_log(&GLINFO_LOCATION, programId);
+        } else {
+            /* Bind vertex attributes to a corresponding index number */
+            int i;
+	    char tmp_name[10];
+            for (i = 0; i < 16; ++i) {
+                sprintf(tmp_name, "attrib%i", i);
+                glBindAttribLocationARB(programId, i, tmp_name);
+            }
+            checkGLcall("glBindAttribLocationARB");
+        }
+    }
+
     if (pShader != NULL && ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration != NULL) {
         TRACE("(%p) : setting vertexDeclaration(%p)\n", This, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration);
         IWineD3DDevice_SetVertexDeclaration(iface, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration);
@@ -4522,6 +4569,41 @@ HRESULT WINAPI IWineD3DDeviceImpl_SetPix
         IWineD3DPixelShader_Release(oldShader);
     }
 
+    /* If we're using GLSL, we need to possibly create a Shader Program at this point,
+    * unless one is already set, then we need to attach the pixel shader object to it */
+    if (NULL != pShader && wined3d_settings.shader_mode == SHADER_GLSL) {
+
+        GLhandleARB programId = This->updateStateBlock->shaderPrgId;
+        GLhandleARB shaderObj = ((IWineD3DPixelShaderImpl*)pShader)->baseShader.prgId;
+        int success_flag = 0;
+
+        if (programId == 0) {
+            /* No shader program is set, create a new program */
+            programId = GL_EXTCALL(glCreateProgramObjectARB());
+            TRACE_(d3d_shader)("Creating new shader program %u\n", programId);
+
+            /* Store this programId on the stateblock */
+            This->updateStateBlock->shaderPrgId = programId;
+        } else if (oldShader != NULL) {
+            /* Detach the old shader object */
+            TRACE_(d3d_shader)("Detaching shader object %u from program %u\n",
+            ((IWineD3DPixelShaderImpl*)oldShader)->baseShader.prgId, programId);
+            GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
+            checkGLcall("glDetachObjectARB");
+        }
+
+        TRACE_(d3d_shader)("Attaching shader object %u to program %u\n", shaderObj, programId);
+        GL_EXTCALL(glAttachObjectARB(programId, shaderObj));
+        checkGLcall("glAttachObjectARB");
+        GL_EXTCALL(glLinkProgramARB(programId));
+        GL_EXTCALL(glGetObjectParameterivARB(programId,
+                   GL_OBJECT_LINK_STATUS_ARB, &success_flag));
+        if (!success_flag) {
+            /* Print any linking errors in our shader */
+            print_glsl_info_log(&GLINFO_LOCATION, programId);
+        }
+    }
+
     TRACE("(%p) : setting pShader(%p)\n", This, pShader);
     /**
      * TODO: merge HAL shaders context switching from prototype
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index af1a265..79e5a61 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -24,6 +24,7 @@ #include "config.h"
 #include "wined3d_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
+WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->wineD3DDevice)->wineD3D))->gl_info
 
 /**********************************************************
@@ -85,6 +86,14 @@ ULONG WINAPI IWineD3DStateBlockImpl_Rele
                 IWineD3DVertexShader_Release(This->vertexShader);
             }
 
+	    if ((NULL != This->pixelShader || NULL != This->vertexShader) && This->shaderPrgId != 0) {
+                ENTER_GL();
+                TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", This->shaderPrgId);
+                GL_EXTCALL(glDeleteObjectARB(This->shaderPrgId));
+                checkGLcall("glDeleteObjectARB");
+                LEAVE_GL();
+            }
+            
             if (NULL != This->vertexDecl) {
                 IWineD3DVertexDeclaration_Release(This->vertexDecl);
             }
@@ -164,6 +173,7 @@ HRESULT WINAPI IWineD3DStateBlockImpl_Ca
             }
 
             This->vertexShader = targetStateBlock->vertexShader;
+            This->shaderPrgId  = targetStateBlock->shaderPrgId;
         }
 
         /* Vertex Shader Constants */
@@ -228,6 +238,7 @@ HRESULT WINAPI IWineD3DStateBlockImpl_Ca
             }
 
             This->pixelShader = targetStateBlock->pixelShader;
+            This->shaderPrgId = targetStateBlock->shaderPrgId;
         }
 
         /* Pixel Shader Constants */
@@ -853,6 +864,9 @@ #endif
     }
     This->wineD3DDevice->currentPalette = 0;
 
+    /* Set default GLSL program ID to 0 */
+    This->shaderPrgId = 0;
+
     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 3e3bf80..47b9583 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1071,6 +1071,9 @@ struct IWineD3DStateBlockImpl
     DWORD                     textureState[MAX_TEXTURES][WINED3D_HIGHEST_TEXTURE_STATE + 1];
     /* Sampler States */
     DWORD                     samplerState[MAX_SAMPLERS][WINED3D_HIGHEST_SAMPLER_STATE + 1];
+    
+    /* GLSL Shader program ID */
+    GLhandleARB               shaderPrgId;
 
 };
 
-- 
1.3.3







-------------- next part --------------
>From nobody Mon Sep 17 00:00:00 2001
From: Jason Green <jave27 at gmail.com>
Date: Fri, 26 May 2006 01:22:53 -0400
To: wine-patches <wine-patches at winehq.org>
Subject: [PATCH 3/5] Add ability to draw primitives with GLSL shaders.

- If wined3d_settings.shader_mode == SHADER_GLSL, then Wine will now attempt to generate a GLSL shader program.
- Breaks out constant/uniform loading into a separate function
- Fixed up a little bit of whitespace for readability.

---

 dlls/wined3d/drawprim.c |  249 +++++++++++++++++++++++++++--------------------
 1 files changed, 145 insertions(+), 104 deletions(-)

ae930222ec5ac9d6a02ef866779859de49284c79
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 9f5994a..27f0e51 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -28,9 +28,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
 
-#ifdef SHOW_FRAME_MAKEUP
 #include <stdio.h>
-#endif
 
 #if 0 /* TODO */
 extern IWineD3DVertexShaderImpl*            VertexShaders[64];
@@ -1694,10 +1692,67 @@ void drawStridedSoftwareVS(IWineD3DDevic
 
 #endif
 
-void inline  drawPrimitiveDrawStrided(IWineD3DDevice *iface, BOOL useVertexShaderFunction, BOOL usePixelShaderFunction, int useHW, WineDirect3DVertexStridedData *dataLocations,
-UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idxData, short idxSize, int minIndex, long StartIdx) {
+/* Load the given constants into either GLSL or ARB shader programs.
+ * TODO: Add support for ints & bools, too. */
+void loadConstants(IWineD3DDevice *iface,
+                   GLenum target_type, 
+                   float* constants, 
+                   WINESHADERCNST* constant_types, 
+                   unsigned max_constants,
+                   GLhandleARB programId,
+                   BOOL skip_type_compare) {
+
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    int i;
+    char tmp_name[7];
+    GLuint tmp_loc;
+
+    if (wined3d_settings.shader_mode == SHADER_GLSL) {
+        /* TODO: Benchmark and see if it would be beneficial to store the 
+         * locations of the constants to avoid looking up each time */
+        for (i=0; i<max_constants; ++i) {
+            if (skip_type_compare || WINESHADERCNST_FLOAT == constant_types[i]) {
+                TRACE_(d3d_shader)("Loading constants %i: %f, %f, %f, %f\n",
+                        i, constants[i*4], constants[i*4+1], constants[i*4+2], constants[i*4+3]);
+
+                sprintf(tmp_name, "C[%i]", i);
+                tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name));
+                GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, &constants[i*4]));
+                checkGLcall("glUniform4fv");
+            }
+        }
+    } else if (wined3d_settings.shader_mode == SHADER_ARB) {
+        for (i=0; i<max_constants; ++i) {
+            if (skip_type_compare || WINESHADERCNST_FLOAT == constant_types[i]) {
+                TRACE_(d3d_shader)("Loading constants %i: %f, %f, %f, %f\n",
+                        i, constants[i*4], constants[i*4+1], constants[i*4+2], constants[i*4+3]);
+
+                GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, &constants[i*4]));
+                checkGLcall("glProgramEnvParameter4fvARB");
+            }
+        }
+    } else {
+        /* We should never get here */
+        ERR("Cannot load constants\n");
+    }
+}
+
+void inline drawPrimitiveDrawStrided(IWineD3DDevice *iface,
+                              BOOL useVertexShaderFunction,
+                              BOOL usePixelShaderFunction,
+                              int useHW,
+                              WineDirect3DVertexStridedData *dataLocations,
+                              UINT numberOfvertices,
+                              UINT numberOfIndicies,
+                              GLenum glPrimType,
+                              const void *idxData,
+                              short idxSize,
+                              int minIndex,
+                              long StartIdx) {
 
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    GLhandleARB programId = This->stateBlock->shaderPrgId;
+ 
     /* Now draw the graphics to the screen */
     if  (FALSE /* disable software vs for now */ && useVertexShaderFunction && !useHW) {
         FIXME("drawing using software vertex shaders (line %d)\n", __LINE__);
@@ -1768,131 +1823,110 @@ #if 0/* TODO: Vertex fixups (diffuse and
         fixupVertices(This, dataLocations, &transformedDataLocations, 1 + endStride - startStride, startStride);
 #endif
 
-         /* vertex shaders */
-
-        /* If the only vertex data used by the shader is supported by OpenGL then*/
-        if ((!useVertexShaderFunction  && dataLocations->u.s.pSize.lpData == NULL
-                && dataLocations->u.s.diffuse.lpData == NULL  && dataLocations->u.s.specular.lpData == NULL) 
-                || (useVertexShaderFunction && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->namedArrays && !((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->declaredArrays)) {
-
-            /* Load the vertex data using named arrays */
-            TRACE("(%p) Loading vertex data\n", This);
-            loadVertexData(iface, dataLocations);
+    /* vertex shaders */
+    if ((!useVertexShaderFunction  && dataLocations->u.s.pSize.lpData == NULL
+        && dataLocations->u.s.diffuse.lpData == NULL
+        && dataLocations->u.s.specular.lpData == NULL) 
+        || (useVertexShaderFunction && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->namedArrays
+            && !((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->declaredArrays)) {
+        /* The only vertex data used by the shader is supported by OpenGL */
+        
+        /* Load the vertex data using named arrays */
+        TRACE("(%p) Loading vertex data\n", This);
+        loadVertexData(iface, dataLocations);
+
+    } else if(useVertexShaderFunction && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->declaredArrays) {
+        /* load the array data using ordinal mapping */
+        loadNumberedArrays(iface, dataLocations, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->arrayUsageMap);
 
-        } else /* Otherwise */
-            if(useVertexShaderFunction && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->declaredArrays) {
-
-            /* load the array data using ordinal mapping */
-            loadNumberedArrays(iface, dataLocations, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->arrayUsageMap);
-
-        } else { /* If this happens we must drawStridedSlow later on */ 
-		TRACE("Not loading vertex data\n");
-        }
+    } else {
+        /* If this happens we must drawStridedSlow later on */ 
+        TRACE("Not loading vertex data\n");
+    }
 
-        TRACE("Loaded arrays\n");
+    TRACE("Loaded arrays\n");
 
-        if (useVertexShaderFunction) {
-            IWineD3DVertexDeclarationImpl *vertexDeclaration;
-            int i;
+    /* We need to use a single shader program if we are using GLSL and either pixel or vertex shaders */
+    if (wined3d_settings.shader_mode == SHADER_GLSL && 
+        (useVertexShaderFunction || usePixelShaderFunction)) {
+        GL_EXTCALL(glUseProgramObjectARB(programId));
+        checkGLcall("glUseProgramObjectARB");
+    }
+    
+    if (useVertexShaderFunction) {
+        IWineD3DVertexDeclarationImpl *vertexDeclaration;
 
-            TRACE("Using vertex shader\n");
+        TRACE("Using vertex shader\n");
 
+        if (wined3d_settings.shader_mode == SHADER_ARB) {
             /* Bind the vertex program */
             GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB,
-                ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
+                    ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
             checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
 
             /* Enable OpenGL vertex programs */
             glEnable(GL_VERTEX_PROGRAM_ARB);
             checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
             TRACE_(d3d_shader)("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n",
-                This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId);
-
-            /* Vertex Shader 8 constants */
-            vertexDeclaration = (IWineD3DVertexDeclarationImpl *)
+            This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId);
+        }
+        
+        /* Vertex Shader 8 constants */
+        vertexDeclaration = (IWineD3DVertexDeclarationImpl *)
                 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
-            if (vertexDeclaration != NULL) {
-                float *constants = vertexDeclaration->constants;
-                if (constants != NULL) {
-                    for (i = 0; i <=  WINED3D_VSHADER_MAX_CONSTANTS; ++i) {
-                        TRACE_(d3d_shader)("Not loading constants %u = %f %f %f %f\n", i,
-                        constants[i * 4], constants[i * 4 + 1], constants[i * 4 + 2], constants[i * 4 + 3]);
-                        GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, i, &constants[i * 4]));
-                    }
-                }
-            }
+        if (vertexDeclaration != NULL && vertexDeclaration->constants != NULL) {
+            float *constants = vertexDeclaration->constants;
+            loadConstants(iface, GL_VERTEX_PROGRAM_ARB, constants, NULL, WINED3D_VSHADER_MAX_CONSTANTS, programId, TRUE);
+        }
 
-            /* Update the constants */
-            for (i = 0; i < WINED3D_VSHADER_MAX_CONSTANTS; ++i) {
-                /* TODO: add support for Integer and Boolean constants */
-                if (WINESHADERCNST_FLOAT == This->stateBlock->vertexShaderConstantT[i]) {
+        /* Update the constants */
+        loadConstants(iface, GL_VERTEX_PROGRAM_ARB, This->stateBlock->vertexShaderConstantF,
+                      This->stateBlock->vertexShaderConstantT, WINED3D_VSHADER_MAX_CONSTANTS, programId, FALSE);
+    }
 
-                    GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, i,
-                        &This->stateBlock->vertexShaderConstantF[i * 4]));
+    if (usePixelShaderFunction) {
 
-                    TRACE_(d3d_shader)("Loading constants %u = %f %f %f %f\n", i,
-                        This->stateBlock->vertexShaderConstantF[i * 4],
-                        This->stateBlock->vertexShaderConstantF[i * 4 + 1],
-                        This->stateBlock->vertexShaderConstantF[i * 4 + 2],
-                        This->stateBlock->vertexShaderConstantF[i * 4 + 3]);
-                        checkGLcall("glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB");
-                }
-            }
-        }
+        TRACE("Using pixel shader\n");
 
-        if (usePixelShaderFunction) {
-            int i;
-
-            TRACE("Using pixel shader\n");
-
-             /* Bind the fragment program */
-             GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
-                 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
-             checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
-
-             /* Enable OpenGL fragment programs */
-             glEnable(GL_FRAGMENT_PROGRAM_ARB);
-             checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
-             TRACE_(d3d_shader)("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n",
-                 This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
-
-             /* Update the constants */
-             for (i = 0; i < WINED3D_PSHADER_MAX_CONSTANTS; ++i) {
-                 /* TODO: add support for Integer and Boolean constants */
-                 if (WINESHADERCNST_FLOAT == This->stateBlock->pixelShaderConstantT[i]) {
-                     GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i,
-                        &This->stateBlock->pixelShaderConstantF[i * 4]));
-                     TRACE_(d3d_shader)("Loading constants %u = %f %f %f %f\n", i,
-                        This->stateBlock->pixelShaderConstantF[i * 4],
-                        This->stateBlock->pixelShaderConstantF[i * 4 + 1],
-                        This->stateBlock->pixelShaderConstantF[i * 4 + 2],
-                        This->stateBlock->pixelShaderConstantF[i * 4 + 3]);
-                     checkGLcall("glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB");
-                 }
-            }
+        if (wined3d_settings.shader_mode == SHADER_ARB) {
+            /* Bind the fragment program */
+            GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
+                    ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
+            checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
+
+            /* Enable OpenGL fragment programs */
+            glEnable(GL_FRAGMENT_PROGRAM_ARB);
+            checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
+            TRACE_(d3d_shader)("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n",
+                This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
         }
 
-        /* DirectX colours are in a different format to opengl colours
-         * so if diffuse or specular are used then we need to use drawStridedSlow
-         * to correct the colours */
-        if (!useVertexShaderFunction &&
-              ((dataLocations->u.s.pSize.lpData        != NULL)
-           || (dataLocations->u.s.diffuse.lpData      != NULL)
-           || (dataLocations->u.s.specular.lpData     != NULL))) {
-            /* TODO: replace drawStridedSlow with veretx fixups */
+        /* Update the constants */
+        loadConstants(iface, GL_FRAGMENT_PROGRAM_ARB, This->stateBlock->pixelShaderConstantF,
+                      This->stateBlock->pixelShaderConstantT, WINED3D_PSHADER_MAX_CONSTANTS, programId, FALSE);
+    }
 
-            drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType,
-                            idxData, idxSize, minIndex,  StartIdx);
+    /* DirectX colours are in a different format to opengl colours
+    * so if diffuse or specular are used then we need to use drawStridedSlow
+    * to correct the colours */
+    if (!useVertexShaderFunction &&
+        ((dataLocations->u.s.pSize.lpData      != NULL)
+        || (dataLocations->u.s.diffuse.lpData  != NULL)
+        || (dataLocations->u.s.specular.lpData != NULL))) {
+        /* TODO: replace drawStridedSlow with vertex fixups */
+
+        drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType,
+                idxData, idxSize, minIndex,  StartIdx);
 
         } else {
             /* OpenGL can manage everything in hardware so we can use drawStridedFast */
             drawStridedFast(iface, numberOfIndicies, glPrimType,
-                idxData, idxSize, minIndex, StartIdx);
+                    idxData, idxSize, minIndex, StartIdx);
         }
 
         /* Cleanup vertex program */
-        if (useVertexShaderFunction) {
-            /* disable any attribs */
+        if (useVertexShaderFunction && wined3d_settings.shader_mode != SHADER_SW) {
+            /* disable any attribs (Since we bind "attribN" to index #N for GLSL, this works in GLSL & ARB */
             if(((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->declaredArrays) {
                 GLint maxAttribs;
                 int i;
@@ -1900,20 +1934,27 @@ #endif
                 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
                 /* MESA does not support it right not */
                 if (glGetError() != GL_NO_ERROR)
-                maxAttribs = 16;
+                    maxAttribs = 16;
                 for (i = 0; i < maxAttribs; ++i) {
                     GL_EXTCALL(glDisableVertexAttribArrayARB(i));
                     checkGLcall("glDisableVertexAttribArrayARB(reg);");
                 }
             }
 
-            glDisable(GL_VERTEX_PROGRAM_ARB);
+            if (wined3d_settings.shader_mode == SHADER_ARB)
+                glDisable(GL_VERTEX_PROGRAM_ARB);
         }
 
         /* Cleanup fragment program */
-        if (usePixelShaderFunction) {
+        if (usePixelShaderFunction && wined3d_settings.shader_mode == SHADER_ARB) {
             glDisable(GL_FRAGMENT_PROGRAM_ARB);
         }
+
+        /* Cleanup GLSL program */
+        if (wined3d_settings.shader_mode == SHADER_GLSL &&
+            (usePixelShaderFunction || useVertexShaderFunction)) {
+            GL_EXTCALL(glUseProgramObjectARB(0));
+        }
     }
 }
 
-- 
1.3.3









More information about the wine-devel mailing list