Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d11/device.c | 4 +-- dlls/d3d9/device.c | 2 +- dlls/wined3d/context.c | 4 +++ dlls/wined3d/cs.c | 34 +++++++++++++++--------- dlls/wined3d/device.c | 40 ++++++++++++++++++++-------- dlls/wined3d/state.c | 48 ++++++++++++++++++++++++++-------- dlls/wined3d/stateblock.c | 17 ++++++++---- dlls/wined3d/wined3d.spec | 2 +- dlls/wined3d/wined3d_private.h | 6 +++-- include/wine/wined3d.h | 3 ++- 10 files changed, 113 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/context.c b/dlls/wined3d/context.c index d5378e203e..c9325add7b 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -2244,6 +2244,10 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain, if (device->dummy_textures.tex_2d) context_bind_dummy_textures(device, ret);
+ /* Initialize all rectangles to avoid resetting unused ones later. */ + gl_info->gl_ops.gl.p_glScissor(0, 0, 0, 0); + checkGLcall("glScissor"); + TRACE("Created context %p.\n", ret);
return ret; diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 221e51eb94..517b599790 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; + 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_SCISSORRECT); }
-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..6352b3cc79 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -414,6 +414,7 @@ void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, c draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top); } checkGLcall("glScissor"); + context->scissor_rect_count = WINED3D_MAX_VIEWPORTS; gl_info->gl_ops.gl.p_glClear(clear_mask); checkGLcall("glClear"); } @@ -451,6 +452,7 @@ void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, c current_rect.right - current_rect.left, current_rect.bottom - current_rect.top); } checkGLcall("glScissor"); + context->scissor_rect_count = WINED3D_MAX_VIEWPORTS;
gl_info->gl_ops.gl.p_glClear(clear_mask); checkGLcall("glClear"); @@ -2123,19 +2125,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 +2159,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 +4492,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 +5003,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 3563b4b0fd..c869b63b11 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -4252,27 +4252,53 @@ 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); } - checkGLcall("glScissor"); + + if (gl_info->supported[ARB_VIEWPORT_ARRAY]) + { + GLint sr[4 * WINED3D_MAX_VIEWPORTS]; + unsigned int i, reset_count = 0; + + for (i = 0; i < state->scissor_rect_count; ++i) + { + r = &state->scissor_rects[i]; + + sr[i * 4] = r->left; + sr[i * 4 + 1] = height ? height - r->top : r->top; + sr[i * 4 + 2] = r->right - r->left; + sr[i * 4 + 3] = r->bottom - r->top; + } + + if (context->scissor_rect_count > state->scissor_rect_count) + reset_count = context->scissor_rect_count - state->scissor_rect_count; + + if (reset_count) + memset(&sr[state->scissor_rect_count * 4], 0, reset_count * 4 * sizeof(GLint)); + + GL_EXTCALL(glScissorArrayv(0, state->scissor_rect_count + reset_count, sr)); + checkGLcall("glScissorArrayv"); + context->scissor_rect_count = state->scissor_rect_count; + } + 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"); + } }
static void indexbuffer(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index 4ad0331f94..b4d17517b4 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -825,12 +825,18 @@ 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, + src_state->scissor_rect_count * sizeof(*src_state->scissor_rects)); + else + SetRectEmpty(stateblock->state.scissor_rects); }
map = stateblock->changed.streamSource; @@ -1065,7 +1071,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 8cdc3ef6f9..e9e3f86b91 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1995,6 +1995,7 @@ struct wined3d_context GLuint dummy_arbfp_prog;
unsigned int viewport_count; + unsigned int scissor_rect_count; };
struct wined3d_fb_state @@ -2863,7 +2864,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 @@ -3599,7 +3601,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);