GL texture problems

Top Page

Reply to this message
Author: Stefan Dösinger
Date:  
To: wine-devel
Subject: GL texture problems
Hello,
I'm trying to change IWineD3DSurface::UnlockRect for rendertargets to avoid
glDrawPixels. Instead, I'd like to load the image from memory into an OpenGL
texture, and draw that texture with a textured quad onto the front / back
buffer.

The problem I have is that the texture(or better, the resulting image) only
has a solid color: The color of the first pixel in the source memory. I've
read the texture section of the GL programming guide, but I didn't find a
solution. I've attached a patch with my changes.

The reason why I want to make this change is that glDrawPixels and
glReadPixels are horribly slow on radeon cards, they take a few secounds for
a 1024x768 image. The current code doesn't work for the open source driver at
any color depth(mesa software acceleration doesn't work eighter), and it's
broken for some color depths with the fglrx driver.

Index: dlls/wined3d/surface.c
===================================================================
RCS file: /home/wine/wine/dlls/wined3d/surface.c,v
retrieving revision 1.40
diff -u -r1.40 surface.c
--- dlls/wined3d/surface.c    13 Feb 2006 13:10:32 -0000    1.40
+++ dlls/wined3d/surface.c    13 Feb 2006 21:45:10 -0000
@@ -640,6 +640,7 @@
IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
const char *buffername = "";
IWineD3DSwapChainImpl *swapchain = NULL;
+ int i;

if (FALSE == This->locked) {
WARN("trying to Unlock an unlocked surf@%p\n", This);
@@ -690,7 +691,6 @@
if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
GLint prev_store;
GLint prev_draw;
- GLint prev_rasterpos[4];

ENTER_GL();

@@ -700,15 +700,11 @@
vcheckGLcall("glIntegerv");
glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
vcheckGLcall("glIntegerv");
- glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
- vcheckGLcall("glIntegerv");
- glPixelZoom(1.0, -1.0);
- vcheckGLcall("glPixelZoom");

/* glDrawPixels transforms the raster position as though it was a vertex -
we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
per drawprim (and leave set - it will sort itself out due to last_was_rhw */
- if ( (!myDevice->last_was_rhw) || (myDevice->viewport_changed) ) {
+ if (!myDevice->last_was_rhw || myDevice->viewport_changed) {

double X, Y, height, width, minZ, maxZ;
myDevice->last_was_rhw = TRUE;
@@ -746,21 +742,34 @@

if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
glDrawBuffer(GL_BACK);
+ TRACE("Drawing to Back buffer\n");
} else if (iface == implSwapChain->frontBuffer) {
- glDrawBuffer(GL_FRONT);
+ TRACE("Drawing to Front buffer\n");
+ glDrawBuffer(GL_FRONT);
}

vcheckGLcall("glDrawBuffer");

/* If not fullscreen, we need to skip a number of bytes to find the next row of data */
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
+ checkGLcall("glGetIntegerv");
glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
+ checkGLcall("glPixelStorei");

/* And back buffers are not blended */
glDisable(GL_BLEND);
+ checkGLcall("glDisable");
+
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ D3DFmt2GLIntFmt(myDevice, This->resource.format),
+ This->pow2Width,
+ This->pow2Height,
+ 0,
+ D3DFmt2GLFmt(myDevice, This->resource.format),
+ D3DFmt2GLType(myDevice, This->resource.format),
+ NULL);
+ checkGLcall("glTexImage2D");

- glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
- vcheckGLcall("glRasterPos2f");
switch (This->resource.format) {
     case WINED3DFMT_X4R4G4B4:
     {
@@ -776,16 +785,14 @@
        }
     case WINED3DFMT_A4R4G4B4:
     {
- glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
- vcheckGLcall("glDrawPixels");
+ glTexSubImage2D(GL_TEXTURE_2D, 0, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
+ vcheckGLcall("glTexSubImage2D");
     }
        break;
case WINED3DFMT_R5G6B5:
{
- glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
- vcheckGLcall("glDrawPixels");
+ glTexSubImage2D(GL_TEXTURE_2D, 0, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
+ vcheckGLcall("glTexSubImage2D");
}
break;
case WINED3DFMT_X1R5G5B5:
@@ -802,16 +809,14 @@
}
case WINED3DFMT_A1R5G5B5:
{
- glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
- GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
- vcheckGLcall("glDrawPixels");
+ glTexSubImage2D(GL_TEXTURE_2D, 0, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
+ vcheckGLcall("glTexSubImage2D");
}
break;
case WINED3DFMT_R8G8B8:
{
- glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
- GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
- vcheckGLcall("glDrawPixels");
+ glTexSubImage2D(GL_TEXTURE_2D, 0, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top, GL_BGR, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
+ vcheckGLcall("glTexSubImage2D");
}
break;
case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
@@ -831,9 +836,15 @@
{
glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
vcheckGLcall("glPixelStorei");
- glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
- GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
- vcheckGLcall("glDrawPixels");
+ glTexSubImage2D(GL_TEXTURE_2D,
+ 0,
+ This->lockedRect.left, This->lockedRect.top,
+ This->lockedRect.right - This->lockedRect.left,
+ This->lockedRect.bottom - This->lockedRect.top,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ This->resource.allocatedMemory);
+ vcheckGLcall("glTexSubImage2D");
glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
vcheckGLcall("glPixelStorei");
}
@@ -842,9 +853,8 @@
{
glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
vcheckGLcall("glPixelStorei");
- glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
- GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
- vcheckGLcall("glDrawPixels");
+ glTexSubImage2D(GL_TEXTURE_2D, 0, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
+ vcheckGLcall("glTexSubImage2D");
glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
vcheckGLcall("glPixelStorei");
}
@@ -853,12 +863,62 @@
FIXME("Unsupported Format %u in locking func\n", This->resource.format);
}

- glPixelZoom(1.0,1.0);
- vcheckGLcall("glPixelZoom");
+ ERR("left=%ld,top=%ld,right=%ld,bottom=%d\n",
+ This->lockedRect.left,
+ This->lockedRect.top,
+ This->lockedRect.right,
+ This->lockedRect.bottom);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ checkGLcall("glTexParameterf");
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ checkGLcall("glTexParameterf");
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ checkGLcall("glTexParameterf");
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ checkGLcall("glTexParameterf");
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ checkGLcall("glTexEnvf");
+ glDisable(GL_TEXTURE_2D);
+ checkGLcall("glEnable");
+
+ glEnable(GL_TEXTURE_2D);
+ glDisable(GL_LIGHTING);
+ /* Draw a textured quad */
+ glBegin(GL_QUADS);
+
+ /*glColor3f(1.0, 1.0, 0.0);*/
+ glTexCoord2f(This->lockedRect.left / This->pow2Width,
+ This->lockedRect.top / This->pow2Height);
+ glVertex3d(This->lockedRect.left,
+ This->lockedRect.top,
+ 0.5);
+
+ /*glColor3f(1.0, 0.0, 0.0);*/
+ glTexCoord2f(This->lockedRect.right / This->pow2Width,
+ This->lockedRect.top / This->pow2Height);
+ glVertex3d(This->lockedRect.right,
+ This->lockedRect.top,
+ 0.5);
+
+ /*glColor3f(0.0, 1.0, 0.0);*/
+ glTexCoord2f(This->lockedRect.right / This->pow2Width,
+ This->lockedRect.bottom / This->pow2Height);
+ glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.5);
+
+ /*glColor3f(0.0, 0.0, 1.0);*/
+ glTexCoord2f(This->lockedRect.left / This->pow2Width,
+ This->lockedRect.bottom / This->pow2Height);
+ glVertex3d(This->lockedRect.left, This->lockedRect.bottom, 0.5);
+
+ glEnd();
+
+ glEnable(GL_LIGHTING); /* Temponary. Will be replaced by a check for the needed state*/
+
glDrawBuffer(prev_draw);
vcheckGLcall("glDrawBuffer");
- glRasterPos3iv(&prev_rasterpos[0]);
- vcheckGLcall("glRasterPos3iv");

/* Reset to previous pack row length / blending state */
glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
@@ -886,6 +946,27 @@
FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
}

+ /* Can be useful for debugging */
+
+#if 0
+ {
+ static unsigned int gen = 0;
+ char buffer[4096];
+ ++gen;
+ if ((gen % 10) == 0) {
+ snprintf(buffer, sizeof(buffer), "dumps/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
+ IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
+ }
+ /*
+ * debugging crash code
+ if (gen == 250) {
+ void** test = NULL;
+ *test = 0;
+ }
+ */
+ }
+#endif
+
unlock_end:
This->locked = FALSE;
memset(&This->lockedRect, 0, sizeof(RECT));