[PATCH] d3d11: Add support for setting multiple viewports

Henri Verbeet hverbeet at gmail.com
Wed Apr 11 11:53:50 CDT 2018


On 11 April 2018 at 09:36, Nikolay Sivov <nsivov at codeweavers.com> wrote:
> ---
>  dlls/d3d11/device.c            | 52 ++++++++++++------------
>  dlls/d3d11/tests/d3d11.c       |  3 --
>  dlls/d3d8/device.c             |  2 +-
>  dlls/d3d9/device.c             |  2 +-
>  dlls/ddraw/device.c            |  2 +-
>  dlls/wined3d/cs.c              | 34 ++++++++++------
>  dlls/wined3d/device.c          | 50 ++++++++++++++---------
>  dlls/wined3d/glsl_shader.c     | 13 ++++++
>  dlls/wined3d/state.c           | 92 +++++++++++++++++++++++++++++++-----------
>  dlls/wined3d/stateblock.c      | 12 ++++--
>  dlls/wined3d/utils.c           | 16 ++++----
>  dlls/wined3d/wined3d.spec      |  2 +-
>  dlls/wined3d/wined3d_private.h | 11 +++--
>  include/wine/wined3d.h         |  5 ++-
>  14 files changed, 190 insertions(+), 106 deletions(-)
>
One easy way to split this a little further would be to separate the
d3d11 changes for passing multiple viewports from the wined3d API
changes that allow client libraries to pass multiple viewports.

> -struct wined3d_cs_set_viewport
> +struct wined3d_cs_set_viewports
>  {
>      enum wined3d_cs_op opcode;
> -    struct wined3d_viewport viewport;
> +    struct wined3d_viewport viewports[WINED3D_MAX_VIEWPORTS];
> +    unsigned int viewport_count;
>  };
You can probably save a little CS bandwidth by making the viewports[]
array variable sized. See e.g. wined3d_cs_emit_clear() or
wined3d_cs_mt_push_constants() for examples.

> -static void wined3d_cs_exec_set_viewport(struct wined3d_cs *cs, const void *data)
> +static void wined3d_cs_exec_set_viewports(struct wined3d_cs *cs, const void *data)
>  {
> -    const struct wined3d_cs_set_viewport *op = data;
> +    const struct wined3d_cs_set_viewports *op = data;
>
> -    cs->state.viewport = op->viewport;
> +    if (op->viewport_count)
> +        memcpy(cs->state.viewports, op->viewports, op->viewport_count * sizeof(*op->viewports));
> +    else
> +        memset(cs->state.viewports, 0, sizeof(*cs->state.viewports));
> +    cs->state.viewport_count = op->viewport_count;
>      device_invalidate_state(cs->device, STATE_VIEWPORT);
>  }
>
> -void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_viewport *viewport)
> +void wined3d_cs_emit_set_viewports(struct wined3d_cs *cs, unsigned int viewport_count,
> +        const struct wined3d_viewport *viewports)
>  {
> -    struct wined3d_cs_set_viewport *op;
> +    struct wined3d_cs_set_viewports *op;
>
>      op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
> -    op->opcode = WINED3D_CS_OP_SET_VIEWPORT;
> -    op->viewport = *viewport;
> +    op->opcode = WINED3D_CS_OP_SET_VIEWPORTS;
> +    if (viewport_count)
> +        memcpy(op->viewports, viewports, viewport_count * sizeof(*viewports));
> +    else
> +        memset(op->viewports, 0, sizeof(*op->viewports));
The memset() here should be unnecessary, since you already handle 0
viewport count in wined3d_cs_exec_set_viewports().

> @@ -811,11 +811,15 @@ void CDECL wined3d_stateblock_capture(struct wined3d_stateblock *stateblock)
>      }
>
>      if (stateblock->changed.viewport
> -            && memcmp(&src_state->viewport, &stateblock->state.viewport, sizeof(stateblock->state.viewport)))
> +            && src_state->viewport_count != stateblock->state.viewport_count
> +            && memcmp(src_state->viewports, stateblock->state.viewports, sizeof(stateblock->state.viewports)))
>      {
Should that second "&&" be a "||"? Should the memcmp() size just be
src_state->viewport_count?

> @@ -5097,7 +5097,7 @@ void get_pointsize(const struct wined3d_context *context, const struct wined3d_s
>
>      if (state->render_states[WINED3D_RS_POINTSCALEENABLE])
>      {
> -        float scale_factor = state->viewport.height * state->viewport.height;
> +        float scale_factor = state->viewports[0].height * state->viewports[0].height;
>
This is ok because WINED3D_RS_POINTSCALEENABLE has no d3d10/11
equivalent, so we can just define it to operate with respect to the
first viewport in wined3d, but that could do with a comment.

> @@ -4106,8 +4109,8 @@ static inline void shader_get_position_fixup(const struct wined3d_context *conte
>
>      position_fixup[0] = 1.0f;
>      position_fixup[1] = 1.0f;
> -    position_fixup[2] = center_offset / state->viewport.width;
> -    position_fixup[3] = -center_offset / state->viewport.height;
> +    position_fixup[2] = center_offset / state->viewports[0].width;
> +    position_fixup[3] = -center_offset / state->viewports[0].height;
>
This is a bit of a problem, since it will potentially result in
incorrect offsets for viewports other than the first. Requiring
ARB_clip_control for multiple viewport support would avoid the issue,
but would disable d3d10/11 support on setups without that extension,
or setups with GL_VIEWPORT_SUBPIXEL_BITS < 8.



More information about the wine-devel mailing list