From 052a86301080912e79b5316d69d30f0ab508a0f4 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Thu, 3 Oct 2013 08:54:13 +0200 Subject: [PATCH] wined3d: Send texture binding updates through the command stream. --- dlls/wined3d/cs.c | 78 ++++++++++++++++++++++++++++++++++ dlls/wined3d/device.c | 63 +-------------------------- dlls/wined3d/wined3d_private.h | 1 + 3 files changed, 81 insertions(+), 61 deletions(-) diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 0f060b47274..176f36b3bd3 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -36,6 +36,7 @@ enum wined3d_cs_op WINED3D_CS_OP_SET_STREAM_SOURCE, WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ, WINED3D_CS_OP_SET_INDEX_BUFFER, + WINED3D_CS_OP_SET_TEXTURE, }; struct wined3d_cs_present @@ -125,6 +126,13 @@ struct wined3d_cs_set_index_buffer enum wined3d_format_id format_id; }; +struct wined3d_cs_set_texture +{ + enum wined3d_cs_op opcode; + UINT stage; + struct wined3d_texture *texture; +}; + static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data) { const struct wined3d_cs_present *op = data; @@ -427,6 +435,75 @@ void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buff cs->ops->submit(cs); } +static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data) +{ + const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info; + const struct wined3d_cs_set_texture *op = data; + struct wined3d_texture *prev; + + prev = cs->state.textures[op->stage]; + cs->state.textures[op->stage] = op->texture; + + if (op->texture) + { + if (InterlockedIncrement(&op->texture->resource.bind_count) == 1) + op->texture->sampler = op->stage; + + if (!prev || op->texture->target != prev->target) + device_invalidate_state(cs->device, STATE_PIXELSHADER); + + if (!prev && op->stage < d3d_info->limits.ffp_blend_stages) + { + /* The source arguments for color and alpha ops have different + * meanings when a NULL texture is bound, so the COLOR_OP and + * ALPHA_OP have to be dirtified. */ + device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP)); + device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP)); + } + } + + if (prev) + { + if (InterlockedDecrement(&prev->resource.bind_count) && prev->sampler == op->stage) + { + unsigned int i; + + /* Search for other stages the texture is bound to. Shouldn't + * happen if applications bind textures to a single stage only. */ + TRACE("Searching for other stages the texture is bound to.\n"); + for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i) + { + if (cs->state.textures[i] == prev) + { + TRACE("Texture is also bound to stage %u.\n", i); + prev->sampler = i; + break; + } + } + } + + if (!op->texture && op->stage < d3d_info->limits.ffp_blend_stages) + { + device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP)); + device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP)); + } + } + + device_invalidate_state(cs->device, STATE_SAMPLER(op->stage)); +} + +void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined3d_texture *texture) +{ + struct wined3d_cs_set_texture *op; + + op = cs->ops->require_space(cs, sizeof(*op)); + op->opcode = WINED3D_CS_OP_SET_TEXTURE; + op->stage = stage; + op->texture = texture; + + cs->ops->submit(cs); +} + static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) = { /* WINED3D_CS_OP_PRESENT */ wined3d_cs_exec_present, @@ -440,6 +517,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void /* WINED3D_CS_OP_SET_STREAM_SOURCE */ wined3d_cs_exec_set_stream_source, /* WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ */ wined3d_cs_exec_set_stream_source_freq, /* WINED3D_CS_OP_SET_INDEX_BUFFER */ wined3d_cs_exec_set_index_buffer, + /* WINED3D_CS_OP_SET_TEXTURE */ wined3d_cs_exec_set_texture, }; static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index acca498c0aa..0c2f3e8a6db 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -3164,7 +3164,6 @@ DWORD CDECL wined3d_device_get_texture_stage_state(const struct wined3d_device * HRESULT CDECL wined3d_device_set_texture(struct wined3d_device *device, UINT stage, struct wined3d_texture *texture) { - const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info; struct wined3d_texture *prev; TRACE("device %p, stage %u, texture %p.\n", device, stage, texture); @@ -3200,70 +3199,12 @@ HRESULT CDECL wined3d_device_set_texture(struct wined3d_device *device, TRACE("Setting new texture to %p.\n", texture); device->update_state->textures[stage] = texture; - if (device->recording) - { - TRACE("Recording... not performing anything\n"); - - if (texture) wined3d_texture_incref(texture); - if (prev) wined3d_texture_decref(prev); - - return WINED3D_OK; - } - if (texture) - { - LONG bind_count = InterlockedIncrement(&texture->resource.bind_count); - wined3d_texture_incref(texture); - - if (!prev || texture->target != prev->target) - device_invalidate_state(device, STATE_PIXELSHADER); - - if (!prev && stage < d3d_info->limits.ffp_blend_stages) - { - /* The source arguments for color and alpha ops have different - * meanings when a NULL texture is bound, so the COLOR_OP and - * ALPHA_OP have to be dirtified. */ - device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP)); - device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP)); - } - - if (bind_count == 1) - texture->sampler = stage; - } - + if (!device->recording) + wined3d_cs_emit_set_texture(device->cs, stage, texture); if (prev) - { - LONG bind_count = InterlockedDecrement(&prev->resource.bind_count); - - if (!texture && stage < d3d_info->limits.ffp_blend_stages) - { - device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP)); - device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP)); - } - - if (bind_count && prev->sampler == stage) - { - unsigned int i; - - /* Search for other stages the texture is bound to. Shouldn't - * happen if applications bind textures to a single stage only. */ - TRACE("Searching for other stages the texture is bound to.\n"); - for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i) - { - if (device->update_state->textures[i] == prev) - { - TRACE("Texture is also bound to stage %u.\n", i); - prev->sampler = i; - break; - } - } - } - wined3d_texture_decref(prev); - } - - device_invalidate_state(device, STATE_SAMPLER(stage)); return WINED3D_OK; } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 45ead8875ca..6cde5b0f045 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2496,6 +2496,7 @@ void wined3d_cs_emit_set_stream_source(struct wined3d_cs *cs, UINT stream_idx, struct wined3d_buffer *buffer, UINT offset, UINT stride) DECLSPEC_HIDDEN; void wined3d_cs_emit_set_stream_source_freq(struct wined3d_cs *cs, UINT stream_idx, UINT frequency, UINT flags) DECLSPEC_HIDDEN; +void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined3d_texture *texture) 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;