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;
}
}