Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d11/device.c | 4 ++-- dlls/d3d9/device.c | 2 +- dlls/wined3d/cs.c | 36 +++++++++++++++++++------------ dlls/wined3d/device.c | 38 +++++++++++++++++++++++---------- dlls/wined3d/state.c | 39 +++++++++++++++++++++++++--------- dlls/wined3d/stateblock.c | 16 +++++++++----- dlls/wined3d/wined3d.spec | 2 +- dlls/wined3d/wined3d_private.h | 5 +++-- include/wine/wined3d.h | 3 ++- 9 files changed, 98 insertions(+), 47 deletions(-)
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index 7377952036..a8251aad27 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -998,7 +998,7 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_RSSetScissorRects(ID3D11De return;
wined3d_mutex_lock(); - wined3d_device_set_scissor_rect(device->wined3d_device, rects); + wined3d_device_set_scissor_rects(device->wined3d_device, 1, rects); wined3d_mutex_unlock(); }
@@ -4192,7 +4192,7 @@ static void STDMETHODCALLTYPE d3d10_device_RSSetScissorRects(ID3D10Device1 *ifac return;
wined3d_mutex_lock(); - wined3d_device_set_scissor_rect(device->wined3d_device, rects); + wined3d_device_set_scissor_rects(device->wined3d_device, 1, rects); wined3d_mutex_unlock(); }
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 0a77b3e316..b73d974860 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -2564,7 +2564,7 @@ static HRESULT WINAPI d3d9_device_SetScissorRect(IDirect3DDevice9Ex *iface, cons TRACE("iface %p, rect %p.\n", iface, rect);
wined3d_mutex_lock(); - wined3d_device_set_scissor_rect(device->wined3d_device, rect); + wined3d_device_set_scissor_rects(device->wined3d_device, 1, rect); wined3d_mutex_unlock();
return D3D_OK; diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 221e51eb94..6273ec04a1 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -34,7 +34,7 @@ enum wined3d_cs_op WINED3D_CS_OP_FLUSH, WINED3D_CS_OP_SET_PREDICATION, WINED3D_CS_OP_SET_VIEWPORTS, - WINED3D_CS_OP_SET_SCISSOR_RECT, + WINED3D_CS_OP_SET_SCISSOR_RECTS, WINED3D_CS_OP_SET_RENDERTARGET_VIEW, WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW, WINED3D_CS_OP_SET_VERTEX_DECLARATION, @@ -145,10 +145,11 @@ struct wined3d_cs_set_viewports struct wined3d_viewport viewports[1]; };
-struct wined3d_cs_set_scissor_rect +struct wined3d_cs_set_scissor_rects { enum wined3d_cs_op opcode; - RECT rect; + unsigned int rect_count; + RECT rects[1]; };
struct wined3d_cs_set_rendertarget_view @@ -545,7 +546,7 @@ void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT * op->fb = &cs->fb; SetRect(&op->draw_rect, vp->x, vp->y, vp->x + vp->width, vp->y + vp->height); if (state->render_states[WINED3D_RS_SCISSORTESTENABLE]) - IntersectRect(&op->draw_rect, &op->draw_rect, &state->scissor_rect); + IntersectRect(&op->draw_rect, &op->draw_rect, &state->scissor_rects[0]); op->color = *color; op->depth = depth; op->stencil = stencil; @@ -989,21 +990,28 @@ void wined3d_cs_emit_set_viewports(struct wined3d_cs *cs, unsigned int viewport_ cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); }
-static void wined3d_cs_exec_set_scissor_rect(struct wined3d_cs *cs, const void *data) +static void wined3d_cs_exec_set_scissor_rects(struct wined3d_cs *cs, const void *data) { - const struct wined3d_cs_set_scissor_rect *op = data; + const struct wined3d_cs_set_scissor_rects *op = data;
- cs->state.scissor_rect = op->rect; - device_invalidate_state(cs->device, STATE_SCISSORRECT); + if (op->rect_count) + memcpy(cs->state.scissor_rects, op->rects, op->rect_count * sizeof(*op->rects)); + else + SetRectEmpty(cs->state.scissor_rects); + cs->state.scissor_rect_count = op->rect_count; + device_invalidate_state(cs->device, STATE_VIEWPORT); }
-void wined3d_cs_emit_set_scissor_rect(struct wined3d_cs *cs, const RECT *rect) +void wined3d_cs_emit_set_scissor_rects(struct wined3d_cs *cs, unsigned int rect_count, const RECT *rects) { - struct wined3d_cs_set_scissor_rect *op; + struct wined3d_cs_set_scissor_rects *op;
- op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); - op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECT; - op->rect = *rect; + op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_set_scissor_rects, rects[rect_count]), + WINED3D_CS_QUEUE_DEFAULT); + op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECTS; + if (rect_count) + memcpy(op->rects, rects, rect_count * sizeof(*rects)); + op->rect_count = rect_count;
cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); } @@ -2411,7 +2419,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void /* WINED3D_CS_OP_FLUSH */ wined3d_cs_exec_flush, /* WINED3D_CS_OP_SET_PREDICATION */ wined3d_cs_exec_set_predication, /* WINED3D_CS_OP_SET_VIEWPORTS */ wined3d_cs_exec_set_viewports, - /* WINED3D_CS_OP_SET_SCISSOR_RECT */ wined3d_cs_exec_set_scissor_rect, + /* WINED3D_CS_OP_SET_SCISSOR_RECTS */ wined3d_cs_exec_set_scissor_rects, /* WINED3D_CS_OP_SET_RENDERTARGET_VIEW */ wined3d_cs_exec_set_rendertarget_view, /* WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW */ wined3d_cs_exec_set_depth_stencil_view, /* WINED3D_CS_OP_SET_VERTEX_DECLARATION */ wined3d_cs_exec_set_vertex_declaration, diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 8d4f4cde0e..e2852570d9 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -2123,19 +2123,33 @@ DWORD CDECL wined3d_device_get_sampler_state(const struct wined3d_device *device return device->state.sampler_states[sampler_idx][state]; }
-void CDECL wined3d_device_set_scissor_rect(struct wined3d_device *device, const RECT *rect) +void CDECL wined3d_device_set_scissor_rects(struct wined3d_device *device, unsigned int rect_count, + const RECT *rects) { - TRACE("device %p, rect %s.\n", device, wine_dbgstr_rect(rect)); + unsigned int i; + + TRACE("device %p, rect_count %u, rects %p.\n", device, rect_count, rects); + + for (i = 0; i < rect_count; ++i) + { + TRACE("%u: %s\n", i, wine_dbgstr_rect(&rects[i])); + }
if (device->recording) device->recording->changed.scissorRect = TRUE;
- if (EqualRect(&device->update_state->scissor_rect, rect)) + if (device->update_state->scissor_rect_count == rect_count + && !memcmp(device->update_state->scissor_rects, rects, rect_count * sizeof(*rects))) { - TRACE("App is setting the old scissor rectangle over, nothing to do.\n"); + TRACE("App is setting the old scissor rectangles over, nothing to do.\n"); return; } - CopyRect(&device->update_state->scissor_rect, rect); + + if (rect_count) + memcpy(device->update_state->scissor_rects, rects, rect_count * sizeof(*rects)); + else + memset(device->update_state->scissor_rects, 0, sizeof(device->update_state->scissor_rects)); + device->update_state->scissor_rect_count = rect_count;
if (device->recording) { @@ -2143,14 +2157,14 @@ void CDECL wined3d_device_set_scissor_rect(struct wined3d_device *device, const return; }
- wined3d_cs_emit_set_scissor_rect(device->cs, rect); + wined3d_cs_emit_set_scissor_rects(device->cs, rect_count, rects); }
void CDECL wined3d_device_get_scissor_rect(const struct wined3d_device *device, RECT *rect) { TRACE("device %p, rect %p.\n", device, rect);
- *rect = device->state.scissor_rect; + *rect = device->state.scissor_rects[0]; TRACE("Returning rect %s.\n", wine_dbgstr_rect(rect)); }
@@ -4476,8 +4490,9 @@ HRESULT CDECL wined3d_device_set_rendertarget_view(struct wined3d_device *device state->viewport_count = 1; wined3d_cs_emit_set_viewports(device->cs, 1, state->viewports);
- SetRect(&state->scissor_rect, 0, 0, view->width, view->height); - wined3d_cs_emit_set_scissor_rect(device->cs, &state->scissor_rect); + SetRect(&state->scissor_rects[0], 0, 0, view->width, view->height); + state->scissor_rect_count = 1; + wined3d_cs_emit_set_scissor_rects(device->cs, 1, state->scissor_rects); }
prev = device->fb.render_targets[view_idx]; @@ -4986,8 +5001,9 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device, state->viewport_count = 1; wined3d_cs_emit_set_viewports(device->cs, 1, state->viewports);
- SetRect(&state->scissor_rect, 0, 0, view->width, view->height); - wined3d_cs_emit_set_scissor_rect(device->cs, &state->scissor_rect); + SetRect(&state->scissor_rects[0], 0, 0, view->width, view->height); + state->scissor_rect_count = 1; + wined3d_cs_emit_set_scissor_rects(device->cs, 1, state->scissor_rects); }
if (device->d3d_initialized) diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index 5bcd244d93..6e4c2452c9 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -4770,25 +4770,44 @@ static void light(struct wined3d_context *context, const struct wined3d_state *s static void scissorrect(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { const struct wined3d_gl_info *gl_info = context->gl_info; - const RECT *r = &state->scissor_rect; + unsigned int height = 0; + const RECT *r;
/* Warning: glScissor uses window coordinates, not viewport coordinates, * so our viewport correction does not apply. Warning2: Even in windowed * mode the coords are relative to the window, not the screen. */ - TRACE("Setting new scissor rect to %s.\n", wine_dbgstr_rect(r));
- if (context->render_offscreen) - { - gl_info->gl_ops.gl.p_glScissor(r->left, r->top, r->right - r->left, r->bottom - r->top); - } - else + if (!context->render_offscreen) { const struct wined3d_rendertarget_view *target = state->fb->render_targets[0]; - UINT height; - UINT width; + unsigned int width;
wined3d_rendertarget_view_get_drawable_size(target, context, &width, &height); - gl_info->gl_ops.gl.p_glScissor(r->left, height - r->bottom, r->right - r->left, r->bottom - r->top); + } + + if (gl_info->supported[ARB_VIEWPORT_ARRAY]) + { + unsigned int i; + + for (i = 0; i < state->scissor_rect_count; ++i) + { + r = &state->scissor_rects[i]; + GL_EXTCALL(glScissorIndexed(i, r->left, height ? height - r->top : r->top, + r->right - r->left, r->bottom - r->top)); + } + + if (state->viewport_count > state->scissor_rect_count) + { + static const GLint reset[4 * WINED3D_MAX_VIEWPORTS]; + unsigned int reset_count = state->viewport_count - state->scissor_rect_count; + GL_EXTCALL(glScissorArrayv(state->scissor_rect_count, reset_count, reset)); + } + } + else + { + r = &state->scissor_rects[0]; + gl_info->gl_ops.gl.p_glScissor(r->left, height ? height - r->top : r->top, + r->right - r->left, r->bottom - r->top); } checkGLcall("glScissor"); } diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index 4ad0331f94..a70fed0806 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -825,12 +825,17 @@ void CDECL wined3d_stateblock_capture(struct wined3d_stateblock *stateblock) memset(stateblock->state.viewports, 0, sizeof(*stateblock->state.viewports)); }
- if (stateblock->changed.scissorRect && memcmp(&src_state->scissor_rect, - &stateblock->state.scissor_rect, sizeof(stateblock->state.scissor_rect))) + if (stateblock->changed.scissorRect + && (src_state->scissor_rect_count != stateblock->state.scissor_rect_count + || memcmp(src_state->scissor_rects, stateblock->state.scissor_rects, + src_state->scissor_rect_count * sizeof(*stateblock->state.scissor_rects)))) { - TRACE("Updating scissor rect.\n"); + TRACE("Updating scissor rects.\n");
- stateblock->state.scissor_rect = src_state->scissor_rect; + if ((stateblock->state.scissor_rect_count = src_state->scissor_rect_count)) + memcpy(stateblock->state.scissor_rects, src_state->scissor_rects, sizeof(src_state->scissor_rects)); + else + SetRectEmpty(stateblock->state.scissor_rects); }
map = stateblock->changed.streamSource; @@ -1065,7 +1070,8 @@ void CDECL wined3d_stateblock_apply(const struct wined3d_stateblock *stateblock) wined3d_device_set_viewports(device, stateblock->state.viewport_count, stateblock->state.viewports);
if (stateblock->changed.scissorRect) - wined3d_device_set_scissor_rect(device, &stateblock->state.scissor_rect); + wined3d_device_set_scissor_rects(device, stateblock->state.scissor_rect_count, + stateblock->state.scissor_rects);
map = stateblock->changed.streamSource; for (i = 0; map; map >>= 1, ++i) diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 1b59178296..21b2414bbe 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -176,7 +176,7 @@ @ cdecl wined3d_device_set_render_state(ptr long long) @ cdecl wined3d_device_set_rendertarget_view(ptr long ptr long) @ cdecl wined3d_device_set_sampler_state(ptr long long long) -@ cdecl wined3d_device_set_scissor_rect(ptr ptr) +@ cdecl wined3d_device_set_scissor_rects(ptr long ptr) @ cdecl wined3d_device_set_software_vertex_processing(ptr long) @ cdecl wined3d_device_set_stream_output(ptr long ptr long) @ cdecl wined3d_device_set_stream_source(ptr long ptr long long) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 7e6a87fe2f..dcdfcbe413 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2856,7 +2856,8 @@ struct wined3d_state struct wined3d_material material; struct wined3d_viewport viewports[WINED3D_MAX_VIEWPORTS]; unsigned int viewport_count; - RECT scissor_rect; + RECT scissor_rects[WINED3D_MAX_VIEWPORTS]; + unsigned int scissor_rect_count;
/* Light hashmap. Collisions are handled using linked lists. */ #define LIGHTMAP_SIZE 43 @@ -3592,7 +3593,7 @@ void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type UINT sampler_idx, struct wined3d_sampler *sampler) DECLSPEC_HIDDEN; void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx, enum wined3d_sampler_state state, DWORD value) DECLSPEC_HIDDEN; -void wined3d_cs_emit_set_scissor_rect(struct wined3d_cs *cs, const RECT *rect) DECLSPEC_HIDDEN; +void wined3d_cs_emit_set_scissor_rects(struct wined3d_cs *cs, unsigned int rect_count, const RECT *rects) DECLSPEC_HIDDEN; void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader) DECLSPEC_HIDDEN; void wined3d_cs_emit_set_stream_output(struct wined3d_cs *cs, UINT stream_idx, diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index ccda987405..6223706f57 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2426,7 +2426,8 @@ HRESULT __cdecl wined3d_device_set_rendertarget_view(struct wined3d_device *devi unsigned int view_idx, struct wined3d_rendertarget_view *view, BOOL set_viewport); void __cdecl wined3d_device_set_sampler_state(struct wined3d_device *device, UINT sampler_idx, enum wined3d_sampler_state state, DWORD value); -void __cdecl wined3d_device_set_scissor_rect(struct wined3d_device *device, const RECT *rect); +void __cdecl wined3d_device_set_scissor_rects(struct wined3d_device *device, + unsigned int rect_count, const RECT *rect); void __cdecl wined3d_device_set_software_vertex_processing(struct wined3d_device *device, BOOL software); void __cdecl wined3d_device_set_stream_output(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer, UINT offset);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10core/tests/device.c | 79 ++++++++++++++++++++++++++++++++--- dlls/d3d11/device.c | 14 ++----- dlls/d3d11/tests/d3d11.c | 73 +++++++++++++++++++++++++++++++- 3 files changed, 149 insertions(+), 17 deletions(-)
diff --git a/dlls/d3d10core/tests/device.c b/dlls/d3d10core/tests/device.c index 26218bf8e0..7e79d06c7f 100644 --- a/dlls/d3d10core/tests/device.c +++ b/dlls/d3d10core/tests/device.c @@ -5461,10 +5461,9 @@ float4 main(float4 color : COLOR) : SV_TARGET ID3D10Device_RSGetScissorRects(device, &count, tmp_rect); for (i = 0; i < D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; ++i) { - todo_wine_if(!i) - ok(!tmp_rect[i].left && !tmp_rect[i].top && !tmp_rect[i].right && !tmp_rect[i].bottom, - "Got unexpected scissor rect %s in slot %u.\n", - wine_dbgstr_rect(&tmp_rect[i]), i); + ok(!tmp_rect[i].left && !tmp_rect[i].top && !tmp_rect[i].right && !tmp_rect[i].bottom, + "Got unexpected scissor rect %s in slot %u.\n", + wine_dbgstr_rect(&tmp_rect[i]), i); } ID3D10Device_RSGetViewports(device, &count, NULL); ok(!count, "Got unexpected viewport count %u.\n", count); @@ -16274,10 +16273,14 @@ static void test_multiple_viewports(void) }; static const struct vec4 expected_values[] = { - {0.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 2.0f}, {0.5f, 0.5f}, {0.5f, 0.5f}, + {0.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 2.0f}, {0.5f, 0.5f}, {0.5f, 0.5f}, {0.0f, 4.0f}, {0.5f, 0.5f}, {0.5f, 0.5f}, + {0.5f, 0.5f}, {0.0f, 6.0f}, {0.5f, 0.5f}, {1.0f, 6.0f}, {0.5f, 0.5f}, }; static const float clear_color[] = {0.5f, 0.5f, 0.0f, 0.0f}; + ID3D10RasterizerState *rasterizer_state; + D3D10_RASTERIZER_DESC rasterizer_desc; unsigned int count, i; + D3D10_RECT rects[2]; RECT rect; int width;
@@ -16365,6 +16368,71 @@ static void test_multiple_viewports(void) draw_quad(&test_context); check_texture_sub_resource_vec4(texture, 0, NULL, &expected_values[4], 1);
+ /* Two viewports, empty second scissor rectangle. */ + memset(&rasterizer_desc, 0, sizeof(rasterizer_desc)); + rasterizer_desc.FillMode = D3D10_FILL_SOLID; + rasterizer_desc.CullMode = D3D10_CULL_BACK; + rasterizer_desc.DepthClipEnable = TRUE; + rasterizer_desc.ScissorEnable = TRUE; + hr = ID3D10Device_CreateRasterizerState(device, &rasterizer_desc, &rasterizer_state); + ok(SUCCEEDED(hr), "Failed to create rasterizer state, hr %#x.\n", hr); + + ID3D10Device_RSSetState(device, rasterizer_state); + + ID3D10Device_ClearRenderTargetView(device, rtv, clear_color); + ID3D10Device_RSSetViewports(device, 2, vp); + + rects[0].left = 0; + rects[0].top = 0; + rects[0].right = width; + rects[0].bottom = texture_desc.Height / 2; + memset(&rects[1], 0, sizeof(*rects)); + ID3D10Device_RSSetScissorRects(device, 1, rects); + constant.draw_id = 4; + ID3D10Device_UpdateSubresource(device, (ID3D10Resource *)cb, 0, NULL, &constant, 0, 0); + draw_quad(&test_context); + + SetRect(&rect, 0, 0, width - 1, texture_desc.Height / 2 - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[5], 1); + SetRect(&rect, 0, texture_desc.Height / 2, width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[6], 1); + SetRect(&rect, width, 0, 2 * width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[7], 1); + + /* Set scissor count to zero. */ + ID3D10Device_ClearRenderTargetView(device, rtv, clear_color); + ID3D10Device_RSSetScissorRects(device, 0, rects); + constant.draw_id = 5; + ID3D10Device_UpdateSubresource(device, (ID3D10Resource *)cb, 0, NULL, &constant, 0, 0); + draw_quad(&test_context); + SetRect(&rect, 0, 0, texture_desc.Width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[8], 1); + + /* Set both rectangles. */ + rects[0].left = 0; + rects[0].top = 0; + rects[0].right = width; + rects[0].bottom = texture_desc.Height / 2; + rects[1].left = width; + rects[1].top = 0; + rects[1].right = width * 2; + rects[1].bottom = texture_desc.Height / 2; + ID3D10Device_ClearRenderTargetView(device, rtv, clear_color); + ID3D10Device_RSSetScissorRects(device, 2, rects); + constant.draw_id = 6; + ID3D10Device_UpdateSubresource(device, (ID3D10Resource *)cb, 0, NULL, &constant, 0, 0); + draw_quad(&test_context); + + SetRect(&rect, 0, 0, width - 1, texture_desc.Height / 2 - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[9], 1); + SetRect(&rect, 0, texture_desc.Height / 2, width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[10], 1); + + SetRect(&rect, width, 0, 2 * width - 1, texture_desc.Height / 2 - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[11], 1); + SetRect(&rect, width, texture_desc.Height / 2, 2 * width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[12], 1); + /* Viewport count exceeding maximum value. */ ID3D10Device_RSSetViewports(device, 1, vp);
@@ -16386,6 +16454,7 @@ static void test_multiple_viewports(void) ok(count == 1, "Unexpected viewport count %d.\n", count); ok(vp[0].TopLeftX == 0.0f && vp[0].Width == width, "Unexpected viewport.\n");
+ ID3D10RasterizerState_Release(rasterizer_state); ID3D10RenderTargetView_Release(rtv); ID3D10Texture2D_Release(texture);
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index a8251aad27..c6a7218fb7 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -991,14 +991,11 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_RSSetScissorRects(ID3D11De
TRACE("iface %p, rect_count %u, rects %p.\n", iface, rect_count, rects);
- if (rect_count > 1) - FIXME("Multiple scissor rects not implemented.\n"); - - if (!rect_count) + if (rect_count > WINED3D_MAX_VIEWPORTS) return;
wined3d_mutex_lock(); - wined3d_device_set_scissor_rects(device->wined3d_device, 1, rects); + wined3d_device_set_scissor_rects(device->wined3d_device, rect_count, rects); wined3d_mutex_unlock(); }
@@ -4185,14 +4182,11 @@ static void STDMETHODCALLTYPE d3d10_device_RSSetScissorRects(ID3D10Device1 *ifac
TRACE("iface %p, rect_count %u, rects %p.\n", iface, rect_count, rects);
- if (rect_count > 1) - FIXME("Multiple scissor rects not implemented.\n"); - - if (!rect_count) + if (rect_count > WINED3D_MAX_VIEWPORTS) return;
wined3d_mutex_lock(); - wined3d_device_set_scissor_rects(device->wined3d_device, 1, rects); + wined3d_device_set_scissor_rects(device->wined3d_device, rect_count, rects); wined3d_mutex_unlock(); }
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index e59145292e..96521016c2 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -10566,7 +10566,6 @@ static void test_clear_state(void) ID3D11DeviceContext_RSGetScissorRects(context, &count, tmp_rect); for (i = 0; i < D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; ++i) { - todo_wine_if(!i) ok(!tmp_rect[i].left && !tmp_rect[i].top && !tmp_rect[i].right && !tmp_rect[i].bottom, "Got unexpected scissor rect %s in slot %u.\n", wine_dbgstr_rect(&tmp_rect[i]), i); @@ -26011,10 +26010,14 @@ static void test_multiple_viewports(void) }; static const struct vec4 expected_values[] = { - {0.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 2.0f}, {0.5f, 0.5f}, {0.5f, 0.5f}, + {0.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 2.0f}, {0.5f, 0.5f}, {0.5f, 0.5f}, {0.0f, 4.0f}, {0.5f, 0.5f}, {0.5f, 0.5f}, + {0.5f, 0.5f}, {0.0f, 6.0f}, {0.5f, 0.5f}, {1.0f, 6.0f}, {0.5f, 0.5f}, }; static const float clear_color[] = {0.5f, 0.5f, 0.0f, 0.0f}; + ID3D11RasterizerState *rasterizer_state; + D3D11_RASTERIZER_DESC rasterizer_desc; unsigned int count, i; + D3D11_RECT rects[2]; RECT rect; int width;
@@ -26103,6 +26106,72 @@ static void test_multiple_viewports(void) draw_quad(&test_context); check_texture_sub_resource_vec4(texture, 0, NULL, &expected_values[4], 1);
+ /* Two viewports, only first scissor rectangle set. */ + memset(&rasterizer_desc, 0, sizeof(rasterizer_desc)); + rasterizer_desc.FillMode = D3D11_FILL_SOLID; + rasterizer_desc.CullMode = D3D11_CULL_BACK; + rasterizer_desc.DepthClipEnable = TRUE; + rasterizer_desc.ScissorEnable = TRUE; + hr = ID3D11Device_CreateRasterizerState(device, &rasterizer_desc, &rasterizer_state); + ok(SUCCEEDED(hr), "Failed to create rasterizer state, hr %#x.\n", hr); + + ID3D11DeviceContext_RSSetState(context, rasterizer_state); + ID3D11RasterizerState_Release(rasterizer_state); + + ID3D11DeviceContext_ClearRenderTargetView(context, rtv, clear_color); + ID3D11DeviceContext_RSSetViewports(context, 2, vp); + + rects[0].left = 0; + rects[0].top = 0; + rects[0].right = width; + rects[0].bottom = texture_desc.Height / 2; + memset(&rects[1], 0, sizeof(*rects)); + ID3D11DeviceContext_RSSetScissorRects(context, 1, rects); + constant.draw_id = 4; + ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)cb, 0, NULL, &constant, 0, 0); + draw_quad(&test_context); + + SetRect(&rect, 0, 0, width - 1, texture_desc.Height / 2 - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[5], 1); + SetRect(&rect, 0, texture_desc.Height / 2, width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[6], 1); + SetRect(&rect, width, 0, 2 * width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[7], 1); + + /* Set scissor count to zero. */ + ID3D11DeviceContext_ClearRenderTargetView(context, rtv, clear_color); + ID3D11DeviceContext_RSSetScissorRects(context, 0, rects); + constant.draw_id = 5; + ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)cb, 0, NULL, &constant, 0, 0); + draw_quad(&test_context); + SetRect(&rect, 0, 0, texture_desc.Width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[8], 1); + + /* Set both rectangles. */ + rects[0].left = 0; + rects[0].top = 0; + rects[0].right = width; + rects[0].bottom = texture_desc.Height / 2; + rects[1].left = width; + rects[1].top = 0; + rects[1].right = width * 2; + rects[1].bottom = texture_desc.Height / 2; + ID3D11DeviceContext_ClearRenderTargetView(context, rtv, clear_color); + ID3D11DeviceContext_RSSetScissorRects(context, 2, rects); + constant.draw_id = 6; + ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)cb, 0, NULL, &constant, 0, 0); + draw_quad(&test_context); + + SetRect(&rect, 0, 0, width - 1, texture_desc.Height / 2 - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[9], 1); + SetRect(&rect, 0, texture_desc.Height / 2, width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[10], 1); + + SetRect(&rect, width, 0, 2 * width - 1, texture_desc.Height / 2 - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[11], 1); + SetRect(&rect, width, texture_desc.Height / 2, 2 * width - 1, texture_desc.Height - 1); + check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[12], 1); + /* Viewport count exceeding maximum value. */ ID3D11DeviceContext_RSSetViewports(context, 1, vp);
On 19 April 2018 at 08:50, Nikolay Sivov nsivov@codeweavers.com wrote:
@@ -4770,25 +4770,44 @@ static void light(struct wined3d_context *context, const struct wined3d_state *s static void scissorrect(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { const struct wined3d_gl_info *gl_info = context->gl_info;
- const RECT *r = &state->scissor_rect;
unsigned int height = 0;
const RECT *r;
/* Warning: glScissor uses window coordinates, not viewport coordinates,
- so our viewport correction does not apply. Warning2: Even in windowed
- mode the coords are relative to the window, not the screen. */
TRACE("Setting new scissor rect to %s.\n", wine_dbgstr_rect(r));
if (context->render_offscreen)
{
gl_info->gl_ops.gl.p_glScissor(r->left, r->top, r->right - r->left, r->bottom - r->top);
}
else
- if (!context->render_offscreen) { const struct wined3d_rendertarget_view *target = state->fb->render_targets[0];
UINT height;
UINT width;
unsigned int width; wined3d_rendertarget_view_get_drawable_size(target, context, &width, &height);
gl_info->gl_ops.gl.p_glScissor(r->left, height - r->bottom, r->right - r->left, r->bottom - r->top);
- }
- if (gl_info->supported[ARB_VIEWPORT_ARRAY])
- {
unsigned int i;
for (i = 0; i < state->scissor_rect_count; ++i)
{
r = &state->scissor_rects[i];
GL_EXTCALL(glScissorIndexed(i, r->left, height ? height - r->top : r->top,
r->right - r->left, r->bottom - r->top));
}
if (state->viewport_count > state->scissor_rect_count)
{
static const GLint reset[4 * WINED3D_MAX_VIEWPORTS];
unsigned int reset_count = state->viewport_count - state->scissor_rect_count;
GL_EXTCALL(glScissorArrayv(state->scissor_rect_count, reset_count, reset));
}
Does this also do the right thing if the viewport count is changed after setting the scissor rectangles?
@@ -825,12 +825,17 @@ void CDECL wined3d_stateblock_capture(struct wined3d_stateblock *stateblock) memset(stateblock->state.viewports, 0, sizeof(*stateblock->state.viewports)); }
- if (stateblock->changed.scissorRect && memcmp(&src_state->scissor_rect,
&stateblock->state.scissor_rect, sizeof(stateblock->state.scissor_rect)))
- if (stateblock->changed.scissorRect
&& (src_state->scissor_rect_count != stateblock->state.scissor_rect_count
|| memcmp(src_state->scissor_rects, stateblock->state.scissor_rects,
{src_state->scissor_rect_count * sizeof(*stateblock->state.scissor_rects))))
TRACE("Updating scissor rect.\n");
TRACE("Updating scissor rects.\n");
stateblock->state.scissor_rect = src_state->scissor_rect;
if ((stateblock->state.scissor_rect_count = src_state->scissor_rect_count))
memcpy(stateblock->state.scissor_rects, src_state->scissor_rects, sizeof(src_state->scissor_rects));
else
SetRectEmpty(stateblock->state.scissor_rects);
This works, but is it intentional to copy the entire array in the non-zero scissor rect count case?