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

diff --git a/dlls/d3d8/d3d8_private.h b/dlls/d3d8/d3d8_private.h
index 28b639f..387a6d1 100644
--- a/dlls/d3d8/d3d8_private.h
+++ b/dlls/d3d8/d3d8_private.h
@@ -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 --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c
index 8c5e316..beba774 100644
--- a/dlls/d3d8/device.c
+++ b/dlls/d3d8/device.c
@@ -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");
 
@@ -2256,15 +2262,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:
@@ -4403,7 +4419,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);
   
@@ -4503,7 +4519,7 @@
 #endif
 
     if (NULL != This->renderTarget) {
-      GLenum prev_read;      
+      /*GLenum prev_read; */
       glFlush();
       vcheckGLcall("glFlush");
 
@@ -4514,6 +4530,7 @@
       getchar();
 #endif
 
+#if 0
       glGetIntegerv(GL_READ_BUFFER, &prev_read);
       vcheckGLcall("glIntegerv");
       glReadBuffer(GL_BACK);
@@ -4538,6 +4555,7 @@
       }      
       glReadBuffer(prev_read);
       vcheckGLcall("glReadBuffer");
+#endif
     }
 
     if (BackBufferFormat != This->renderTarget->myDesc.Format && 
@@ -4571,6 +4589,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 --git a/dlls/d3d8/drawprim.c b/dlls/d3d8/drawprim.c
index d98a6a4..54b2908 100644
--- a/dlls/d3d8/drawprim.c
+++ b/dlls/d3d8/drawprim.c
@@ -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 --git a/dlls/d3d8/surface.c b/dlls/d3d8/surface.c
index 7cd32e7..073377a 100644
--- a/dlls/d3d8/surface.c
+++ b/dlls/d3d8/surface.c
@@ -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 --git a/dlls/d3d8/utils.c b/dlls/d3d8/utils.c
index c8ceacb..3133998 100644
--- a/dlls/d3d8/utils.c
+++ b/dlls/d3d8/utils.c
@@ -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;
   }
 }