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 */
This->view_ident = 1;
This->numContexts = 1;
This->contexts[0].last_was_rhw = 0;
glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
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 idx;
BYTE shift;
UINT i;
WineD3DContext *context;
if(!rep || isStateDirty(This, rep)) return;
if(!rep) return;
This->dirtyArray[This->numDirtyEntries++] = rep;
idx = rep >> 5;
shift = rep & 0x1f;
This->isStateDirty[idx] |= (1 << shift);
for(i = 0; i < This->numContexts; i++) {
context = &This->contexts[i];
if(isStateDirty(context, rep)) continue;
context->dirtyArray[context->numDirtyEntries++] = rep;
idx = rep >> 5;
shift = rep & 0x1f;
context->isStateDirty[idx] |= (1 << shift);
}
}

View File

@ -1202,14 +1202,14 @@ void drawPrimitive(IWineD3DDevice *iface,
context = &This->contexts[This->activeContext];
/* Apply dirty states */
for(i=0; i < This->numDirtyEntries; i++) {
dirtyState = This->dirtyArray[i];
for(i=0; i < context->numDirtyEntries; i++) {
dirtyState = context->dirtyArray[i];
idx = dirtyState >> 5;
shift = dirtyState & 0x1f;
This->isStateDirty[idx] &= ~(1 << shift);
context->isStateDirty[idx] &= ~(1 << shift);
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) {
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
*/
if(isStateDirty(stateblock->wineD3DDevice, STATE_VDECL)) {
if(isStateDirty(context, STATE_VDECL)) {
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.
* 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;
}
@ -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
* 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);
}
@ -1734,11 +1735,11 @@ static void tex_coordindex(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
}
/* 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);
}
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
* source. Call loadVertexData directly because there is no need to reparse the vertex declaration
* and do all the things linked to it
@ -1864,7 +1865,7 @@ static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont
glEnable(stateblock->textureDimensions[sampler]);
checkGLcall("glEnable(stateblock->textureDimensions[sampler])");
} 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);
}
@ -1878,7 +1879,7 @@ static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont
} else if(sampler < GL_LIMITS(texture_stages)) {
if(sampler < stateblock->lowest_disabled_stage) {
/* 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);
}
} /* 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
* has an update pending
*/
if(isStateDirty(device, STATE_VDECL) ||
isStateDirty(device, STATE_PIXELSHADER)) {
if(isStateDirty(context, STATE_VDECL) ||
isStateDirty(context, STATE_PIXELSHADER)) {
return;
}
@ -1913,7 +1914,7 @@ static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
* make sure to enable them
*/
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);
}
}
@ -1926,13 +1927,13 @@ static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
/* Compile and bind the shader */
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(
(IWineD3DDevice *) stateblock->wineD3DDevice,
TRUE,
!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);
}
}
@ -1942,19 +1943,19 @@ static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
* while it was enabled, so re-apply them.
*/
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);
}
}
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(
(IWineD3DDevice *) stateblock->wineD3DDevice,
FALSE,
!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);
}
}
@ -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
* 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);
}
}
@ -2692,8 +2693,8 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W
updateFog = TRUE;
}
/* Reapply lighting if it is not scheduled for reapplication already */
if(!isStateDirty(device, STATE_RENDER(WINED3DRS_LIGHTING))) {
/* Reapply lighting if it is not sheduled for reapplication already */
if(!isStateDirty(context, STATE_RENDER(WINED3DRS_LIGHTING))) {
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
*/
if(wasrhw != context->last_was_rhw &&
!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_PROJECTION)) &&
!isStateDirty(stateblock->wineD3DDevice, STATE_VIEWPORT)) {
!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION)) &&
!isStateDirty(context, STATE_VIEWPORT)) {
transform_projection(STATE_TRANSFORM(WINED3DTS_PROJECTION), stateblock, context);
}
/* 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
*/
if(transformed != wasrhw &&
!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))) &&
!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_VIEW))) {
!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))) &&
!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_VIEW))) {
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);
}
} 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
* application
*/
if(!isStateDirty(device, STATE_PIXELSHADER)) {
if(!isStateDirty(context, STATE_PIXELSHADER)) {
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);
}
}
@ -2793,7 +2794,7 @@ static void viewport(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCon
stateblock->wineD3DDevice->posFixup[2] = 0.9 / stateblock->viewport.Width;
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);
}

View File

@ -405,23 +405,8 @@ DWORD get_flexible_vertex_size(DWORD d3dvtVertexType);
#define GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_num) \
(((((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 */
typedef struct WineD3DContext WineD3DContext;
typedef void (*APPLYSTATEFUNC)(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *ctx);
#define STATE_RENDER(a) (a)
@ -468,6 +453,31 @@ struct StateEntry
/* Global state table */
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 */
BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display);
@ -665,16 +675,6 @@ typedef struct IWineD3DDeviceImpl
/* Final position fixup constant */
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 */
DWORD texUnitMap[MAX_SAMPLERS];
BOOL oneToOneTexUnitMap;
@ -687,15 +687,16 @@ typedef struct IWineD3DDeviceImpl
/* Context management */
WineD3DContext contexts[1]; /* Dynamic array later */
UINT activeContext; /* Only 0 for now */
UINT numContexts; /* Always 1 for now */
} IWineD3DDeviceImpl;
extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl;
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;
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