Commit 603e7933 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

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.
parent 850bd7b4
......@@ -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) {
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment