[D3D8] Implemented fast rendering to a texture using glCopyTexImage2D

Christian Costa titan.costa at wanadoo.fr
Mon Apr 26 17:19:21 CDT 2004


Hi,

Here is a patch that directly copy data from the PBuffer to a texture.
The patch enables rendering of render targets upside down so the flip 
that occurs during
the copy to the texture is cancelled.
This makes the cubemap demo from dx8 sdk work perfectly.

This patch is based on last Raphael's patch (dx112.diff) although there 
should not be any conflict.

Changelog:
Implemented fast rendering to a texture using glCopyTexImage2D
Fixed SetViewport.
Fixed SetRenderTarget (based on Jason Edmeades' work).
Improved trace.

Christian Costa   titan.costa at wanadoo.fr

-------------- next part --------------
diff -u -r /home/titan/winebase/wine/dlls/d3d8/d3d8_private.h ./d3d8_private.h
--- /home/titan/winebase/wine/dlls/d3d8/d3d8_private.h	2004-04-26 21:16:29.000000000 +0000
+++ ./d3d8_private.h	2004-04-26 21:28:18.000000000 +0000
@@ -393,6 +393,8 @@
 
     UINT                          dummyTextureName[8];
 
+    /* For rendering to a texture using glCopyTexImage */
+    BOOL                          renderUpsideDown;
 };
 
 /* IUnknown: */
@@ -627,6 +629,8 @@
     RECT                    lockedRect;
     RECT                    dirtyRect;
     BOOL                    Dirty;
+    BOOL                    inTexture;
+    BOOL                    inPBuffer;
 };
 
 /* IUnknown: */
diff -u -r /home/titan/winebase/wine/dlls/d3d8/device.c ./device.c
--- /home/titan/winebase/wine/dlls/d3d8/device.c	2004-04-26 21:21:15.000000000 +0000
+++ ./device.c	2004-04-26 21:52:50.000000000 +0000
@@ -1221,38 +1221,39 @@
     return hr;
 }
 HRESULT  WINAPI  IDirect3DDevice8Impl_SetRenderTarget(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8* pRenderTarget, IDirect3DSurface8* pNewZStencil) {
-    HRESULT hr;
+    HRESULT      hr = D3D_OK;
+    D3DVIEWPORT8 viewport;
 
     ICOM_THIS(IDirect3DDevice8Impl,iface);
 
+    /* If pRenderTarget == NULL, it seems to default to back buffer */
+    if (pRenderTarget == NULL) pRenderTarget = (IDirect3DSurface8*)This->backBuffer;
+ 
+    /* For ease of code later on, handle a null depth as leave alone
+        - Have not tested real d3d for this case but doing this avoids 
+        numerous null pointer checks                                   */
+    if (pNewZStencil == NULL) pNewZStencil = (IDirect3DSurface8*)This->stencilBufferTarget;
+
+    /* If we are trying to set what we already have, dont bother */
     if ((IDirect3DSurface8Impl*) pRenderTarget == This->renderTarget && (IDirect3DSurface8Impl*) pNewZStencil == This->stencilBufferTarget) {
       TRACE("Trying to do a NOP SetRenderTarget operation\n");
-      return D3D_OK;
+    } else {
+      /* Otherwise, set the render target up */
+      TRACE("(%p) : newRender@%p newZStencil@%p (default is backbuffer=(%p))\n", This, pRenderTarget, pNewZStencil, This->backBuffer);
+      IDirect3DDevice8Impl_CleanRender(iface);
+      hr = IDirect3DDevice8Impl_ActiveRender(iface, pRenderTarget, pNewZStencil);
     }
 
-    IDirect3DDevice8Impl_CleanRender(iface);
-
-    if ((IDirect3DSurface8Impl*) pRenderTarget == This->frontBuffer && (IDirect3DSurface8Impl*) pNewZStencil == This->depthStencilBuffer) {
-      IDirect3DSurface8Impl* tmp;
-
-      TRACE("retoring SetRenderTarget defaults\n");
-
-      tmp = This->renderTarget;
-      This->renderTarget = (IDirect3DSurface8Impl*) This->frontBuffer;
-      IDirect3DSurface8Impl_AddRef((LPDIRECT3DSURFACE8) This->renderTarget);
-      IDirect3DSurface8Impl_Release((LPDIRECT3DSURFACE8) tmp);
-      
-      tmp = This->stencilBufferTarget;
-      This->stencilBufferTarget = (IDirect3DSurface8Impl*) This->depthStencilBuffer;
-      if (NULL != This->stencilBufferTarget) IDirect3DSurface8Impl_AddRef((LPDIRECT3DSURFACE8) This->stencilBufferTarget);
-      if (NULL != tmp) IDirect3DSurface8Impl_Release((LPDIRECT3DSURFACE8) tmp);
-
-      return D3D_OK;
+    if (SUCCEEDED(hr)) {
+	/* Finally, reset the viewport as the MSDN states. */
+	viewport.Height = ((IDirect3DSurface8Impl*)pRenderTarget)->myDesc.Height;
+	viewport.Width  = ((IDirect3DSurface8Impl*)pRenderTarget)->myDesc.Width;
+	viewport.X      = 0;
+	viewport.Y      = 0;
+	viewport.MaxZ   = 1.0f;
+	viewport.MinZ   = 0.0f;
+	IDirect3DDevice8Impl_SetViewport(iface, &viewport);
     }
-
-    FIXME("(%p) : expect crash newRender@%p newZStencil@%p\n", This, pRenderTarget, pNewZStencil);
-
-    hr = IDirect3DDevice8Impl_ActiveRender(iface, pRenderTarget, pNewZStencil);
     
     return hr;
 }
@@ -1285,6 +1286,7 @@
     TRACE("(%p) : stub\n", This);
     return D3D_OK;
 }
+
 HRESULT  WINAPI  IDirect3DDevice8Impl_EndScene(LPDIRECT3DDEVICE8 iface) {
     IDirect3DBaseTexture8* cont = NULL;
     HRESULT hr;
@@ -1296,12 +1298,13 @@
     glFlush();
     checkGLcall("glFlush");
 
-    /* Useful for debugging sometimes!
+#if 0 /* Useful for debugging sometimes! */
     printf("Hit Enter ...\n");
-    getchar(); */
+    getchar();
+#endif
 
     if (This->frontBuffer != This->renderTarget) {
-      {
+#if 0
 	GLenum prev_read;
 	glGetIntegerv(GL_READ_BUFFER, &prev_read);
 	vcheckGLcall("glIntegerv");
@@ -1327,13 +1330,16 @@
 	}      
 	glReadBuffer(prev_read);
 	vcheckGLcall("glReadBuffer");
-      }
+#endif
 
       hr = IDirect3DSurface8_GetContainer((LPDIRECT3DSURFACE8) This->renderTarget, &IID_IDirect3DBaseTexture8, (void**) &cont);
       if (SUCCEEDED(hr) && NULL != cont) {
 	/** always dirtify for now. we must find a better way to see that surface have been modified */
-	IDirect3DBaseTexture8Impl_SetDirty(cont, TRUE);
+	This->renderTarget->inPBuffer = TRUE;
+	This->renderTarget->inTexture = FALSE;
+      	IDirect3DBaseTexture8Impl_SetDirty(cont, TRUE);
 	IDirect3DBaseTexture8_PreLoad(cont);
+	This->renderTarget->inPBuffer = FALSE;
 	IDirect3DBaseTexture8Impl_Release(cont);
 	cont = NULL;
       }
@@ -1640,7 +1646,7 @@
     glDepthRange(pViewport->MinZ, pViewport->MaxZ);
     checkGLcall("glDepthRange");
     /* Note: GL requires lower left, DirectX supplies upper left */
-    glViewport(pViewport->X, (This->PresentParms.BackBufferHeight - (pViewport->Y + pViewport->Height)), 
+    glViewport(pViewport->X, (This->renderTarget->myDesc.Height - (pViewport->Y + pViewport->Height)), 
                pViewport->Width, pViewport->Height);
     checkGLcall("glViewport");
 
@@ -2252,15 +2258,25 @@
         case D3DCULL_CW:
             glEnable(GL_CULL_FACE);
             checkGLcall("glEnable GL_CULL_FACE");
-            glFrontFace(GL_CCW);
-            checkGLcall("glFrontFace GL_CCW");
+            if (This->renderUpsideDown) {
+                glFrontFace(GL_CW);
+                checkGLcall("glFrontFace GL_CW");
+            } else {
+                glFrontFace(GL_CCW);
+                checkGLcall("glFrontFace GL_CCW");
+            }
             glCullFace(GL_BACK);
             break;
         case D3DCULL_CCW:
             glEnable(GL_CULL_FACE);
             checkGLcall("glEnable GL_CULL_FACE");
-            glFrontFace(GL_CW); 
-            checkGLcall("glFrontFace GL_CW");
+            if (This->renderUpsideDown) {
+                glFrontFace(GL_CCW); 
+                checkGLcall("glFrontFace GL_CCW");
+            } else {
+                glFrontFace(GL_CW);
+                checkGLcall("glFrontFace GL_CW");
+            }
             glCullFace(GL_BACK);
             break;
         default:
@@ -4385,7 +4401,7 @@
 #define PUSH1(att)        attribs[nAttribs++] = (att); 
 #define PUSH2(att,value)  attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
 
-  PUSH2(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_WINDOW | GLX_PBUFFER_BIT);
+  PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
   PUSH2(GLX_X_RENDERABLE,  TRUE);
   PUSH2(GLX_DOUBLEBUFFER, TRUE);
   
@@ -4485,7 +4501,7 @@
 #endif
 
     if (NULL != This->renderTarget) {
-      GLenum prev_read;      
+      //GLenum prev_read;      
       glFlush();
       vcheckGLcall("glFlush");
 
@@ -4496,6 +4512,7 @@
       getchar();
 #endif
 
+#if 0
       glGetIntegerv(GL_READ_BUFFER, &prev_read);
       vcheckGLcall("glIntegerv");
       glReadBuffer(GL_BACK);
@@ -4520,6 +4537,7 @@
       }      
       glReadBuffer(prev_read);
       vcheckGLcall("glReadBuffer");
+#endif
     }
 
     if (BackBufferFormat != This->renderTarget->myDesc.Format && 
@@ -4553,6 +4571,18 @@
     if (NULL != This->stencilBufferTarget) IDirect3DSurface8Impl_AddRef((LPDIRECT3DSURFACE8) This->stencilBufferTarget);
     if (NULL != tmp) IDirect3DSurface8Impl_Release((LPDIRECT3DSURFACE8) tmp);
 
+    {
+      DWORD value;
+      /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
+      This->renderUpsideDown = This->renderTarget != This->frontBuffer;
+      /* Force updating the cull mode */
+      IDirect3DDevice8_GetRenderState(iface, D3DRS_CULLMODE, &value);
+      IDirect3DDevice8_SetRenderState(iface, D3DRS_CULLMODE, value);
+      /* Force updating projection matrix */
+      This->last_was_rhw = FALSE;
+      This->proj_valid = FALSE;
+    }
+
     ret = D3D_OK;
 
   } else {
diff -u -r /home/titan/winebase/wine/dlls/d3d8/drawprim.c ./drawprim.c
--- /home/titan/winebase/wine/dlls/d3d8/drawprim.c	2004-04-18 10:16:46.000000000 +0000
+++ ./drawprim.c	2004-04-26 21:56:13.000000000 +0000
@@ -218,6 +218,12 @@
 
 }
 
+static GLfloat invymat[16]={
+	1.0f, 0.0f, 0.0f, 0.0f,
+	0.0f, -1.0f, 0.0f, 0.0f,
+	0.0f, 0.0f, 1.0f, 0.0f,
+	0.0f, 0.0f, 0.0f, 1.0f};
+
 /* Setup views - Transformed & lit if RHW, else untransformed.
        Only unlit if Normals are supplied                       
     Returns: Whether to restore lighting afterwards           */
@@ -271,6 +277,10 @@
                a pixel (See comment above glTranslate below)                         */
             glTranslatef(0.5, 0.5, 0);
             checkGLcall("glTranslatef(0.5, 0.5, 0)");
+            if (This->renderUpsideDown) {
+                glMultMatrixf(invymat);
+                checkGLcall("glMultMatrixf(invymat)");
+            }
         }
 
     } else {
@@ -311,6 +321,11 @@
             glLoadIdentity();
             glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0);
             checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
+
+            if (This->renderUpsideDown) {
+                glMultMatrixf(invymat);
+                checkGLcall("glMultMatrixf(invymat)");
+            }
             glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]);
             checkGLcall("glLoadMatrixf");
         }
@@ -330,6 +345,10 @@
                a pixel (See comment above glTranslate above)                         */
             glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0);
             checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
+            if (This->renderUpsideDown) {
+                glMultMatrixf(invymat);
+                checkGLcall("glMultMatrixf(invymat)");
+            }
             This->modelview_valid = FALSE;
             This->proj_valid = FALSE;
         } 
diff -u -r /home/titan/winebase/wine/dlls/d3d8/surface.c ./surface.c
--- /home/titan/winebase/wine/dlls/d3d8/surface.c	2004-04-26 21:21:15.000000000 +0000
+++ ./surface.c	2004-04-25 10:40:39.000000000 +0000
@@ -129,7 +129,12 @@
     ICOM_THIS(IDirect3DSurface8Impl,iface);
   
     /* fixme: should we really lock as such? */
-
+    if (This->inTexture && This->inPBuffer) {
+	FIXME("Warning: Surface is in texture memory or pbuffer\n");
+	This->inTexture = 0;
+	This->inPBuffer = 0;
+    }
+    
     if (FALSE == This->lockable) {
       /* Note: UpdateTextures calls CopyRects which calls this routine to populate the 
             texture regions, and since the destination is an unlockable region we need
@@ -474,6 +479,33 @@
 HRESULT WINAPI IDirect3DSurface8Impl_LoadTexture(LPDIRECT3DSURFACE8 iface, GLenum gl_target, GLenum gl_level) {
   ICOM_THIS(IDirect3DSurface8Impl,iface);
 
+  if (This->inTexture)
+    return D3D_OK;
+  if (This->inPBuffer) {
+    ENTER_GL();
+    if (gl_level != 0)
+      FIXME("Surface in texture is only supported for level 0\n");
+    else if (This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8 ||
+        This->myDesc.Format == D3DFMT_DXT1 || This->myDesc.Format == D3DFMT_DXT3 ||
+        This->myDesc.Format == D3DFMT_DXT5)
+      FIXME("Format %d not supported\n", This->myDesc.Format);
+    else {
+	glCopyTexImage2D(gl_target,
+			 0,
+			 D3DFmt2GLIntFmt(This->Device,
+		         This->myDesc.Format),
+			 0,
+			 0,/*This->surfaces[j][i]->myDesc.Height-1,*/
+			 This->myDesc.Width,
+			 This->myDesc.Height,
+			 0);
+	TRACE("Updating target %d\n", gl_target);
+	This->inTexture = TRUE;
+    }
+    LEAVE_GL();
+    return D3D_OK;
+  }
+  
   if ((This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8) && 
       !GL_SUPPORT_DEV(EXT_PALETTED_TEXTURE, This->Device)) {
     /**
diff -u -r /home/titan/winebase/wine/dlls/d3d8/utils.c ./utils.c
--- /home/titan/winebase/wine/dlls/d3d8/utils.c	2004-04-26 21:21:15.000000000 +0000
+++ ./utils.c	2004-04-26 21:38:01.000000000 +0000
@@ -653,14 +653,17 @@
   case D3DTA_TFACTOR:   *source  = GL_CONSTANT_EXT;
     break;
   case D3DTA_SPECULAR:
-    /**
+    /*
      * According to the GL_ARB_texture_env_combine specs, SPECULAR is
      * 'Secondary color' and isn't supported until base GL supports it
      * There is no concept of temp registers as far as I can tell
      */
+    FIXME("Unhandled texture arg D3DTA_SPECULAR\n");
+    *source = GL_TEXTURE;
+    break;
 
   default:
-    FIXME("Unrecognized or unhandled texture arg %ld\n", iValue);
+    FIXME("Unrecognized texture arg %ld\n", iValue);
     *source = GL_TEXTURE;
   }
 }



More information about the wine-patches mailing list