diff --git a/dlls/d3d8/tests/visual.c b/dlls/d3d8/tests/visual.c index 0f09012e54a..9915fa9cda8 100644 --- a/dlls/d3d8/tests/visual.c +++ b/dlls/d3d8/tests/visual.c @@ -259,6 +259,54 @@ static void lighting_test(IDirect3DDevice8 *device) ok(hr == D3D_OK, "IDirect3DDevice8_SetRenderState returned %s\n", DXGetErrorString8(hr)); } +static void clear_test(IDirect3DDevice8 *device) +{ + /* Tests the correctness of clearing parameters */ + HRESULT hr; + D3DRECT rect[2]; + D3DRECT rect_negneg; + DWORD color; + + hr = IDirect3DDevice8_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffffff, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice8_Clear failed with %s\n", DXGetErrorString8(hr)); + + /* Positive x, negative y */ + rect[0].x1 = 0; + rect[0].y1 = 480; + rect[0].x2 = 320; + rect[0].y2 = 240; + + /* Positive x, positive y */ + rect[1].x1 = 0; + rect[1].y1 = 0; + rect[1].x2 = 320; + rect[1].y2 = 240; + /* Clear 2 rectangles with one call. Shows that a positive value is returned, but the negative rectangle + * is ignored, the positive is still cleared afterwards + */ + hr = IDirect3DDevice8_Clear(device, 2, rect, D3DCLEAR_TARGET, 0xffff0000, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice8_Clear failed with %s\n", DXGetErrorString8(hr)); + + /* negative x, negative y */ + rect_negneg.x1 = 640; + rect_negneg.x1 = 240; + rect_negneg.x2 = 320; + rect_negneg.y2 = 0; + hr = IDirect3DDevice8_Clear(device, 1, &rect_negneg, D3DCLEAR_TARGET, 0xff00ff00, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice8_Clear failed with %s\n", DXGetErrorString8(hr)); + + IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL); + + color = getPixelColor(device, 160, 360); /* lower left quad */ + ok(color == 0x00ffffff, "Clear rectangle 3(pos, neg) has color %08x\n", color); + color = getPixelColor(device, 160, 120); /* upper left quad */ + ok(color == 0x00ff0000, "Clear rectangle 1(pos, pos) has color %08x\n", color); + color = getPixelColor(device, 480, 360); /* lower right quad */ + 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); +} + START_TEST(visual) { IDirect3DDevice8 *device_ptr; @@ -308,6 +356,7 @@ START_TEST(visual) /* Now run the real test */ lighting_test(device_ptr); + clear_test(device_ptr); cleanup: if(device_ptr) IDirect3DDevice8_Release(device_ptr); diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index f5c15a058db..b586c22946f 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -266,6 +266,54 @@ static void lighting_test(IDirect3DDevice9 *device) IDirect3DDevice9_SetVertexDeclaration(device, NULL); } +static void clear_test(IDirect3DDevice9 *device) +{ + /* Tests the correctness of clearing parameters */ + HRESULT hr; + D3DRECT rect[2]; + D3DRECT rect_negneg; + DWORD color; + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffffff, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed with %s\n", DXGetErrorString9(hr)); + + /* Positive x, negative y */ + rect[0].x1 = 0; + rect[0].y1 = 480; + rect[0].x2 = 320; + rect[0].y2 = 240; + + /* Positive x, positive y */ + rect[1].x1 = 0; + rect[1].y1 = 0; + rect[1].x2 = 320; + rect[1].y2 = 240; + /* Clear 2 rectangles with one call. Shows that a positive value is returned, but the negative rectangle + * is ignored, the positive is still cleared afterwards + */ + hr = IDirect3DDevice9_Clear(device, 2, rect, D3DCLEAR_TARGET, 0xffff0000, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed with %s\n", DXGetErrorString9(hr)); + + /* negative x, negative y */ + rect_negneg.x1 = 640; + rect_negneg.x1 = 240; + rect_negneg.x2 = 320; + rect_negneg.y2 = 0; + hr = IDirect3DDevice9_Clear(device, 1, &rect_negneg, D3DCLEAR_TARGET, 0xff00ff00, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed with %s\n", DXGetErrorString9(hr)); + + IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + + color = getPixelColor(device, 160, 360); /* lower left quad */ + ok(color == 0x00ffffff, "Clear rectangle 3(pos, neg) has color %08x\n", color); + color = getPixelColor(device, 160, 120); /* upper left quad */ + ok(color == 0x00ff0000, "Clear rectangle 1(pos, pos) has color %08x\n", color); + color = getPixelColor(device, 480, 360); /* lower right quad */ + 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); +} + START_TEST(visual) { IDirect3DDevice9 *device_ptr; @@ -315,6 +363,7 @@ START_TEST(visual) /* Now execute the real tests */ lighting_test(device_ptr); + clear_test(device_ptr); cleanup: if(device_ptr) IDirect3DDevice9_Release(device_ptr); diff --git a/dlls/ddraw/tests/visual.c b/dlls/ddraw/tests/visual.c index 58a701d99d2..09725659397 100644 --- a/dlls/ddraw/tests/visual.c +++ b/dlls/ddraw/tests/visual.c @@ -301,6 +301,52 @@ static void lighting_test(IDirect3DDevice7 *device) ok(hr == D3D_OK, "IDirect3DDevice7_SetRenderState returned %08x\n", hr); } +static void clear_test(IDirect3DDevice7 *device) +{ + /* Tests the correctness of clearing parameters */ + HRESULT hr; + D3DRECT rect[2]; + D3DRECT rect_negneg; + DWORD color; + + hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffffff, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice7_Clear failed with %08x\n", hr); + + /* Positive x, negative y */ + rect[0].x1 = 0; + rect[0].y1 = 480; + rect[0].x2 = 320; + rect[0].y2 = 240; + + /* Positive x, positive y */ + rect[1].x1 = 0; + rect[1].y1 = 0; + rect[1].x2 = 320; + rect[1].y2 = 240; + /* Clear 2 rectangles with one call. Shows that a positive value is returned, but the negative rectangle + * is ignored, the positive is still cleared afterwards + */ + hr = IDirect3DDevice7_Clear(device, 2, rect, D3DCLEAR_TARGET, 0xffff0000, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice7_Clear failed with %08x\n", hr); + + /* negative x, negative y */ + rect_negneg.x1 = 640; + rect_negneg.x1 = 240; + rect_negneg.x2 = 320; + rect_negneg.y2 = 0; + hr = IDirect3DDevice7_Clear(device, 1, &rect_negneg, D3DCLEAR_TARGET, 0xff00ff00, 0.0, 0); + ok(hr == D3D_OK, "IDirect3DDevice7_Clear failed with %08x\n", hr); + + color = getPixelColor(device, 160, 360); /* lower left quad */ + ok(color == 0x00ffffff, "Clear rectangle 3(pos, neg) has color %08x\n", color); + color = getPixelColor(device, 160, 120); /* upper left quad */ + ok(color == 0x00ff0000, "Clear rectangle 1(pos, pos) has color %08x\n", color); + color = getPixelColor(device, 480, 360); /* lower right quad */ + 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); +} + START_TEST(visual) { HRESULT hr; @@ -342,6 +388,7 @@ START_TEST(visual) /* Now run the tests */ lighting_test(Direct3DDevice); + clear_test(Direct3DDevice); cleanup: releaseObjects(); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 500a857215e..e614559bb21 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -4226,26 +4226,34 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun glMask = glMask | GL_COLOR_BUFFER_BIT; } - /* Now process each rect in turn */ - for (i = 0; i < Count || i == 0; i++) { - - if (curRect) { - /* 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->x1, curRect->y1, curRect->x2, curRect->y2, - curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2), - curRect->x2 - curRect->x1, curRect->y2 - curRect->y1); - glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2), - curRect->x2 - curRect->x1, curRect->y2 - curRect->y1); - checkGLcall("glScissor"); - } - - /* Clear the selected rectangle (or full screen) */ + if (!curRect) { glClear(glMask); checkGLcall("glClear"); + } else { + /* 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].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); - /* Step to the next rectangle */ - if (curRect) curRect = curRect + sizeof(WINED3DRECT); + /* 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) { + TRACE("Rectangle with negative dimensions, ignoring\n"); + continue; + } + + glScissor(curRect[i].x1, ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2, + curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); + checkGLcall("glScissor"); + + glClear(glMask); + checkGLcall("glClear"); + } } /* Restore the old values (why..?) */ @@ -4253,10 +4261,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]); } if (Flags & WINED3DCLEAR_TARGET) { - glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE, - This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE, - This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE, - This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE); + 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); } LEAVE_GL();