diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index f7620aa8f6d..5fe2b58258f 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -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) { diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index c7eda3bcb85..1c2080bb873 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -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; } diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 4efd3e7c886..c34c642ad9d 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -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); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index df0ff6a9973..9d80d83d6cd 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -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) \