wined3d: Blit the offscreen texture into the drawable if needed.

When using pbuffer or back buffer offscreen rendering the content of
the drawable will have been overwritten. Thus the texture has to be
written into the drawable. An exception is the (pretty common) case
that the whole render target is cleared before rendering to it.
This commit is contained in:
Stefan Dösinger 2007-03-10 00:55:08 +01:00 committed by Alexandre Julliard
parent 850bd7b414
commit 603e7933ea
4 changed files with 153 additions and 6 deletions

View File

@ -710,6 +710,9 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU
* Read the back buffer of the old drawable into the destination texture * Read the back buffer of the old drawable into the destination texture
*/ */
IWineD3DSurface_PreLoad(This->lastActiveRenderTarget); IWineD3DSurface_PreLoad(This->lastActiveRenderTarget);
/* Assume that the drawable will be modified by some other things now */
((IWineD3DSurfaceImpl *) This->lastActiveRenderTarget)->Flags &= ~SFLAG_INDRAWABLE;
} }
This->lastActiveRenderTarget = target; This->lastActiveRenderTarget = target;
if(oldRenderOffscreen != This->render_offscreen && This->depth_copy_state != WINED3D_DCS_NO_COPY) { if(oldRenderOffscreen != This->render_offscreen && This->depth_copy_state != WINED3D_DCS_NO_COPY) {

View File

@ -4124,6 +4124,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects, static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) { DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
GLbitfield glMask = 0; GLbitfield glMask = 0;
unsigned int i; unsigned int i;
@ -4181,6 +4182,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
} }
if (!curRect) { if (!curRect) {
/* In drawable flag is set below */
glScissor(This->stateBlock->viewport.X, glScissor(This->stateBlock->viewport.X,
(((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
(This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)), (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
@ -4190,12 +4193,23 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
glClear(glMask); glClear(glMask);
checkGLcall("glClear"); checkGLcall("glClear");
} else { } else {
if(!(target->Flags & SFLAG_INDRAWABLE) &&
!(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
curRect[0].x2 < target->currentDesc.Width ||
curRect[0].y2 < target->currentDesc.Height) {
TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
blt_to_drawable(This, target);
}
}
/* Now process each rect in turn */ /* Now process each rect in turn */
for (i = 0; i < Count; i++) { for (i = 0; i < Count; i++) {
/* Note gl uses lower left, width/height */ /* Note gl uses lower left, width/height */
TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect, TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2, curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
curRect[i].x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2), curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
/* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently. /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
@ -4207,7 +4221,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
continue; continue;
} }
glScissor(curRect[i].x1, ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2, glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
checkGLcall("glScissor"); checkGLcall("glScissor");
@ -4234,11 +4248,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
* it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
*/ */
if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) { if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INTEXTURE; target->Flags |= SFLAG_INTEXTURE;
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~SFLAG_INSYSMEM; target->Flags &= ~SFLAG_INSYSMEM;
} else { } else {
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INDRAWABLE; target->Flags |= SFLAG_INDRAWABLE;
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM); target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
} }
return WINED3D_OK; return WINED3D_OK;
} }

View File

@ -989,6 +989,127 @@ inline void drawStridedInstanced(IWineD3DDevice *iface, WineDirect3DVertexStride
} }
} }
struct coords {
int x, y, z;
};
void blt_to_drawable(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *surface) {
struct coords coords[4];
int low_coord;
/* TODO: This could be supported for lazy unlocking */
if(!(surface->Flags & SFLAG_INTEXTURE)) {
/* It is ok at init to be nowhere */
if(!(surface->Flags & SFLAG_INSYSMEM)) {
ERR("Blitting surfaces from sysmem not supported yet\n");
}
return;
}
ENTER_GL();
ActivateContext(This, This->render_targets[0], CTXUSAGE_BLIT);
if(surface->glDescription.target == GL_TEXTURE_2D) {
glBindTexture(GL_TEXTURE_2D, surface->glDescription.textureName);
checkGLcall("GL_TEXTURE_2D, This->glDescription.textureName)");
coords[0].x = 0; coords[0].y = 0; coords[0].z = 0;
coords[1].x = 0; coords[1].y = 1; coords[1].z = 0;
coords[2].x = 1; coords[2].y = 1; coords[2].z = 0;
coords[3].x = 1; coords[3].y = 0; coords[3].z = 0;
low_coord = 0;
} else {
/* Must be a cube map */
glDisable(GL_TEXTURE_2D);
checkGLcall("glDisable(GL_TEXTURE_2D)");
glEnable(GL_TEXTURE_CUBE_MAP_ARB);
checkGLcall("glEnable(surface->glDescription.target)");
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, surface->glDescription.textureName);
checkGLcall("GL_TEXTURE_CUBE_MAP_ARB, This->glDescription.textureName)");
switch(surface->glDescription.target) {
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
coords[0].x = 1; coords[0].y = -1; coords[0].z = 1;
coords[1].x = 1; coords[1].y = 1; coords[1].z = 1;
coords[2].x = 1; coords[2].y = 1; coords[2].z = -1;
coords[3].x = 1; coords[3].y = -1; coords[3].z = -1;
break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
coords[0].x = -1; coords[0].y = -1; coords[0].z = 1;
coords[1].x = -1; coords[1].y = 1; coords[1].z = 1;
coords[2].x = -1; coords[2].y = 1; coords[2].z = -1;
coords[3].x = -1; coords[3].y = -1; coords[3].z = -1;
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
coords[0].x = -1; coords[0].y = 1; coords[0].z = 1;
coords[1].x = 1; coords[1].y = 1; coords[1].z = 1;
coords[2].x = 1; coords[2].y = 1; coords[2].z = -1;
coords[3].x = -1; coords[3].y = 1; coords[3].z = -1;
break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
coords[0].x = -1; coords[0].y = -1; coords[0].z = 1;
coords[1].x = 1; coords[1].y = -1; coords[1].z = 1;
coords[2].x = 1; coords[2].y = -1; coords[2].z = -1;
coords[3].x = -1; coords[3].y = -1; coords[3].z = -1;
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
coords[0].x = -1; coords[0].y = -1; coords[0].z = 1;
coords[1].x = 1; coords[1].y = -1; coords[1].z = 1;
coords[2].x = 1; coords[2].y = -1; coords[2].z = 1;
coords[3].x = -1; coords[3].y = -1; coords[3].z = 1;
break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
coords[0].x = -1; coords[0].y = -1; coords[0].z = -1;
coords[1].x = 1; coords[1].y = -1; coords[1].z = -1;
coords[2].x = 1; coords[2].y = -1; coords[2].z = -1;
coords[3].x = -1; coords[3].y = -1; coords[3].z = -1;
default:
ERR("Unexpected texture target \n");
LEAVE_GL();
return;
}
low_coord = -1;
}
if(This->render_offscreen) {
coords[0].y = coords[0].y == 1 ? low_coord : 1;
coords[1].y = coords[1].y == 1 ? low_coord : 1;
coords[2].y = coords[2].y == 1 ? low_coord : 1;
coords[3].y = coords[3].y == 1 ? low_coord : 1;
}
glBegin(GL_QUADS);
glTexCoord3iv((GLint *) &coords[0]);
glVertex2i(0, 0);
glTexCoord3iv((GLint *) &coords[1]);
glVertex2i(0, surface->pow2Height);
glTexCoord3iv((GLint *) &coords[2]);
glVertex2i(surface->pow2Width, surface->pow2Height);
glTexCoord3iv((GLint *) &coords[3]);
glVertex2i(surface->pow2Width, 0);
glEnd();
checkGLcall("glEnd");
if(surface->glDescription.target != GL_TEXTURE_2D) {
glEnable(GL_TEXTURE_2D);
checkGLcall("glEnable(GL_TEXTURE_2D)");
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
}
LEAVE_GL();
}
/* Routine common to the draw primitive and draw indexed primitive routines */ /* Routine common to the draw primitive and draw indexed primitive routines */
void drawPrimitive(IWineD3DDevice *iface, void drawPrimitive(IWineD3DDevice *iface,
int PrimitiveType, int PrimitiveType,
@ -1013,6 +1134,7 @@ void drawPrimitive(IWineD3DDevice *iface,
/* Invalidate the back buffer memory so LockRect will read it the next time */ /* Invalidate the back buffer memory so LockRect will read it the next time */
for(i = 0; i < GL_LIMITS(buffers); i++) { for(i = 0; i < GL_LIMITS(buffers); i++) {
target = (IWineD3DSurfaceImpl *) This->render_targets[i]; target = (IWineD3DSurfaceImpl *) This->render_targets[i];
/* TODO: Only do all that if we're going to change anything /* TODO: Only do all that if we're going to change anything
* Texture container dirtification does not work quite right yet * Texture container dirtification does not work quite right yet
*/ */
@ -1022,6 +1144,12 @@ void drawPrimitive(IWineD3DDevice *iface,
if(i == 0) { if(i == 0) {
IWineD3DSurface_GetContainer((IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain); IWineD3DSurface_GetContainer((IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain);
/* Need the surface in the drawable! */
if(!(target->Flags & SFLAG_INDRAWABLE) && (swapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO)) {
blt_to_drawable(This, target);
}
if(swapchain) { if(swapchain) {
/* Onscreen target. Invalidate system memory copy and texture copy */ /* Onscreen target. Invalidate system memory copy and texture copy */
target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE); target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE);

View File

@ -427,6 +427,8 @@ void primitiveConvertFVFtoOffset(DWORD thisFVF,
DWORD get_flexible_vertex_size(DWORD d3dvtVertexType); DWORD get_flexible_vertex_size(DWORD d3dvtVertexType);
void blt_to_drawable(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *surface);
#define eps 1e-8 #define eps 1e-8
#define GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_num) \ #define GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_num) \