From c6232e1d111ae8929c53c02211cde4a9777311fd Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Thu, 15 Jan 2015 17:19:06 +0100 Subject: [PATCH] wined3d: Create GL sampler objects for wined3d sampler objects. --- 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 7e7d19bee80..460bc8d200a 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 ead7e1bd9f8..851eb9a91af 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 271a2166a63..1156a7e3d47 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 8b529fac359..a91090ed896 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 0ab591f8598..24a8b465c2c 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 ed9002ecda1..ffa1155ed0f 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 cccc82af947..3c672dbe3fb 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]; @@ -3709,8 +3709,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 e6383b0d9f6..63e18c7d070 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 aadc3d5caca..cbb99e57536 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 bee7f610ad3..91076978d84 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 0e8b2f9479f..cdb5dc20408 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);