[PATCH] d3d11: Add support for setting multiple viewports

Nikolay Sivov nsivov at codeweavers.com
Wed Apr 11 02:36:20 CDT 2018


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 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(-)

diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
index 1fe62975d5..b941115ebc 100644
--- a/dlls/d3d11/device.c
+++ b/dlls/d3d11/device.c
@@ -961,25 +961,25 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_RSSetViewports(ID3D11Devic
         UINT viewport_count, const D3D11_VIEWPORT *viewports)
 {
     struct d3d_device *device = device_from_immediate_ID3D11DeviceContext(iface);
-    struct wined3d_viewport wined3d_vp;
+    struct wined3d_viewport wined3d_vp[WINED3D_MAX_VIEWPORTS];
+    unsigned int i;
 
     TRACE("iface %p, viewport_count %u, viewports %p.\n", iface, viewport_count, viewports);
 
-    if (viewport_count > 1)
-        FIXME("Multiple viewports not implemented.\n");
-
-    if (!viewport_count)
-        return;
+    viewport_count = min(WINED3D_MAX_VIEWPORTS, viewport_count);
 
-    wined3d_vp.x = viewports[0].TopLeftX;
-    wined3d_vp.y = viewports[0].TopLeftY;
-    wined3d_vp.width = viewports[0].Width;
-    wined3d_vp.height = viewports[0].Height;
-    wined3d_vp.min_z = viewports[0].MinDepth;
-    wined3d_vp.max_z = viewports[0].MaxDepth;
+    for (i = 0; i < viewport_count; ++i)
+    {
+        wined3d_vp[i].x = viewports[i].TopLeftX;
+        wined3d_vp[i].y = viewports[i].TopLeftY;
+        wined3d_vp[i].width = viewports[i].Width;
+        wined3d_vp[i].height = viewports[i].Height;
+        wined3d_vp[i].min_z = viewports[i].MinDepth;
+        wined3d_vp[i].max_z = viewports[i].MaxDepth;
+    }
 
     wined3d_mutex_lock();
-    wined3d_device_set_viewport(device->wined3d_device, &wined3d_vp);
+    wined3d_device_set_viewports(device->wined3d_device, viewport_count, wined3d_vp);
     wined3d_mutex_unlock();
 }
 
@@ -4149,25 +4149,25 @@ static void STDMETHODCALLTYPE d3d10_device_RSSetViewports(ID3D10Device1 *iface,
         UINT viewport_count, const D3D10_VIEWPORT *viewports)
 {
     struct d3d_device *device = impl_from_ID3D10Device(iface);
-    struct wined3d_viewport wined3d_vp;
+    struct wined3d_viewport wined3d_vp[WINED3D_MAX_VIEWPORTS];
+    unsigned int i;
 
     TRACE("iface %p, viewport_count %u, viewports %p.\n", iface, viewport_count, viewports);
 
-    if (viewport_count > 1)
-        FIXME("Multiple viewports not implemented.\n");
-
-    if (!viewport_count)
-        return;
+    viewport_count = min(WINED3D_MAX_VIEWPORTS, viewport_count);
 
-    wined3d_vp.x = viewports[0].TopLeftX;
-    wined3d_vp.y = viewports[0].TopLeftY;
-    wined3d_vp.width = viewports[0].Width;
-    wined3d_vp.height = viewports[0].Height;
-    wined3d_vp.min_z = viewports[0].MinDepth;
-    wined3d_vp.max_z = viewports[0].MaxDepth;
+    for (i = 0; i < viewport_count; ++i)
+    {
+        wined3d_vp[i].x = viewports[i].TopLeftX;
+        wined3d_vp[i].y = viewports[i].TopLeftY;
+        wined3d_vp[i].width = viewports[i].Width;
+        wined3d_vp[i].height = viewports[i].Height;
+        wined3d_vp[i].min_z = viewports[i].MinDepth;
+        wined3d_vp[i].max_z = viewports[i].MaxDepth;
+    }
 
     wined3d_mutex_lock();
-    wined3d_device_set_viewport(device->wined3d_device, &wined3d_vp);
+    wined3d_device_set_viewports(device->wined3d_device, viewport_count, wined3d_vp);
     wined3d_mutex_unlock();
 }
 
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index b3597ad1b3..6feac2bc9a 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -10578,7 +10578,6 @@ static void test_clear_state(void)
     ID3D11DeviceContext_RSGetViewports(context, &count, tmp_viewport);
     for (i = 0; i < D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; ++i)
     {
-        todo_wine_if(!i)
         ok(!tmp_viewport[i].TopLeftX && !tmp_viewport[i].TopLeftY && !tmp_viewport[i].Width
                 && !tmp_viewport[i].Height && !tmp_viewport[i].MinDepth && !tmp_viewport[i].MaxDepth,
                 "Got unexpected viewport {%.8e, %.8e, %.8e, %.8e, %.8e, %.8e} in slot %u.\n",
@@ -26078,7 +26077,6 @@ static void test_multiple_viewports(void)
     SetRect(&rect, 0, 0, width - 1, texture_desc.Height - 1);
     check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[0], 1);
     SetRect(&rect, width, 0, 2 * width - 1, texture_desc.Height - 1);
-todo_wine
     check_texture_sub_resource_vec4(texture, 0, &rect, &expected_values[1], 1);
 
     /* One viewport. */
@@ -26098,7 +26096,6 @@ todo_wine
     constant.draw_id = 3;
     ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)cb, 0, NULL, &constant, 0, 0);
     draw_quad(&test_context);
-todo_wine
     check_texture_sub_resource_vec4(texture, 0, NULL, &expected_values[4], 1);
 
     ID3D11RenderTargetView_Release(rtv);
diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c
index 65480876d3..3bdb278ec5 100644
--- a/dlls/d3d8/device.c
+++ b/dlls/d3d8/device.c
@@ -1650,7 +1650,7 @@ static HRESULT WINAPI d3d8_device_SetViewport(IDirect3DDevice8 *iface, const D3D
     vp.min_z = viewport->MinZ;
     vp.max_z = viewport->MaxZ;
 
-    wined3d_device_set_viewport(device->wined3d_device, &vp);
+    wined3d_device_set_viewports(device->wined3d_device, 1, &vp);
     wined3d_mutex_unlock();
 
     return D3D_OK;
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c
index 2265c1dca2..a1b25f9b04 100644
--- a/dlls/d3d9/device.c
+++ b/dlls/d3d9/device.c
@@ -2072,7 +2072,7 @@ static HRESULT WINAPI d3d9_device_SetViewport(IDirect3DDevice9Ex *iface, const D
     vp.max_z = viewport->MaxZ;
 
     wined3d_mutex_lock();
-    wined3d_device_set_viewport(device->wined3d_device, &vp);
+    wined3d_device_set_viewports(device->wined3d_device, 1, &vp);
     wined3d_mutex_unlock();
 
     return D3D_OK;
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c
index 35995625e4..23c61c5d80 100644
--- a/dlls/ddraw/device.c
+++ b/dlls/ddraw/device.c
@@ -5333,7 +5333,7 @@ static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *vi
     vp.min_z = viewport->dvMinZ;
     vp.max_z = viewport->dvMaxZ;
 
-    wined3d_device_set_viewport(device->wined3d_device, &vp);
+    wined3d_device_set_viewports(device->wined3d_device, 1, &vp);
     wined3d_mutex_unlock();
 
     return D3D_OK;
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 2f0c4ed52e..8148cf73ad 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -33,7 +33,7 @@ enum wined3d_cs_op
     WINED3D_CS_OP_DRAW,
     WINED3D_CS_OP_FLUSH,
     WINED3D_CS_OP_SET_PREDICATION,
-    WINED3D_CS_OP_SET_VIEWPORT,
+    WINED3D_CS_OP_SET_VIEWPORTS,
     WINED3D_CS_OP_SET_SCISSOR_RECT,
     WINED3D_CS_OP_SET_RENDERTARGET_VIEW,
     WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW,
@@ -138,10 +138,11 @@ struct wined3d_cs_set_predication
     BOOL value;
 };
 
-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;
 };
 
 struct wined3d_cs_set_scissor_rect
@@ -530,7 +531,7 @@ void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *
 {
     unsigned int rt_count = cs->device->adapter->gl_info.limits.buffers;
     const struct wined3d_state *state = &cs->device->state;
-    const struct wined3d_viewport *vp = &state->viewport;
+    const struct wined3d_viewport *vp = &state->viewports[0];
     struct wined3d_rendertarget_view *view;
     struct wined3d_cs_clear *op;
     RECT view_rect;
@@ -961,21 +962,30 @@ void wined3d_cs_emit_set_predication(struct wined3d_cs *cs, struct wined3d_query
     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
 }
 
-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));
+    op->viewport_count = viewport_count;
 
     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
 }
@@ -2401,7 +2411,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_DRAW                        */ wined3d_cs_exec_draw,
     /* WINED3D_CS_OP_FLUSH                       */ wined3d_cs_exec_flush,
     /* WINED3D_CS_OP_SET_PREDICATION             */ wined3d_cs_exec_set_predication,
-    /* WINED3D_CS_OP_SET_VIEWPORT                */ wined3d_cs_exec_set_viewport,
+    /* 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_RENDERTARGET_VIEW       */ wined3d_cs_exec_set_rendertarget_view,
     /* WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW      */ wined3d_cs_exec_set_depth_stencil_view,
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index cc42dba45d..ae53628e48 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1909,13 +1909,24 @@ INT CDECL wined3d_device_get_base_vertex_index(const struct wined3d_device *devi
     return device->state.base_vertex_index;
 }
 
-void CDECL wined3d_device_set_viewport(struct wined3d_device *device, const struct wined3d_viewport *viewport)
+void CDECL wined3d_device_set_viewports(struct wined3d_device *device, unsigned int viewport_count,
+        const struct wined3d_viewport *viewports)
 {
-    TRACE("device %p, viewport %p.\n", device, viewport);
-    TRACE("x %.8e, y %.8e, w %.8e, h %.8e, min_z %.8e, max_z %.8e.\n",
-          viewport->x, viewport->y, viewport->width, viewport->height, viewport->min_z, viewport->max_z);
+    unsigned int i;
+
+    TRACE("device %p, viewport_count %u, viewports %p.\n", device, viewport_count, viewports);
+
+    for (i = 0; i < viewport_count; ++i)
+    {
+        TRACE("%u: x %.8e, y %.8e, w %.8e, h %.8e, min_z %.8e, max_z %.8e.\n",  i, viewports[i].x, viewports[i].y,
+                viewports[i].width, viewports[i].height, viewports[i].min_z, viewports[i].max_z);
+    }
 
-    device->update_state->viewport = *viewport;
+    if (viewport_count)
+        memcpy(device->update_state->viewports, viewports, viewport_count * sizeof(*viewports));
+    else
+        memset(device->update_state->viewports, 0, sizeof(device->update_state->viewports));
+    device->update_state->viewport_count = viewport_count;
 
     /* Handle recording of state blocks */
     if (device->recording)
@@ -1925,14 +1936,14 @@ void CDECL wined3d_device_set_viewport(struct wined3d_device *device, const stru
         return;
     }
 
-    wined3d_cs_emit_set_viewport(device->cs, viewport);
+    wined3d_cs_emit_set_viewports(device->cs, viewport_count, viewports);
 }
 
 void CDECL wined3d_device_get_viewport(const struct wined3d_device *device, struct wined3d_viewport *viewport)
 {
     TRACE("device %p, viewport %p.\n", device, viewport);
 
-    *viewport = device->state.viewport;
+    *viewport = device->state.viewports[0];
 }
 
 static void resolve_depth_buffer(struct wined3d_device *device)
@@ -4448,19 +4459,18 @@ HRESULT CDECL wined3d_device_set_rendertarget_view(struct wined3d_device *device
     {
         struct wined3d_state *state = &device->state;
 
-        state->viewport.x = 0;
-        state->viewport.y = 0;
-        state->viewport.width = view->width;
-        state->viewport.height = view->height;
-        state->viewport.min_z = 0.0f;
-        state->viewport.max_z = 1.0f;
-        wined3d_cs_emit_set_viewport(device->cs, &state->viewport);
+        state->viewports[0].x = 0;
+        state->viewports[0].y = 0;
+        state->viewports[0].width = view->width;
+        state->viewports[0].height = view->height;
+        state->viewports[0].min_z = 0.0f;
+        state->viewports[0].max_z = 1.0f;
+        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);
     }
 
-
     prev = device->fb.render_targets[view_idx];
     if (view == prev)
         return WINED3D_OK;
@@ -4960,11 +4970,11 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
         wined3d_device_set_rendertarget_view(device, 0, view, FALSE);
 
         /* Note the min_z / max_z is not reset. */
-        state->viewport.x = 0;
-        state->viewport.y = 0;
-        state->viewport.width = view->width;
-        state->viewport.height = view->height;
-        wined3d_cs_emit_set_viewport(device->cs, &state->viewport);
+        state->viewports[0].x = 0;
+        state->viewports[0].y = 0;
+        state->viewports[0].width = view->width;
+        state->viewports[0].height = view->height;
+        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);
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 121892dd47..acd2c48a63 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -6766,6 +6766,14 @@ static void shader_glsl_input_pack(const struct wined3d_shader *shader, struct w
                 else
                     FIXME("ARB_fragment_layer_viewport is not supported.\n");
             }
+            else if (input->sysval_semantic == WINED3D_SV_VIEWPORT_ARRAY_INDEX && !semantic_idx)
+            {
+                if (gl_info->supported[ARB_VIEWPORT_ARRAY])
+                    shader_addline(buffer, "ps_in[%u]%s = intBitsToFloat(gl_ViewportIndex);\n",
+                            input->register_idx, reg_mask);
+                else
+                    FIXME("ARB_viewport_array is not supported.\n");
+            }
             else
             {
                 if (input->sysval_semantic)
@@ -7057,6 +7065,11 @@ static void shader_glsl_setup_sm3_rasterizer_input(struct shader_glsl_priv *priv
             shader_addline(buffer, "gl_Layer = floatBitsToInt(outputs[%u])%s;\n",
                     output->register_idx, reg_mask);
         }
+        else if (output->sysval_semantic == WINED3D_SV_VIEWPORT_ARRAY_INDEX && !semantic_idx)
+        {
+            shader_addline(buffer, "gl_ViewportIndex = floatBitsToInt(outputs[%u])%s;\n",
+                    output->register_idx, reg_mask);
+        }
         else if (output->sysval_semantic == WINED3D_SV_CLIP_DISTANCE)
         {
             shader_glsl_generate_clip_or_cull_distances(buffer, output, reg_maps_out->clip_distance_mask);
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 83cc484be8..5a37fadabd 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -4514,21 +4514,24 @@ static void vertexdeclaration(struct wined3d_context *context, const struct wine
     }
 }
 
-static void get_viewport(struct wined3d_context *context, const struct wined3d_state *state,
-        struct wined3d_viewport *viewport)
+static void get_viewports(struct wined3d_context *context, const struct wined3d_state *state,
+        unsigned int viewport_count, struct wined3d_viewport *viewports)
 {
     const struct wined3d_rendertarget_view *depth_stencil = state->fb->depth_stencil;
     const struct wined3d_rendertarget_view *target = state->fb->render_targets[0];
-    unsigned int width, height;
+    unsigned int width, height, i;
 
-    *viewport = state->viewport;
-
-    if (target)
+    for (i = 0; i < viewport_count; ++i)
     {
-        if (viewport->width > target->width)
-            viewport->width = target->width;
-        if (viewport->height > target->height)
-            viewport->height = target->height;
+        viewports[i] = state->viewports[i];
+
+        if (target)
+        {
+            if (viewports[i].width > target->width)
+                viewports[i].width = target->width;
+            if (viewports[i].height > target->height)
+                viewports[i].height = target->height;
+        }
     }
 
     /*
@@ -4552,22 +4555,45 @@ static void get_viewport(struct wined3d_context *context, const struct wined3d_s
         return;
     }
 
-    viewport->y = height - (viewport->y + viewport->height);
+    for (i = 0; i < viewport_count; ++i)
+        viewports[i].y = height - (viewports[i].y + viewports[i].height);
 }
 
 static void viewport_miscpart(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
-    struct wined3d_viewport vp;
+    struct wined3d_viewport vp[WINED3D_MAX_VIEWPORTS];
+
+    if (gl_info->supported[ARB_VIEWPORT_ARRAY])
+    {
+        unsigned int i, reset_count = 0;
 
-    get_viewport(context, state, &vp);
+        get_viewports(context, state, state->viewport_count, vp);
+        for (i = 0; i < state->viewport_count; ++i)
+        {
+            GL_EXTCALL(glDepthRangeIndexed(i, vp[i].min_z, vp[i].max_z));
+            GL_EXTCALL(glViewportIndexedf(i, vp[i].x, vp[i].y, vp[i].width, vp[i].height));
+        }
 
-    gl_info->gl_ops.gl.p_glDepthRange(vp.min_z, vp.max_z);
+        if (context->viewport_count > state->viewport_count)
+            reset_count = context->viewport_count - state->viewport_count;
 
-    if (gl_info->supported[ARB_VIEWPORT_ARRAY])
-        GL_EXTCALL(glViewportIndexedf(0, vp.x, vp.y, vp.width, vp.height));
+        if (reset_count)
+        {
+            static const GLfloat reset[4 * WINED3D_MAX_VIEWPORTS];
+            static const GLdouble resetd[2 * WINED3D_MAX_VIEWPORTS];
+
+            GL_EXTCALL(glDepthRangeArrayv(state->viewport_count, reset_count, resetd));
+            GL_EXTCALL(glViewportArrayv(state->viewport_count, reset_count, reset));
+        }
+        context->viewport_count = state->viewport_count;
+    }
     else
-        gl_info->gl_ops.gl.p_glViewport(vp.x, vp.y, vp.width, vp.height);
+    {
+        get_viewports(context, state, 1, vp);
+        gl_info->gl_ops.gl.p_glDepthRange(vp[0].min_z, vp[0].max_z);
+        gl_info->gl_ops.gl.p_glViewport(vp[0].x, vp[0].y, vp[0].width, vp[0].height);
+    }
     checkGLcall("setting clip space and viewport");
 }
 
@@ -4578,16 +4604,34 @@ static void viewport_miscpart_cc(struct wined3d_context *context,
     float pixel_center_offset = context->d3d_info->wined3d_creation_flags
             & WINED3D_PIXEL_CENTER_INTEGER ? 63.0f / 128.0f : -1.0f / 128.0f;
     const struct wined3d_gl_info *gl_info = context->gl_info;
-    struct wined3d_viewport vp;
-
-    get_viewport(context, state, &vp);
-    vp.x += pixel_center_offset;
-    vp.y += pixel_center_offset;
+    struct wined3d_viewport vp[WINED3D_MAX_VIEWPORTS];
+    unsigned int i, reset_count = 0;
 
-    gl_info->gl_ops.gl.p_glDepthRange(vp.min_z, vp.max_z);
+    get_viewports(context, state, state->viewport_count, vp);
 
     GL_EXTCALL(glClipControl(context->render_offscreen ? GL_UPPER_LEFT : GL_LOWER_LEFT, GL_ZERO_TO_ONE));
-    GL_EXTCALL(glViewportIndexedf(0, vp.x, vp.y, vp.width, vp.height));
+
+    for (i = 0; i < state->viewport_count; ++i)
+    {
+        vp[i].x += pixel_center_offset;
+        vp[i].y += pixel_center_offset;
+        GL_EXTCALL(glDepthRangeIndexed(i, vp[i].min_z, vp[i].max_z));
+        GL_EXTCALL(glViewportIndexedf(i, vp[i].x, vp[i].y, vp[i].width, vp[i].height));
+    }
+
+    if (context->viewport_count > state->viewport_count)
+        reset_count = context->viewport_count - state->viewport_count;
+
+    if (reset_count)
+    {
+        static const GLfloat reset[4 * WINED3D_MAX_VIEWPORTS];
+        static const GLdouble resetd[2 * WINED3D_MAX_VIEWPORTS];
+
+        GL_EXTCALL(glDepthRangeArrayv(state->viewport_count, reset_count, resetd));
+        GL_EXTCALL(glViewportArrayv(state->viewport_count, reset_count, reset));
+    }
+    context->viewport_count = state->viewport_count;
+
     checkGLcall("setting clip space and viewport");
 }
 
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index 4c28eb55e8..d6a7189d83 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -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)))
     {
-        TRACE("Updating viewport.\n");
+        TRACE("Updating viewports.\n");
 
-        stateblock->state.viewport = src_state->viewport;
+        if ((stateblock->state.viewport_count = src_state->viewport_count))
+            memcpy(stateblock->state.viewports, src_state->viewports, sizeof(src_state->viewports));
+        else
+            memset(stateblock->state.viewports, 0, sizeof(*stateblock->state.viewports));
     }
 
     if (stateblock->changed.scissorRect && memcmp(&src_state->scissor_rect,
@@ -1055,7 +1059,7 @@ void CDECL wined3d_stateblock_apply(const struct wined3d_stateblock *stateblock)
         wined3d_device_set_material(device, &stateblock->state.material);
 
     if (stateblock->changed.viewport)
-        wined3d_device_set_viewport(device, &stateblock->state.viewport);
+        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);
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 0775f53b7a..cf199b955a 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -4865,10 +4865,10 @@ void get_projection_matrix(const struct wined3d_context *context, const struct w
     if (context->last_was_rhw)
     {
         /* Transform D3D RHW coordinates to OpenGL clip coordinates. */
-        float x = state->viewport.x;
-        float y = state->viewport.y;
-        float w = state->viewport.width;
-        float h = state->viewport.height;
+        float x = state->viewports[0].x;
+        float y = state->viewports[0].y;
+        float w = state->viewports[0].width;
+        float h = state->viewports[0].height;
         float x_scale = 2.0f / w;
         float x_offset = (center_offset - (2.0f * x) - w) / w;
         float y_scale = flip ? 2.0f / h : 2.0f / -h;
@@ -4892,10 +4892,10 @@ void get_projection_matrix(const struct wined3d_context *context, const struct w
     else
     {
         float y_scale = flip ? -1.0f : 1.0f;
-        float x_offset = center_offset / state->viewport.width;
+        float x_offset = center_offset / state->viewports[0].width;
         float y_offset = flip
-                ? center_offset / state->viewport.height
-                : -center_offset / state->viewport.height;
+                ? center_offset / state->viewports[0].height
+                : -center_offset / state->viewports[0].height;
         float z_scale = clip_control ? 1.0f : 2.0f;
         float z_offset = clip_control ? 0.0f : -1.0f;
         const struct wined3d_matrix projection =
@@ -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;
 
         out_att[0] = a.f / scale_factor;
         out_att[1] = b.f / scale_factor;
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index 16d22f5263..b4c41cc59a 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -187,7 +187,7 @@
 @ cdecl wined3d_device_set_unordered_access_view(ptr long ptr long)
 @ cdecl wined3d_device_set_vertex_declaration(ptr ptr)
 @ cdecl wined3d_device_set_vertex_shader(ptr ptr)
-@ cdecl wined3d_device_set_viewport(ptr ptr)
+@ cdecl wined3d_device_set_viewports(ptr long ptr)
 @ cdecl wined3d_device_set_vs_cb(ptr long ptr)
 @ cdecl wined3d_device_set_vs_consts_b(ptr long long ptr)
 @ cdecl wined3d_device_set_vs_consts_f(ptr long long ptr)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index cdea1125f3..69b8b0d935 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1990,6 +1990,8 @@ struct wined3d_context
     GLfloat                 fog_coord_value;
     GLfloat                 color[4], fogstart, fogend, fogcolor[4];
     GLuint                  dummy_arbfp_prog;
+
+    unsigned int viewport_count;
 };
 
 struct wined3d_fb_state
@@ -2843,7 +2845,8 @@ struct wined3d_state
     struct wined3d_matrix transforms[HIGHEST_TRANSFORMSTATE + 1];
     struct wined3d_vec4 clip_planes[MAX_CLIP_DISTANCES];
     struct wined3d_material material;
-    struct wined3d_viewport viewport;
+    struct wined3d_viewport viewports[WINED3D_MAX_VIEWPORTS];
+    unsigned int viewport_count;
     RECT scissor_rect;
 
     /* Light hashmap. Collisions are handled using linked lists. */
@@ -3592,7 +3595,7 @@ void wined3d_cs_emit_set_unordered_access_view(struct wined3d_cs *cs, enum wined
         unsigned int initial_count) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs,
         struct wined3d_vertex_declaration *declaration) DECLSPEC_HIDDEN;
-void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_viewport *viewport) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_set_viewports(struct wined3d_cs *cs, unsigned int viewport_count, const struct wined3d_viewport *viewports) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource,
         unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch,
@@ -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;
 
     if (context->render_offscreen)
     {
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 446e98b96f..3539b4eb06 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -1561,6 +1561,8 @@ enum wined3d_shader_byte_code_format
 #define WINED3D_VIEW_TEXTURE_CUBE                               0x00000008
 #define WINED3D_VIEW_TEXTURE_ARRAY                              0x00000010
 
+#define WINED3D_MAX_VIEWPORTS                                   16
+
 struct wined3d_display_mode
 {
     UINT width;
@@ -2440,7 +2442,8 @@ void __cdecl wined3d_device_set_unordered_access_view(struct wined3d_device *dev
 void __cdecl wined3d_device_set_vertex_declaration(struct wined3d_device *device,
         struct wined3d_vertex_declaration *declaration);
 void __cdecl wined3d_device_set_vertex_shader(struct wined3d_device *device, struct wined3d_shader *shader);
-void __cdecl wined3d_device_set_viewport(struct wined3d_device *device, const struct wined3d_viewport *viewport);
+void __cdecl wined3d_device_set_viewports(struct wined3d_device *device, unsigned int viewport_count,
+        const struct wined3d_viewport *viewports);
 void __cdecl wined3d_device_set_vs_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer);
 HRESULT __cdecl wined3d_device_set_vs_consts_b(struct wined3d_device *device,
         unsigned int start_idx, unsigned int count, const BOOL *constants);
-- 
2.16.3




More information about the wine-devel mailing list