wined3d: Store dirty states per context.

This commit is contained in:
Stefan Dösinger 2007-02-12 19:18:31 +01:00 committed by Alexandre Julliard
parent e6c9a073b0
commit 380930dc54
4 changed files with 73 additions and 63 deletions

View File

@ -2007,6 +2007,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPR
/* Initialize the current view state */ /* Initialize the current view state */
This->view_ident = 1; This->view_ident = 1;
This->numContexts = 1;
This->contexts[0].last_was_rhw = 0; This->contexts[0].last_was_rhw = 0;
glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights); glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This); TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
@ -6978,11 +6979,18 @@ void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
DWORD rep = StateTable[state].representative; DWORD rep = StateTable[state].representative;
DWORD idx; DWORD idx;
BYTE shift; BYTE shift;
UINT i;
WineD3DContext *context;
if(!rep || isStateDirty(This, rep)) return; if(!rep) return;
This->dirtyArray[This->numDirtyEntries++] = rep; for(i = 0; i < This->numContexts; i++) {
context = &This->contexts[i];
if(isStateDirty(context, rep)) continue;
context->dirtyArray[context->numDirtyEntries++] = rep;
idx = rep >> 5; idx = rep >> 5;
shift = rep & 0x1f; shift = rep & 0x1f;
This->isStateDirty[idx] |= (1 << shift); context->isStateDirty[idx] |= (1 << shift);
}
} }

View File

@ -1202,14 +1202,14 @@ void drawPrimitive(IWineD3DDevice *iface,
context = &This->contexts[This->activeContext]; context = &This->contexts[This->activeContext];
/* Apply dirty states */ /* Apply dirty states */
for(i=0; i < This->numDirtyEntries; i++) { for(i=0; i < context->numDirtyEntries; i++) {
dirtyState = This->dirtyArray[i]; dirtyState = context->dirtyArray[i];
idx = dirtyState >> 5; idx = dirtyState >> 5;
shift = dirtyState & 0x1f; shift = dirtyState & 0x1f;
This->isStateDirty[idx] &= ~(1 << shift); context->isStateDirty[idx] &= ~(1 << shift);
StateTable[dirtyState].apply(dirtyState, This->stateBlock, context); StateTable[dirtyState].apply(dirtyState, This->stateBlock, context);
} }
This->numDirtyEntries = 0; /* This makes the whole list clean */ context->numDirtyEntries = 0; /* This makes the whole list clean */
if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) { if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
check_fbo_status(iface); check_fbo_status(iface);

View File

@ -87,7 +87,7 @@ static void state_lighting(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
* vertex declaration appplying function calls this function for updating * vertex declaration appplying function calls this function for updating
*/ */
if(isStateDirty(stateblock->wineD3DDevice, STATE_VDECL)) { if(isStateDirty(context, STATE_VDECL)) {
return; return;
} }
@ -820,7 +820,8 @@ static void state_colormat(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
/* Depends on the decoded vertex declaration to read the existance of diffuse data. /* Depends on the decoded vertex declaration to read the existance of diffuse data.
* The vertex declaration will call this function if the fixed function pipeline is used. * The vertex declaration will call this function if the fixed function pipeline is used.
*/ */
if(isStateDirty(device, STATE_VDECL)) {
if(isStateDirty(context, STATE_VDECL)) {
return; return;
} }
@ -1486,7 +1487,7 @@ static void tex_colorop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
/* The sampler will also activate the correct texture dimensions, so no need to do it here /* The sampler will also activate the correct texture dimensions, so no need to do it here
* if the sampler for this stage is dirty * if the sampler for this stage is dirty
*/ */
if(!isStateDirty(stateblock->wineD3DDevice, STATE_SAMPLER(stage))) { if(!isStateDirty(context, STATE_SAMPLER(stage))) {
if (mapped_stage != -1) activate_dimensions(stage, stateblock); if (mapped_stage != -1) activate_dimensions(stage, stateblock);
} }
@ -1734,11 +1735,11 @@ static void tex_coordindex(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
} }
/* Update the texture matrix */ /* Update the texture matrix */
if(!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_TEXTURE0 + stage))) { if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_TEXTURE0 + stage))) {
transform_texture(STATE_TRANSFORM(WINED3DTS_TEXTURE0 + stage), stateblock, context); transform_texture(STATE_TRANSFORM(WINED3DTS_TEXTURE0 + stage), stateblock, context);
} }
if(!isStateDirty(stateblock->wineD3DDevice, STATE_VDECL) && context->namedArraysLoaded) { if(!isStateDirty(context, STATE_VDECL) && context->namedArraysLoaded) {
/* Reload the arrays if we are using fixed function arrays to reflect the selected coord input /* Reload the arrays if we are using fixed function arrays to reflect the selected coord input
* source. Call loadVertexData directly because there is no need to reparse the vertex declaration * source. Call loadVertexData directly because there is no need to reparse the vertex declaration
* and do all the things linked to it * and do all the things linked to it
@ -1864,7 +1865,7 @@ static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont
glEnable(stateblock->textureDimensions[sampler]); glEnable(stateblock->textureDimensions[sampler]);
checkGLcall("glEnable(stateblock->textureDimensions[sampler])"); checkGLcall("glEnable(stateblock->textureDimensions[sampler])");
} else if(sampler < stateblock->lowest_disabled_stage) { } else if(sampler < stateblock->lowest_disabled_stage) {
if(!isStateDirty(stateblock->wineD3DDevice, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP))) { if(!isStateDirty(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP))) {
activate_dimensions(sampler, stateblock); activate_dimensions(sampler, stateblock);
} }
@ -1878,7 +1879,7 @@ static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont
} else if(sampler < GL_LIMITS(texture_stages)) { } else if(sampler < GL_LIMITS(texture_stages)) {
if(sampler < stateblock->lowest_disabled_stage) { if(sampler < stateblock->lowest_disabled_stage) {
/* TODO: What should I do with pixel shaders here ??? */ /* TODO: What should I do with pixel shaders here ??? */
if(!isStateDirty(stateblock->wineD3DDevice, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP))) { if(!isStateDirty(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP))) {
activate_dimensions(sampler, stateblock); activate_dimensions(sampler, stateblock);
} }
} /* Otherwise tex_colorop disables the stage */ } /* Otherwise tex_colorop disables the stage */
@ -1893,8 +1894,8 @@ static void shaderconstant(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
/* Vertex and pixel shader states will call a shader upload, don't do anything as long one of them /* Vertex and pixel shader states will call a shader upload, don't do anything as long one of them
* has an update pending * has an update pending
*/ */
if(isStateDirty(device, STATE_VDECL) || if(isStateDirty(context, STATE_VDECL) ||
isStateDirty(device, STATE_PIXELSHADER)) { isStateDirty(context, STATE_PIXELSHADER)) {
return; return;
} }
@ -1913,7 +1914,7 @@ static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
* make sure to enable them * make sure to enable them
*/ */
for(i=0; i < MAX_SAMPLERS; i++) { for(i=0; i < MAX_SAMPLERS; i++) {
if(!isStateDirty(stateblock->wineD3DDevice, STATE_SAMPLER(i))) { if(!isStateDirty(context, STATE_SAMPLER(i))) {
sampler(STATE_SAMPLER(i), stateblock, context); sampler(STATE_SAMPLER(i), stateblock, context);
} }
} }
@ -1926,13 +1927,13 @@ static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
/* Compile and bind the shader */ /* Compile and bind the shader */
IWineD3DPixelShader_CompileShader(stateblock->pixelShader); IWineD3DPixelShader_CompileShader(stateblock->pixelShader);
if(!isStateDirty(stateblock->wineD3DDevice, StateTable[STATE_VSHADER].representative)) { if(!isStateDirty(context, StateTable[STATE_VSHADER].representative)) {
stateblock->wineD3DDevice->shader_backend->shader_select( stateblock->wineD3DDevice->shader_backend->shader_select(
(IWineD3DDevice *) stateblock->wineD3DDevice, (IWineD3DDevice *) stateblock->wineD3DDevice,
TRUE, TRUE,
!stateblock->vertexShader ? FALSE : ((IWineD3DVertexShaderImpl *) stateblock->vertexShader)->baseShader.function != NULL); !stateblock->vertexShader ? FALSE : ((IWineD3DVertexShaderImpl *) stateblock->vertexShader)->baseShader.function != NULL);
if(!isStateDirty(stateblock->wineD3DDevice, STATE_VERTEXSHADERCONSTANT)) { if(!isStateDirty(context, STATE_VERTEXSHADERCONSTANT)) {
shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context); shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context);
} }
} }
@ -1942,19 +1943,19 @@ static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
* while it was enabled, so re-apply them. * while it was enabled, so re-apply them.
*/ */
for(i=0; i < MAX_TEXTURES; i++) { for(i=0; i < MAX_TEXTURES; i++) {
if(!isStateDirty(stateblock->wineD3DDevice, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP))) { if(!isStateDirty(context, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP))) {
tex_colorop(STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP), stateblock, context); tex_colorop(STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP), stateblock, context);
} }
} }
context->last_was_pshader = FALSE; context->last_was_pshader = FALSE;
if(!isStateDirty(stateblock->wineD3DDevice, StateTable[STATE_VSHADER].representative)) { if(!isStateDirty(context, StateTable[STATE_VSHADER].representative)) {
stateblock->wineD3DDevice->shader_backend->shader_select( stateblock->wineD3DDevice->shader_backend->shader_select(
(IWineD3DDevice *) stateblock->wineD3DDevice, (IWineD3DDevice *) stateblock->wineD3DDevice,
FALSE, FALSE,
!stateblock->vertexShader ? FALSE : ((IWineD3DVertexShaderImpl *) stateblock->vertexShader)->baseShader.function != NULL); !stateblock->vertexShader ? FALSE : ((IWineD3DVertexShaderImpl *) stateblock->vertexShader)->baseShader.function != NULL);
if(!isStateDirty(stateblock->wineD3DDevice, STATE_VERTEXSHADERCONSTANT)) { if(!isStateDirty(context, STATE_VERTEXSHADERCONSTANT)) {
shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context); shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context);
} }
} }
@ -2031,7 +2032,7 @@ static void transform_view(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
/* Call the world matrix state, this will apply the combined WORLD + VIEW matrix /* Call the world matrix state, this will apply the combined WORLD + VIEW matrix
* No need to do it here if the state is scheduled for update. * No need to do it here if the state is scheduled for update.
*/ */
if(!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)))) { if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)))) {
transform_world(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), stateblock, context); transform_world(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), stateblock, context);
} }
} }
@ -2692,8 +2693,8 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W
updateFog = TRUE; updateFog = TRUE;
} }
/* Reapply lighting if it is not scheduled for reapplication already */ /* Reapply lighting if it is not sheduled for reapplication already */
if(!isStateDirty(device, STATE_RENDER(WINED3DRS_LIGHTING))) { if(!isStateDirty(context, STATE_RENDER(WINED3DRS_LIGHTING))) {
state_lighting(STATE_RENDER(WINED3DRS_LIGHTING), stateblock, context); state_lighting(STATE_RENDER(WINED3DRS_LIGHTING), stateblock, context);
} }
@ -2726,8 +2727,8 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W
* or transformed / untransformed was switched * or transformed / untransformed was switched
*/ */
if(wasrhw != context->last_was_rhw && if(wasrhw != context->last_was_rhw &&
!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_PROJECTION)) && !isStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION)) &&
!isStateDirty(stateblock->wineD3DDevice, STATE_VIEWPORT)) { !isStateDirty(context, STATE_VIEWPORT)) {
transform_projection(STATE_TRANSFORM(WINED3DTS_PROJECTION), stateblock, context); transform_projection(STATE_TRANSFORM(WINED3DTS_PROJECTION), stateblock, context);
} }
/* World matrix needs reapplication here only if we're switching between rhw and non-rhw /* World matrix needs reapplication here only if we're switching between rhw and non-rhw
@ -2742,12 +2743,12 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W
* dirty * dirty
*/ */
if(transformed != wasrhw && if(transformed != wasrhw &&
!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))) && !isStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))) &&
!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_VIEW))) { !isStateDirty(context, STATE_TRANSFORM(WINED3DTS_VIEW))) {
transform_world(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), stateblock, context); transform_world(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), stateblock, context);
} }
if(!isStateDirty(stateblock->wineD3DDevice, STATE_RENDER(WINED3DRS_COLORVERTEX))) { if(!isStateDirty(context, STATE_RENDER(WINED3DRS_COLORVERTEX))) {
state_colormat(STATE_RENDER(WINED3DRS_COLORVERTEX), stateblock, context); state_colormat(STATE_RENDER(WINED3DRS_COLORVERTEX), stateblock, context);
} }
} else { } else {
@ -2765,10 +2766,10 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W
/* Vertex and pixel shaders are applied together for now, so let the last dirty state do the /* Vertex and pixel shaders are applied together for now, so let the last dirty state do the
* application * application
*/ */
if(!isStateDirty(device, STATE_PIXELSHADER)) { if(!isStateDirty(context, STATE_PIXELSHADER)) {
device->shader_backend->shader_select((IWineD3DDevice *) device, usePixelShaderFunction, useVertexShaderFunction); device->shader_backend->shader_select((IWineD3DDevice *) device, usePixelShaderFunction, useVertexShaderFunction);
if(!isStateDirty(stateblock->wineD3DDevice, STATE_VERTEXSHADERCONSTANT) && (useVertexShaderFunction || usePixelShaderFunction)) { if(!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && (useVertexShaderFunction || usePixelShaderFunction)) {
shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context); shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context);
} }
} }
@ -2793,7 +2794,7 @@ static void viewport(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCon
stateblock->wineD3DDevice->posFixup[2] = 0.9 / stateblock->viewport.Width; stateblock->wineD3DDevice->posFixup[2] = 0.9 / stateblock->viewport.Width;
stateblock->wineD3DDevice->posFixup[3] = -0.9 / stateblock->viewport.Height; stateblock->wineD3DDevice->posFixup[3] = -0.9 / stateblock->viewport.Height;
if(!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(D3DTS_PROJECTION))) { if(!isStateDirty(context, STATE_TRANSFORM(D3DTS_PROJECTION))) {
transform_projection(STATE_TRANSFORM(D3DTS_PROJECTION), stateblock, context); transform_projection(STATE_TRANSFORM(D3DTS_PROJECTION), stateblock, context);
} }

View File

@ -405,23 +405,8 @@ DWORD get_flexible_vertex_size(DWORD d3dvtVertexType);
#define GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_num) \ #define GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_num) \
(((((d3dvtVertexType) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1) (((((d3dvtVertexType) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1)
/* The new context manager that should deal with onscreen and offscreen rendering */
typedef struct WineD3DContext {
/* TODO: Dirty State list */
/* TODO: Render target / swapchain this ctx belongs to */
/* TODO: Thread this ctx belongs to */
/* Stores some inforation about the context state for optimization */
BOOL last_was_rhw; /* true iff last draw_primitive was in xyzrhw mode */
BOOL last_was_pshader;
BOOL last_was_vshader;
BOOL last_was_foggy_shader;
BOOL namedArraysLoaded, numberedArraysLoaded;
BOOL lastWasPow2Texture[MAX_TEXTURES];
GLenum tracking_parm; /* Which source is tracking current colour */
} WineD3DContext;
/* Routines and structures related to state management */ /* Routines and structures related to state management */
typedef struct WineD3DContext WineD3DContext;
typedef void (*APPLYSTATEFUNC)(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *ctx); typedef void (*APPLYSTATEFUNC)(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *ctx);
#define STATE_RENDER(a) (a) #define STATE_RENDER(a) (a)
@ -468,6 +453,31 @@ struct StateEntry
/* Global state table */ /* Global state table */
extern const struct StateEntry StateTable[]; extern const struct StateEntry StateTable[];
/* The new context manager that should deal with onscreen and offscreen rendering */
struct WineD3DContext {
/* State dirtification
* dirtyArray is an array that contains markers for dirty states. numDirtyEntries states are dirty, their numbers are in indices
* 0...numDirtyEntries - 1. isStateDirty is a redundant copy of the dirtyArray. Technically only one of them would be needed,
* but with the help of both it is easy to find out if a state is dirty(just check the array index), and for applying dirty states
* only numDirtyEntries array elements have to be checked, not STATE_HIGHEST states.
*/
DWORD dirtyArray[STATE_HIGHEST + 1]; /* Won't get bigger than that, a state is never marked dirty 2 times */
DWORD numDirtyEntries;
DWORD isStateDirty[STATE_HIGHEST/32 + 1]; /* Bitmap to find out quickly if a state is dirty */
/* TODO: Render target / swapchain this ctx belongs to */
/* TODO: Thread this ctx belongs to */
/* Stores some inforation about the context state for optimization */
BOOL last_was_rhw; /* true iff last draw_primitive was in xyzrhw mode */
BOOL last_was_pshader;
BOOL last_was_vshader;
BOOL last_was_foggy_shader;
BOOL namedArraysLoaded, numberedArraysLoaded;
BOOL lastWasPow2Texture[MAX_TEXTURES];
GLenum tracking_parm; /* Which source is tracking current colour */
};
/* Routine to fill gl caps for swapchains and IWineD3D */ /* Routine to fill gl caps for swapchains and IWineD3D */
BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display); BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display);
@ -665,16 +675,6 @@ typedef struct IWineD3DDeviceImpl
/* Final position fixup constant */ /* Final position fixup constant */
float posFixup[4]; float posFixup[4];
/* State dirtification
* dirtyArray is an array that contains markers for dirty states. numDirtyEntries states are dirty, their numbers are in indices
* 0...numDirtyEntries - 1. isStateDirty is a redundant copy of the dirtyArray. Technically only one of them would be needed,
* but with the help of both it is easy to find out if a state is dirty(just check the array index), and for applying dirty states
* only numDirtyEntries array elements have to be checked, not STATE_HIGHEST states.
*/
DWORD dirtyArray[STATE_HIGHEST + 1]; /* Won't get bigger than that, a state is never marked dirty 2 times */
DWORD numDirtyEntries;
DWORD isStateDirty[STATE_HIGHEST/32 + 1]; /* Bitmap to find out quickly if a state is dirty */
/* With register combiners we can skip junk texture stages */ /* With register combiners we can skip junk texture stages */
DWORD texUnitMap[MAX_SAMPLERS]; DWORD texUnitMap[MAX_SAMPLERS];
BOOL oneToOneTexUnitMap; BOOL oneToOneTexUnitMap;
@ -687,15 +687,16 @@ typedef struct IWineD3DDeviceImpl
/* Context management */ /* Context management */
WineD3DContext contexts[1]; /* Dynamic array later */ WineD3DContext contexts[1]; /* Dynamic array later */
UINT activeContext; /* Only 0 for now */ UINT activeContext; /* Only 0 for now */
UINT numContexts; /* Always 1 for now */
} IWineD3DDeviceImpl; } IWineD3DDeviceImpl;
extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl; extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl;
void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state); void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state);
static inline BOOL isStateDirty(IWineD3DDeviceImpl *This, DWORD state) { static inline BOOL isStateDirty(WineD3DContext *context, DWORD state) {
DWORD idx = state >> 5; DWORD idx = state >> 5;
BYTE shift = state & 0x1f; BYTE shift = state & 0x1f;
return This->isStateDirty[idx] & (1 << shift); return context->isStateDirty[idx] & (1 << shift);
} }
/* Support for IWineD3DResource ::Set/Get/FreePrivateData. I don't think /* Support for IWineD3DResource ::Set/Get/FreePrivateData. I don't think