After mulling over this and the comments on patch 4/4, I'd like to propose the following:
struct wined3d_device_context { const struct wined3d_device_context_ops *ops; struct wined3d_device *device; struct wined3d_state state; };
struct wined3d_device_context_deferred { struct wined3d_device_context c;
size_t data_size, start, end; void *data; };
struct wined3d_cs { struct wined3d_device_context c;
struct wined3d_state cs_state;
struct list query_poll_list; BOOL queries_flushed;
LONG pending_presents; };
struct wined3d_cs_st { struct wined3d_cs c;
size_t data_size, start, end; void *data; };
struct wined3d_cs_mt { struct wined3d_cs c;
struct wined3d_cs_queue queue[WINED3D_CS_QUEUE_COUNT];
HMODULE wined3d_module; HANDLE thread; DWORD thread_id; BOOL serialize_commands;
HANDLE event; BOOL waiting_for_event; };
...
void d3d11_immediate_context_PSSetShader(...) { struct d3d_device_context *context = impl_from_immediate_ID3D11DeviceContext1(iface);
wined3d_mutex_lock(); wined3d_device_context_set_shader(context->wined3d_device_context, WINED3D_SHADER_TYPE_PIXEL, ps ? ps->wined3d_shader : NULL); wined3d_mutex_unlock(); }
...
void CDECL wined3d_device_context_set_shader( struct wined3d_device_context *device_context, enum wined3d_shader_type type, struct wined3d_shader *shader) { struct wined3d_state *state = device_context->state; struct wined3d_device_context_set_shader *op; struct wined3d_shader *prev;
prev = state->shader[type]; if (shader == prev) return;
if (shader) wined3d_shader_incref(shader); state->shader[type] = shader; if (prev) wined3d_shader_decref(prev);
op = wined3d_device_context_require_space(device_context, sizeof(*op), WINED3D_DEVICE_CONTEXT_QUEUE_DEFAULT); op->opcode = WINED3D_DEVICE_CONTEXT_OP_SET_SHADER; op->type = type; op->shader = shader;
wined3d_device_context_submit(device_context, WINED3D_DEVICE_CONTEXT_QUEUE_DEFAULT); }
...
static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data) { const struct wined3d_device_context_set_shader *op = data;
cs->cs_state.shader[op->type] = op->shader; device_invalidate_state(cs->c.device, STATE_SHADER(op->type)); if (op->type != WINED3D_SHADER_TYPE_COMPUTE) device_invalidate_state(cs->c.device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); else device_invalidate_state(cs->c.device, STATE_COMPUTE_SHADER_RESOURCE_BINDING); }
In essence, this is pretty much the same thing as I was proposing with patch 4/4, except with different names, and with the struct inheritance as proposed in patch 1/4. Actually, in terms of naming, it's even closer to how I originally started writing this series, before I decided to try an approach that would thrash cs.c less.
The naming is arguably still a little janky (e.g. "wined3d_cs" inheriting from "wined3d_device_context"), but maybe un-janky enough to work.
"wined3d_device_context" is very long, though. I would also propose using "wined3d_queue" instead, which seems shorter and about as accurate. (I think I may have borrowed that one from Matteo.)
SwapContextState() isn't valid on deferred contexts. I'm not sure whether we should ignore that detail in wined3d and treat it like it is, or effectively make it into a wined3d_device_context_ops method. Either way, I think we'd either need to keep state management and op queuing separate (as they are now), or make wined3d_device_set_state into a proper CS operation. I guess I don't have a strong feeling either way.