Commit c54a0fc2 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: Rework surface dirtification.

Previously the surfaces stored a flag if the system memory copy was ahead of the gl copy(SFLAG_DIRTY) or the gl copy is ahead(SFLAG_GLDIRTY). The pbuffer copy was 'managed' differently using SFLAG_INPBUFFER and SFLAG_INTEXTURE. This patch replaces them with 3 flags, INSYSMEM, INPBUFFER and INTEXTURE which specify which copy contains the most up to date copy. It is perfectly valid to have more than one of those flags set. One must be set at least (except at init, when no content is in the surface yet). When one copy is modified, the flags for the others are removed.
parent ebe274fe
......@@ -709,12 +709,7 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU
/* Do that before switching the context:
* Read the back buffer of the old drawable into the destination texture
*/
((IWineD3DSurfaceImpl *) This->lastActiveRenderTarget)->Flags |= SFLAG_INPBUFFER;
((IWineD3DSurfaceImpl *) This->lastActiveRenderTarget)->Flags &= ~SFLAG_INTEXTURE;
IWineD3DSurface_AddDirtyRect(This->lastActiveRenderTarget, NULL);
IWineD3DSurface_PreLoad(This->lastActiveRenderTarget);
((IWineD3DSurfaceImpl *) This->lastActiveRenderTarget)->Flags &= ~SFLAG_INPBUFFER;
((IWineD3DSurfaceImpl *) This->lastActiveRenderTarget)->Flags &= ~SFLAG_INTEXTURE;
}
This->lastActiveRenderTarget = target;
if(oldRenderOffscreen != This->render_offscreen && This->depth_copy_state != WINED3D_DCS_NO_COPY) {
......
......@@ -4233,7 +4233,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
/* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
* it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
*/
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INTEXTURE;
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~SFLAG_INSYSMEM;
} else {
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INDRAWABLE;
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
}
return WINED3D_OK;
}
......@@ -4827,7 +4833,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
LEAVE_GL();
((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
return WINED3D_OK;
......
......@@ -1002,6 +1002,9 @@ void drawPrimitive(IWineD3DDevice *iface,
int minIndex) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DSwapChain *swapchain;
IWineD3DBaseTexture *texture = NULL;
IWineD3DSurfaceImpl *target;
int i;
/* Signals other modules that a drawing is in progress and the stateblock finalized */
......@@ -1009,8 +1012,41 @@ void drawPrimitive(IWineD3DDevice *iface,
/* Invalidate the back buffer memory so LockRect will read it the next time */
for(i = 0; i < GL_LIMITS(buffers); i++) {
if(This->render_targets[i]) {
((IWineD3DSurfaceImpl *) This->render_targets[i])->Flags |= SFLAG_GLDIRTY;
target = (IWineD3DSurfaceImpl *) This->render_targets[i];
/* TODO: Only do all that if we're going to change anything
* Texture container dirtification does not work quite right yet
*/
if(target /*&& target->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)*/) {
swapchain = NULL;
texture = NULL;
if(i == 0) {
IWineD3DSurface_GetContainer((IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain);
if(swapchain) {
/* Onscreen target. Invalidate system memory copy and texture copy */
target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE);
target->Flags |= SFLAG_INDRAWABLE;
IWineD3DSwapChain_Release(swapchain);
} else if(wined3d_settings.offscreen_rendering_mode != ORM_FBO) {
/* Non-FBO target: Invalidate system copy, texture copy and dirtify the container */
IWineD3DSurface_GetContainer((IWineD3DSurface *) target, &IID_IWineD3DBaseTexture, (void **)&texture);
if(texture) {
IWineD3DBaseTexture_SetDirty(texture, TRUE);
IWineD3DTexture_Release(texture);
}
target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE);
target->Flags |= SFLAG_INDRAWABLE;
} else {
/* FBO offscreen target. Invalidate system memory copy */
target->Flags &= ~SFLAG_INSYSMEM;
}
} else {
/* Must be an fbo render target */
target->Flags &= ~SFLAG_INSYSMEM;
target->Flags |= SFLAG_INTEXTURE;
}
}
}
......
......@@ -1600,7 +1600,6 @@ const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
IWineD3DSurfaceImpl_UpdateOverlayZOrder,
IWineD3DSurfaceImpl_UpdateOverlay,
/* Internal use: */
IWineD3DSurfaceImpl_CleanDirtyRect,
IWineD3DSurfaceImpl_AddDirtyRect,
IWineGDISurfaceImpl_LoadTexture,
IWineGDISurfaceImpl_SaveSnapshot,
......
......@@ -177,6 +177,8 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO
/* The cursor must have pow2 sizes */
cursor.pow2Width = cursor.currentDesc.Width;
cursor.pow2Height = cursor.currentDesc.Height;
/* The surface is in the texture */
cursor.Flags |= SFLAG_INTEXTURE;
/* DDBLT_KEYSRC will cause BltOverride to enable the alpha test with GL_NOTEQUAL, 0.0,
* which is exactly what we want :-)
*/
......@@ -299,13 +301,13 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO
IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER, 0x00, 1.0, 0);
}
if(!(((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags & SFLAG_GLDIRTY) ||
!(((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_GLDIRTY) ) {
if(((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags & SFLAG_INSYSMEM ||
((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_INSYSMEM ) {
/* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying */
IWineD3DSurfaceImpl *front = (IWineD3DSurfaceImpl *) This->frontBuffer;
IWineD3DSurfaceImpl *back = (IWineD3DSurfaceImpl *) This->backBuffer[0];
BOOL frontdirty = front->Flags & SFLAG_GLDIRTY;
BOOL backdirty = back->Flags & SFLAG_GLDIRTY;
BOOL frontuptodate = front->Flags & SFLAG_INSYSMEM;
BOOL backuptodate = back->Flags & SFLAG_INSYSMEM;
/* Flip the DC */
{
......@@ -349,10 +351,10 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO
front->dib.client_memory = back->dib.client_memory;
back->dib.client_memory = tmp;
}
if(frontdirty) back->Flags |= SFLAG_GLDIRTY;
else back->Flags &= ~SFLAG_GLDIRTY;
if(backdirty) front->Flags |= SFLAG_GLDIRTY;
else front->Flags &= ~SFLAG_GLDIRTY;
if(frontuptodate) back->Flags |= SFLAG_INSYSMEM;
else back->Flags &= ~SFLAG_INSYSMEM;
if(backuptodate) front->Flags |= SFLAG_INSYSMEM;
else front->Flags &= ~SFLAG_INSYSMEM;
}
TRACE("returning\n");
......
......@@ -2508,7 +2508,7 @@ BOOL CalculateTexRect(IWineD3DSurfaceImpl *This, RECT *Rect, float glTexCoord[4]
* If the texture is dirty, or the part can't be used,
* re-position the part to load
*/
if(!(This->Flags & SFLAG_DIRTY)) {
if(This->Flags & SFLAG_INTEXTURE) {
if(This->glRect.left <= x1 && This->glRect.right >= x2 &&
This->glRect.top <= y1 && This->glRect.bottom >= x2 ) {
/* Ok, the rectangle is ok, re-use it */
......@@ -2516,12 +2516,12 @@ BOOL CalculateTexRect(IWineD3DSurfaceImpl *This, RECT *Rect, float glTexCoord[4]
} else {
/* Rectangle is not ok, dirtify the texture to reload it */
TRACE("Dirtifying texture to force reload\n");
This->Flags |= SFLAG_DIRTY;
This->Flags &= ~SFLAG_INTEXTURE;
}
}
/* Now if we are dirty(no else if!) */
if(This->Flags & SFLAG_DIRTY) {
if(!(This->Flags & SFLAG_INTEXTURE)) {
/* Set the new rectangle. Use the following strategy:
* 1) Use as big textures as possible.
* 2) Place the texture part in the way that the requested
......
......@@ -1103,27 +1103,25 @@ HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *S
#define SFLAG_OVERSIZE 0x00000001 /* Surface is bigger than gl size, blts only */
#define SFLAG_CONVERTED 0x00000002 /* Converted for color keying or Palettized */
#define SFLAG_DIBSECTION 0x00000004 /* Has a DIB section attached for getdc */
#define SFLAG_DIRTY 0x00000008 /* Surface was locked by the app */
#define SFLAG_LOCKABLE 0x00000010 /* Surface can be locked */
#define SFLAG_DISCARD 0x00000020 /* ??? */
#define SFLAG_LOCKED 0x00000040 /* Surface is locked atm */
#define SFLAG_INTEXTURE 0x00000080 /* ??? */
#define SFLAG_INPBUFFER 0x00000100 /* ??? */
#define SFLAG_LOCKABLE 0x00000008 /* Surface can be locked */
#define SFLAG_DISCARD 0x00000010 /* ??? */
#define SFLAG_LOCKED 0x00000020 /* Surface is locked atm */
#define SFLAG_INTEXTURE 0x00000040 /* The GL texture contains the newest surface content */
#define SFLAG_INDRAWABLE 0x00000080 /* The gl drawable contains the most up to date data */
#define SFLAG_INSYSMEM 0x00000100 /* The system memory copy is most up to date */
#define SFLAG_NONPOW2 0x00000200 /* Surface sizes are not a power of 2 */
#define SFLAG_DYNLOCK 0x00000400 /* Surface is often locked by the app */
#define SFLAG_DYNCHANGE 0x00000C00 /* Surface contents are changed very often, implies DYNLOCK */
#define SFLAG_DCINUSE 0x00001000 /* Set between GetDC and ReleaseDC calls */
#define SFLAG_GLDIRTY 0x00002000 /* The opengl texture is more up to date than the surface mem */
#define SFLAG_LOST 0x00004000 /* Surface lost flag for DDraw */
#define SFLAG_FORCELOAD 0x00008000 /* To force PreLoading of a scratch cursor */
#define SFLAG_USERPTR 0x00010000 /* The application allocated the memory for this surface */
#define SFLAG_GLCKEY 0x00020000 /* The gl texture was created with a color key */
#define SFLAG_LOST 0x00002000 /* Surface lost flag for DDraw */
#define SFLAG_FORCELOAD 0x00004000 /* To force PreLoading of a scratch cursor */
#define SFLAG_USERPTR 0x00008000 /* The application allocated the memory for this surface */
#define SFLAG_GLCKEY 0x00010000 /* The gl texture was created with a color key */
/* In some conditions the surface memory must not be freed:
* SFLAG_OVERSIZE: Not all data can be kept in GL
* SFLAG_CONVERTED: Converting the data back would take too long
* SFLAG_DIBSECTION: The dib code manages the memory
* SFLAG_DIRTY: GL surface isn't up to date
* SFLAG_LOCKED: The app requires access to the surface data
* SFLAG_DYNLOCK: Avoid freeing the data for performance
* SFLAG_DYNCHANGE: Same reason as DYNLOCK
......@@ -1131,7 +1129,6 @@ HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *S
#define SFLAG_DONOTFREE (SFLAG_OVERSIZE | \
SFLAG_CONVERTED | \
SFLAG_DIBSECTION | \
SFLAG_DIRTY | \
SFLAG_LOCKED | \
SFLAG_DYNLOCK | \
SFLAG_DYNCHANGE | \
......
......@@ -1108,7 +1108,6 @@ DECLARE_INTERFACE_(IWineD3DSurface,IWineD3DResource)
STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD Flags, IWineD3DSurface *Ref) PURE;
STDMETHOD(UpdateOverlay)(THIS_ RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX);
/* Internally used methods */
STDMETHOD(CleanDirtyRect)(THIS) PURE;
STDMETHOD(AddDirtyRect)(THIS_ CONST RECT* pRect) PURE;
STDMETHOD(LoadTexture)(THIS) PURE;
STDMETHOD(SaveSnapshot)(THIS_ const char *filename) PURE;
......@@ -1162,7 +1161,6 @@ DECLARE_INTERFACE_(IWineD3DSurface,IWineD3DResource)
#define IWineD3DSurface_UpdateOverlayZOrder(p, a, b) (p)->lpVtbl->UpdateOverlayZOrder(p, a, b)
#define IWineD3DSurface_UpdateOverlay(p, a, b, c, d, e) (p)->lpVtbl->UpdateOverlay(p, a, b, c, d, e)
/*** IWineD3DSurface (Internal, no d3d mapping) methods ***/
#define IWineD3DSurface_CleanDirtyRect(p) (p)->lpVtbl->CleanDirtyRect(p)
#define IWineD3DSurface_AddDirtyRect(p,a) (p)->lpVtbl->AddDirtyRect(p,a)
#define IWineD3DSurface_LoadTexture(p) (p)->lpVtbl->LoadTexture(p)
#define IWineD3DSurface_SaveSnapshot(p,a) (p)->lpVtbl->SaveSnapshot(p,a)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment