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
*/
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;
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,
DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
GLbitfield glMask = 0;
unsigned int i;
@ -4181,6 +4182,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
}
if (!curRect) {
/* In drawable flag is set below */
glScissor(This->stateBlock->viewport.X,
(((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
(This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
@ -4190,12 +4193,23 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
glClear(glMask);
checkGLcall("glClear");
} 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 */
for (i = 0; i < Count; i++) {
/* 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,
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);
/* 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;
}
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);
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
*/
if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INTEXTURE;
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~SFLAG_INSYSMEM;
target->Flags |= SFLAG_INTEXTURE;
target->Flags &= ~SFLAG_INSYSMEM;
} else {
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INDRAWABLE;
((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
target->Flags |= SFLAG_INDRAWABLE;
target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
}
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 */
void drawPrimitive(IWineD3DDevice *iface,
int PrimitiveType,
@ -1013,6 +1134,7 @@ void drawPrimitive(IWineD3DDevice *iface,
/* Invalidate the back buffer memory so LockRect will read it the next time */
for(i = 0; i < GL_LIMITS(buffers); i++) {
target = (IWineD3DSurfaceImpl *) This->render_targets[i];
/* TODO: Only do all that if we're going to change anything
* Texture container dirtification does not work quite right yet
*/
@ -1022,6 +1144,12 @@ void drawPrimitive(IWineD3DDevice *iface,
if(i == 0) {
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) {
/* Onscreen target. Invalidate system memory copy and texture copy */
target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE);

View File

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