[PATCH 4/5] wined3d: Introduce wined3d_depth_stencil_state.

Chip Davis cdavis at codeweavers.com
Mon Apr 13 02:27:26 CDT 2020


Move the depth enable state to it.

Signed-off-by: Chip Davis <cdavis at codeweavers.com>
---
 dlls/d3d11/d3d11_private.h     |  1 +
 dlls/d3d11/device.c            |  4 +-
 dlls/d3d11/state.c             | 57 ++++++++++++++-------
 dlls/wined3d/context.c         |  5 +-
 dlls/wined3d/cs.c              | 30 +++++++++++-
 dlls/wined3d/device.c          | 90 ++++++++++++++++++++++++++++++++--
 dlls/wined3d/state.c           | 76 ++++++++++++++++++++++++++--
 dlls/wined3d/utils.c           |  9 +++-
 dlls/wined3d/wined3d.spec      |  7 +++
 dlls/wined3d/wined3d_private.h | 22 ++++++++-
 include/wine/wined3d.h         | 16 ++++++
 11 files changed, 283 insertions(+), 34 deletions(-)

diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h
index 48c76959fae..a7258cada71 100644
--- a/dlls/d3d11/d3d11_private.h
+++ b/dlls/d3d11/d3d11_private.h
@@ -440,6 +440,7 @@ struct d3d_depthstencil_state
     LONG refcount;
 
     struct wined3d_private_store private_store;
+    struct wined3d_depth_stencil_state *wined3d_state;
     D3D11_DEPTH_STENCIL_DESC desc;
     struct wine_rb_entry entry;
     ID3D11Device2 *device;
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
index 23d05e08b49..ed290750ac3 100644
--- a/dlls/d3d11/device.c
+++ b/dlls/d3d11/device.c
@@ -726,7 +726,6 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_OMSetBlendState(ID3D11Devi
 
 static void set_default_depth_stencil_state(struct wined3d_device *wined3d_device)
 {
-    wined3d_device_set_render_state(wined3d_device, WINED3D_RS_ZENABLE, TRUE);
     wined3d_device_set_render_state(wined3d_device, WINED3D_RS_ZWRITEENABLE, D3D11_DEPTH_WRITE_MASK_ALL);
     wined3d_device_set_render_state(wined3d_device, WINED3D_RS_ZFUNC, WINED3D_CMP_LESS);
     wined3d_device_set_render_state(wined3d_device, WINED3D_RS_STENCILENABLE, FALSE);
@@ -746,6 +745,7 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_OMSetDepthStencilState(ID3
     device->stencil_ref = stencil_ref;
     if (!(device->depth_stencil_state = unsafe_impl_from_ID3D11DepthStencilState(depth_stencil_state)))
     {
+        wined3d_device_set_depth_stencil_state(device->wined3d_device, NULL);
         set_default_depth_stencil_state(device->wined3d_device);
         wined3d_mutex_unlock();
         return;
@@ -756,7 +756,7 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_OMSetDepthStencilState(ID3
     front = &desc->FrontFace;
     back = &desc->BackFace;
 
-    wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_ZENABLE, desc->DepthEnable);
+    wined3d_device_set_depth_stencil_state(device->wined3d_device, device->depth_stencil_state->wined3d_state);
     if (desc->DepthEnable)
     {
         wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_ZWRITEENABLE, desc->DepthWriteMask);
diff --git a/dlls/d3d11/state.c b/dlls/d3d11/state.c
index 6d7f70664e7..6d3736a1d95 100644
--- a/dlls/d3d11/state.c
+++ b/dlls/d3d11/state.c
@@ -496,12 +496,6 @@ static ULONG STDMETHODCALLTYPE d3d11_depthstencil_state_AddRef(ID3D11DepthStenci
     return refcount;
 }
 
-static void d3d_depthstencil_state_cleanup(struct d3d_depthstencil_state *state)
-{
-    wined3d_private_store_cleanup(&state->private_store);
-    ID3D11Device2_Release(state->device);
-}
-
 static ULONG STDMETHODCALLTYPE d3d11_depthstencil_state_Release(ID3D11DepthStencilState *iface)
 {
     struct d3d_depthstencil_state *state = impl_from_ID3D11DepthStencilState(iface);
@@ -511,12 +505,11 @@ static ULONG STDMETHODCALLTYPE d3d11_depthstencil_state_Release(ID3D11DepthStenc
 
     if (!refcount)
     {
-        struct d3d_device *device = impl_from_ID3D11Device2(state->device);
         wined3d_mutex_lock();
-        wine_rb_remove(&device->depthstencil_states, &state->entry);
-        d3d_depthstencil_state_cleanup(state);
+        wined3d_depth_stencil_state_decref(state->wined3d_state);
         wined3d_mutex_unlock();
-        heap_free(state);
+
+        ID3D11Device2_Release(state->device);
     }
 
     return refcount;
@@ -695,9 +688,45 @@ static const struct ID3D10DepthStencilStateVtbl d3d10_depthstencil_state_vtbl =
     d3d10_depthstencil_state_GetDesc,
 };
 
+static void STDMETHODCALLTYPE d3d_depthstencil_state_wined3d_object_destroyed(void *parent)
+{
+    struct d3d_depthstencil_state *state = parent;
+    struct d3d_device *device = impl_from_ID3D11Device2(state->device);
+
+    wine_rb_remove(&device->depthstencil_states, &state->entry);
+    wined3d_private_store_cleanup(&state->private_store);
+    heap_free(parent);
+}
+
+static const struct wined3d_parent_ops d3d_depthstencil_state_wined3d_parent_ops =
+{
+    d3d_depthstencil_state_wined3d_object_destroyed,
+};
+
 static HRESULT d3d_depthstencil_state_init(struct d3d_depthstencil_state *state, struct d3d_device *device,
         const D3D11_DEPTH_STENCIL_DESC *desc)
 {
+    struct wined3d_depth_stencil_state_desc wined3d_desc;
+    HRESULT hr;
+
+    wined3d_desc.depth = desc->DepthEnable;
+
+    if (wine_rb_put(&device->depthstencil_states, desc, &state->entry) == -1)
+    {
+        ERR("Failed to insert depth/stencil state entry.\n");
+        return E_FAIL;
+    }
+
+    /* We cannot fail after creating a wined3d_depth_stencil_state object. It
+     * would lead to double free. */
+    if (FAILED(hr = wined3d_depth_stencil_state_create(device->wined3d_device, &wined3d_desc,
+            state, &d3d_depthstencil_state_wined3d_parent_ops, &state->wined3d_state)))
+    {
+        WARN("Failed to create wined3d depth/stencil state, hr %#x.\n", hr);
+        wine_rb_remove(&device->depthstencil_states, &state->entry);
+        return hr;
+    }
+
     state->ID3D11DepthStencilState_iface.lpVtbl = &d3d11_depthstencil_state_vtbl;
     state->ID3D10DepthStencilState_iface.lpVtbl = &d3d10_depthstencil_state_vtbl;
     state->refcount = 1;
@@ -783,14 +812,6 @@ HRESULT d3d_depthstencil_state_create(struct d3d_device *device, const D3D11_DEP
         return hr;
     }
 
-    if (wine_rb_put(&device->depthstencil_states, &tmp_desc, &object->entry) == -1)
-    {
-        ERR("Failed to insert depthstencil state entry.\n");
-        d3d_depthstencil_state_cleanup(object);
-        heap_free(object);
-        wined3d_mutex_unlock();
-        return E_FAIL;
-    }
     wined3d_mutex_unlock();
 
     TRACE("Created depthstencil state %p.\n", object);
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 41dbca24dbc..e280b6cd91b 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -3146,7 +3146,7 @@ void wined3d_context_gl_apply_blit_state(struct wined3d_context_gl *context_gl,
         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHATESTENABLE));
     }
     gl_info->gl_ops.gl.p_glDisable(GL_DEPTH_TEST);
-    context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZENABLE));
+    context_invalidate_state(context, STATE_DEPTH_STENCIL);
     gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
     gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
     context_invalidate_state(context, STATE_BLEND);
@@ -5193,7 +5193,8 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s
          * that we never copy the stencil data.*/
         DWORD location = context->render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
 
-        if (state->render_states[WINED3D_RS_ZWRITEENABLE] || state->render_states[WINED3D_RS_ZENABLE])
+        if (!state->depth_stencil_state || state->render_states[WINED3D_RS_ZWRITEENABLE]
+                || state->depth_stencil_state->desc.depth)
             wined3d_rendertarget_view_load_location(dsv, context, location);
         else
             wined3d_rendertarget_view_prepare_location(dsv, context, location);
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 943ffe9af62..42dba4daa4b 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -49,6 +49,7 @@ enum wined3d_cs_op
     WINED3D_CS_OP_SET_SAMPLER,
     WINED3D_CS_OP_SET_SHADER,
     WINED3D_CS_OP_SET_BLEND_STATE,
+    WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE,
     WINED3D_CS_OP_SET_RASTERIZER_STATE,
     WINED3D_CS_OP_SET_RENDER_STATE,
     WINED3D_CS_OP_SET_TEXTURE_STATE,
@@ -268,6 +269,12 @@ struct wined3d_cs_set_blend_state
     unsigned int sample_mask;
 };
 
+struct wined3d_cs_set_depth_stencil_state
+{
+    enum wined3d_cs_op opcode;
+    struct wined3d_depth_stencil_state *state;
+};
+
 struct wined3d_cs_set_rasterizer_state
 {
     enum wined3d_cs_op opcode;
@@ -1148,7 +1155,7 @@ static void wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const
     if (!prev != !op->view)
     {
         /* Swapping NULL / non NULL depth stencil affects the depth and tests */
-        device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
+        device_invalidate_state(device, STATE_DEPTH_STENCIL);
         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
         device_invalidate_state(device, STATE_RASTERIZER);
@@ -1585,6 +1592,26 @@ void wined3d_cs_emit_set_blend_state(struct wined3d_cs *cs, struct wined3d_blend
     wined3d_cs_submit(cs, WINED3D_CS_QUEUE_DEFAULT);
 }
 
+static void wined3d_cs_exec_set_depth_stencil_state(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_depth_stencil_state *op = data;
+    struct wined3d_state *state = &cs->state;
+
+    state->depth_stencil_state = op->state;
+    device_invalidate_state(cs->device, STATE_DEPTH_STENCIL);
+}
+
+void wined3d_cs_emit_set_depth_stencil_state(struct wined3d_cs *cs, struct wined3d_depth_stencil_state *state)
+{
+    struct wined3d_cs_set_depth_stencil_state *op;
+
+    op = wined3d_cs_require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
+    op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE;
+    op->state = state;
+
+    wined3d_cs_submit(cs, WINED3D_CS_QUEUE_DEFAULT);
+}
+
 static void wined3d_cs_exec_set_rasterizer_state(struct wined3d_cs *cs, const void *data)
 {
     const struct wined3d_cs_set_rasterizer_state *op = data;
@@ -2536,6 +2563,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_SET_SAMPLER                 */ wined3d_cs_exec_set_sampler,
     /* WINED3D_CS_OP_SET_SHADER                  */ wined3d_cs_exec_set_shader,
     /* WINED3D_CS_OP_SET_BLEND_STATE             */ wined3d_cs_exec_set_blend_state,
+    /* WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE     */ wined3d_cs_exec_set_depth_stencil_state,
     /* WINED3D_CS_OP_SET_RASTERIZER_STATE        */ wined3d_cs_exec_set_rasterizer_state,
     /* WINED3D_CS_OP_SET_RENDER_STATE            */ wined3d_cs_exec_set_render_state,
     /* WINED3D_CS_OP_SET_TEXTURE_STATE           */ wined3d_cs_exec_set_texture_state,
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 4c60c140784..3993b2a6fcf 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -532,6 +532,13 @@ static void device_leftover_blend_state(struct wine_rb_entry *entry, void *conte
     ERR("Leftover blend state %p.\n", blend_state);
 }
 
+static void device_leftover_depth_stencil_state(struct wine_rb_entry *entry, void *context)
+{
+    struct wined3d_depth_stencil_state *state = WINE_RB_ENTRY_VALUE(entry, struct wined3d_depth_stencil_state, entry);
+
+    ERR("Leftover depth/stencil state %p.\n", state);
+}
+
 void wined3d_device_cleanup(struct wined3d_device *device)
 {
     unsigned int i;
@@ -569,6 +576,7 @@ void wined3d_device_cleanup(struct wined3d_device *device)
     wine_rb_destroy(&device->samplers, device_leftover_sampler, NULL);
     wine_rb_destroy(&device->rasterizer_states, device_leftover_rasterizer_state, NULL);
     wine_rb_destroy(&device->blend_states, device_leftover_blend_state, NULL);
+    wine_rb_destroy(&device->depth_stencil_states, device_leftover_depth_stencil_state, NULL);
 
     wined3d_decref(device->wined3d);
     device->wined3d = NULL;
@@ -1124,6 +1132,13 @@ static void device_free_blend_state(struct wine_rb_entry *entry, void *context)
     wined3d_blend_state_decref(blend_state);
 }
 
+static void device_free_depth_stencil_state(struct wine_rb_entry *entry, void *context)
+{
+    struct wined3d_depth_stencil_state *state = WINE_RB_ENTRY_VALUE(entry, struct wined3d_depth_stencil_state, entry);
+
+    wined3d_depth_stencil_state_decref(state);
+}
+
 void wined3d_device_uninit_3d(struct wined3d_device *device)
 {
     BOOL no3d = device->wined3d->flags & WINED3D_NO3D;
@@ -1166,6 +1181,7 @@ void wined3d_device_uninit_3d(struct wined3d_device *device)
     wine_rb_clear(&device->samplers, device_free_sampler, NULL);
     wine_rb_clear(&device->rasterizer_states, device_free_rasterizer_state, NULL);
     wine_rb_clear(&device->blend_states, device_free_blend_state, NULL);
+    wine_rb_clear(&device->depth_stencil_states, device_free_depth_stencil_state, NULL);
 
     LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
     {
@@ -1713,6 +1729,33 @@ struct wined3d_blend_state * CDECL wined3d_device_get_blend_state(const struct w
     return state->blend_state;
 }
 
+void CDECL wined3d_device_set_depth_stencil_state(struct wined3d_device *device,
+        struct wined3d_depth_stencil_state *depth_stencil_state)
+{
+    struct wined3d_state *state = &device->state;
+    struct wined3d_depth_stencil_state *prev;
+
+    TRACE("device %p, depth_stencil_state %p.\n", device, depth_stencil_state);
+
+    prev = state->depth_stencil_state;
+    if (prev == depth_stencil_state)
+        return;
+
+    if (depth_stencil_state)
+        wined3d_depth_stencil_state_incref(depth_stencil_state);
+    state->depth_stencil_state = depth_stencil_state;
+    wined3d_cs_emit_set_depth_stencil_state(device->cs, depth_stencil_state);
+    if (prev)
+        wined3d_depth_stencil_state_decref(prev);
+}
+
+struct wined3d_depth_stencil_state * CDECL wined3d_device_get_depth_stencil_state(const struct wined3d_device *device)
+{
+    TRACE("device %p.\n", device);
+
+    return device->state.depth_stencil_state;
+}
+
 void CDECL wined3d_device_set_rasterizer_state(struct wined3d_device *device,
         struct wined3d_rasterizer_state *rasterizer_state)
 {
@@ -3503,7 +3546,7 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
     const struct wined3d_stateblock_state *state = &stateblock->stateblock_state;
     const struct wined3d_saved_states *changed = &stateblock->changed;
     const unsigned int word_bit_count = sizeof(DWORD) * CHAR_BIT;
-    BOOL set_blend_state = FALSE, set_rasterizer_state = FALSE;
+    BOOL set_blend_state = FALSE, set_depth_stencil_state = FALSE, set_rasterizer_state = FALSE;
     unsigned int i, j, start, idx;
     struct wined3d_range range;
     uint32_t map;
@@ -3608,6 +3651,10 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
                     set_blend_state = TRUE;
                     break;
 
+                case WINED3D_RS_ZENABLE:
+                    set_depth_stencil_state = TRUE;
+                    break;
+
                 case WINED3D_RS_FILLMODE:
                 case WINED3D_RS_CULLMODE:
                 case WINED3D_RS_SLOPESCALEDEPTHBIAS:
@@ -3739,6 +3786,32 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
         }
     }
 
+    if (set_depth_stencil_state)
+    {
+        struct wined3d_depth_stencil_state *depth_stencil_state;
+        struct wined3d_depth_stencil_state_desc desc;
+        struct wine_rb_entry *entry;
+
+        memset(&desc, 0, sizeof(desc));
+        desc.depth = state->rs[WINED3D_RS_ZENABLE];
+
+        if ((entry = wine_rb_get(&device->depth_stencil_states, &desc)))
+        {
+            depth_stencil_state = WINE_RB_ENTRY_VALUE(entry, struct wined3d_depth_stencil_state, entry);
+            wined3d_device_set_depth_stencil_state(device, depth_stencil_state);
+        }
+        else if (SUCCEEDED(wined3d_depth_stencil_state_create(device, &desc, NULL,
+                &wined3d_null_parent_ops, &depth_stencil_state)))
+        {
+            wined3d_device_set_depth_stencil_state(device, depth_stencil_state);
+            if (wine_rb_put(&device->depth_stencil_states, &desc, &depth_stencil_state->entry) == -1)
+            {
+                ERR("Failed to insert depth/stencil state.\n");
+                wined3d_depth_stencil_state_decref(depth_stencil_state);
+            }
+        }
+    }
+
     for (i = 0; i < ARRAY_SIZE(changed->textureState); ++i)
     {
         map = changed->textureState[i];
@@ -4240,8 +4313,8 @@ HRESULT CDECL wined3d_device_validate_device(const struct wined3d_device *device
         }
     }
 
-    if (state->render_states[WINED3D_RS_ZENABLE] || state->render_states[WINED3D_RS_ZWRITEENABLE]
-            || state->render_states[WINED3D_RS_STENCILENABLE])
+    if (!state->depth_stencil_state || state->depth_stencil_state->desc.depth
+            || state->render_states[WINED3D_RS_ZWRITEENABLE] || state->render_states[WINED3D_RS_STENCILENABLE])
     {
         struct wined3d_rendertarget_view *rt = device->state.fb.render_targets[0];
         struct wined3d_rendertarget_view *ds = device->state.fb.depth_stencil;
@@ -5343,6 +5416,7 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
     wine_rb_clear(&device->samplers, device_free_sampler, NULL);
     wine_rb_clear(&device->rasterizer_states, device_free_rasterizer_state, NULL);
     wine_rb_clear(&device->blend_states, device_free_blend_state, NULL);
+    wine_rb_clear(&device->depth_stencil_states, device_free_depth_stencil_state, NULL);
 
     if (reset_state)
     {
@@ -5540,6 +5614,13 @@ static int wined3d_blend_state_compare(const void *key, const struct wine_rb_ent
     return memcmp(&state->desc, key, sizeof(state->desc));
 }
 
+static int wined3d_depth_stencil_state_compare(const void *key, const struct wine_rb_entry *entry)
+{
+    const struct wined3d_depth_stencil_state *state = WINE_RB_ENTRY_VALUE(entry, struct wined3d_depth_stencil_state, entry);
+
+    return memcmp(&state->desc, key, sizeof(state->desc));
+}
+
 static BOOL wined3d_select_feature_level(const struct wined3d_adapter *adapter,
         const enum wined3d_feature_level *levels, unsigned int level_count,
         enum wined3d_feature_level *selected_level)
@@ -5601,6 +5682,7 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined
     wine_rb_init(&device->samplers, wined3d_sampler_compare);
     wine_rb_init(&device->rasterizer_states, wined3d_rasterizer_state_compare);
     wine_rb_init(&device->blend_states, wined3d_blend_state_compare);
+    wine_rb_init(&device->depth_stencil_states, wined3d_depth_stencil_state_compare);
 
     if (vertex_pipeline->vp_states && fragment_pipeline->states
             && FAILED(hr = compile_state_table(device->state_table, device->multistate_funcs,
@@ -5611,6 +5693,7 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined
         wine_rb_destroy(&device->samplers, NULL, NULL);
         wine_rb_destroy(&device->rasterizer_states, NULL, NULL);
         wine_rb_destroy(&device->blend_states, NULL, NULL);
+        wine_rb_destroy(&device->depth_stencil_states, NULL, NULL);
         wined3d_decref(device->wined3d);
         return hr;
     }
@@ -5637,6 +5720,7 @@ err:
     wine_rb_destroy(&device->samplers, NULL, NULL);
     wine_rb_destroy(&device->rasterizer_states, NULL, NULL);
     wine_rb_destroy(&device->blend_states, NULL, NULL);
+    wine_rb_destroy(&device->depth_stencil_states, NULL, NULL);
     wined3d_decref(device->wined3d);
     return hr;
 }
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 42666e9ccc2..decfd996566 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -109,6 +109,67 @@ HRESULT CDECL wined3d_blend_state_create(struct wined3d_device *device,
     return WINED3D_OK;
 }
 
+ULONG CDECL wined3d_depth_stencil_state_incref(struct wined3d_depth_stencil_state *state)
+{
+    ULONG refcount = InterlockedIncrement(&state->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", state, refcount);
+
+    return refcount;
+}
+
+static void wined3d_depth_stencil_state_destroy_object(void *object)
+{
+    heap_free(object);
+}
+
+ULONG CDECL wined3d_depth_stencil_state_decref(struct wined3d_depth_stencil_state *state)
+{
+    ULONG refcount = InterlockedDecrement(&state->refcount);
+    struct wined3d_device *device = state->device;
+
+    TRACE("%p decreasing refcount to %u.\n", state, refcount);
+
+    if (!refcount)
+    {
+        state->parent_ops->wined3d_object_destroyed(state->parent);
+        wined3d_cs_destroy_object(device->cs, wined3d_depth_stencil_state_destroy_object, state);
+    }
+
+    return refcount;
+}
+
+void * CDECL wined3d_depth_stencil_state_get_parent(const struct wined3d_depth_stencil_state *state)
+{
+    TRACE("depth_stencil_state %p.\n", state);
+
+    return state->parent;
+}
+
+HRESULT CDECL wined3d_depth_stencil_state_create(struct wined3d_device *device,
+        const struct wined3d_depth_stencil_state_desc *desc, void *parent,
+        const struct wined3d_parent_ops *parent_ops, struct wined3d_depth_stencil_state **state)
+{
+    struct wined3d_depth_stencil_state *object;
+
+    TRACE("device %p, desc %p, parent %p, parent_ops %p, state %p.\n",
+            device, desc, parent, parent_ops, state);
+
+    if (!(object = heap_alloc_zero(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->refcount = 1;
+    object->desc = *desc;
+    object->parent = parent;
+    object->parent_ops = parent_ops;
+    object->device = device;
+
+    TRACE("Created depth/stencil state %p.\n", object);
+    *state = object;
+
+    return WINED3D_OK;
+}
+
 ULONG CDECL wined3d_rasterizer_state_incref(struct wined3d_rasterizer_state *state)
 {
     ULONG refcount = InterlockedIncrement(&state->refcount);
@@ -230,10 +291,11 @@ static void state_lighting(struct wined3d_context *context, const struct wined3d
     }
 }
 
-static void state_zenable(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
+static void depth(struct wined3d_context *context, const struct wined3d_state *state)
 {
-    enum wined3d_depth_buffer_type zenable = state->render_states[WINED3D_RS_ZENABLE];
     const struct wined3d_gl_info *gl_info = wined3d_context_gl(context)->gl_info;
+    const struct wined3d_depth_stencil_state *ds = state->depth_stencil_state;
+    enum wined3d_depth_buffer_type zenable = ds ? ds->desc.depth : WINED3D_ZB_TRUE;
 
     /* No z test without depth stencil buffers */
     if (!state->fb.depth_stencil)
@@ -266,6 +328,11 @@ static void state_zenable(struct wined3d_context *context, const struct wined3d_
         context_apply_state(context, state, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
 }
 
+static void depthstencil(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
+{
+    depth(context, state);
+}
+
 static void cullmode(const struct wined3d_rasterizer_state *r, const struct wined3d_gl_info *gl_info)
 {
     enum wined3d_cull mode = r ? r->desc.cull_mode : WINED3D_CULL_BACK;
@@ -4603,6 +4670,7 @@ const struct wined3d_state_entry_template misc_state_template[] =
     { STATE_BLEND_FACTOR,                                 { STATE_BLEND_FACTOR,                                 state_blend_factor  }, EXT_BLEND_COLOR                 },
     { STATE_BLEND_FACTOR,                                 { STATE_BLEND_FACTOR,                                 state_blend_factor_w}, WINED3D_GL_EXT_NONE             },
     { STATE_SAMPLE_MASK,                                  { STATE_SAMPLE_MASK,                                  state_multisampmask }, WINED3D_GL_EXT_NONE             },
+    { STATE_DEPTH_STENCIL,                                { STATE_DEPTH_STENCIL,                                depthstencil        }, WINED3D_GL_EXT_NONE             },
     { STATE_STREAMSRC,                                    { STATE_STREAMSRC,                                    streamsrc           }, WINED3D_GL_EXT_NONE             },
     { STATE_VDECL,                                        { STATE_VDECL,                                        vdecl_miscpart      }, WINED3D_GL_EXT_NONE             },
     { STATE_RASTERIZER,                                   { STATE_RASTERIZER,                                   rasterizer_cc       }, ARB_CLIP_CONTROL                },
@@ -4670,7 +4738,6 @@ const struct wined3d_state_entry_template misc_state_template[] =
     { STATE_INDEXBUFFER,                                  { STATE_INDEXBUFFER,                                  state_nop           }, WINED3D_GL_EXT_NONE             },
     { STATE_RENDER(WINED3D_RS_ANTIALIAS),                 { STATE_RENDER(WINED3D_RS_ANTIALIAS),                 state_antialias     }, WINED3D_GL_EXT_NONE             },
     { STATE_RENDER(WINED3D_RS_TEXTUREPERSPECTIVE),        { STATE_RENDER(WINED3D_RS_TEXTUREPERSPECTIVE),        state_nop           }, WINED3D_GL_EXT_NONE             },
-    { STATE_RENDER(WINED3D_RS_ZENABLE),                   { STATE_RENDER(WINED3D_RS_ZENABLE),                   state_zenable       }, WINED3D_GL_EXT_NONE             },
     { STATE_RENDER(WINED3D_RS_WRAPU),                     { STATE_RENDER(WINED3D_RS_WRAPU),                     state_wrapu         }, WINED3D_GL_EXT_NONE             },
     { STATE_RENDER(WINED3D_RS_WRAPV),                     { STATE_RENDER(WINED3D_RS_WRAPV),                     state_wrapv         }, WINED3D_GL_EXT_NONE             },
     { STATE_RENDER(WINED3D_RS_LINEPATTERN),               { STATE_RENDER(WINED3D_RS_LINEPATTERN),               state_linepattern   }, WINED3D_GL_LEGACY_CONTEXT       },
@@ -5493,7 +5560,7 @@ static void validate_state_table(struct wined3d_state_entry *state_table)
     {
         {  1,   1},
         {  3,   3},
-        {  8,   8},
+        {  7,   8},
         { 17,  22},
         { 27,  27},
         { 40,  40},
@@ -5544,6 +5611,7 @@ static void validate_state_table(struct wined3d_state_entry *state_table)
         STATE_BLEND,
         STATE_BLEND_FACTOR,
         STATE_SAMPLE_MASK,
+        STATE_DEPTH_STENCIL,
     };
     unsigned int i, current;
 
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 916d90cf215..753d0080fd7 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -5247,6 +5247,8 @@ const char *debug_d3dstate(DWORD state)
         return "STATE_BLEND_FACTOR";
     if (STATE_IS_SAMPLE_MASK(state))
         return "STATE_SAMPLE_MASK";
+    if (STATE_IS_DEPTH_STENCIL(state))
+        return "STATE_DEPTH_STENCIL";
 
     return wine_dbg_sprintf("UNKNOWN_STATE(%#x)", state);
 }
@@ -5495,8 +5497,11 @@ void get_projection_matrix(const struct wined3d_context *context, const struct w
         float y_offset = flip
                 ? (center_offset - (2.0f * y) - h) / h
                 : (center_offset - (2.0f * y) - h) / -h;
-        enum wined3d_depth_buffer_type zenable = state->fb.depth_stencil ?
-                state->render_states[WINED3D_RS_ZENABLE] : WINED3D_ZB_FALSE;
+        enum wined3d_depth_buffer_type zenable = WINED3D_ZB_TRUE;
+        if (!state->fb.depth_stencil)
+            zenable = WINED3D_ZB_FALSE;
+        else if (state->depth_stencil_state)
+            zenable = state->depth_stencil_state->desc.depth;
         float z_scale = zenable ? clip_control ? 1.0f : 2.0f : 0.0f;
         float z_offset = zenable ? clip_control ? 0.0f : -1.0f : 0.0f;
         const struct wined3d_matrix projection =
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index 22a9a9dd740..48dc739784c 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -32,6 +32,11 @@
 @ cdecl wined3d_buffer_get_resource(ptr)
 @ cdecl wined3d_buffer_incref(ptr)
 
+@ cdecl wined3d_depth_stencil_state_create(ptr ptr ptr ptr ptr)
+@ cdecl wined3d_depth_stencil_state_decref(ptr)
+@ cdecl wined3d_depth_stencil_state_get_parent(ptr)
+@ cdecl wined3d_depth_stencil_state_incref(ptr)
+
 @ cdecl wined3d_device_acquire_focus_window(ptr ptr)
 @ cdecl wined3d_device_apply_stateblock(ptr ptr)
 @ cdecl wined3d_device_begin_scene(ptr)
@@ -62,6 +67,7 @@
 @ cdecl wined3d_device_get_cs_resource_view(ptr long)
 @ cdecl wined3d_device_get_cs_sampler(ptr long)
 @ cdecl wined3d_device_get_cs_uav(ptr long)
+@ cdecl wined3d_device_get_depth_stencil_state(ptr)
 @ cdecl wined3d_device_get_depth_stencil_view(ptr)
 @ cdecl wined3d_device_get_device_caps(ptr ptr)
 @ cdecl wined3d_device_get_display_mode(ptr long ptr ptr)
@@ -116,6 +122,7 @@
 @ cdecl wined3d_device_set_cs_uav(ptr long ptr long)
 @ cdecl wined3d_device_set_cursor_position(ptr long long long)
 @ cdecl wined3d_device_set_cursor_properties(ptr long long ptr long)
+@ cdecl wined3d_device_set_depth_stencil_state(ptr ptr)
 @ cdecl wined3d_device_set_depth_stencil_view(ptr ptr)
 @ cdecl wined3d_device_set_dialog_box_mode(ptr long)
 @ cdecl wined3d_device_set_domain_shader(ptr ptr)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index db17305c76b..a051406a7a3 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1705,7 +1705,10 @@ enum wined3d_pipeline
 #define STATE_STREAM_OUTPUT (STATE_COLOR_KEY + 1)
 #define STATE_IS_STREAM_OUTPUT(a) ((a) == STATE_STREAM_OUTPUT)
 
-#define STATE_BLEND (STATE_STREAM_OUTPUT + 1)
+#define STATE_DEPTH_STENCIL (STATE_STREAM_OUTPUT + 1)
+#define STATE_IS_DEPTH_STENCIL(a) ((a) == STATE_DEPTH_STENCIL)
+
+#define STATE_BLEND (STATE_DEPTH_STENCIL + 1)
 #define STATE_IS_BLEND(a) ((a) == STATE_BLEND)
 
 #define STATE_BLEND_FACTOR (STATE_BLEND + 1)
@@ -3154,6 +3157,18 @@ struct wined3d_blend_state
     struct wine_rb_entry entry;
 };
 
+struct wined3d_depth_stencil_state
+{
+    LONG refcount;
+    struct wined3d_depth_stencil_state_desc desc;
+
+    void *parent;
+    const struct wined3d_parent_ops *parent_ops;
+
+    struct wined3d_device *device;
+    struct wine_rb_entry entry;
+};
+
 struct wined3d_rasterizer_state
 {
     LONG refcount;
@@ -3235,6 +3250,7 @@ struct wined3d_state
     struct wined3d_blend_state *blend_state;
     struct wined3d_color blend_factor;
     unsigned int sample_mask;
+    struct wined3d_depth_stencil_state *depth_stencil_state;
     struct wined3d_rasterizer_state *rasterizer_state;
 };
 
@@ -3303,7 +3319,7 @@ struct wined3d_device
 
     struct list             resources; /* a linked list to track resources created by the device */
     struct list             shaders;   /* a linked list to track shaders (pixel and vertex)      */
-    struct wine_rb_tree samplers, rasterizer_states, blend_states;
+    struct wine_rb_tree samplers, rasterizer_states, blend_states, depth_stencil_states;
 
     /* Render Target Support */
     struct wined3d_rendertarget_view *auto_depth_stencil_view;
@@ -4094,6 +4110,8 @@ void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture
         WORD flags, const struct wined3d_color_key *color_key) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_shader_type type,
         UINT cb_idx, struct wined3d_buffer *buffer) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_set_depth_stencil_state(struct wined3d_cs *cs,
+        struct wined3d_depth_stencil_state *state) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_set_depth_stencil_view(struct wined3d_cs *cs,
         struct wined3d_rendertarget_view *view) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer,
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 3b541714f4f..55dad1bfd6b 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2033,6 +2033,11 @@ struct wined3d_blend_state_desc
     } rt[WINED3D_MAX_RENDER_TARGETS];
 };
 
+struct wined3d_depth_stencil_state_desc
+{
+    enum wined3d_depth_buffer_type depth;
+};
+
 struct wined3d_rasterizer_state_desc
 {
     enum wined3d_fill_mode fill_mode;
@@ -2191,6 +2196,7 @@ struct wined3d;
 struct wined3d_adapter;
 struct wined3d_blend_state;
 struct wined3d_buffer;
+struct wined3d_depth_stencil_state;
 struct wined3d_device;
 struct wined3d_output;
 struct wined3d_palette;
@@ -2349,6 +2355,7 @@ struct wined3d_shader_resource_view * __cdecl wined3d_device_get_cs_resource_vie
 struct wined3d_sampler * __cdecl wined3d_device_get_cs_sampler(const struct wined3d_device *device, unsigned int idx);
 struct wined3d_unordered_access_view * __cdecl wined3d_device_get_cs_uav(const struct wined3d_device *device,
         unsigned int idx);
+struct wined3d_depth_stencil_state * __cdecl wined3d_device_get_depth_stencil_state(const struct wined3d_device *device);
 struct wined3d_rendertarget_view * __cdecl wined3d_device_get_depth_stencil_view(const struct wined3d_device *device);
 HRESULT __cdecl wined3d_device_get_device_caps(const struct wined3d_device *device, struct wined3d_caps *caps);
 HRESULT __cdecl wined3d_device_get_display_mode(const struct wined3d_device *device, UINT swapchain_idx,
@@ -2435,6 +2442,8 @@ void __cdecl wined3d_device_set_cursor_position(struct wined3d_device *device,
         int x_screen_space, int y_screen_space, DWORD flags);
 HRESULT __cdecl wined3d_device_set_cursor_properties(struct wined3d_device *device,
         UINT x_hotspot, UINT y_hotspot, struct wined3d_texture *texture, unsigned int sub_resource_idx);
+void __cdecl wined3d_device_set_depth_stencil_state(struct wined3d_device *device,
+        struct wined3d_depth_stencil_state *depth_stencil_state);
 HRESULT __cdecl wined3d_device_set_depth_stencil_view(struct wined3d_device *device,
         struct wined3d_rendertarget_view *view);
 HRESULT __cdecl wined3d_device_set_dialog_box_mode(struct wined3d_device *device, BOOL enable_dialogs);
@@ -2618,6 +2627,13 @@ ULONG __cdecl wined3d_blend_state_decref(struct wined3d_blend_state *state);
 void * __cdecl wined3d_blend_state_get_parent(const struct wined3d_blend_state *state);
 ULONG __cdecl wined3d_blend_state_incref(struct wined3d_blend_state *state);
 
+HRESULT __cdecl wined3d_depth_stencil_state_create(struct wined3d_device *device,
+        const struct wined3d_depth_stencil_state_desc *desc, void *parent,
+        const struct wined3d_parent_ops *parent_ops, struct wined3d_depth_stencil_state **state);
+ULONG __cdecl wined3d_depth_stencil_state_decref(struct wined3d_depth_stencil_state *state);
+void * __cdecl wined3d_depth_stencil_state_get_parent(const struct wined3d_depth_stencil_state *state);
+ULONG __cdecl wined3d_depth_stencil_state_incref(struct wined3d_depth_stencil_state *state);
+
 HRESULT __cdecl wined3d_rasterizer_state_create(struct wined3d_device *device,
         const struct wined3d_rasterizer_state_desc *desc, void *parent,
         const struct wined3d_parent_ops *parent_ops, struct wined3d_rasterizer_state **state);
-- 
2.24.0




More information about the wine-devel mailing list