wined3d: Store dirty states per context.
This commit is contained in:
parent
e6c9a073b0
commit
380930dc54
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue