[PATCH 4/5] wined3d: Create GL sampler objects for wined3d sampler objects.

Henri Verbeet hverbeet at codeweavers.com
Thu Jan 15 10:19:06 CST 2015


---
 dlls/d3d10core/state.c         |    2 +-
 dlls/wined3d/context.c         |    2 ++
 dlls/wined3d/device.c          |   44 +++++++++++++++++++++++++++
 dlls/wined3d/directx.c         |   16 ++++++++++
 dlls/wined3d/glsl_shader.c     |    2 +-
 dlls/wined3d/sampler.c         |   66 +++++++++++++++++++++++++++++++++++++---
 dlls/wined3d/state.c           |   46 ++++++++++++++++++++++++----
 dlls/wined3d/wined3d.spec      |    2 +-
 dlls/wined3d/wined3d_gl.h      |    1 +
 dlls/wined3d/wined3d_private.h |    4 +++
 include/wine/wined3d.h         |    2 +-
 11 files changed, 173 insertions(+), 14 deletions(-)

diff --git a/dlls/d3d10core/state.c b/dlls/d3d10core/state.c
index 7e7d19b..460bc8d 100644
--- a/dlls/d3d10core/state.c
+++ b/dlls/d3d10core/state.c
@@ -657,7 +657,7 @@ HRESULT d3d10_sampler_state_init(struct d3d10_sampler_state *state, struct d3d10
     wined3d_desc.comparison_func = wined3d_cmp_func_from_d3d10core(desc->ComparisonFunc);
     wined3d_desc.srgb_decode = FALSE;
 
-    if (FAILED(hr = wined3d_sampler_create(&wined3d_desc, state, &state->wined3d_sampler)))
+    if (FAILED(hr = wined3d_sampler_create(device->wined3d_device, &wined3d_desc, state, &state->wined3d_sampler)))
     {
         WARN("Failed to create wined3d sampler, hr %#x.\n", hr);
         return hr;
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index ead7e1b..851eb9a 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -1920,6 +1920,8 @@ static void SetupForBlit(const struct wined3d_device *device, struct wined3d_con
             context_invalidate_state(context, STATE_SAMPLER(sampler));
         }
     }
+    if (gl_info->supported[ARB_SAMPLER_OBJECTS])
+        GL_EXTCALL(glBindSampler(0, 0));
     context_active_texture(context, gl_info, 0);
 
     sampler = context->rev_tex_unit_map[0];
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 1d293bf..7ba7517 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -479,6 +479,13 @@ ULONG CDECL wined3d_device_incref(struct wined3d_device *device)
     return refcount;
 }
 
+static void device_leftover_sampler(struct wine_rb_entry *entry, void *context)
+{
+    struct wined3d_sampler *sampler = WINE_RB_ENTRY_VALUE(entry, struct wined3d_sampler, entry);
+
+    ERR("Leftover sampler %p.\n", sampler);
+}
+
 ULONG CDECL wined3d_device_decref(struct wined3d_device *device)
 {
     ULONG refcount = InterlockedDecrement(&device->ref);
@@ -522,6 +529,8 @@ ULONG CDECL wined3d_device_decref(struct wined3d_device *device)
             DestroyCursor(device->hardwareCursor);
         device->hardwareCursor = 0;
 
+        wine_rb_destroy(&device->samplers, device_leftover_sampler, NULL);
+
         wined3d_decref(device->wined3d);
         device->wined3d = NULL;
         HeapFree(GetProcessHeap(), 0, device);
@@ -1020,6 +1029,14 @@ err_out:
     return hr;
 }
 
+static void device_free_sampler(struct wine_rb_entry *entry, void *context)
+{
+    struct wined3d_sampler *sampler = WINE_RB_ENTRY_VALUE(entry, struct wined3d_sampler, entry);
+    struct wined3d_device *device = context;
+
+    wine_rb_remove(&device->samplers, &sampler->desc);
+}
+
 HRESULT CDECL wined3d_device_uninit_3d(struct wined3d_device *device)
 {
     struct wined3d_resource *resource, *cursor;
@@ -1054,6 +1071,8 @@ HRESULT CDECL wined3d_device_uninit_3d(struct wined3d_device *device)
         resource->resource_ops->resource_unload(resource);
     }
 
+    wine_rb_for_each_entry(&device->samplers, device_free_sampler, device);
+
     /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
      * private data, it might contain opengl pointers
      */
@@ -4658,6 +4677,8 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
     swapchain_update_render_to_fbo(swapchain);
     swapchain_update_draw_bindings(swapchain);
 
+    wine_rb_for_each_entry(&device->samplers, device_free_sampler, device);
+
     if (reset_state && device->d3d_initialized)
         hr = create_primary_opengl_context(device, swapchain);
 
@@ -4850,6 +4871,21 @@ struct wined3d_surface * CDECL wined3d_device_get_surface_from_dc(const struct w
     return NULL;
 }
 
+static int wined3d_sampler_compare(const void *key, const struct wine_rb_entry *entry)
+{
+    const struct wined3d_sampler *sampler = WINE_RB_ENTRY_VALUE(entry, struct wined3d_sampler, entry);
+
+    return memcmp(&sampler->desc, key, sizeof(sampler->desc));
+}
+
+static const struct wine_rb_functions wined3d_sampler_rb_functions =
+{
+    wined3d_rb_alloc,
+    wined3d_rb_realloc,
+    wined3d_rb_free,
+    wined3d_sampler_compare,
+};
+
 HRESULT device_init(struct wined3d_device *device, struct wined3d *wined3d,
         UINT adapter_idx, enum wined3d_device_type device_type, HWND focus_window, DWORD flags,
         BYTE surface_alignment, struct wined3d_device_parent *device_parent)
@@ -4881,12 +4917,19 @@ HRESULT device_init(struct wined3d_device *device, struct wined3d *wined3d,
 
     fragment_pipeline = adapter->fragment_pipe;
 
+    if (wine_rb_init(&device->samplers, &wined3d_sampler_rb_functions) == -1)
+    {
+        ERR("Failed to initialize sampler rbtree.\n");
+        return E_OUTOFMEMORY;
+    }
+
     if (vertex_pipeline->vp_states && fragment_pipeline->states
             && FAILED(hr = compile_state_table(device->StateTable, device->multistate_funcs,
             &adapter->gl_info, &adapter->d3d_info, vertex_pipeline,
             fragment_pipeline, misc_state_template)))
     {
         ERR("Failed to compile state table, hr %#x.\n", hr);
+        wine_rb_destroy(&device->samplers, NULL, NULL);
         wined3d_decref(device->wined3d);
         return hr;
     }
@@ -4916,6 +4959,7 @@ err:
     {
         HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]);
     }
+    wine_rb_destroy(&device->samplers, NULL, NULL);
     wined3d_decref(device->wined3d);
     return hr;
 }
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 26910b1..0cf397f 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -135,6 +135,7 @@ static const struct wined3d_extension_map gl_extension_map[] =
     {"GL_ARB_point_parameters",             ARB_POINT_PARAMETERS          },
     {"GL_ARB_point_sprite",                 ARB_POINT_SPRITE              },
     {"GL_ARB_provoking_vertex",             ARB_PROVOKING_VERTEX          },
+    {"GL_ARB_sampler_objects",              ARB_SAMPLER_OBJECTS           },
     {"GL_ARB_shader_bit_encoding",          ARB_SHADER_BIT_ENCODING       },
     {"GL_ARB_shader_objects",               ARB_SHADER_OBJECTS            },
     {"GL_ARB_shader_texture_lod",           ARB_SHADER_TEXTURE_LOD        },
@@ -2517,6 +2518,21 @@ static void load_gl_funcs(struct wined3d_gl_info *gl_info)
     USE_GL_FUNC(glPointParameterfvARB)
     /* GL_ARB_provoking_vertex */
     USE_GL_FUNC(glProvokingVertex)
+    /* GL_ARB_sampler_objects */
+    USE_GL_FUNC(glGenSamplers)
+    USE_GL_FUNC(glDeleteSamplers)
+    USE_GL_FUNC(glIsSampler)
+    USE_GL_FUNC(glBindSampler)
+    USE_GL_FUNC(glSamplerParameteri)
+    USE_GL_FUNC(glSamplerParameterf)
+    USE_GL_FUNC(glSamplerParameteriv)
+    USE_GL_FUNC(glSamplerParameterfv)
+    USE_GL_FUNC(glSamplerParameterIiv)
+    USE_GL_FUNC(glSamplerParameterIuiv)
+    USE_GL_FUNC(glGetSamplerParameteriv)
+    USE_GL_FUNC(glGetSamplerParameterfv)
+    USE_GL_FUNC(glGetSamplerParameterIiv)
+    USE_GL_FUNC(glGetSamplerParameterIuiv)
     /* GL_ARB_shader_objects */
     USE_GL_FUNC(glAttachObjectARB)
     USE_GL_FUNC(glBindAttribLocationARB)
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 0ab591f..24a8b46 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -6604,7 +6604,7 @@ static void shader_glsl_get_caps(const struct wined3d_gl_info *gl_info, struct s
     if (gl_info->supported[EXT_GPU_SHADER4] && gl_info->supported[ARB_SHADER_BIT_ENCODING]
             && gl_info->supported[ARB_GEOMETRY_SHADER4] && gl_info->glsl_version >= MAKEDWORD_VERSION(1, 50)
             && gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX] && gl_info->supported[ARB_DRAW_INSTANCED]
-            && gl_info->supported[ARB_TEXTURE_RG])
+            && gl_info->supported[ARB_TEXTURE_RG] && gl_info->supported[ARB_SAMPLER_OBJECTS])
         shader_model = 4;
     /* ARB_shader_texture_lod or EXT_gpu_shader4 is required for the SM3
      * texldd and texldl instructions. */
diff --git a/dlls/wined3d/sampler.c b/dlls/wined3d/sampler.c
index ed9002e..ffa1155 100644
--- a/dlls/wined3d/sampler.c
+++ b/dlls/wined3d/sampler.c
@@ -36,11 +36,20 @@ ULONG CDECL wined3d_sampler_incref(struct wined3d_sampler *sampler)
 ULONG CDECL wined3d_sampler_decref(struct wined3d_sampler *sampler)
 {
     ULONG refcount = InterlockedDecrement(&sampler->refcount);
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context *context;
 
     TRACE("%p decreasing refcount to %u.\n", sampler, refcount);
 
     if (!refcount)
+    {
+        context = context_acquire(sampler->device, NULL);
+        gl_info = context->gl_info;
+        GL_EXTCALL(glDeleteSamplers(1, &sampler->name));
+        context_release(context);
+
         HeapFree(GetProcessHeap(), 0, sampler);
+    }
 
     return refcount;
 }
@@ -52,25 +61,74 @@ void * CDECL wined3d_sampler_get_parent(const struct wined3d_sampler *sampler)
     return sampler->parent;
 }
 
-static void wined3d_sampler_init(struct wined3d_sampler *sampler,
+static void wined3d_sampler_init(struct wined3d_sampler *sampler, struct wined3d_device *device,
         const struct wined3d_sampler_desc *desc, void *parent)
 {
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context *context;
+
     sampler->refcount = 1;
+    sampler->device = device;
     sampler->parent = parent;
     sampler->desc = *desc;
+
+    context = context_acquire(device, NULL);
+    gl_info = context->gl_info;
+
+    GL_EXTCALL(glGenSamplers(1, &sampler->name));
+    GL_EXTCALL(glSamplerParameteri(sampler->name, GL_TEXTURE_WRAP_S,
+            gl_info->wrap_lookup[desc->address_u - WINED3D_TADDRESS_WRAP]));
+    GL_EXTCALL(glSamplerParameteri(sampler->name, GL_TEXTURE_WRAP_T,
+            gl_info->wrap_lookup[desc->address_v - WINED3D_TADDRESS_WRAP]));
+    GL_EXTCALL(glSamplerParameteri(sampler->name, GL_TEXTURE_WRAP_R,
+            gl_info->wrap_lookup[desc->address_w - WINED3D_TADDRESS_WRAP]));
+    GL_EXTCALL(glSamplerParameterfv(sampler->name, GL_TEXTURE_BORDER_COLOR, &desc->border_color[0]));
+    GL_EXTCALL(glSamplerParameteri(sampler->name, GL_TEXTURE_MAG_FILTER,
+            wined3d_gl_mag_filter(desc->mag_filter)));
+    GL_EXTCALL(glSamplerParameteri(sampler->name, GL_TEXTURE_MIN_FILTER,
+            wined3d_gl_min_mip_filter(desc->min_filter, desc->mip_filter)));
+    GL_EXTCALL(glSamplerParameterf(sampler->name, GL_TEXTURE_LOD_BIAS, desc->lod_bias));
+    GL_EXTCALL(glSamplerParameterf(sampler->name, GL_TEXTURE_MIN_LOD, desc->min_lod));
+    GL_EXTCALL(glSamplerParameterf(sampler->name, GL_TEXTURE_MAX_LOD, desc->max_lod));
+    if (gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC])
+        GL_EXTCALL(glSamplerParameteri(sampler->name, GL_TEXTURE_MAX_ANISOTROPY_EXT, desc->max_anisotropy));
+    if (desc->compare)
+        GL_EXTCALL(glSamplerParameteri(sampler->name, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE));
+    GL_EXTCALL(glSamplerParameteri(sampler->name, GL_TEXTURE_COMPARE_FUNC,
+            wined3d_gl_compare_func(desc->comparison_func)));
+    if (gl_info->supported[EXT_TEXTURE_SRGB_DECODE] && !desc->srgb_decode)
+        GL_EXTCALL(glSamplerParameteri(sampler->name, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT));
+    checkGLcall("sampler creation");
+
+    TRACE("Created sampler %u.\n", sampler->name);
+
+    context_release(context);
 }
 
-HRESULT CDECL wined3d_sampler_create(const struct wined3d_sampler_desc *desc,
+HRESULT CDECL wined3d_sampler_create(struct wined3d_device *device, const struct wined3d_sampler_desc *desc,
         void *parent, struct wined3d_sampler **sampler)
 {
     struct wined3d_sampler *object;
 
-    TRACE("desc %p, parent %p, sampler %p.\n", desc, parent, sampler);
+    TRACE("device %p, desc %p, parent %p, sampler %p.\n", device, desc, parent, sampler);
+
+    if (!device->adapter->gl_info.supported[ARB_SAMPLER_OBJECTS])
+        return WINED3DERR_INVALIDCALL;
+
+    if (desc->address_u < WINED3D_TADDRESS_WRAP || desc->address_u > WINED3D_TADDRESS_MIRROR_ONCE
+            || desc->address_v < WINED3D_TADDRESS_WRAP || desc->address_v > WINED3D_TADDRESS_MIRROR_ONCE
+            || desc->address_w < WINED3D_TADDRESS_WRAP || desc->address_w > WINED3D_TADDRESS_MIRROR_ONCE)
+        return WINED3DERR_INVALIDCALL;
+
+    if (desc->mag_filter < WINED3D_TEXF_POINT || desc->mag_filter > WINED3D_TEXF_LINEAR
+            || desc->min_filter < WINED3D_TEXF_POINT || desc->min_filter > WINED3D_TEXF_LINEAR
+            || desc->mip_filter > WINED3D_TEXF_LINEAR)
+        return WINED3DERR_INVALIDCALL;
 
     if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
         return E_OUTOFMEMORY;
 
-    wined3d_sampler_init(object, desc, parent);
+    wined3d_sampler_init(object, device, desc, parent);
 
     TRACE("Created sampler %p.\n", object);
     *sampler = object;
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index a6d9b16..df01715 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -234,7 +234,7 @@ static void state_zwritenable(struct wined3d_context *context, const struct wine
     }
 }
 
-static GLenum gl_compare_func(enum wined3d_cmp_func f)
+GLenum wined3d_gl_compare_func(enum wined3d_cmp_func f)
 {
     switch (f)
     {
@@ -262,7 +262,7 @@ static GLenum gl_compare_func(enum wined3d_cmp_func f)
 
 static void state_zfunc(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
-    GLenum depth_func = gl_compare_func(state->render_states[WINED3D_RS_ZFUNC]);
+    GLenum depth_func = wined3d_gl_compare_func(state->render_states[WINED3D_RS_ZFUNC]);
     const struct wined3d_gl_info *gl_info = context->gl_info;
 
     if (!depth_func) return;
@@ -566,7 +566,7 @@ static void state_alpha(struct wined3d_context *context, const struct wined3d_st
     else
     {
         ref = ((float)state->render_states[WINED3D_RS_ALPHAREF]) / 255.0f;
-        glParm = gl_compare_func(state->render_states[WINED3D_RS_ALPHAFUNC]);
+        glParm = wined3d_gl_compare_func(state->render_states[WINED3D_RS_ALPHAFUNC]);
     }
     if (glParm)
     {
@@ -835,9 +835,9 @@ static void state_stencil(struct wined3d_context *context, const struct wined3d_
 
     onesided_enable = state->render_states[WINED3D_RS_STENCILENABLE];
     twosided_enable = state->render_states[WINED3D_RS_TWOSIDEDSTENCILMODE];
-    if (!(func = gl_compare_func(state->render_states[WINED3D_RS_STENCILFUNC])))
+    if (!(func = wined3d_gl_compare_func(state->render_states[WINED3D_RS_STENCILFUNC])))
         func = GL_ALWAYS;
-    if (!(func_ccw = gl_compare_func(state->render_states[WINED3D_RS_CCW_STENCILFUNC])))
+    if (!(func_ccw = wined3d_gl_compare_func(state->render_states[WINED3D_RS_CCW_STENCILFUNC])))
         func_ccw = GL_ALWAYS;
     ref = state->render_states[WINED3D_RS_STENCILREF];
     mask = state->render_states[WINED3D_RS_STENCILMASK];
@@ -3708,8 +3708,42 @@ static void sampler(struct wined3d_context *context, const struct wined3d_state
         unsigned int base_level;
 
         wined3d_sampler_desc_from_sampler_states(&desc, gl_info, sampler_states, texture);
+
         wined3d_texture_bind(texture, context, srgb);
-        wined3d_texture_apply_sampler_desc(texture, &desc, gl_info);
+        if (!gl_info->supported[ARB_SAMPLER_OBJECTS])
+        {
+            wined3d_texture_apply_sampler_desc(texture, &desc, gl_info);
+        }
+        else
+        {
+            struct wined3d_device *device = context->swapchain->device;
+            struct wined3d_sampler *sampler;
+            struct wine_rb_entry *entry;
+
+            if ((entry = wine_rb_get(&device->samplers, &desc)))
+            {
+                sampler = WINE_RB_ENTRY_VALUE(entry, struct wined3d_sampler, entry);
+            }
+            else
+            {
+                if (FAILED(wined3d_sampler_create(device, &desc, NULL, &sampler)))
+                {
+                    ERR("Failed to create sampler.\n");
+                    sampler = NULL;
+                }
+                else
+                {
+                    if (wine_rb_put(&device->samplers, &desc, &sampler->entry) == -1)
+                        ERR("Failed to insert sampler.\n");
+                }
+            }
+
+            if (sampler)
+            {
+                GL_EXTCALL(glBindSampler(sampler_idx, sampler->name));
+                checkGLcall("glBindSampler");
+            }
+        }
 
         if (texture->flags & WINED3D_TEXTURE_COND_NP2)
             base_level = 0;
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index e6383b0..63e18c7 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -194,7 +194,7 @@
 @ cdecl wined3d_rendertarget_view_incref(ptr)
 @ cdecl wined3d_rendertarget_view_set_parent(ptr ptr)
 
-@ cdecl wined3d_sampler_create(ptr ptr ptr)
+@ cdecl wined3d_sampler_create(ptr ptr ptr ptr)
 @ cdecl wined3d_sampler_decref(ptr)
 @ cdecl wined3d_sampler_get_parent(ptr)
 @ cdecl wined3d_sampler_incref(ptr)
diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h
index aadc3d5..cbb99e5 100644
--- a/dlls/wined3d/wined3d_gl.h
+++ b/dlls/wined3d/wined3d_gl.h
@@ -71,6 +71,7 @@ enum wined3d_gl_extension
     ARB_POINT_PARAMETERS,
     ARB_POINT_SPRITE,
     ARB_PROVOKING_VERTEX,
+    ARB_SAMPLER_OBJECTS,
     ARB_SHADER_BIT_ENCODING,
     ARB_SHADER_OBJECTS,
     ARB_SHADER_TEXTURE_LOD,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index bee7f61..9107697 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1994,6 +1994,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;
 
     /* Render Target Support */
     struct wined3d_fb_state fb;
@@ -2388,9 +2389,12 @@ void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back) D
 
 struct wined3d_sampler
 {
+    struct wine_rb_entry entry;
     LONG refcount;
+    struct wined3d_device *device;
     void *parent;
     struct wined3d_sampler_desc desc;
+    GLuint name;
 };
 
 struct wined3d_vertex_declaration_element
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 0e8b2f9..cdb5dc2 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2452,7 +2452,7 @@ void * __cdecl wined3d_rendertarget_view_get_sub_resource_parent(const struct wi
 ULONG __cdecl wined3d_rendertarget_view_incref(struct wined3d_rendertarget_view *view);
 void __cdecl wined3d_rendertarget_view_set_parent(struct wined3d_rendertarget_view *view, void *parent);
 
-HRESULT __cdecl wined3d_sampler_create(const struct wined3d_sampler_desc *desc,
+HRESULT __cdecl wined3d_sampler_create(struct wined3d_device *device, const struct wined3d_sampler_desc *desc,
         void *parent, struct wined3d_sampler **sampler);
 ULONG __cdecl wined3d_sampler_decref(struct wined3d_sampler *sampler);
 void * __cdecl wined3d_sampler_get_parent(const struct wined3d_sampler *sampler);
-- 
1.7.10.4




More information about the wine-patches mailing list