From fce9abd0950c0882636bbcda25c355c5d6b95bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sat, 1 Dec 2007 15:49:42 +0100 Subject: [PATCH] wined3d: Clear honors the viewport. --- dlls/d3d9/tests/visual.c | 64 ++++++++++++++++++++++++++++++++++++++++ dlls/wined3d/device.c | 59 ++++++++++++++++++++++-------------- 2 files changed, 101 insertions(+), 22 deletions(-) diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index c624962dc41..2403881d795 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -276,6 +276,7 @@ static void clear_test(IDirect3DDevice9 *device) D3DRECT rect[2]; D3DRECT rect_negneg; DWORD color; + D3DVIEWPORT9 old_vp, vp; hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffffff, 0.0, 0); ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed with %s\n", DXGetErrorString9(hr)); @@ -315,6 +316,69 @@ static void clear_test(IDirect3DDevice9 *device) ok(color == 0x00ffffff, "Clear rectangle 4(NULL) has color %08x\n", color); color = getPixelColor(device, 480, 120); /* upper right quad */ ok(color == 0x00ffffff, "Clear rectangle 4(neg, neg) has color %08x\n", color); + + /* Test how the viewport affects clears */ + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffffff, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_GetViewport(device, &old_vp); + ok(hr == D3D_OK, "IDirect3DDevice9_GetViewport failed with %s\n", DXGetErrorString9(hr)); + + vp.X = 160; + vp.Y = 120; + vp.Width = 160; + vp.Height = 120; + vp.MinZ = 0.0; + vp.MaxZ = 1.0; + hr = IDirect3DDevice9_SetViewport(device, &vp); + ok(hr == D3D_OK, "IDirect3DDevice9_SetViewport failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed with %s\n", DXGetErrorString9(hr)); + + vp.X = 320; + vp.Y = 240; + vp.Width = 320; + vp.Height = 240; + vp.MinZ = 0.0; + vp.MaxZ = 1.0; + hr = IDirect3DDevice9_SetViewport(device, &vp); + ok(hr == D3D_OK, "IDirect3DDevice9_SetViewport failed with %s\n", DXGetErrorString9(hr)); + rect[0].x1 = 160; + rect[0].y1 = 120; + rect[0].x2 = 480; + rect[0].y2 = 360; + hr = IDirect3DDevice9_Clear(device, 1, &rect[0], D3DCLEAR_TARGET, 0xff00ff00, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed with %s\n", DXGetErrorString9(hr)); + + hr = IDirect3DDevice9_SetViewport(device, &old_vp); + ok(hr == D3D_OK, "IDirect3DDevice9_SetViewport failed with %s\n", DXGetErrorString9(hr)); + + IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + color = getPixelColor(device, 158, 118); + ok(color == 0x00ffffff, "(158,118) has color %08x\n", color); + color = getPixelColor(device, 162, 118); + ok(color == 0x00ffffff, "(162,118) has color %08x\n", color); + color = getPixelColor(device, 158, 122); + ok(color == 0x00ffffff, "(158,122) has color %08x\n", color); + color = getPixelColor(device, 162, 122); + ok(color == 0x000000ff, "(162,122) has color %08x\n", color); + + color = getPixelColor(device, 318, 238); + ok(color == 0x000000ff, "(318,238) has color %08x\n", color); + color = getPixelColor(device, 322, 238); + ok(color == 0x00ffffff, "(322,328) has color %08x\n", color); + color = getPixelColor(device, 318, 242); + ok(color == 0x00ffffff, "(318,242) has color %08x\n", color); + color = getPixelColor(device, 322, 242); + ok(color == 0x0000ff00, "(322,242) has color %08x\n", color); + + color = getPixelColor(device, 478, 358); + ok(color == 0x0000ff00, "(478,358 has color %08x\n", color); + color = getPixelColor(device, 482, 358); + ok(color == 0x00ffffff, "(482,358) has color %08x\n", color); + color = getPixelColor(device, 478, 362); + ok(color == 0x00ffffff, "(478,362) has color %08x\n", color); + color = getPixelColor(device, 482, 362); + ok(color == 0x00ffffff, "(482,362) has color %08x\n", color); } typedef struct { diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index b1fe2515616..b0e8dc44f24 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -4786,7 +4786,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun GLbitfield glMask = 0; unsigned int i; - CONST WINED3DRECT* curRect; + WINED3DRECT curRect; + RECT vp_rect; + WINED3DVIEWPORT *vp = &This->stateBlock->viewport; TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This, Count, pRects, Flags, Color, Z, Stencil); @@ -4803,19 +4805,25 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun * * 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 + * 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 (Count > 0 && pRects) { - if(Flags & WINED3DCLEAR_TARGET) { - if(pRects[0].x1 > 0 || pRects[0].y1 > 0 || - pRects[0].x2 < target->currentDesc.Width || - pRects[0].y2 < target->currentDesc.Height) { + 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(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; } - curRect = pRects; - } else { - curRect = NULL; } /* This is for offscreen rendering as well as for multithreading, thus activate the set render target @@ -4857,9 +4865,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun glMask = glMask | GL_COLOR_BUFFER_BIT; } - if (!curRect) { - /* In drawable flag is set below */ - + if (!(Count > 0 && pRects)) { if (This->render_offscreen) { glScissor(This->stateBlock->viewport.X, This->stateBlock->viewport.Y, @@ -4876,29 +4882,38 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun glClear(glMask); checkGLcall("glClear"); } else { + /* The viewport cap still applies, we have to intersect each clear rect with the viewport + * range because glClear ignores the viewport(and the viewport isn't even applied in this state) + */ + vp_rect.left = vp->X; + vp_rect.top = vp->Y; + vp_rect.right = vp->X + vp->Width; + vp_rect.bottom = vp->Y + vp->Height; + /* 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, (target->currentDesc.Height - curRect[i].y2), - curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); + IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]); + 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[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) { + if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) { TRACE("Rectangle with negative dimensions, ignoring\n"); continue; } if(This->render_offscreen) { - glScissor(curRect[i].x1, curRect[i].y1, - curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); + glScissor(curRect.x1, curRect.y1, + curRect.x2 - curRect.x1, curRect.y2 - curRect.y1); } else { - glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2, - curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); + glScissor(curRect.x1, target->currentDesc.Height - curRect.y2, + curRect.x2 - curRect.x1, curRect.y2 - curRect.y1); } checkGLcall("glScissor");