wined3d: Partial render target locking.

This commit is contained in:
Stefan Dösinger 2007-02-13 20:24:00 +01:00 committed by Alexandre Julliard
parent b48dfb3c54
commit 403b5ecf60
1 changed files with 68 additions and 68 deletions

View File

@ -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");
glReadPixels(0, rect->top,
This->currentDesc.Width,
rect->bottom - rect->top,
fmt,
type,
mem);
/* TODO: Merge this with the palettization loop below for P8 targets */
/* glReadPixels returns the image upside down, and there is no way to prevent this.
Flip the lines in software */
row = HeapAlloc(GetProcessHeap(), 0, pitch);
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;
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) {