wined3d: Render target locking fixes.

This commit is contained in:
Stefan Dösinger 2006-06-04 16:42:57 +02:00 committed by Alexandre Julliard
parent 473ad39dcb
commit 2c3adec595
3 changed files with 172 additions and 153 deletions

View File

@ -2069,7 +2069,8 @@ void drawPrimitive(IWineD3DDevice *iface,
BOOL usePixelShaderFunction = FALSE; BOOL usePixelShaderFunction = FALSE;
BOOL isLightingOn = FALSE; BOOL isLightingOn = FALSE;
WineDirect3DVertexStridedData *dataLocations; WineDirect3DVertexStridedData *dataLocations;
int useHW = FALSE; IWineD3DSwapChainImpl *swapchain;
int useHW = FALSE, i;
if (This->stateBlock->vertexShader != NULL && wined3d_settings.vs_mode != VS_NONE if (This->stateBlock->vertexShader != NULL && wined3d_settings.vs_mode != VS_NONE
&&((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL &&((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL
@ -2093,6 +2094,15 @@ void drawPrimitive(IWineD3DDevice *iface,
TRACE("(%p) : using vertex declaration %p\n", iface, This->stateBlock->vertexDecl); TRACE("(%p) : using vertex declaration %p\n", iface, This->stateBlock->vertexDecl);
} }
/* Invalidate the back buffer memory so LockRect will read it the next time */
for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
if(swapchain) {
if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer)->Flags |= SFLAG_GLDIRTY;
IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
}
}
/* Ok, we will be updating the screen from here onwards so grab the lock */ /* Ok, we will be updating the screen from here onwards so grab the lock */
ENTER_GL(); ENTER_GL();

View File

@ -480,170 +480,173 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKE
} }
} }
} else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&WINED3DLOCK_DISCARD)) { /* render surfaces */ } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
GLint prev_store; GLint prev_store;
GLint prev_read; GLint prev_read;
BOOL notInContext = FALSE; BOOL notInContext = FALSE;
IWineD3DSwapChainImpl *targetSwapChain = NULL; IWineD3DSwapChainImpl *targetSwapChain = NULL;
ENTER_GL(); ENTER_GL();
/** /**
* for render->surface copy begin to begin of allocatedMemory * for render->surface copy begin to begin of allocatedMemory
* unlock can be more easy * unlock can be more easy
*/ */
TRACE("locking a render target\n"); TRACE("locking a render target\n");
if (This->resource.allocatedMemory == NULL) if (This->resource.allocatedMemory == NULL)
This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size); This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/ This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
pLockedRect->pBits = This->resource.allocatedMemory; pLockedRect->pBits = This->resource.allocatedMemory;
glFlush(); glFlush();
vcheckGLcall("glFlush"); vcheckGLcall("glFlush");
glGetIntegerv(GL_READ_BUFFER, &prev_read); glGetIntegerv(GL_READ_BUFFER, &prev_read);
vcheckGLcall("glIntegerv"); vcheckGLcall("glIntegerv");
glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store); glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
vcheckGLcall("glIntegerv"); vcheckGLcall("glIntegerv");
/* Here's what we have to do: /* Here's what we have to do:
See if the swapchain has the same context as the renderTarget or the surface is the render target. See if the swapchain has the same context as the renderTarget or the surface is the render target.
Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!) Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
and use the front back buffer as required. and use the front back buffer as required.
if not, we need to switch contexts and then switchback at the end. if not, we need to switch contexts and then switchback at the end.
*/ */
IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain); IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain); IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
/* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */ /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) { if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) { if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
TRACE("locking back buffer\n"); TRACE("locking back buffer\n");
glReadBuffer(GL_BACK); glReadBuffer(GL_BACK);
} else if (iface == swapchain->frontBuffer) {
TRACE("locking front\n");
glReadBuffer(GL_FRONT);
} else if (iface == myDevice->depthStencilBuffer) {
FIXME("Stencil Buffer lock unsupported for now\n");
} else {
FIXME("(%p) Shouldn't have got here!\n", This);
glReadBuffer(GL_BACK);
}
} else if (swapchain != NULL) {
IWineD3DSwapChainImpl *implSwapChain;
IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
/* This will fail for the implicit swapchain, which is why there needs to be a context manager */
if (iface == swapchain->backBuffer) {
glReadBuffer(GL_BACK);
} else if (iface == swapchain->frontBuffer) { } else if (iface == swapchain->frontBuffer) {
glReadBuffer(GL_FRONT); TRACE("locking front\n");
glReadBuffer(GL_FRONT);
} else if (iface == myDevice->depthStencilBuffer) { } else if (iface == myDevice->depthStencilBuffer) {
FIXME("Stencil Buffer lock unsupported for now\n"); FIXME("Stencil Buffer lock unsupported for now\n");
} else { } else {
FIXME("Should have got here!\n"); FIXME("(%p) Shouldn't have got here!\n", This);
glReadBuffer(GL_BACK); glReadBuffer(GL_BACK);
} }
} else { } else if (swapchain != NULL) {
/* We need to switch contexts to be able to read the buffer!!! */ IWineD3DSwapChainImpl *implSwapChain;
FIXME("The buffer requested isn't in the current openGL context\n"); IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
notInContext = TRUE; if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
/* TODO: check the contexts, to see if were shared with the current context */ /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
} if (iface == swapchain->backBuffer) {
IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain); glReadBuffer(GL_BACK);
} } else if (iface == swapchain->frontBuffer) {
if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain); glReadBuffer(GL_FRONT);
if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain); } else if (iface == myDevice->depthStencilBuffer) {
FIXME("Stencil Buffer lock unsupported for now\n");
} else {
/** the depth stencil in openGL has a format of GL_FLOAT FIXME("Should have got here!\n");
* which should be good for WINED3DFMT_D16_LOCKABLE glReadBuffer(GL_BACK);
* and WINED3DFMT_D16 }
* it is unclear what format the stencil buffer is in except. } else {
* 'Each index is converted to fixed point... /* We need to switch contexts to be able to read the buffer!!! */
* If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their FIXME("The buffer requested isn't in the current openGL context\n");
* mappings in the table GL_PIXEL_MAP_S_TO_S. notInContext = TRUE;
* glReadPixels(This->lockedRect.left, /* TODO: check the contexts, to see if were shared with the current context */
* This->lockedRect.bottom - j - 1,
* This->lockedRect.right - This->lockedRect.left,
* 1,
* GL_DEPTH_COMPONENT,
* type,
* (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
*****************************************/
if (!notInContext) { /* Only read the buffer if it's in the current context */
long j;
#if 0
/* Bizarly it takes 120 millseconds to get an 800x600 region a line at a time, but only 10 to get the whole lot every time,
* This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
* run ten times faster!
* ************************************/
BOOL ati_performance_hack = FALSE;
ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
#endif
if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
This->lockedRect.right == This->currentDesc.Width
&& This->lockedRect.bottom == This->currentDesc.Height)) {
BYTE *row, *top, *bottom;
int i;
glReadPixels(0, 0,
This->currentDesc.Width,
This->currentDesc.Height,
This->glDescription.glFormat,
This->glDescription.glType,
(char *)pLockedRect->pBits);
/* glReadPixels returns the image upside down, and there is no way to prevent this.
Flip the lines in software*/
row = HeapAlloc(GetProcessHeap(), 0, pLockedRect->Pitch);
if(!row) {
ERR("Out of memory\n");
return E_OUTOFMEMORY;
}
top = This->resource.allocatedMemory;
bottom = ( (BYTE *) This->resource.allocatedMemory) + pLockedRect->Pitch * ( This->currentDesc.Height - 1);
for(i = 0; i < This->currentDesc.Height / 2; i++) {
memcpy(row, top, pLockedRect->Pitch);
memcpy(top, bottom, pLockedRect->Pitch);
memcpy(bottom, row, pLockedRect->Pitch);
top += pLockedRect->Pitch;
bottom -= pLockedRect->Pitch;
}
HeapFree(GetProcessHeap(), 0, row);
} else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
glReadPixels(0,
This->lockedRect.top,
This->currentDesc.Width,
This->currentDesc.Height,
This->glDescription.glFormat,
This->glDescription.glType,
(char *)pLockedRect->pBits);
} else{
for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
glReadPixels(This->lockedRect.left,
This->lockedRect.bottom - j - 1,
This->lockedRect.right - This->lockedRect.left,
1,
This->glDescription.glFormat,
This->glDescription.glType,
(char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
} }
IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
} }
vcheckGLcall("glReadPixels"); if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
TRACE("Resetting buffer\n"); if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
glReadBuffer(prev_read);
vcheckGLcall("glReadBuffer");
}
LEAVE_GL();
/** the depth stencil in openGL has a format of GL_FLOAT
* which should be good for WINED3DFMT_D16_LOCKABLE
* and WINED3DFMT_D16
* it is unclear what format the stencil buffer is in except.
* 'Each index is converted to fixed point...
* If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
* mappings in the table GL_PIXEL_MAP_S_TO_S.
* glReadPixels(This->lockedRect.left,
* This->lockedRect.bottom - j - 1,
* This->lockedRect.right - This->lockedRect.left,
* 1,
* GL_DEPTH_COMPONENT,
* type,
* (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
*****************************************/
if (!notInContext) { /* Only read the buffer if it's in the current context */
long j;
#if 0
/* Bizarly it takes 120 millseconds to get an 800x600 region a line at a time, but only 10 to get the whole lot every time,
* This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
* run ten times faster!
* ************************************/
BOOL ati_performance_hack = FALSE;
ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
#endif
if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
This->lockedRect.right == This->currentDesc.Width
&& This->lockedRect.bottom == This->currentDesc.Height)) {
BYTE *row, *top, *bottom;
int i;
glReadPixels(0, 0,
This->currentDesc.Width,
This->currentDesc.Height,
This->glDescription.glFormat,
This->glDescription.glType,
(char *)pLockedRect->pBits);
/* glReadPixels returns the image upside down, and there is no way to prevent this.
Flip the lines in software*/
row = HeapAlloc(GetProcessHeap(), 0, pLockedRect->Pitch);
if(!row) {
ERR("Out of memory\n");
return E_OUTOFMEMORY;
}
top = This->resource.allocatedMemory;
bottom = ( (BYTE *) This->resource.allocatedMemory) + pLockedRect->Pitch * ( This->currentDesc.Height - 1);
for(i = 0; i < This->currentDesc.Height / 2; i++) {
memcpy(row, top, pLockedRect->Pitch);
memcpy(top, bottom, pLockedRect->Pitch);
memcpy(bottom, row, pLockedRect->Pitch);
top += pLockedRect->Pitch;
bottom -= pLockedRect->Pitch;
}
HeapFree(GetProcessHeap(), 0, row);
This->Flags &= ~SFLAG_GLDIRTY;
} else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
glReadPixels(0,
This->lockedRect.top,
This->currentDesc.Width,
This->currentDesc.Height,
This->glDescription.glFormat,
This->glDescription.glType,
(char *)pLockedRect->pBits);
} else{
for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
glReadPixels(This->lockedRect.left,
This->lockedRect.bottom - j - 1,
This->lockedRect.right - This->lockedRect.left,
1,
This->glDescription.glFormat,
This->glDescription.glType,
(char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
}
}
vcheckGLcall("glReadPixels");
TRACE("Resetting buffer\n");
glReadBuffer(prev_read);
vcheckGLcall("glReadBuffer");
}
LEAVE_GL();
}
} else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */ } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
if (!messages & 1) { if (!messages & 1) {
@ -784,14 +787,14 @@ HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
per drawprim (and leave set - it will sort itself out due to last_was_rhw */ per drawprim (and leave set - it will sort itself out due to last_was_rhw */
d3ddevice_set_ortho(This->resource.wineD3DDevice); d3ddevice_set_ortho(This->resource.wineD3DDevice);
if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) { if (iface == implSwapChain->frontBuffer) {
glDrawBuffer(GL_BACK);
} else if (iface == implSwapChain->frontBuffer) {
glDrawBuffer(GL_FRONT); glDrawBuffer(GL_FRONT);
checkGLcall("glDrawBuffer GL_FRONT");
} else if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
glDrawBuffer(GL_BACK);
checkGLcall("glDrawBuffer GL_BACK");
} }
vcheckGLcall("glDrawBuffer");
/* If not fullscreen, we need to skip a number of bytes to find the next row of data */ /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes); glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width); glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
@ -2244,6 +2247,9 @@ HRESULT WINAPI IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *
LEAVE_GL(); LEAVE_GL();
/* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
This->Flags |= SFLAG_GLDIRTY;
return WINED3D_OK; return WINED3D_OK;
} }

View File

@ -329,6 +329,9 @@ HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST REC
IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0x00, 1.0, 0); IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0x00, 1.0, 0);
} }
((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags |= SFLAG_GLDIRTY;
((IWineD3DSurfaceImpl *) This->backBuffer)->Flags |= SFLAG_GLDIRTY;
TRACE("returning\n"); TRACE("returning\n");
return WINED3D_OK; return WINED3D_OK;
} }