wined3d: Rewrite IWineD3DSurfaceImpl_BltOverride colorfill codepath.
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index f394c3f..6775a61 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4775,6 +4775,168 @@
return WINED3D_OK;
}
+/* Not called from the VTable (internal subroutine) */
+HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
+ CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
+ float Z, DWORD Stencil) {
+ GLbitfield glMask = 0;
+ unsigned int i;
+ WINED3DRECT curRect;
+ RECT vp_rect;
+ WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
+ UINT drawable_width, drawable_height;
+
+ /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
+ * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
+ * for the cleared parts, and the untouched parts.
+ *
+ * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
+ * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
+ * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
+ * checking all this if the dest surface is in the drawable anyway.
+ */
+ if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
+ while(1) {
+ if(vp->X != 0 || vp->Y != 0 ||
+ vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
+ IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
+ break;
+ }
+ if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
+ This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
+ This->stateBlock->scissorRect.right < target->currentDesc.Width ||
+ This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
+ IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
+ break;
+ }
+ if(Count > 0 && pRects && (
+ pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
+ pRects[0].x2 < target->currentDesc.Width ||
+ pRects[0].y2 < target->currentDesc.Height)) {
+ IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
+ break;
+ }
+ break;
+ }
+ }
+
+ target->get_drawable_size(target, &drawable_width, &drawable_height);
+
+ ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
+ ENTER_GL();
+
+ if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
+ apply_fbo_state((IWineD3DDevice *) This);
+ }
+
+ /* Only set the values up once, as they are not changing */
+ if (Flags & WINED3DCLEAR_STENCIL) {
+ glClearStencil(Stencil);
+ checkGLcall("glClearStencil");
+ glMask = glMask | GL_STENCIL_BUFFER_BIT;
+ glStencilMask(0xFFFFFFFF);
+ }
+
+ if (Flags & WINED3DCLEAR_ZBUFFER) {
+ glDepthMask(GL_TRUE);
+ glClearDepth(Z);
+ checkGLcall("glClearDepth");
+ glMask = glMask | GL_DEPTH_BUFFER_BIT;
+ IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
+ }
+
+ if (Flags & WINED3DCLEAR_TARGET) {
+ TRACE("Clearing screen with glClear to color %x\n", Color);
+ glClearColor(D3DCOLOR_R(Color),
+ D3DCOLOR_G(Color),
+ D3DCOLOR_B(Color),
+ D3DCOLOR_A(Color));
+ checkGLcall("glClearColor");
+
+ /* Clear ALL colors! */
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glMask = glMask | GL_COLOR_BUFFER_BIT;
+ }
+
+ vp_rect.left = vp->X;
+ vp_rect.top = vp->Y;
+ vp_rect.right = vp->X + vp->Width;
+ vp_rect.bottom = vp->Y + vp->Height;
+ if (!(Count > 0 && pRects)) {
+ if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
+ IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
+ }
+ if(This->render_offscreen) {
+ glScissor(vp_rect.left, vp_rect.top,
+ vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
+ } else {
+ glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
+ vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
+ }
+ checkGLcall("glScissor");
+ glClear(glMask);
+ checkGLcall("glClear");
+ } else {
+ /* Now process each rect in turn */
+ for (i = 0; i < Count; i++) {
+ /* Note gl uses lower left, width/height */
+ IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
+ if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
+ IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
+ }
+ TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
+ pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
+ curRect.x1, (target->currentDesc.Height - curRect.y2),
+ curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
+
+ /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
+ * The rectangle is not cleared, no error is returned, but further rectanlges are
+ * still cleared if they are valid
+ */
+ if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
+ TRACE("Rectangle with negative dimensions, ignoring\n");
+ continue;
+ }
+
+ if(This->render_offscreen) {
+ glScissor(curRect.x1, curRect.y1,
+ curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
+ } else {
+ glScissor(curRect.x1, drawable_height - curRect.y2,
+ curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
+ }
+ checkGLcall("glScissor");
+
+ glClear(glMask);
+ checkGLcall("glClear");
+ }
+ }
+
+ /* Restore the old values (why..?) */
+ if (Flags & WINED3DCLEAR_STENCIL) {
+ glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
+ }
+ if (Flags & WINED3DCLEAR_TARGET) {
+ DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
+ glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
+ mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
+ mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
+ mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
+
+ /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
+ * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
+ */
+ IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
+ /* TODO: Move the fbo logic into ModifyLocation() */
+ if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
+ target->Flags |= SFLAG_INTEXTURE;
+ }
+ }
+ LEAVE_GL();
+
+ return WINED3D_OK;
+}
+
static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 7ba5125..30d6507 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -3253,6 +3253,15 @@
TRACE("Colorfill\n");
+ /* This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0] || dstSwapchain
+ must be true if we are here */
+ if (This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0] &&
+ !(This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer ||
+ (dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]))) {
+ TRACE("Surface is higher back buffer, falling back to software\n");
+ return WINED3DERR_INVALIDCALL;
+ }
+
/* The color as given in the Blt function is in the format of the frame-buffer...
* 'clear' expect it in ARGB format => we need to do some conversion :-)
*/
@@ -3288,44 +3297,12 @@
return WINED3DERR_INVALIDCALL;
}
- ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_RESOURCELOAD);
- ENTER_GL();
-
- TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
- if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
- glDrawBuffer(GL_BACK);
- checkGLcall("glDrawBuffer(GL_BACK)");
- } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
- glDrawBuffer(GL_FRONT);
- checkGLcall("glDrawBuffer(GL_FRONT)");
- } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
- glDrawBuffer(myDevice->offscreenBuffer);
- checkGLcall("glDrawBuffer(myDevice->offscreenBuffer3)");
- } else {
- LEAVE_GL();
- TRACE("Surface is higher back buffer, falling back to software\n");
- return WINED3DERR_INVALIDCALL;
- }
-
TRACE("(%p) executing Render Target override, color = %x\n", This, color);
-
- IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
- 1 /* Number of rectangles */,
- &rect,
- WINED3DCLEAR_TARGET,
- color,
- 0.0 /* Z */,
- 0 /* Stencil */);
-
- /* Restore the original draw buffer */
- if(!dstSwapchain) {
- glDrawBuffer(myDevice->offscreenBuffer);
- } else if(dstSwapchain->backBuffer && dstSwapchain->backBuffer[0]) {
- glDrawBuffer(GL_BACK);
- }
- vcheckGLcall("glDrawBuffer");
- LEAVE_GL();
-
+ IWineD3DDeviceImpl_ClearSurface(myDevice, This,
+ 1, /* Number of rectangles */
+ &rect, WINED3DCLEAR_TARGET, color,
+ 0.0 /* Z */,
+ 0 /* Stencil */);
return WINED3D_OK;
}
}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index e45d09d..a853903 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -769,6 +769,9 @@
extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl;
+HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
+ CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
+ float Z, DWORD Stencil);
void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This);
void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state);
static inline BOOL isStateDirty(WineD3DContext *context, DWORD state) {