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

wined3d: Render target locking fixes.

parent 473ad39d
...@@ -2069,7 +2069,8 @@ void drawPrimitive(IWineD3DDevice *iface, ...@@ -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, ...@@ -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();
......
...@@ -480,170 +480,173 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKE ...@@ -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_read;
BOOL notInContext = FALSE;
IWineD3DSwapChainImpl *targetSwapChain = NULL;
GLint prev_store;
GLint prev_read;
BOOL notInContext = FALSE;
IWineD3DSwapChainImpl *targetSwapChain = NULL;
ENTER_GL();
ENTER_GL(); /**
* for render->surface copy begin to begin of allocatedMemory
* unlock can be more easy
*/
/** TRACE("locking a render target\n");
* for render->surface copy begin to begin of allocatedMemory
* unlock can be more easy
*/
TRACE("locking a render target\n"); if (This->resource.allocatedMemory == NULL)
This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
if (This->resource.allocatedMemory == NULL) This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size); pLockedRect->pBits = 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;
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) {
glReadBuffer(GL_BACK);
} else if (iface == swapchain->frontBuffer) {
glReadBuffer(GL_FRONT);
} else if (iface == myDevice->depthStencilBuffer) {
FIXME("Stencil Buffer lock unsupported for now\n");
} else {
FIXME("Should have got here!\n");
glReadBuffer(GL_BACK);
}
} else {
/* We need to switch contexts to be able to read the buffer!!! */
FIXME("The buffer requested isn't in the current openGL context\n");
notInContext = TRUE;
/* TODO: check the contexts, to see if were shared with the current context */
}
IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
} }
IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain); if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
} if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain); /** the depth stencil in openGL has a format of GL_FLOAT
* which should be good for WINED3DFMT_D16_LOCKABLE
* and WINED3DFMT_D16
/** the depth stencil in openGL has a format of GL_FLOAT * it is unclear what format the stencil buffer is in except.
* which should be good for WINED3DFMT_D16_LOCKABLE * 'Each index is converted to fixed point...
* and WINED3DFMT_D16 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
* it is unclear what format the stencil buffer is in except. * mappings in the table GL_PIXEL_MAP_S_TO_S.
* 'Each index is converted to fixed point... * glReadPixels(This->lockedRect.left,
* If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their * This->lockedRect.bottom - j - 1,
* mappings in the table GL_PIXEL_MAP_S_TO_S. * This->lockedRect.right - This->lockedRect.left,
* glReadPixels(This->lockedRect.left, * 1,
* This->lockedRect.bottom - j - 1, * GL_DEPTH_COMPONENT,
* This->lockedRect.right - This->lockedRect.left, * type,
* 1, * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
* GL_DEPTH_COMPONENT, *****************************************/
* type, if (!notInContext) { /* Only read the buffer if it's in the current context */
* (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top))); long j;
*****************************************/
if (!notInContext) { /* Only read the buffer if it's in the current context */
long j;
#if 0 #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, /* 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 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
* run ten times faster! * run ten times faster!
* ************************************/ * ************************************/
BOOL ati_performance_hack = FALSE; BOOL ati_performance_hack = FALSE;
ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE; ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
#endif #endif
if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 && if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
This->lockedRect.right == This->currentDesc.Width This->lockedRect.right == This->currentDesc.Width
&& This->lockedRect.bottom == This->currentDesc.Height)) { && This->lockedRect.bottom == This->currentDesc.Height)) {
BYTE *row, *top, *bottom; BYTE *row, *top, *bottom;
int i; 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)));
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)));
} }
vcheckGLcall("glReadPixels");
TRACE("Resetting buffer\n");
glReadBuffer(prev_read);
vcheckGLcall("glReadBuffer");
} }
vcheckGLcall("glReadPixels"); LEAVE_GL();
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) { ...@@ -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 * ...@@ -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;
} }
......
...@@ -329,6 +329,9 @@ HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST REC ...@@ -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;
} }
......
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