[7/10] WineD3D: Partial render target locking
Stefan Dösinger
stefan at codeweavers.com
Tue Feb 13 13:24:00 CST 2007
Selects the proper subrectangle for both reading and writing from/to render
targets. Writing only for the glDrawPixels path, not yet for the texture path
beacuse partial texture updating is not supported yet
-------------- next part --------------
From c37f961643913ef13931935ea38707580e94a836 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Mon, 12 Feb 2007 14:55:40 +0100
Subject: [PATCH] WineD3D: Partial render target locking
---
dlls/wined3d/surface.c | 136 ++++++++++++++++++++++++------------------------
1 files changed, 68 insertions(+), 68 deletions(-)
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 54a5214..ffdc55d 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -421,11 +421,13 @@ const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
return (CONST void*)(This->resource.allocatedMemory);
}
-static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
- long j;
- void *mem;
+static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch, BOOL srcUpsideDown) {
+ BYTE *mem;
GLint fmt;
GLint type;
+ BYTE *row, *top, *bottom;
+ int i;
+ BOOL bpp;
switch(This->resource.format)
{
@@ -443,11 +445,12 @@ static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, v
fmt = GL_RGB;
type = GL_UNSIGNED_BYTE;
pitch *= 3;
- mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
+ mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
if(!mem) {
ERR("Out of memory\n");
return;
}
+ bpp = This->bytesPerPixel * 3;
}
break;
@@ -455,55 +458,43 @@ static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, v
mem = dest;
fmt = This->glDescription.glFormat;
type = This->glDescription.glType;
+ bpp = This->bytesPerPixel;
}
- if (rect->left == 0 &&
- rect->right == This->currentDesc.Width ) {
- BYTE *row, *top, *bottom;
- int i;
+ glReadPixels(rect->left, rect->top,
+ rect->right - rect->left,
+ rect->bottom - rect->top,
+ fmt, type, mem);
+ vcheckGLcall("glReadPixels");
+
+ /* TODO: Merge this with the palettization loop below for P8 targets */
- glReadPixels(0, rect->top,
- This->currentDesc.Width,
- rect->bottom - rect->top,
- fmt,
- type,
- mem);
+ if(!srcUpsideDown) {
+ UINT len, off;
+ /* glReadPixels returns the image upside down, and there is no way to prevent this.
+ Flip the lines in software */
+ len = (rect->right - rect->left) * bpp;
+ off = rect->left * bpp;
- /* glReadPixels returns the image upside down, and there is no way to prevent this.
- Flip the lines in software */
- row = HeapAlloc(GetProcessHeap(), 0, pitch);
+ row = HeapAlloc(GetProcessHeap(), 0, len);
if(!row) {
ERR("Out of memory\n");
+ if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem);
return;
}
- top = mem;
+
+ top = mem + pitch * rect->top;
bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
- memcpy(row, top, pitch);
- memcpy(top, bottom, pitch);
- memcpy(bottom, row, pitch);
+ memcpy(row, top + off, len);
+ memcpy(top + off, bottom + off, len);
+ memcpy(bottom + off, row, len);
top += pitch;
bottom -= pitch;
}
HeapFree(GetProcessHeap(), 0, row);
-
- if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
- This->Flags &= ~SFLAG_GLDIRTY;
- }
- } else {
- for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
- glReadPixels(rect->left,
- rect->bottom - j - 1,
- rect->right - rect->left,
- 1,
- fmt,
- type,
- (char *)mem + (pitch * (j-rect->top)));
- }
}
- vcheckGLcall("glReadPixels");
-
if(This->resource.format == WINED3DFMT_P8) {
PALETTEENTRY *pal;
DWORD width = pitch / 3;
@@ -623,6 +614,8 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED
*/
IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
if(swapchain || iface == myDevice->render_targets[0]) {
+ BOOL srcIsUpsideDown;
+
if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
static BOOL warned = FALSE;
if(!warned) {
@@ -633,17 +626,6 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED
return WINED3D_OK;
}
- /* FIXME: Partial surface locking is broken */
- if(This->lockedRect.left != 0 ||
- This->lockedRect.top != 0 ||
- This->lockedRect.right != This->currentDesc.Width ||
- This->lockedRect.bottom != This->currentDesc.Height) {
- FIXME("Add Support for partial render target locking\n");
- This->lockedRect.left = 0;
- This->lockedRect.top = 0;
- This->lockedRect.right = This->currentDesc.Width;
- This->lockedRect.bottom = This->currentDesc.Height;
- }
/* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
* Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
* should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
@@ -662,6 +644,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED
*/
TRACE("Locking offscreen render target\n");
glReadBuffer(GL_BACK);
+ srcIsUpsideDown = TRUE;
} else {
if(iface == swapchain->frontBuffer) {
TRACE("Locking the front buffer\n");
@@ -677,22 +660,31 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED
glReadBuffer(GL_BACK);
}
IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
+ srcIsUpsideDown = FALSE;
}
switch(wined3d_settings.rendertargetlock_mode) {
case RTL_AUTO:
case RTL_READDRAW:
case RTL_READTEX:
- read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch);
+ read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
break;
case RTL_TEXDRAW:
case RTL_TEXTEX:
- read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch);
+ read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
break;
}
LEAVE_GL();
+
+ /* Mark the local copy up to date if a full download was done */
+ if(This->lockedRect.left == 0 &&
+ This->lockedRect.top == 0 &&
+ This->lockedRect.right == This->currentDesc.Width &&
+ This->lockedRect.bottom == This->currentDesc.Height) {
+ This->Flags &= ~SFLAG_GLDIRTY;
+ }
} else if(iface == myDevice->stencilBufferTarget) {
/** the depth stencil in openGL has a format of GL_FLOAT
* which should be good for WINED3DFMT_D16_LOCKABLE
@@ -737,6 +729,9 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED
surface_download_data(This);
}
+
+ /* The local copy is now up to date to the opengl one because a full download was done */
+ This->Flags &= ~SFLAG_GLDIRTY;
}
lock_end:
@@ -760,9 +755,6 @@ lock_end:
}
}
- /* The local copy is now up to date to the opengl one */
- This->Flags &= ~SFLAG_GLDIRTY;
-
TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
return WINED3D_OK;
}
@@ -773,7 +765,9 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
GLint skipBytes = 0;
BOOL storechanged = FALSE, memory_allocated = FALSE;
GLint fmt, type;
- void *mem;
+ BYTE *mem;
+ UINT bpp;
+ UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
glDisable(GL_TEXTURE_2D);
vcheckGLcall("glDisable(GL_TEXTURE_2D)");
@@ -819,6 +813,7 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
type = This->glDescription.glType;
fmt = This->glDescription.glFormat;
mem = This->resource.allocatedMemory;
+ bpp = This->bytesPerPixel;
break;
case WINED3DFMT_X4R4G4B4:
@@ -835,6 +830,7 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
type = This->glDescription.glType;
fmt = This->glDescription.glFormat;
mem = This->resource.allocatedMemory;
+ bpp = This->bytesPerPixel;
}
break;
@@ -852,6 +848,7 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
type = This->glDescription.glType;
fmt = This->glDescription.glFormat;
mem = This->resource.allocatedMemory;
+ bpp = This->bytesPerPixel;
}
break;
@@ -879,6 +876,7 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
type = This->glDescription.glType;
fmt = This->glDescription.glFormat;
mem = This->resource.allocatedMemory;
+ bpp = This->bytesPerPixel;
}
break;
@@ -890,12 +888,12 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
type = This->glDescription.glType;
fmt = This->glDescription.glFormat;
mem = This->resource.allocatedMemory;
+ bpp = This->bytesPerPixel;
}
break;
case WINED3DFMT_P8:
{
- UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
int height = This->glRect.bottom - This->glRect.top;
type = GL_UNSIGNED_BYTE;
fmt = GL_RGBA;
@@ -914,6 +912,8 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
pitch * 4,
CONVERT_PALETTED,
This);
+ bpp = This->bytesPerPixel * 4;
+ pitch *= 4;
}
break;
@@ -924,12 +924,13 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
type = This->glDescription.glType;
fmt = This->glDescription.glFormat;
mem = This->resource.allocatedMemory;
+ bpp = This->bytesPerPixel;
}
glDrawPixels(This->lockedRect.right - This->lockedRect.left,
(This->lockedRect.bottom - This->lockedRect.top)-1,
fmt, type,
- mem);
+ mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
checkGLcall("glDrawPixels");
glPixelZoom(1.0,1.0);
vcheckGLcall("glPixelZoom");
@@ -949,16 +950,15 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
return;
}
-static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
- IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
+static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
float glTexCoord[4];
- glTexCoord[0] = 0.0; /* left */
- glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
- glTexCoord[2] = 0.0; /* top */
- glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
+ glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */
+ glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */
+ glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */
+ glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
- IWineD3DSurface_PreLoad(iface);
+ IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
ENTER_GL();
@@ -976,16 +976,16 @@ static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
glColor3d(1.0f, 1.0f, 1.0f);
glTexCoord2f(glTexCoord[0], glTexCoord[2]);
- glVertex3f(0, 0, 0.0);
+ glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
glTexCoord2f(glTexCoord[0], glTexCoord[3]);
- glVertex3f(0, This->currentDesc.Height, 0.0);
+ glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
glTexCoord2f(glTexCoord[1], glTexCoord[3]);
- glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
+ glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
glTexCoord2f(glTexCoord[1], glTexCoord[2]);
- glVertex3f(This->currentDesc.Width, 0, 0.0);
+ glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
glEnd();
checkGLcall("glEnd");
@@ -1061,7 +1061,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
case RTL_READTEX:
case RTL_TEXTEX:
- flush_to_framebuffer_texture(iface);
+ flush_to_framebuffer_texture(This);
break;
}
if(!swapchain || swapchain->backBuffer) {
--
1.4.4.3
More information about the wine-patches
mailing list