wined3d: Implement manual mipmap generation.

Signed-off-by: Matteo Bruni <mbruni@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Matteo Bruni 2017-12-04 18:07:31 +01:00 committed by Alexandre Julliard
parent dfba903bb2
commit 0daea6d2a0
6 changed files with 136 additions and 13 deletions

View File

@ -71,6 +71,7 @@ enum wined3d_cs_op
WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION,
WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW,
WINED3D_CS_OP_COPY_UAV_COUNTER,
WINED3D_CS_OP_GENERATE_MIPMAPS,
WINED3D_CS_OP_STOP,
};
@ -421,6 +422,12 @@ struct wined3d_cs_copy_uav_counter
struct wined3d_unordered_access_view *view;
};
struct wined3d_cs_generate_mipmaps
{
enum wined3d_cs_op opcode;
struct wined3d_shader_resource_view *view;
};
struct wined3d_cs_stop
{
enum wined3d_cs_op opcode;
@ -2336,6 +2343,28 @@ void wined3d_cs_emit_copy_uav_counter(struct wined3d_cs *cs, struct wined3d_buff
cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
}
static void wined3d_cs_exec_generate_mipmaps(struct wined3d_cs *cs, const void *data)
{
const struct wined3d_cs_generate_mipmaps *op = data;
struct wined3d_shader_resource_view *view = op->view;
shader_resource_view_generate_mipmaps(view);
wined3d_resource_release(view->resource);
}
void wined3d_cs_emit_generate_mipmaps(struct wined3d_cs *cs, struct wined3d_shader_resource_view *view)
{
struct wined3d_cs_generate_mipmaps *op;
op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
op->opcode = WINED3D_CS_OP_GENERATE_MIPMAPS;
op->view = view;
wined3d_resource_acquire(view->resource);
cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
}
static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
{
struct wined3d_cs_stop *op;
@ -2394,6 +2423,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
/* WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION */ wined3d_cs_exec_add_dirty_texture_region,
/* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view,
/* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter,
/* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps,
};
static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)

View File

@ -1580,17 +1580,6 @@ BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture, unsigned
}
}
void CDECL wined3d_texture_generate_mipmaps(struct wined3d_texture *texture)
{
FIXME("texture %p stub!\n", texture);
if (!(texture->flags & WINED3D_TEXTURE_GENERATE_MIPMAPS))
{
WARN("Texture without the WINED3D_TEXTURE_GENERATE_MIPMAPS flag, ignoring.\n");
return;
}
}
static struct wined3d_texture_sub_resource *wined3d_texture_get_sub_resource(struct wined3d_texture *texture,
unsigned int sub_resource_idx)
{

View File

@ -803,6 +803,108 @@ void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view
wined3d_sampler_bind(sampler, unit, texture, context);
}
/* Context activation is done by the caller. */
static void shader_resource_view_bind_and_dirtify(struct wined3d_shader_resource_view *view,
struct wined3d_context *context)
{
if (context->active_texture < ARRAY_SIZE(context->rev_tex_unit_map))
{
DWORD active_sampler = context->rev_tex_unit_map[context->active_texture];
if (active_sampler != WINED3D_UNMAPPED_STAGE)
context_invalidate_state(context, STATE_SAMPLER(active_sampler));
}
/* FIXME: Ideally we'd only do this when touching a binding that's used by
* a shader. */
context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
context_bind_texture(context, view->gl_view.target, view->gl_view.name);
}
void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
{
struct wined3d_texture *texture = texture_from_resource(view->resource);
unsigned int i, j, layer_count, level_count, base_level, max_level;
const struct wined3d_gl_info *gl_info;
struct wined3d_context *context;
struct gl_texture *gl_tex;
DWORD location;
BOOL srgb;
TRACE("view %p.\n", view);
wined3d_from_cs(view->resource->device->cs);
context = context_acquire(view->resource->device, NULL, 0);
gl_info = context->gl_info;
layer_count = view->desc.u.texture.layer_count;
level_count = view->desc.u.texture.level_count;
base_level = view->desc.u.texture.level_idx;
max_level = base_level + level_count - 1;
srgb = !!(texture->flags & WINED3D_TEXTURE_IS_SRGB);
location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
for (i = 0; i < layer_count; ++i)
wined3d_texture_load_location(texture, i * level_count + base_level, context, location);
if (view->gl_view.name)
shader_resource_view_bind_and_dirtify(view, context);
else
wined3d_texture_bind_and_dirtify(texture, context, srgb);
if (gl_info->supported[ARB_SAMPLER_OBJECTS])
GL_EXTCALL(glBindSampler(context->active_texture, 0));
gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, base_level);
gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, max_level);
gl_tex = wined3d_texture_get_gl_texture(texture, srgb);
if (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
{
gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_SRGB_DECODE_EXT,
GL_SKIP_DECODE_EXT);
gl_tex->sampler_desc.srgb_decode = FALSE;
}
gl_info->fbo_ops.glGenerateMipmap(texture->target);
checkGLcall("glGenerateMipMap()");
for (i = 0; i < layer_count; ++i)
{
for (j = base_level + 1; j <= max_level; ++j)
{
wined3d_texture_validate_location(texture, i * level_count + j, location);
wined3d_texture_invalidate_location(texture, i * level_count + j, ~location);
}
}
gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, level_count - 1);
if (srgb)
texture->texture_srgb.base_level = base_level;
else
texture->texture_rgb.base_level = base_level;
context_release(context);
}
void CDECL wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
{
struct wined3d_texture *texture;
TRACE("view %p.\n", view);
if (view->resource->type == WINED3D_RTYPE_BUFFER)
{
WARN("Called on buffer resource %p.\n", view->resource);
return;
}
texture = texture_from_resource(view->resource);
if (!(texture->flags & WINED3D_TEXTURE_GENERATE_MIPMAPS))
{
WARN("Texture without the WINED3D_TEXTURE_GENERATE_MIPMAPS flag, ignoring.\n");
return;
}
wined3d_cs_emit_generate_mipmaps(view->resource->device->cs, view);
}
ULONG CDECL wined3d_unordered_access_view_incref(struct wined3d_unordered_access_view *view)
{
ULONG refcount = InterlockedIncrement(&view->refcount);

View File

@ -254,6 +254,7 @@
@ cdecl wined3d_shader_resource_view_create(ptr ptr ptr ptr ptr)
@ cdecl wined3d_shader_resource_view_decref(ptr)
@ cdecl wined3d_shader_resource_view_generate_mipmaps(ptr)
@ cdecl wined3d_shader_resource_view_get_parent(ptr)
@ cdecl wined3d_shader_resource_view_incref(ptr)
@ -287,7 +288,6 @@
@ cdecl wined3d_texture_create(ptr ptr long long long ptr ptr ptr ptr)
@ cdecl wined3d_texture_decref(ptr)
@ cdecl wined3d_texture_from_resource(ptr)
@ cdecl wined3d_texture_generate_mipmaps(ptr)
@ cdecl wined3d_texture_get_autogen_filter_type(ptr)
@ cdecl wined3d_texture_get_dc(ptr long ptr)
@ cdecl wined3d_texture_get_level_count(ptr)

View File

@ -3508,6 +3508,7 @@ void wined3d_cs_emit_draw(struct wined3d_cs *cs, GLenum primitive_type, unsigned
void wined3d_cs_emit_draw_indirect(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
struct wined3d_buffer *buffer, unsigned int offset, BOOL indexed) DECLSPEC_HIDDEN;
void wined3d_cs_emit_flush(struct wined3d_cs *cs) DECLSPEC_HIDDEN;
void wined3d_cs_emit_generate_mipmaps(struct wined3d_cs *cs, struct wined3d_shader_resource_view *view) DECLSPEC_HIDDEN;
void wined3d_cs_emit_preload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource) DECLSPEC_HIDDEN;
void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain,
const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, DWORD flags) DECLSPEC_HIDDEN;
@ -3705,6 +3706,7 @@ struct wined3d_shader_resource_view
struct wined3d_view_desc desc;
};
void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view) DECLSPEC_HIDDEN;
void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view, unsigned int unit,
struct wined3d_sampler *sampler, struct wined3d_context *context) DECLSPEC_HIDDEN;

View File

@ -2609,6 +2609,7 @@ HRESULT __cdecl wined3d_shader_resource_view_create(const struct wined3d_view_de
struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
struct wined3d_shader_resource_view **view);
ULONG __cdecl wined3d_shader_resource_view_decref(struct wined3d_shader_resource_view *view);
void __cdecl wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view);
void * __cdecl wined3d_shader_resource_view_get_parent(const struct wined3d_shader_resource_view *view);
ULONG __cdecl wined3d_shader_resource_view_incref(struct wined3d_shader_resource_view *view);
@ -2661,7 +2662,6 @@ HRESULT __cdecl wined3d_texture_create(struct wined3d_device *device, const stru
void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture);
struct wined3d_texture * __cdecl wined3d_texture_from_resource(struct wined3d_resource *resource);
ULONG __cdecl wined3d_texture_decref(struct wined3d_texture *texture);
void __cdecl wined3d_texture_generate_mipmaps(struct wined3d_texture *texture);
enum wined3d_texture_filter_type __cdecl wined3d_texture_get_autogen_filter_type(const struct wined3d_texture *texture);
HRESULT __cdecl wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc);
DWORD __cdecl wined3d_texture_get_level_count(const struct wined3d_texture *texture);