wined3d: Replace memset/memcpy routines on stateblock (fixes dynamic shader constants regression)

Jason Green jave27 at gmail.com
Sun Jul 23 14:08:27 CDT 2006


Since making the shader constants dynamic, there was a regression when
the app tried to create a new stateblock because that code used memcpy
and memset to copy a StateBlockImpl.  This can't be done anymore since
we now have dynamically sized arrays for shader float constants.

This patch replaces all calls to memset and memcpy which operate on a
StateBlockImpl with calls to new functions which explicitly set each
variable on the stateblock.

It also moves the routine to select the number of shader constants
based on selected shader model into its own function which makes more
logical sense.

Jason
-------------- next part --------------
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 2f6c46a..6a86132 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -799,11 +799,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         return temp_result;
 
     /* Otherwise, might as well set the whole state block to the appropriate values  */
-    if ( This->stateBlock != NULL) {
-       memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
-    } else {
-       memset(object->streamFreq, 1, sizeof(object->streamFreq));
-    }
+    if (This->stateBlock != NULL)
+        stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
+    else
+        memset(object->streamFreq, 1, sizeof(object->streamFreq));
 
     /* Reset the ref and type after kludging it */
     object->wineD3DDevice = This;
@@ -815,11 +814,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     if (Type == WINED3DSBT_ALL) {
 
         TRACE("ALL => Pretend everything has changed\n");
-        memset(&object->changed, TRUE, sizeof(This->stateBlock->changed));
+        stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
+    
     } else if (Type == WINED3DSBT_PIXELSTATE) {
 
         TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
-        memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
+        stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
 
         object->changed.pixelShader = TRUE;
 
@@ -849,7 +849,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     } else if (Type == WINED3DSBT_VERTEXSTATE) {
 
         TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
-        memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
+        stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
 
         object->changed.vertexShader = TRUE;
 
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 35542af..d2c306d 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -208,10 +208,6 @@ static void select_shader_mode(
     int* ps_selected,
     int* vs_selected) {
 
-    /* Default # of constants to 0 */
-    gl_info->max_vshader_constantsF = 0;
-    gl_info->max_pshader_constantsF = 0;
-
     /* Give priority to user disable/emulation request.
      * Then respect REF device for software.
      * Then check capabilities for hardware, and fallback to software */
@@ -222,12 +218,8 @@ static void select_shader_mode(
         *vs_selected = SHADER_SW;
     } else if (gl_info->supported[ARB_SHADING_LANGUAGE_100] && wined3d_settings.glslRequested) {
         *vs_selected = SHADER_GLSL;
-        /* Subtract the other potential uniforms from the max available (bools & ints) */
-        gl_info->max_vshader_constantsF = gl_info->vs_glsl_constantsF - MAX_CONST_B - MAX_CONST_I;
     } else if (gl_info->supported[ARB_VERTEX_PROGRAM]) {
         *vs_selected = SHADER_ARB;
-        /* ARB shaders seem to have an implicit PARAM when fog is used, so we need to subtract 1 from the total available */
-        gl_info->max_vshader_constantsF = gl_info->vs_arb_constantsF - 1;
     } else {
         *vs_selected = SHADER_SW;
     }
@@ -239,16 +231,50 @@ static void select_shader_mode(
         *ps_selected = SHADER_NONE;
     } else if (gl_info->supported[ARB_SHADING_LANGUAGE_100] && wined3d_settings.glslRequested) {
         *ps_selected = SHADER_GLSL;
-        /* Subtract the other potential uniforms from the max available (bools & ints) */
-        gl_info->max_pshader_constantsF = gl_info->ps_glsl_constantsF - MAX_CONST_B - MAX_CONST_I;
     } else if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) {
         *ps_selected = SHADER_ARB;
-        gl_info->max_pshader_constantsF = gl_info->ps_arb_constantsF;
     } else {
         *ps_selected = SHADER_NONE;
     }
 }
 
+/** Select the number of report maximum shader constants based on the selected shader modes */
+void select_shader_max_constants(WineD3D_GL_Info *gl_info) {
+
+    switch (wined3d_settings.vs_selected_mode) {
+        case SHADER_GLSL:
+            /* Subtract the other potential uniforms from the max available (bools & ints) */
+            gl_info->max_vshader_constantsF = gl_info->vs_glsl_constantsF - MAX_CONST_B - MAX_CONST_I;
+            break;
+        case SHADER_ARB:
+            /* ARB shaders seem to have an implicit PARAM when fog is used, so we need to subtract 1 from the total available */
+            gl_info->max_vshader_constantsF = gl_info->vs_arb_constantsF - 1;
+            break;
+        case SHADER_SW:
+            gl_info->max_vshader_constantsF = 96;  /* TODO: Fixup software shaders */
+            break;
+        default:
+            gl_info->max_vshader_constantsF = 0;
+            break;
+    }
+
+    switch (wined3d_settings.ps_selected_mode) {
+        case SHADER_GLSL:
+            /* Subtract the other potential uniforms from the max available (bools & ints) */
+            gl_info->max_pshader_constantsF = gl_info->ps_glsl_constantsF - MAX_CONST_B - MAX_CONST_I;
+            break;
+        case SHADER_ARB:
+            gl_info->max_pshader_constantsF = gl_info->ps_arb_constantsF;
+            break;
+        case SHADER_SW:
+            gl_info->max_pshader_constantsF = 96;  /* TODO: Fixup software shaders */
+            break;
+        default:
+            gl_info->max_pshader_constantsF = 0;
+            break;
+    }
+}
+
 /**********************************************************
  * IWineD3D parts follows
  **********************************************************/
@@ -1528,6 +1554,7 @@ static HRESULT WINAPI IWineD3DImpl_GetDe
     }
     select_shader_mode(&This->gl_info, DeviceType,
         &wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
+    select_shader_max_constants(&This->gl_info);
 
     /* ------------------------------------------------
        The following fields apply to both d3d8 and d3d9
@@ -1914,6 +1941,7 @@ static HRESULT  WINAPI IWineD3DImpl_Crea
     LEAVE_GL();
     select_shader_mode(&This->gl_info, DeviceType,
         &wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
+    select_shader_max_constants(&This->gl_info);
 
     temp_result = allocate_shader_constants(object->updateStateBlock);
     if (WINED3D_OK != temp_result)
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index e3d0e7c..85697f4 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -58,6 +58,140 @@ #undef WINED3D_MEMCHECK
     return WINED3D_OK;
 }
 
+/** Copy all members of one stateblock to another */
+void stateblock_savedstates_copy(
+    IWineD3DStateBlock* iface,
+    SAVEDSTATES* dest,
+    SAVEDSTATES* source) {
+    
+    IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface;
+    unsigned bsize = sizeof(BOOL);
+
+    /* Single values */
+    dest->indices = source->indices;
+    dest->material = source->material;
+    dest->fvf = source->fvf;
+    dest->viewport = source->viewport;
+    dest->vertexDecl = source->vertexDecl;
+    dest->pixelShader = source->pixelShader;
+    dest->vertexShader = source->vertexShader;
+
+    /* Fixed size arrays */
+    memcpy(dest->streamSource, source->streamSource, bsize * MAX_STREAMS);
+    memcpy(dest->streamFreq, source->streamFreq, bsize * MAX_STREAMS);
+    memcpy(dest->textures, source->textures, bsize * MAX_SAMPLERS);
+    memcpy(dest->transform, source->transform, bsize * (HIGHEST_TRANSFORMSTATE + 1));
+    memcpy(dest->renderState, source->renderState, bsize * (WINEHIGHEST_RENDER_STATE + 1));
+    memcpy(dest->textureState, source->textureState, bsize * MAX_TEXTURES * (WINED3D_HIGHEST_TEXTURE_STATE + 1));
+    memcpy(dest->samplerState, source->samplerState, bsize * MAX_SAMPLERS * (WINED3D_HIGHEST_SAMPLER_STATE + 1));
+    memcpy(dest->clipplane, source->clipplane, bsize * MAX_CLIPPLANES);
+    memcpy(dest->pixelShaderConstantsB, source->pixelShaderConstantsB, bsize * MAX_CONST_B);
+    memcpy(dest->pixelShaderConstantsI, source->pixelShaderConstantsI, bsize * MAX_CONST_I);
+    memcpy(dest->vertexShaderConstantsB, source->vertexShaderConstantsB, bsize * MAX_CONST_B);
+    memcpy(dest->vertexShaderConstantsI, source->vertexShaderConstantsI, bsize * MAX_CONST_I);
+
+    /* Dynamically sized arrays */
+    memcpy(dest->pixelShaderConstantsF, source->pixelShaderConstantsF, bsize * GL_LIMITS(pshader_constantsF));
+    memcpy(dest->vertexShaderConstantsF, source->vertexShaderConstantsF, bsize * GL_LIMITS(vshader_constantsF));
+}
+
+/** Set all members of a stateblock savedstate to the given value */
+void stateblock_savedstates_set(
+    IWineD3DStateBlock* iface,
+    SAVEDSTATES* states,
+    BOOL value) {
+    
+    IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface;
+    unsigned bsize = sizeof(BOOL);
+
+    /* Single values */
+    states->indices = value;
+    states->material = value;
+    states->fvf = value;
+    states->viewport = value;
+    states->vertexDecl = value;
+    states->pixelShader = value;
+    states->vertexShader = value;
+
+    /* Fixed size arrays */
+    memset(states->streamSource, value, bsize * MAX_STREAMS);
+    memset(states->streamFreq, value, bsize * MAX_STREAMS);
+    memset(states->textures, value, bsize * MAX_SAMPLERS);
+    memset(states->transform, value, bsize * (HIGHEST_TRANSFORMSTATE + 1));
+    memset(states->renderState, value, bsize * (WINEHIGHEST_RENDER_STATE + 1));
+    memset(states->textureState, value, bsize * MAX_TEXTURES * (WINED3D_HIGHEST_TEXTURE_STATE + 1));
+    memset(states->samplerState, value, bsize * MAX_SAMPLERS * (WINED3D_HIGHEST_SAMPLER_STATE + 1));
+    memset(states->clipplane, value, bsize * MAX_CLIPPLANES);
+    memset(states->pixelShaderConstantsB, value, bsize * MAX_CONST_B);
+    memset(states->pixelShaderConstantsI, value, bsize * MAX_CONST_I);
+    memset(states->vertexShaderConstantsB, value, bsize * MAX_CONST_B);
+    memset(states->vertexShaderConstantsI, value, bsize * MAX_CONST_I);
+
+    /* Dynamically sized arrays */
+    memset(states->pixelShaderConstantsF, value, bsize * GL_LIMITS(pshader_constantsF));
+    memset(states->vertexShaderConstantsF, value, bsize * GL_LIMITS(vshader_constantsF));
+}
+
+void stateblock_copy(
+    IWineD3DStateBlock* destination,
+    IWineD3DStateBlock* source) {
+
+    IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)source;
+    IWineD3DStateBlockImpl *Dest = (IWineD3DStateBlockImpl *)destination;
+
+    /* IUnknown fields */
+    Dest->lpVtbl                = This->lpVtbl;
+    Dest->ref                   = This->ref;
+
+    /* IWineD3DStateBlock information */
+    Dest->parent                = This->parent;
+    Dest->wineD3DDevice         = This->wineD3DDevice;
+    Dest->blockType             = This->blockType;
+
+    /* Saved states */
+    stateblock_savedstates_copy(source, &Dest->set, &This->set);
+    stateblock_savedstates_copy(source, &Dest->changed, &This->changed);
+
+    /* Single items */
+    Dest->fvf = This->fvf;
+    Dest->vertexDecl = This->vertexDecl;
+    Dest->vertexShader = This->vertexShader;
+    Dest->streamIsUP = This->streamIsUP;
+    Dest->pIndexData = This->pIndexData;
+    Dest->baseVertexIndex = This->baseVertexIndex;
+    Dest->lights = This->lights;
+    Dest->clip_status = This->clip_status;
+    Dest->viewport = This->viewport;
+    Dest->material = This->material;
+    Dest->pixelShader = This->pixelShader;
+    Dest->vertex_blend = This->vertex_blend;
+    Dest->tween_factor = This->tween_factor;
+    Dest->shaderPrgId = This->shaderPrgId;
+
+    /* Fixed size arrays */
+    memcpy(Dest->vertexShaderConstantB, This->vertexShaderConstantB, sizeof(BOOL) * MAX_CONST_B);
+    memcpy(Dest->vertexShaderConstantI, This->vertexShaderConstantI, sizeof(INT) * MAX_CONST_I * 4);
+    memcpy(Dest->pixelShaderConstantB, This->pixelShaderConstantB, sizeof(BOOL) * MAX_CONST_B);
+    memcpy(Dest->pixelShaderConstantI, This->pixelShaderConstantI, sizeof(INT) * MAX_CONST_I * 4);
+    
+    memcpy(Dest->streamStride, This->streamStride, sizeof(UINT) * MAX_STREAMS);
+    memcpy(Dest->streamOffset, This->streamOffset, sizeof(UINT) * MAX_STREAMS);
+    memcpy(Dest->streamSource, This->streamSource, sizeof(IWineD3DVertexBuffer*) * MAX_STREAMS);
+    memcpy(Dest->streamFreq,   This->streamFreq,   sizeof(UINT) * MAX_STREAMS);
+    memcpy(Dest->streamFlags,  This->streamFlags,  sizeof(UINT) * MAX_STREAMS);
+    memcpy(Dest->transforms,   This->transforms,   sizeof(D3DMATRIX) * (HIGHEST_TRANSFORMSTATE + 1));
+    memcpy(Dest->clipplane,    This->clipplane,    sizeof(double) * MAX_CLIPPLANES * 4);
+    memcpy(Dest->renderState,  This->renderState,  sizeof(DWORD) * (WINEHIGHEST_RENDER_STATE + 1));
+    memcpy(Dest->textures,     This->textures,     sizeof(IWineD3DBaseTexture*) * MAX_SAMPLERS);
+    memcpy(Dest->textureDimensions, This->textureDimensions, sizeof(int) * MAX_SAMPLERS);
+    memcpy(Dest->textureState, This->textureState, sizeof(DWORD) * MAX_TEXTURES * (WINED3D_HIGHEST_TEXTURE_STATE + 1));
+    memcpy(Dest->samplerState, This->samplerState, sizeof(DWORD) * MAX_SAMPLERS * (WINED3D_HIGHEST_SAMPLER_STATE + 1));
+
+    /* Dynamically sized arrays */
+    memcpy(Dest->vertexShaderConstantF, This->vertexShaderConstantF, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4);
+    memcpy(Dest->pixelShaderConstantF,  This->pixelShaderConstantF,  sizeof(float) * GL_LIMITS(pshader_constantsF) * 4);
+}
+
 /**********************************************************
  * IWineD3DStateBlockImpl IUnknown parts follows
  **********************************************************/
@@ -654,7 +788,7 @@ should really perform a delta so that on
     } else {
         FIXME("Unrecognized state block type %d\n", This->blockType);
     }
-    memcpy(&((IWineD3DDeviceImpl*)pDevice)->stateBlock->changed, &This->changed, sizeof(((IWineD3DDeviceImpl*)pDevice)->stateBlock->changed));
+    stateblock_savedstates_copy(iface, &((IWineD3DDeviceImpl*)pDevice)->stateBlock->changed, &This->changed);
     TRACE("(%p) : Applied state block %p ------------------^\n", This, pDevice);
 
     return WINED3D_OK;
diff --git a/dlls/wined3d/vertexbuffer.c b/dlls/wined3d/vertexbuffer.c
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index efff579..cd73c3a 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1113,6 +1113,20 @@ struct IWineD3DStateBlockImpl
     GLhandleARB               shaderPrgId;
 };
 
+extern void stateblock_savedstates_set(
+    IWineD3DStateBlock* iface,
+    SAVEDSTATES* states,
+    BOOL value);
+
+extern void stateblock_savedstates_copy(
+    IWineD3DStateBlock* iface,
+    SAVEDSTATES* dest,
+    SAVEDSTATES* source);
+
+extern void stateblock_copy(
+    IWineD3DStateBlock* destination,
+    IWineD3DStateBlock* source);
+
 extern const IWineD3DStateBlockVtbl IWineD3DStateBlock_Vtbl;
 
 /*****************************************************************************


More information about the wine-patches mailing list