wined3d: Get rid of wined3d_get_draw_rect().
[wine.git] / dlls / wined3d / cs.c
blobed249f40140aa33ab8ca8d8d27fa95f9f266c7e5
1 /*
2 * Copyright 2013 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
21 #include "wined3d_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
25 #define WINED3D_INITIAL_CS_SIZE 4096
27 enum wined3d_cs_op
29 WINED3D_CS_OP_NOP,
30 WINED3D_CS_OP_PRESENT,
31 WINED3D_CS_OP_CLEAR,
32 WINED3D_CS_OP_DISPATCH,
33 WINED3D_CS_OP_DRAW,
34 WINED3D_CS_OP_FLUSH,
35 WINED3D_CS_OP_SET_PREDICATION,
36 WINED3D_CS_OP_SET_VIEWPORT,
37 WINED3D_CS_OP_SET_SCISSOR_RECT,
38 WINED3D_CS_OP_SET_RENDERTARGET_VIEW,
39 WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW,
40 WINED3D_CS_OP_SET_VERTEX_DECLARATION,
41 WINED3D_CS_OP_SET_STREAM_SOURCE,
42 WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ,
43 WINED3D_CS_OP_SET_STREAM_OUTPUT,
44 WINED3D_CS_OP_SET_INDEX_BUFFER,
45 WINED3D_CS_OP_SET_CONSTANT_BUFFER,
46 WINED3D_CS_OP_SET_TEXTURE,
47 WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW,
48 WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW,
49 WINED3D_CS_OP_SET_SAMPLER,
50 WINED3D_CS_OP_SET_SHADER,
51 WINED3D_CS_OP_SET_BLEND_STATE,
52 WINED3D_CS_OP_SET_RASTERIZER_STATE,
53 WINED3D_CS_OP_SET_RENDER_STATE,
54 WINED3D_CS_OP_SET_TEXTURE_STATE,
55 WINED3D_CS_OP_SET_SAMPLER_STATE,
56 WINED3D_CS_OP_SET_TRANSFORM,
57 WINED3D_CS_OP_SET_CLIP_PLANE,
58 WINED3D_CS_OP_SET_COLOR_KEY,
59 WINED3D_CS_OP_SET_MATERIAL,
60 WINED3D_CS_OP_SET_LIGHT,
61 WINED3D_CS_OP_SET_LIGHT_ENABLE,
62 WINED3D_CS_OP_PUSH_CONSTANTS,
63 WINED3D_CS_OP_RESET_STATE,
64 WINED3D_CS_OP_CALLBACK,
65 WINED3D_CS_OP_QUERY_ISSUE,
66 WINED3D_CS_OP_PRELOAD_RESOURCE,
67 WINED3D_CS_OP_UNLOAD_RESOURCE,
68 WINED3D_CS_OP_MAP,
69 WINED3D_CS_OP_UNMAP,
70 WINED3D_CS_OP_BLT_SUB_RESOURCE,
71 WINED3D_CS_OP_UPDATE_SUB_RESOURCE,
72 WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION,
73 WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW,
74 WINED3D_CS_OP_COPY_UAV_COUNTER,
75 WINED3D_CS_OP_GENERATE_MIPMAPS,
76 WINED3D_CS_OP_STOP,
79 struct wined3d_cs_packet
81 size_t size;
82 BYTE data[1];
85 struct wined3d_cs_nop
87 enum wined3d_cs_op opcode;
90 struct wined3d_cs_present
92 enum wined3d_cs_op opcode;
93 HWND dst_window_override;
94 struct wined3d_swapchain *swapchain;
95 RECT src_rect;
96 RECT dst_rect;
97 DWORD flags;
100 struct wined3d_cs_clear
102 enum wined3d_cs_op opcode;
103 DWORD flags;
104 unsigned int rt_count;
105 struct wined3d_fb_state *fb;
106 RECT draw_rect;
107 struct wined3d_color color;
108 float depth;
109 DWORD stencil;
110 unsigned int rect_count;
111 RECT rects[1];
114 struct wined3d_cs_dispatch
116 enum wined3d_cs_op opcode;
117 struct wined3d_dispatch_parameters parameters;
120 struct wined3d_cs_draw
122 enum wined3d_cs_op opcode;
123 GLenum primitive_type;
124 GLint patch_vertex_count;
125 struct wined3d_draw_parameters parameters;
128 struct wined3d_cs_flush
130 enum wined3d_cs_op opcode;
133 struct wined3d_cs_set_predication
135 enum wined3d_cs_op opcode;
136 struct wined3d_query *predicate;
137 BOOL value;
140 struct wined3d_cs_set_viewport
142 enum wined3d_cs_op opcode;
143 struct wined3d_viewport viewport;
146 struct wined3d_cs_set_scissor_rect
148 enum wined3d_cs_op opcode;
149 RECT rect;
152 struct wined3d_cs_set_rendertarget_view
154 enum wined3d_cs_op opcode;
155 unsigned int view_idx;
156 struct wined3d_rendertarget_view *view;
159 struct wined3d_cs_set_depth_stencil_view
161 enum wined3d_cs_op opcode;
162 struct wined3d_rendertarget_view *view;
165 struct wined3d_cs_set_vertex_declaration
167 enum wined3d_cs_op opcode;
168 struct wined3d_vertex_declaration *declaration;
171 struct wined3d_cs_set_stream_source
173 enum wined3d_cs_op opcode;
174 UINT stream_idx;
175 struct wined3d_buffer *buffer;
176 UINT offset;
177 UINT stride;
180 struct wined3d_cs_set_stream_source_freq
182 enum wined3d_cs_op opcode;
183 UINT stream_idx;
184 UINT frequency;
185 UINT flags;
188 struct wined3d_cs_set_stream_output
190 enum wined3d_cs_op opcode;
191 UINT stream_idx;
192 struct wined3d_buffer *buffer;
193 UINT offset;
196 struct wined3d_cs_set_index_buffer
198 enum wined3d_cs_op opcode;
199 struct wined3d_buffer *buffer;
200 enum wined3d_format_id format_id;
201 unsigned int offset;
204 struct wined3d_cs_set_constant_buffer
206 enum wined3d_cs_op opcode;
207 enum wined3d_shader_type type;
208 UINT cb_idx;
209 struct wined3d_buffer *buffer;
212 struct wined3d_cs_set_texture
214 enum wined3d_cs_op opcode;
215 UINT stage;
216 struct wined3d_texture *texture;
219 struct wined3d_cs_set_color_key
221 enum wined3d_cs_op opcode;
222 struct wined3d_texture *texture;
223 WORD flags;
224 WORD set;
225 struct wined3d_color_key color_key;
228 struct wined3d_cs_set_shader_resource_view
230 enum wined3d_cs_op opcode;
231 enum wined3d_shader_type type;
232 UINT view_idx;
233 struct wined3d_shader_resource_view *view;
236 struct wined3d_cs_set_unordered_access_view
238 enum wined3d_cs_op opcode;
239 enum wined3d_pipeline pipeline;
240 unsigned int view_idx;
241 struct wined3d_unordered_access_view *view;
242 unsigned int initial_count;
245 struct wined3d_cs_set_sampler
247 enum wined3d_cs_op opcode;
248 enum wined3d_shader_type type;
249 UINT sampler_idx;
250 struct wined3d_sampler *sampler;
253 struct wined3d_cs_set_shader
255 enum wined3d_cs_op opcode;
256 enum wined3d_shader_type type;
257 struct wined3d_shader *shader;
260 struct wined3d_cs_set_blend_state
262 enum wined3d_cs_op opcode;
263 struct wined3d_blend_state *state;
266 struct wined3d_cs_set_rasterizer_state
268 enum wined3d_cs_op opcode;
269 struct wined3d_rasterizer_state *state;
272 struct wined3d_cs_set_render_state
274 enum wined3d_cs_op opcode;
275 enum wined3d_render_state state;
276 DWORD value;
279 struct wined3d_cs_set_texture_state
281 enum wined3d_cs_op opcode;
282 UINT stage;
283 enum wined3d_texture_stage_state state;
284 DWORD value;
287 struct wined3d_cs_set_sampler_state
289 enum wined3d_cs_op opcode;
290 UINT sampler_idx;
291 enum wined3d_sampler_state state;
292 DWORD value;
295 struct wined3d_cs_set_transform
297 enum wined3d_cs_op opcode;
298 enum wined3d_transform_state state;
299 struct wined3d_matrix matrix;
302 struct wined3d_cs_set_clip_plane
304 enum wined3d_cs_op opcode;
305 UINT plane_idx;
306 struct wined3d_vec4 plane;
309 struct wined3d_cs_set_material
311 enum wined3d_cs_op opcode;
312 struct wined3d_material material;
315 struct wined3d_cs_set_light
317 enum wined3d_cs_op opcode;
318 struct wined3d_light_info light;
321 struct wined3d_cs_set_light_enable
323 enum wined3d_cs_op opcode;
324 unsigned int idx;
325 BOOL enable;
328 struct wined3d_cs_push_constants
330 enum wined3d_cs_op opcode;
331 enum wined3d_push_constants type;
332 unsigned int start_idx;
333 unsigned int count;
334 BYTE constants[1];
337 struct wined3d_cs_reset_state
339 enum wined3d_cs_op opcode;
342 struct wined3d_cs_callback
344 enum wined3d_cs_op opcode;
345 void (*callback)(void *object);
346 void *object;
349 struct wined3d_cs_query_issue
351 enum wined3d_cs_op opcode;
352 struct wined3d_query *query;
353 DWORD flags;
356 struct wined3d_cs_preload_resource
358 enum wined3d_cs_op opcode;
359 struct wined3d_resource *resource;
362 struct wined3d_cs_unload_resource
364 enum wined3d_cs_op opcode;
365 struct wined3d_resource *resource;
368 struct wined3d_cs_map
370 enum wined3d_cs_op opcode;
371 struct wined3d_resource *resource;
372 unsigned int sub_resource_idx;
373 struct wined3d_map_desc *map_desc;
374 const struct wined3d_box *box;
375 DWORD flags;
376 HRESULT *hr;
379 struct wined3d_cs_unmap
381 enum wined3d_cs_op opcode;
382 struct wined3d_resource *resource;
383 unsigned int sub_resource_idx;
384 HRESULT *hr;
387 struct wined3d_cs_blt_sub_resource
389 enum wined3d_cs_op opcode;
390 struct wined3d_resource *dst_resource;
391 unsigned int dst_sub_resource_idx;
392 struct wined3d_box dst_box;
393 struct wined3d_resource *src_resource;
394 unsigned int src_sub_resource_idx;
395 struct wined3d_box src_box;
396 DWORD flags;
397 struct wined3d_blt_fx fx;
398 enum wined3d_texture_filter_type filter;
401 struct wined3d_cs_update_sub_resource
403 enum wined3d_cs_op opcode;
404 struct wined3d_resource *resource;
405 unsigned int sub_resource_idx;
406 struct wined3d_box box;
407 struct wined3d_sub_resource_data data;
410 struct wined3d_cs_add_dirty_texture_region
412 enum wined3d_cs_op opcode;
413 struct wined3d_texture *texture;
414 unsigned int layer;
417 struct wined3d_cs_clear_unordered_access_view
419 enum wined3d_cs_op opcode;
420 struct wined3d_unordered_access_view *view;
421 struct wined3d_uvec4 clear_value;
424 struct wined3d_cs_copy_uav_counter
426 enum wined3d_cs_op opcode;
427 struct wined3d_buffer *buffer;
428 unsigned int offset;
429 struct wined3d_unordered_access_view *view;
432 struct wined3d_cs_generate_mipmaps
434 enum wined3d_cs_op opcode;
435 struct wined3d_shader_resource_view *view;
438 struct wined3d_cs_stop
440 enum wined3d_cs_op opcode;
443 static void wined3d_cs_exec_nop(struct wined3d_cs *cs, const void *data)
447 static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data)
449 const struct wined3d_cs_present *op = data;
450 struct wined3d_swapchain *swapchain;
451 unsigned int i;
453 swapchain = op->swapchain;
454 wined3d_swapchain_set_window(swapchain, op->dst_window_override);
456 swapchain->swapchain_ops->swapchain_present(swapchain, &op->src_rect, &op->dst_rect, op->flags);
458 wined3d_resource_release(&swapchain->front_buffer->resource);
459 for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
461 wined3d_resource_release(&swapchain->back_buffers[i]->resource);
464 InterlockedDecrement(&cs->pending_presents);
467 void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain,
468 const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, DWORD flags)
470 struct wined3d_cs_present *op;
471 unsigned int i;
472 LONG pending;
474 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
475 op->opcode = WINED3D_CS_OP_PRESENT;
476 op->dst_window_override = dst_window_override;
477 op->swapchain = swapchain;
478 op->src_rect = *src_rect;
479 op->dst_rect = *dst_rect;
480 op->flags = flags;
482 pending = InterlockedIncrement(&cs->pending_presents);
484 wined3d_resource_acquire(&swapchain->front_buffer->resource);
485 for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
487 wined3d_resource_acquire(&swapchain->back_buffers[i]->resource);
490 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
492 /* Limit input latency by limiting the number of presents that we can get
493 * ahead of the worker thread. We have a constant limit here, but
494 * IDXGIDevice1 allows tuning this. */
495 while (pending > 1)
497 wined3d_pause();
498 pending = InterlockedCompareExchange(&cs->pending_presents, 0, 0);
502 static void wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
504 const struct wined3d_cs_clear *op = data;
505 struct wined3d_device *device;
506 unsigned int i;
508 device = cs->device;
509 device->blitter->ops->blitter_clear(device->blitter, device, op->rt_count, op->fb,
510 op->rect_count, op->rects, &op->draw_rect, op->flags, &op->color, op->depth, op->stencil);
512 if (op->flags & WINED3DCLEAR_TARGET)
514 for (i = 0; i < op->rt_count; ++i)
516 if (op->fb->render_targets[i])
517 wined3d_resource_release(op->fb->render_targets[i]->resource);
520 if (op->flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
521 wined3d_resource_release(op->fb->depth_stencil->resource);
524 void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects,
525 DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
527 unsigned int rt_count = cs->device->adapter->gl_info.limits.buffers;
528 const struct wined3d_state *state = &cs->device->state;
529 const struct wined3d_viewport *vp = &state->viewport;
530 struct wined3d_cs_clear *op;
531 unsigned int i;
533 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_clear, rects[rect_count]),
534 WINED3D_CS_QUEUE_DEFAULT);
535 op->opcode = WINED3D_CS_OP_CLEAR;
536 op->flags = flags;
537 op->rt_count = rt_count;
538 op->fb = &cs->fb;
539 SetRect(&op->draw_rect, vp->x, vp->y, vp->x + vp->width, vp->y + vp->height);
540 if (state->render_states[WINED3D_RS_SCISSORTESTENABLE])
541 IntersectRect(&op->draw_rect, &op->draw_rect, &state->scissor_rect);
542 op->color = *color;
543 op->depth = depth;
544 op->stencil = stencil;
545 op->rect_count = rect_count;
546 memcpy(op->rects, rects, sizeof(*rects) * rect_count);
548 if (flags & WINED3DCLEAR_TARGET)
550 for (i = 0; i < rt_count; ++i)
552 if (state->fb->render_targets[i])
553 wined3d_resource_acquire(state->fb->render_targets[i]->resource);
556 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
557 wined3d_resource_acquire(state->fb->depth_stencil->resource);
559 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
562 void wined3d_cs_emit_clear_rendertarget_view(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view,
563 const RECT *rect, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
565 struct wined3d_cs_clear *op;
566 struct
568 struct wined3d_rendertarget_view *rt;
569 struct wined3d_fb_state fb;
570 } *extra;
572 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_clear, rects[1]) + sizeof(*extra),
573 WINED3D_CS_QUEUE_DEFAULT);
574 extra = (void *)&op->rects[1];
575 extra->fb.render_targets = &extra->rt;
576 op->fb = &extra->fb;
578 op->opcode = WINED3D_CS_OP_CLEAR;
579 op->flags = flags;
580 if (flags & WINED3DCLEAR_TARGET)
582 op->rt_count = 1;
583 op->fb->render_targets[0] = view;
584 op->fb->depth_stencil = NULL;
585 op->color = *color;
587 else
589 op->rt_count = 0;
590 op->fb->render_targets[0] = NULL;
591 op->fb->depth_stencil = view;
592 op->depth = depth;
593 op->stencil = stencil;
595 SetRect(&op->draw_rect, 0, 0, view->width, view->height);
596 op->rect_count = 1;
597 op->rects[0] = *rect;
599 wined3d_resource_acquire(view->resource);
601 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
604 static void acquire_shader_resources(const struct wined3d_state *state, unsigned int shader_mask)
606 struct wined3d_shader_sampler_map_entry *entry;
607 struct wined3d_shader_resource_view *view;
608 struct wined3d_shader *shader;
609 unsigned int i, j;
611 for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
613 if (!(shader_mask & (1u << i)))
614 continue;
616 if (!(shader = state->shader[i]))
617 continue;
619 for (j = 0; j < WINED3D_MAX_CBS; ++j)
621 if (state->cb[i][j])
622 wined3d_resource_acquire(&state->cb[i][j]->resource);
625 for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
627 entry = &shader->reg_maps.sampler_map.entries[j];
629 if (!(view = state->shader_resource_view[i][entry->resource_idx]))
630 continue;
632 wined3d_resource_acquire(view->resource);
637 static void release_shader_resources(const struct wined3d_state *state, unsigned int shader_mask)
639 struct wined3d_shader_sampler_map_entry *entry;
640 struct wined3d_shader_resource_view *view;
641 struct wined3d_shader *shader;
642 unsigned int i, j;
644 for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
646 if (!(shader_mask & (1u << i)))
647 continue;
649 if (!(shader = state->shader[i]))
650 continue;
652 for (j = 0; j < WINED3D_MAX_CBS; ++j)
654 if (state->cb[i][j])
655 wined3d_resource_release(&state->cb[i][j]->resource);
658 for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
660 entry = &shader->reg_maps.sampler_map.entries[j];
662 if (!(view = state->shader_resource_view[i][entry->resource_idx]))
663 continue;
665 wined3d_resource_release(view->resource);
670 static void acquire_unordered_access_resources(const struct wined3d_shader *shader,
671 struct wined3d_unordered_access_view * const *views)
673 unsigned int i;
675 if (!shader)
676 return;
678 for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
680 if (!shader->reg_maps.uav_resource_info[i].type)
681 continue;
683 if (!views[i])
684 continue;
686 wined3d_resource_acquire(views[i]->resource);
690 static void release_unordered_access_resources(const struct wined3d_shader *shader,
691 struct wined3d_unordered_access_view * const *views)
693 unsigned int i;
695 if (!shader)
696 return;
698 for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
700 if (!shader->reg_maps.uav_resource_info[i].type)
701 continue;
703 if (!views[i])
704 continue;
706 wined3d_resource_release(views[i]->resource);
710 static void wined3d_cs_exec_dispatch(struct wined3d_cs *cs, const void *data)
712 const struct wined3d_cs_dispatch *op = data;
713 struct wined3d_state *state = &cs->state;
715 dispatch_compute(cs->device, state, &op->parameters);
717 if (op->parameters.indirect)
718 wined3d_resource_release(&op->parameters.u.indirect.buffer->resource);
720 release_shader_resources(state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
721 release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_COMPUTE],
722 state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
725 static void acquire_compute_pipeline_resources(const struct wined3d_state *state)
727 acquire_shader_resources(state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
728 acquire_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_COMPUTE],
729 state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
732 void wined3d_cs_emit_dispatch(struct wined3d_cs *cs,
733 unsigned int group_count_x, unsigned int group_count_y, unsigned int group_count_z)
735 const struct wined3d_state *state = &cs->device->state;
736 struct wined3d_cs_dispatch *op;
738 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
739 op->opcode = WINED3D_CS_OP_DISPATCH;
740 op->parameters.indirect = FALSE;
741 op->parameters.u.direct.group_count_x = group_count_x;
742 op->parameters.u.direct.group_count_y = group_count_y;
743 op->parameters.u.direct.group_count_z = group_count_z;
745 acquire_compute_pipeline_resources(state);
747 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
750 void wined3d_cs_emit_dispatch_indirect(struct wined3d_cs *cs,
751 struct wined3d_buffer *buffer, unsigned int offset)
753 const struct wined3d_state *state = &cs->device->state;
754 struct wined3d_cs_dispatch *op;
756 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
757 op->opcode = WINED3D_CS_OP_DISPATCH;
758 op->parameters.indirect = TRUE;
759 op->parameters.u.indirect.buffer = buffer;
760 op->parameters.u.indirect.offset = offset;
762 acquire_compute_pipeline_resources(state);
763 wined3d_resource_acquire(&buffer->resource);
765 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
768 static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
770 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
771 struct wined3d_state *state = &cs->state;
772 const struct wined3d_cs_draw *op = data;
773 int load_base_vertex_idx;
774 unsigned int i;
776 /* ARB_draw_indirect always supports a base vertex offset. */
777 if (!op->parameters.indirect && !gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
778 load_base_vertex_idx = op->parameters.u.direct.base_vertex_idx;
779 else
780 load_base_vertex_idx = 0;
782 if (state->load_base_vertex_index != load_base_vertex_idx)
784 state->load_base_vertex_index = load_base_vertex_idx;
785 device_invalidate_state(cs->device, STATE_BASEVERTEXINDEX);
788 if (state->gl_primitive_type != op->primitive_type)
790 if (state->gl_primitive_type == GL_POINTS || op->primitive_type == GL_POINTS)
791 device_invalidate_state(cs->device, STATE_POINT_ENABLE);
792 state->gl_primitive_type = op->primitive_type;
794 state->gl_patch_vertices = op->patch_vertex_count;
796 draw_primitive(cs->device, state, &op->parameters);
798 if (op->parameters.indirect)
800 struct wined3d_buffer *buffer = op->parameters.u.indirect.buffer;
801 wined3d_resource_release(&buffer->resource);
804 if (op->parameters.indexed)
805 wined3d_resource_release(&state->index_buffer->resource);
806 for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
808 if (state->streams[i].buffer)
809 wined3d_resource_release(&state->streams[i].buffer->resource);
811 for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
813 if (state->stream_output[i].buffer)
814 wined3d_resource_release(&state->stream_output[i].buffer->resource);
816 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
818 if (state->textures[i])
819 wined3d_resource_release(&state->textures[i]->resource);
821 for (i = 0; i < gl_info->limits.buffers; ++i)
823 if (state->fb->render_targets[i])
824 wined3d_resource_release(state->fb->render_targets[i]->resource);
826 if (state->fb->depth_stencil)
827 wined3d_resource_release(state->fb->depth_stencil->resource);
828 release_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
829 release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL],
830 state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
833 static void acquire_graphics_pipeline_resources(const struct wined3d_state *state,
834 BOOL indexed, const struct wined3d_gl_info *gl_info)
836 unsigned int i;
838 if (indexed)
839 wined3d_resource_acquire(&state->index_buffer->resource);
840 for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
842 if (state->streams[i].buffer)
843 wined3d_resource_acquire(&state->streams[i].buffer->resource);
845 for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
847 if (state->stream_output[i].buffer)
848 wined3d_resource_acquire(&state->stream_output[i].buffer->resource);
850 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
852 if (state->textures[i])
853 wined3d_resource_acquire(&state->textures[i]->resource);
855 for (i = 0; i < gl_info->limits.buffers; ++i)
857 if (state->fb->render_targets[i])
858 wined3d_resource_acquire(state->fb->render_targets[i]->resource);
860 if (state->fb->depth_stencil)
861 wined3d_resource_acquire(state->fb->depth_stencil->resource);
862 acquire_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
863 acquire_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL],
864 state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
867 void wined3d_cs_emit_draw(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
868 int base_vertex_idx, unsigned int start_idx, unsigned int index_count,
869 unsigned int start_instance, unsigned int instance_count, BOOL indexed)
871 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
872 const struct wined3d_state *state = &cs->device->state;
873 struct wined3d_cs_draw *op;
875 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
876 op->opcode = WINED3D_CS_OP_DRAW;
877 op->primitive_type = primitive_type;
878 op->patch_vertex_count = patch_vertex_count;
879 op->parameters.indirect = FALSE;
880 op->parameters.u.direct.base_vertex_idx = base_vertex_idx;
881 op->parameters.u.direct.start_idx = start_idx;
882 op->parameters.u.direct.index_count = index_count;
883 op->parameters.u.direct.start_instance = start_instance;
884 op->parameters.u.direct.instance_count = instance_count;
885 op->parameters.indexed = indexed;
887 acquire_graphics_pipeline_resources(state, indexed, gl_info);
889 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
892 void wined3d_cs_emit_draw_indirect(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
893 struct wined3d_buffer *buffer, unsigned int offset, BOOL indexed)
895 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
896 const struct wined3d_state *state = &cs->device->state;
897 struct wined3d_cs_draw *op;
899 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
900 op->opcode = WINED3D_CS_OP_DRAW;
901 op->primitive_type = primitive_type;
902 op->patch_vertex_count = patch_vertex_count;
903 op->parameters.indirect = TRUE;
904 op->parameters.u.indirect.buffer = buffer;
905 op->parameters.u.indirect.offset = offset;
906 op->parameters.indexed = indexed;
908 acquire_graphics_pipeline_resources(state, indexed, gl_info);
909 wined3d_resource_acquire(&buffer->resource);
911 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
914 static void wined3d_cs_exec_flush(struct wined3d_cs *cs, const void *data)
916 struct wined3d_context *context;
918 context = context_acquire(cs->device, NULL, 0);
919 if (context->valid)
920 context->gl_info->gl_ops.gl.p_glFlush();
921 context_release(context);
924 void wined3d_cs_emit_flush(struct wined3d_cs *cs)
926 struct wined3d_cs_flush *op;
928 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
929 op->opcode = WINED3D_CS_OP_FLUSH;
931 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
932 cs->queries_flushed = TRUE;
935 static void wined3d_cs_exec_set_predication(struct wined3d_cs *cs, const void *data)
937 const struct wined3d_cs_set_predication *op = data;
939 cs->state.predicate = op->predicate;
940 cs->state.predicate_value = op->value;
943 void wined3d_cs_emit_set_predication(struct wined3d_cs *cs, struct wined3d_query *predicate, BOOL value)
945 struct wined3d_cs_set_predication *op;
947 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
948 op->opcode = WINED3D_CS_OP_SET_PREDICATION;
949 op->predicate = predicate;
950 op->value = value;
952 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
955 static void wined3d_cs_exec_set_viewport(struct wined3d_cs *cs, const void *data)
957 const struct wined3d_cs_set_viewport *op = data;
959 cs->state.viewport = op->viewport;
960 device_invalidate_state(cs->device, STATE_VIEWPORT);
963 void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_viewport *viewport)
965 struct wined3d_cs_set_viewport *op;
967 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
968 op->opcode = WINED3D_CS_OP_SET_VIEWPORT;
969 op->viewport = *viewport;
971 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
974 static void wined3d_cs_exec_set_scissor_rect(struct wined3d_cs *cs, const void *data)
976 const struct wined3d_cs_set_scissor_rect *op = data;
978 cs->state.scissor_rect = op->rect;
979 device_invalidate_state(cs->device, STATE_SCISSORRECT);
982 void wined3d_cs_emit_set_scissor_rect(struct wined3d_cs *cs, const RECT *rect)
984 struct wined3d_cs_set_scissor_rect *op;
986 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
987 op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECT;
988 op->rect = *rect;
990 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
993 static void wined3d_cs_exec_set_rendertarget_view(struct wined3d_cs *cs, const void *data)
995 const struct wined3d_cs_set_rendertarget_view *op = data;
997 cs->state.fb->render_targets[op->view_idx] = op->view;
998 device_invalidate_state(cs->device, STATE_FRAMEBUFFER);
1001 void wined3d_cs_emit_set_rendertarget_view(struct wined3d_cs *cs, unsigned int view_idx,
1002 struct wined3d_rendertarget_view *view)
1004 struct wined3d_cs_set_rendertarget_view *op;
1006 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1007 op->opcode = WINED3D_CS_OP_SET_RENDERTARGET_VIEW;
1008 op->view_idx = view_idx;
1009 op->view = view;
1011 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1014 static void wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const void *data)
1016 const struct wined3d_cs_set_depth_stencil_view *op = data;
1017 struct wined3d_device *device = cs->device;
1018 struct wined3d_rendertarget_view *prev;
1020 if ((prev = cs->state.fb->depth_stencil))
1022 struct wined3d_surface *prev_surface = wined3d_rendertarget_view_get_surface(prev);
1024 if (prev_surface && (device->swapchains[0]->desc.flags & WINED3D_SWAPCHAIN_DISCARD_DEPTHSTENCIL
1025 || prev_surface->container->flags & WINED3D_TEXTURE_DISCARD))
1027 wined3d_texture_validate_location(prev_surface->container,
1028 prev->sub_resource_idx, WINED3D_LOCATION_DISCARDED);
1032 cs->fb.depth_stencil = op->view;
1034 if (!prev != !op->view)
1036 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
1037 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
1038 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
1039 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
1040 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
1042 else if (prev && prev->format->depth_bias_scale != op->view->format->depth_bias_scale)
1044 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
1047 device_invalidate_state(device, STATE_FRAMEBUFFER);
1050 void wined3d_cs_emit_set_depth_stencil_view(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view)
1052 struct wined3d_cs_set_depth_stencil_view *op;
1054 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1055 op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW;
1056 op->view = view;
1058 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1061 static void wined3d_cs_exec_set_vertex_declaration(struct wined3d_cs *cs, const void *data)
1063 const struct wined3d_cs_set_vertex_declaration *op = data;
1065 cs->state.vertex_declaration = op->declaration;
1066 device_invalidate_state(cs->device, STATE_VDECL);
1069 void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs, struct wined3d_vertex_declaration *declaration)
1071 struct wined3d_cs_set_vertex_declaration *op;
1073 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1074 op->opcode = WINED3D_CS_OP_SET_VERTEX_DECLARATION;
1075 op->declaration = declaration;
1077 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1080 static void wined3d_cs_exec_set_stream_source(struct wined3d_cs *cs, const void *data)
1082 const struct wined3d_cs_set_stream_source *op = data;
1083 struct wined3d_stream_state *stream;
1084 struct wined3d_buffer *prev;
1086 stream = &cs->state.streams[op->stream_idx];
1087 prev = stream->buffer;
1088 stream->buffer = op->buffer;
1089 stream->offset = op->offset;
1090 stream->stride = op->stride;
1092 if (op->buffer)
1093 InterlockedIncrement(&op->buffer->resource.bind_count);
1094 if (prev)
1095 InterlockedDecrement(&prev->resource.bind_count);
1097 device_invalidate_state(cs->device, STATE_STREAMSRC);
1100 void wined3d_cs_emit_set_stream_source(struct wined3d_cs *cs, UINT stream_idx,
1101 struct wined3d_buffer *buffer, UINT offset, UINT stride)
1103 struct wined3d_cs_set_stream_source *op;
1105 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1106 op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE;
1107 op->stream_idx = stream_idx;
1108 op->buffer = buffer;
1109 op->offset = offset;
1110 op->stride = stride;
1112 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1115 static void wined3d_cs_exec_set_stream_source_freq(struct wined3d_cs *cs, const void *data)
1117 const struct wined3d_cs_set_stream_source_freq *op = data;
1118 struct wined3d_stream_state *stream;
1120 stream = &cs->state.streams[op->stream_idx];
1121 stream->frequency = op->frequency;
1122 stream->flags = op->flags;
1124 device_invalidate_state(cs->device, STATE_STREAMSRC);
1127 void wined3d_cs_emit_set_stream_source_freq(struct wined3d_cs *cs, UINT stream_idx, UINT frequency, UINT flags)
1129 struct wined3d_cs_set_stream_source_freq *op;
1131 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1132 op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ;
1133 op->stream_idx = stream_idx;
1134 op->frequency = frequency;
1135 op->flags = flags;
1137 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1140 static void wined3d_cs_exec_set_stream_output(struct wined3d_cs *cs, const void *data)
1142 const struct wined3d_cs_set_stream_output *op = data;
1143 struct wined3d_stream_output *stream;
1144 struct wined3d_buffer *prev;
1146 stream = &cs->state.stream_output[op->stream_idx];
1147 prev = stream->buffer;
1148 stream->buffer = op->buffer;
1149 stream->offset = op->offset;
1151 if (op->buffer)
1152 InterlockedIncrement(&op->buffer->resource.bind_count);
1153 if (prev)
1154 InterlockedDecrement(&prev->resource.bind_count);
1156 device_invalidate_state(cs->device, STATE_STREAM_OUTPUT);
1159 void wined3d_cs_emit_set_stream_output(struct wined3d_cs *cs, UINT stream_idx,
1160 struct wined3d_buffer *buffer, UINT offset)
1162 struct wined3d_cs_set_stream_output *op;
1164 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1165 op->opcode = WINED3D_CS_OP_SET_STREAM_OUTPUT;
1166 op->stream_idx = stream_idx;
1167 op->buffer = buffer;
1168 op->offset = offset;
1170 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1173 static void wined3d_cs_exec_set_index_buffer(struct wined3d_cs *cs, const void *data)
1175 const struct wined3d_cs_set_index_buffer *op = data;
1176 struct wined3d_buffer *prev;
1178 prev = cs->state.index_buffer;
1179 cs->state.index_buffer = op->buffer;
1180 cs->state.index_format = op->format_id;
1181 cs->state.index_offset = op->offset;
1183 if (op->buffer)
1184 InterlockedIncrement(&op->buffer->resource.bind_count);
1185 if (prev)
1186 InterlockedDecrement(&prev->resource.bind_count);
1188 device_invalidate_state(cs->device, STATE_INDEXBUFFER);
1191 void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer,
1192 enum wined3d_format_id format_id, unsigned int offset)
1194 struct wined3d_cs_set_index_buffer *op;
1196 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1197 op->opcode = WINED3D_CS_OP_SET_INDEX_BUFFER;
1198 op->buffer = buffer;
1199 op->format_id = format_id;
1200 op->offset = offset;
1202 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1205 static void wined3d_cs_exec_set_constant_buffer(struct wined3d_cs *cs, const void *data)
1207 const struct wined3d_cs_set_constant_buffer *op = data;
1208 struct wined3d_buffer *prev;
1210 prev = cs->state.cb[op->type][op->cb_idx];
1211 cs->state.cb[op->type][op->cb_idx] = op->buffer;
1213 if (op->buffer)
1214 InterlockedIncrement(&op->buffer->resource.bind_count);
1215 if (prev)
1216 InterlockedDecrement(&prev->resource.bind_count);
1218 device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(op->type));
1221 void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_shader_type type,
1222 UINT cb_idx, struct wined3d_buffer *buffer)
1224 struct wined3d_cs_set_constant_buffer *op;
1226 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1227 op->opcode = WINED3D_CS_OP_SET_CONSTANT_BUFFER;
1228 op->type = type;
1229 op->cb_idx = cb_idx;
1230 op->buffer = buffer;
1232 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1235 static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data)
1237 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
1238 const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info;
1239 const struct wined3d_cs_set_texture *op = data;
1240 struct wined3d_texture *prev;
1241 BOOL old_use_color_key = FALSE, new_use_color_key = FALSE;
1243 prev = cs->state.textures[op->stage];
1244 cs->state.textures[op->stage] = op->texture;
1246 if (op->texture)
1248 const struct wined3d_format *new_format = op->texture->resource.format;
1249 const struct wined3d_format *old_format = prev ? prev->resource.format : NULL;
1250 unsigned int old_fmt_flags = prev ? prev->resource.format_flags : 0;
1251 unsigned int new_fmt_flags = op->texture->resource.format_flags;
1253 if (InterlockedIncrement(&op->texture->resource.bind_count) == 1)
1254 op->texture->sampler = op->stage;
1256 if (!prev || op->texture->target != prev->target
1257 || (!is_same_fixup(new_format->color_fixup, old_format->color_fixup)
1258 && !(can_use_texture_swizzle(gl_info, new_format) && can_use_texture_swizzle(gl_info, old_format)))
1259 || (new_fmt_flags & WINED3DFMT_FLAG_SHADOW) != (old_fmt_flags & WINED3DFMT_FLAG_SHADOW))
1260 device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
1262 if (!prev && op->stage < d3d_info->limits.ffp_blend_stages)
1264 /* The source arguments for color and alpha ops have different
1265 * meanings when a NULL texture is bound, so the COLOR_OP and
1266 * ALPHA_OP have to be dirtified. */
1267 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1268 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1271 if (!op->stage && op->texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1272 new_use_color_key = TRUE;
1275 if (prev)
1277 if (InterlockedDecrement(&prev->resource.bind_count) && prev->sampler == op->stage)
1279 unsigned int i;
1281 /* Search for other stages the texture is bound to. Shouldn't
1282 * happen if applications bind textures to a single stage only. */
1283 TRACE("Searching for other stages the texture is bound to.\n");
1284 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
1286 if (cs->state.textures[i] == prev)
1288 TRACE("Texture is also bound to stage %u.\n", i);
1289 prev->sampler = i;
1290 break;
1295 if (!op->texture && op->stage < d3d_info->limits.ffp_blend_stages)
1297 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1298 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1301 if (!op->stage && prev->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1302 old_use_color_key = TRUE;
1305 device_invalidate_state(cs->device, STATE_SAMPLER(op->stage));
1307 if (new_use_color_key != old_use_color_key)
1308 device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1310 if (new_use_color_key)
1311 device_invalidate_state(cs->device, STATE_COLOR_KEY);
1314 void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined3d_texture *texture)
1316 struct wined3d_cs_set_texture *op;
1318 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1319 op->opcode = WINED3D_CS_OP_SET_TEXTURE;
1320 op->stage = stage;
1321 op->texture = texture;
1323 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1326 static void wined3d_cs_exec_set_shader_resource_view(struct wined3d_cs *cs, const void *data)
1328 const struct wined3d_cs_set_shader_resource_view *op = data;
1329 struct wined3d_shader_resource_view *prev;
1331 prev = cs->state.shader_resource_view[op->type][op->view_idx];
1332 cs->state.shader_resource_view[op->type][op->view_idx] = op->view;
1334 if (op->view)
1335 InterlockedIncrement(&op->view->resource->bind_count);
1336 if (prev)
1337 InterlockedDecrement(&prev->resource->bind_count);
1339 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1340 device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1341 else
1342 device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1345 void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3d_shader_type type,
1346 UINT view_idx, struct wined3d_shader_resource_view *view)
1348 struct wined3d_cs_set_shader_resource_view *op;
1350 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1351 op->opcode = WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW;
1352 op->type = type;
1353 op->view_idx = view_idx;
1354 op->view = view;
1356 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1359 static void wined3d_cs_exec_set_unordered_access_view(struct wined3d_cs *cs, const void *data)
1361 const struct wined3d_cs_set_unordered_access_view *op = data;
1362 struct wined3d_unordered_access_view *prev;
1364 prev = cs->state.unordered_access_view[op->pipeline][op->view_idx];
1365 cs->state.unordered_access_view[op->pipeline][op->view_idx] = op->view;
1367 if (op->view)
1368 InterlockedIncrement(&op->view->resource->bind_count);
1369 if (prev)
1370 InterlockedDecrement(&prev->resource->bind_count);
1372 if (op->view && op->initial_count != ~0u)
1373 wined3d_unordered_access_view_set_counter(op->view, op->initial_count);
1375 device_invalidate_state(cs->device, STATE_UNORDERED_ACCESS_VIEW_BINDING(op->pipeline));
1378 void wined3d_cs_emit_set_unordered_access_view(struct wined3d_cs *cs, enum wined3d_pipeline pipeline,
1379 unsigned int view_idx, struct wined3d_unordered_access_view *view, unsigned int initial_count)
1381 struct wined3d_cs_set_unordered_access_view *op;
1383 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1384 op->opcode = WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW;
1385 op->pipeline = pipeline;
1386 op->view_idx = view_idx;
1387 op->view = view;
1388 op->initial_count = initial_count;
1390 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1393 static void wined3d_cs_exec_set_sampler(struct wined3d_cs *cs, const void *data)
1395 const struct wined3d_cs_set_sampler *op = data;
1397 cs->state.sampler[op->type][op->sampler_idx] = op->sampler;
1398 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1399 device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1400 else
1401 device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1404 void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type,
1405 UINT sampler_idx, struct wined3d_sampler *sampler)
1407 struct wined3d_cs_set_sampler *op;
1409 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1410 op->opcode = WINED3D_CS_OP_SET_SAMPLER;
1411 op->type = type;
1412 op->sampler_idx = sampler_idx;
1413 op->sampler = sampler;
1415 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1418 static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
1420 const struct wined3d_cs_set_shader *op = data;
1422 cs->state.shader[op->type] = op->shader;
1423 device_invalidate_state(cs->device, STATE_SHADER(op->type));
1424 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1425 device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1426 else
1427 device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1430 void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader)
1432 struct wined3d_cs_set_shader *op;
1434 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1435 op->opcode = WINED3D_CS_OP_SET_SHADER;
1436 op->type = type;
1437 op->shader = shader;
1439 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1442 static void wined3d_cs_exec_set_blend_state(struct wined3d_cs *cs, const void *data)
1444 const struct wined3d_cs_set_blend_state *op = data;
1446 cs->state.blend_state = op->state;
1447 device_invalidate_state(cs->device, STATE_BLEND);
1450 void wined3d_cs_emit_set_blend_state(struct wined3d_cs *cs, struct wined3d_blend_state *state)
1452 struct wined3d_cs_set_blend_state *op;
1454 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1455 op->opcode = WINED3D_CS_OP_SET_BLEND_STATE;
1456 op->state = state;
1458 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1461 static void wined3d_cs_exec_set_rasterizer_state(struct wined3d_cs *cs, const void *data)
1463 const struct wined3d_cs_set_rasterizer_state *op = data;
1465 cs->state.rasterizer_state = op->state;
1466 device_invalidate_state(cs->device, STATE_FRONTFACE);
1469 void wined3d_cs_emit_set_rasterizer_state(struct wined3d_cs *cs,
1470 struct wined3d_rasterizer_state *rasterizer_state)
1472 struct wined3d_cs_set_rasterizer_state *op;
1474 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1475 op->opcode = WINED3D_CS_OP_SET_RASTERIZER_STATE;
1476 op->state = rasterizer_state;
1478 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1481 static void wined3d_cs_exec_set_render_state(struct wined3d_cs *cs, const void *data)
1483 const struct wined3d_cs_set_render_state *op = data;
1485 cs->state.render_states[op->state] = op->value;
1486 device_invalidate_state(cs->device, STATE_RENDER(op->state));
1489 void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render_state state, DWORD value)
1491 struct wined3d_cs_set_render_state *op;
1493 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1494 op->opcode = WINED3D_CS_OP_SET_RENDER_STATE;
1495 op->state = state;
1496 op->value = value;
1498 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1501 static void wined3d_cs_exec_set_texture_state(struct wined3d_cs *cs, const void *data)
1503 const struct wined3d_cs_set_texture_state *op = data;
1505 cs->state.texture_states[op->stage][op->state] = op->value;
1506 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, op->state));
1509 void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage,
1510 enum wined3d_texture_stage_state state, DWORD value)
1512 struct wined3d_cs_set_texture_state *op;
1514 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1515 op->opcode = WINED3D_CS_OP_SET_TEXTURE_STATE;
1516 op->stage = stage;
1517 op->state = state;
1518 op->value = value;
1520 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1523 static void wined3d_cs_exec_set_sampler_state(struct wined3d_cs *cs, const void *data)
1525 const struct wined3d_cs_set_sampler_state *op = data;
1527 cs->state.sampler_states[op->sampler_idx][op->state] = op->value;
1528 device_invalidate_state(cs->device, STATE_SAMPLER(op->sampler_idx));
1531 void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx,
1532 enum wined3d_sampler_state state, DWORD value)
1534 struct wined3d_cs_set_sampler_state *op;
1536 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1537 op->opcode = WINED3D_CS_OP_SET_SAMPLER_STATE;
1538 op->sampler_idx = sampler_idx;
1539 op->state = state;
1540 op->value = value;
1542 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1545 static void wined3d_cs_exec_set_transform(struct wined3d_cs *cs, const void *data)
1547 const struct wined3d_cs_set_transform *op = data;
1549 cs->state.transforms[op->state] = op->matrix;
1550 if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->d3d_info.limits.ffp_vertex_blend_matrices))
1551 device_invalidate_state(cs->device, STATE_TRANSFORM(op->state));
1554 void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform_state state,
1555 const struct wined3d_matrix *matrix)
1557 struct wined3d_cs_set_transform *op;
1559 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1560 op->opcode = WINED3D_CS_OP_SET_TRANSFORM;
1561 op->state = state;
1562 op->matrix = *matrix;
1564 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1567 static void wined3d_cs_exec_set_clip_plane(struct wined3d_cs *cs, const void *data)
1569 const struct wined3d_cs_set_clip_plane *op = data;
1571 cs->state.clip_planes[op->plane_idx] = op->plane;
1572 device_invalidate_state(cs->device, STATE_CLIPPLANE(op->plane_idx));
1575 void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const struct wined3d_vec4 *plane)
1577 struct wined3d_cs_set_clip_plane *op;
1579 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1580 op->opcode = WINED3D_CS_OP_SET_CLIP_PLANE;
1581 op->plane_idx = plane_idx;
1582 op->plane = *plane;
1584 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1587 static void wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *data)
1589 const struct wined3d_cs_set_color_key *op = data;
1590 struct wined3d_texture *texture = op->texture;
1592 if (op->set)
1594 switch (op->flags)
1596 case WINED3D_CKEY_DST_BLT:
1597 texture->async.dst_blt_color_key = op->color_key;
1598 texture->async.color_key_flags |= WINED3D_CKEY_DST_BLT;
1599 break;
1601 case WINED3D_CKEY_DST_OVERLAY:
1602 texture->async.dst_overlay_color_key = op->color_key;
1603 texture->async.color_key_flags |= WINED3D_CKEY_DST_OVERLAY;
1604 break;
1606 case WINED3D_CKEY_SRC_BLT:
1607 if (texture == cs->state.textures[0])
1609 device_invalidate_state(cs->device, STATE_COLOR_KEY);
1610 if (!(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT))
1611 device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1614 texture->async.src_blt_color_key = op->color_key;
1615 texture->async.color_key_flags |= WINED3D_CKEY_SRC_BLT;
1616 break;
1618 case WINED3D_CKEY_SRC_OVERLAY:
1619 texture->async.src_overlay_color_key = op->color_key;
1620 texture->async.color_key_flags |= WINED3D_CKEY_SRC_OVERLAY;
1621 break;
1624 else
1626 switch (op->flags)
1628 case WINED3D_CKEY_DST_BLT:
1629 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_BLT;
1630 break;
1632 case WINED3D_CKEY_DST_OVERLAY:
1633 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_OVERLAY;
1634 break;
1636 case WINED3D_CKEY_SRC_BLT:
1637 if (texture == cs->state.textures[0] && texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1638 device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1640 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_BLT;
1641 break;
1643 case WINED3D_CKEY_SRC_OVERLAY:
1644 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_OVERLAY;
1645 break;
1650 void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture *texture,
1651 WORD flags, const struct wined3d_color_key *color_key)
1653 struct wined3d_cs_set_color_key *op;
1655 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1656 op->opcode = WINED3D_CS_OP_SET_COLOR_KEY;
1657 op->texture = texture;
1658 op->flags = flags;
1659 if (color_key)
1661 op->color_key = *color_key;
1662 op->set = 1;
1664 else
1665 op->set = 0;
1667 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1670 static void wined3d_cs_exec_set_material(struct wined3d_cs *cs, const void *data)
1672 const struct wined3d_cs_set_material *op = data;
1674 cs->state.material = op->material;
1675 device_invalidate_state(cs->device, STATE_MATERIAL);
1678 void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_material *material)
1680 struct wined3d_cs_set_material *op;
1682 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1683 op->opcode = WINED3D_CS_OP_SET_MATERIAL;
1684 op->material = *material;
1686 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1689 static void wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data)
1691 const struct wined3d_cs_set_light *op = data;
1692 struct wined3d_light_info *light_info;
1693 unsigned int light_idx, hash_idx;
1695 light_idx = op->light.OriginalIndex;
1697 if (!(light_info = wined3d_state_get_light(&cs->state, light_idx)))
1699 TRACE("Adding new light.\n");
1700 if (!(light_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*light_info))))
1702 ERR("Failed to allocate light info.\n");
1703 return;
1706 hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1707 list_add_head(&cs->state.light_map[hash_idx], &light_info->entry);
1708 light_info->glIndex = -1;
1709 light_info->OriginalIndex = light_idx;
1712 if (light_info->glIndex != -1)
1714 if (light_info->OriginalParms.type != op->light.OriginalParms.type)
1715 device_invalidate_state(cs->device, STATE_LIGHT_TYPE);
1716 device_invalidate_state(cs->device, STATE_ACTIVELIGHT(light_info->glIndex));
1719 light_info->OriginalParms = op->light.OriginalParms;
1720 light_info->position = op->light.position;
1721 light_info->direction = op->light.direction;
1722 light_info->exponent = op->light.exponent;
1723 light_info->cutoff = op->light.cutoff;
1726 void wined3d_cs_emit_set_light(struct wined3d_cs *cs, const struct wined3d_light_info *light)
1728 struct wined3d_cs_set_light *op;
1730 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1731 op->opcode = WINED3D_CS_OP_SET_LIGHT;
1732 op->light = *light;
1734 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1737 static void wined3d_cs_exec_set_light_enable(struct wined3d_cs *cs, const void *data)
1739 const struct wined3d_cs_set_light_enable *op = data;
1740 struct wined3d_device *device = cs->device;
1741 struct wined3d_light_info *light_info;
1742 int prev_idx;
1744 if (!(light_info = wined3d_state_get_light(&cs->state, op->idx)))
1746 ERR("Light doesn't exist.\n");
1747 return;
1750 prev_idx = light_info->glIndex;
1751 wined3d_state_enable_light(&cs->state, &device->adapter->d3d_info, light_info, op->enable);
1752 if (light_info->glIndex != prev_idx)
1754 device_invalidate_state(device, STATE_LIGHT_TYPE);
1755 device_invalidate_state(device, STATE_ACTIVELIGHT(op->enable ? light_info->glIndex : prev_idx));
1759 void wined3d_cs_emit_set_light_enable(struct wined3d_cs *cs, unsigned int idx, BOOL enable)
1761 struct wined3d_cs_set_light_enable *op;
1763 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1764 op->opcode = WINED3D_CS_OP_SET_LIGHT_ENABLE;
1765 op->idx = idx;
1766 op->enable = enable;
1768 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1771 static const struct
1773 size_t offset;
1774 size_t size;
1775 DWORD mask;
1777 wined3d_cs_push_constant_info[] =
1779 /* WINED3D_PUSH_CONSTANTS_VS_F */
1780 {FIELD_OFFSET(struct wined3d_state, vs_consts_f), sizeof(struct wined3d_vec4), WINED3D_SHADER_CONST_VS_F},
1781 /* WINED3D_PUSH_CONSTANTS_PS_F */
1782 {FIELD_OFFSET(struct wined3d_state, ps_consts_f), sizeof(struct wined3d_vec4), WINED3D_SHADER_CONST_PS_F},
1783 /* WINED3D_PUSH_CONSTANTS_VS_I */
1784 {FIELD_OFFSET(struct wined3d_state, vs_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_VS_I},
1785 /* WINED3D_PUSH_CONSTANTS_PS_I */
1786 {FIELD_OFFSET(struct wined3d_state, ps_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_PS_I},
1787 /* WINED3D_PUSH_CONSTANTS_VS_B */
1788 {FIELD_OFFSET(struct wined3d_state, vs_consts_b), sizeof(BOOL), WINED3D_SHADER_CONST_VS_B},
1789 /* WINED3D_PUSH_CONSTANTS_PS_B */
1790 {FIELD_OFFSET(struct wined3d_state, ps_consts_b), sizeof(BOOL), WINED3D_SHADER_CONST_PS_B},
1793 static void wined3d_cs_st_push_constants(struct wined3d_cs *cs, enum wined3d_push_constants p,
1794 unsigned int start_idx, unsigned int count, const void *constants)
1796 struct wined3d_device *device = cs->device;
1797 unsigned int context_count;
1798 unsigned int i;
1799 size_t offset;
1801 if (p == WINED3D_PUSH_CONSTANTS_VS_F)
1802 device->shader_backend->shader_update_float_vertex_constants(device, start_idx, count);
1803 else if (p == WINED3D_PUSH_CONSTANTS_PS_F)
1804 device->shader_backend->shader_update_float_pixel_constants(device, start_idx, count);
1806 offset = wined3d_cs_push_constant_info[p].offset + start_idx * wined3d_cs_push_constant_info[p].size;
1807 memcpy((BYTE *)&cs->state + offset, constants, count * wined3d_cs_push_constant_info[p].size);
1808 for (i = 0, context_count = device->context_count; i < context_count; ++i)
1810 device->contexts[i]->constant_update_mask |= wined3d_cs_push_constant_info[p].mask;
1814 static void wined3d_cs_exec_push_constants(struct wined3d_cs *cs, const void *data)
1816 const struct wined3d_cs_push_constants *op = data;
1818 wined3d_cs_st_push_constants(cs, op->type, op->start_idx, op->count, op->constants);
1821 static void wined3d_cs_mt_push_constants(struct wined3d_cs *cs, enum wined3d_push_constants p,
1822 unsigned int start_idx, unsigned int count, const void *constants)
1824 struct wined3d_cs_push_constants *op;
1825 size_t size;
1827 size = count * wined3d_cs_push_constant_info[p].size;
1828 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_push_constants, constants[size]),
1829 WINED3D_CS_QUEUE_DEFAULT);
1830 op->opcode = WINED3D_CS_OP_PUSH_CONSTANTS;
1831 op->type = p;
1832 op->start_idx = start_idx;
1833 op->count = count;
1834 memcpy(op->constants, constants, size);
1836 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1839 static void wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data)
1841 struct wined3d_adapter *adapter = cs->device->adapter;
1843 state_cleanup(&cs->state);
1844 memset(&cs->state, 0, sizeof(cs->state));
1845 state_init(&cs->state, &cs->fb, &adapter->gl_info, &adapter->d3d_info,
1846 WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT);
1849 void wined3d_cs_emit_reset_state(struct wined3d_cs *cs)
1851 struct wined3d_cs_reset_state *op;
1853 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1854 op->opcode = WINED3D_CS_OP_RESET_STATE;
1856 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1859 static void wined3d_cs_exec_callback(struct wined3d_cs *cs, const void *data)
1861 const struct wined3d_cs_callback *op = data;
1863 op->callback(op->object);
1866 static void wined3d_cs_emit_callback(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1868 struct wined3d_cs_callback *op;
1870 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1871 op->opcode = WINED3D_CS_OP_CALLBACK;
1872 op->callback = callback;
1873 op->object = object;
1875 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1878 void wined3d_cs_destroy_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1880 wined3d_cs_emit_callback(cs, callback, object);
1883 void wined3d_cs_init_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1885 wined3d_cs_emit_callback(cs, callback, object);
1888 static void wined3d_cs_exec_query_issue(struct wined3d_cs *cs, const void *data)
1890 const struct wined3d_cs_query_issue *op = data;
1891 struct wined3d_query *query = op->query;
1892 BOOL poll;
1894 poll = query->query_ops->query_issue(query, op->flags);
1896 if (!cs->thread)
1897 return;
1899 if (poll && list_empty(&query->poll_list_entry))
1901 list_add_tail(&cs->query_poll_list, &query->poll_list_entry);
1902 return;
1905 /* This can happen if occlusion queries are restarted. This discards the
1906 * old result, since polling it could result in a GL error. */
1907 if ((op->flags & WINED3DISSUE_BEGIN) && !poll && !list_empty(&query->poll_list_entry))
1909 list_remove(&query->poll_list_entry);
1910 list_init(&query->poll_list_entry);
1911 InterlockedIncrement(&query->counter_retrieved);
1912 return;
1915 /* This can happen when an occlusion query is ended without being started,
1916 * in which case we don't want to poll, but still have to counter-balance
1917 * the increment of the main counter.
1919 * This can also happen if an event query is re-issued before the first
1920 * fence was reached. In this case the query is already in the list and
1921 * the poll function will check the new fence. We have to counter-balance
1922 * the discarded increment. */
1923 if (op->flags & WINED3DISSUE_END)
1924 InterlockedIncrement(&query->counter_retrieved);
1927 void wined3d_cs_emit_query_issue(struct wined3d_cs *cs, struct wined3d_query *query, DWORD flags)
1929 struct wined3d_cs_query_issue *op;
1931 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1932 op->opcode = WINED3D_CS_OP_QUERY_ISSUE;
1933 op->query = query;
1934 op->flags = flags;
1936 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1937 cs->queries_flushed = FALSE;
1940 static void wined3d_cs_exec_preload_resource(struct wined3d_cs *cs, const void *data)
1942 const struct wined3d_cs_preload_resource *op = data;
1943 struct wined3d_resource *resource = op->resource;
1945 resource->resource_ops->resource_preload(resource);
1946 wined3d_resource_release(resource);
1949 void wined3d_cs_emit_preload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
1951 struct wined3d_cs_preload_resource *op;
1953 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1954 op->opcode = WINED3D_CS_OP_PRELOAD_RESOURCE;
1955 op->resource = resource;
1957 wined3d_resource_acquire(resource);
1959 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1962 static void wined3d_cs_exec_unload_resource(struct wined3d_cs *cs, const void *data)
1964 const struct wined3d_cs_unload_resource *op = data;
1965 struct wined3d_resource *resource = op->resource;
1967 resource->resource_ops->resource_unload(resource);
1968 wined3d_resource_release(resource);
1971 void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
1973 struct wined3d_cs_unload_resource *op;
1975 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1976 op->opcode = WINED3D_CS_OP_UNLOAD_RESOURCE;
1977 op->resource = resource;
1979 wined3d_resource_acquire(resource);
1981 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1984 static void wined3d_cs_exec_map(struct wined3d_cs *cs, const void *data)
1986 const struct wined3d_cs_map *op = data;
1987 struct wined3d_resource *resource = op->resource;
1989 *op->hr = resource->resource_ops->resource_sub_resource_map(resource,
1990 op->sub_resource_idx, op->map_desc, op->box, op->flags);
1993 HRESULT wined3d_cs_map(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx,
1994 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, unsigned int flags)
1996 struct wined3d_cs_map *op;
1997 HRESULT hr;
1999 /* Mapping resources from the worker thread isn't an issue by itself, but
2000 * increasing the map count would be visible to applications. */
2001 wined3d_not_from_cs(cs);
2003 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2004 op->opcode = WINED3D_CS_OP_MAP;
2005 op->resource = resource;
2006 op->sub_resource_idx = sub_resource_idx;
2007 op->map_desc = map_desc;
2008 op->box = box;
2009 op->flags = flags;
2010 op->hr = &hr;
2012 cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2013 cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2015 return hr;
2018 static void wined3d_cs_exec_unmap(struct wined3d_cs *cs, const void *data)
2020 const struct wined3d_cs_unmap *op = data;
2021 struct wined3d_resource *resource = op->resource;
2023 *op->hr = resource->resource_ops->resource_sub_resource_unmap(resource, op->sub_resource_idx);
2026 HRESULT wined3d_cs_unmap(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx)
2028 struct wined3d_cs_unmap *op;
2029 HRESULT hr;
2031 wined3d_not_from_cs(cs);
2033 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2034 op->opcode = WINED3D_CS_OP_UNMAP;
2035 op->resource = resource;
2036 op->sub_resource_idx = sub_resource_idx;
2037 op->hr = &hr;
2039 cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2040 cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2042 return hr;
2045 static void wined3d_cs_exec_blt_sub_resource(struct wined3d_cs *cs, const void *data)
2047 const struct wined3d_cs_blt_sub_resource *op = data;
2049 if (op->dst_resource->type == WINED3D_RTYPE_BUFFER)
2051 wined3d_buffer_copy(buffer_from_resource(op->dst_resource), op->dst_box.left,
2052 buffer_from_resource(op->src_resource), op->src_box.left,
2053 op->src_box.right - op->src_box.left);
2055 else if (op->dst_resource->type == WINED3D_RTYPE_TEXTURE_2D)
2057 struct wined3d_surface *dst_surface, *src_surface;
2058 struct wined3d_texture *dst_texture, *src_texture;
2059 RECT dst_rect, src_rect;
2061 dst_texture = texture_from_resource(op->dst_resource);
2062 src_texture = texture_from_resource(op->src_resource);
2063 dst_surface = dst_texture->sub_resources[op->dst_sub_resource_idx].u.surface;
2064 src_surface = src_texture->sub_resources[op->src_sub_resource_idx].u.surface;
2065 SetRect(&dst_rect, op->dst_box.left, op->dst_box.top, op->dst_box.right, op->dst_box.bottom);
2066 SetRect(&src_rect, op->src_box.left, op->src_box.top, op->src_box.right, op->src_box.bottom);
2068 if (FAILED(wined3d_surface_blt(dst_surface, &dst_rect, src_surface,
2069 &src_rect, op->flags, &op->fx, op->filter)))
2070 FIXME("Blit failed.\n");
2072 else if (op->dst_resource->type == WINED3D_RTYPE_TEXTURE_3D)
2074 struct wined3d_texture *src_texture, *dst_texture;
2075 unsigned int level, update_w, update_h, update_d;
2076 unsigned int row_pitch, slice_pitch;
2077 struct wined3d_context *context;
2078 struct wined3d_bo_address addr;
2080 if (op->flags & ~WINED3D_BLT_RAW)
2082 FIXME("Flags %#x not implemented for %s resources.\n",
2083 op->flags, debug_d3dresourcetype(op->dst_resource->type));
2084 goto error;
2087 if (!(op->flags & WINED3D_BLT_RAW) && op->src_resource->format != op->dst_resource->format)
2089 FIXME("Format conversion not implemented for %s resources.\n",
2090 debug_d3dresourcetype(op->dst_resource->type));
2091 goto error;
2094 update_w = op->dst_box.right - op->dst_box.left;
2095 update_h = op->dst_box.bottom - op->dst_box.top;
2096 update_d = op->dst_box.back - op->dst_box.front;
2097 if (op->src_box.right - op->src_box.left != update_w
2098 || op->src_box.bottom - op->src_box.top != update_h
2099 || op->src_box.back - op->src_box.front != update_d)
2101 FIXME("Stretching not implemented for %s resources.\n",
2102 debug_d3dresourcetype(op->dst_resource->type));
2103 goto error;
2106 if (op->src_box.left || op->src_box.top || op->src_box.front)
2108 FIXME("Source box %s not supported for %s resources.\n",
2109 debug_box(&op->src_box), debug_d3dresourcetype(op->dst_resource->type));
2110 goto error;
2113 dst_texture = texture_from_resource(op->dst_resource);
2114 src_texture = texture_from_resource(op->src_resource);
2116 context = context_acquire(cs->device, NULL, 0);
2118 if (!wined3d_texture_load_location(src_texture, op->src_sub_resource_idx,
2119 context, src_texture->resource.map_binding))
2121 ERR("Failed to load source sub-resource into %s.\n",
2122 wined3d_debug_location(src_texture->resource.map_binding));
2123 context_release(context);
2124 goto error;
2127 level = op->dst_sub_resource_idx % dst_texture->level_count;
2128 if (update_w == wined3d_texture_get_level_width(dst_texture, level)
2129 && update_h == wined3d_texture_get_level_height(dst_texture, level)
2130 && update_d == wined3d_texture_get_level_depth(dst_texture, level))
2132 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
2134 else if (!wined3d_texture_load_location(dst_texture, op->dst_sub_resource_idx,
2135 context, WINED3D_LOCATION_TEXTURE_RGB))
2137 ERR("Failed to load destination sub-resource.\n");
2138 context_release(context);
2139 goto error;
2142 wined3d_texture_get_memory(src_texture, op->src_sub_resource_idx, &addr, src_texture->resource.map_binding);
2143 wined3d_texture_get_pitch(src_texture, op->src_sub_resource_idx % src_texture->level_count,
2144 &row_pitch, &slice_pitch);
2146 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
2147 wined3d_texture_upload_data(dst_texture, op->dst_sub_resource_idx, context, &op->dst_box,
2148 wined3d_const_bo_address(&addr), row_pitch, slice_pitch);
2149 wined3d_texture_validate_location(dst_texture, op->dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2150 wined3d_texture_invalidate_location(dst_texture, op->dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2152 context_release(context);
2154 else
2156 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(op->dst_resource->type));
2159 error:
2160 if (op->src_resource)
2161 wined3d_resource_release(op->src_resource);
2162 wined3d_resource_release(op->dst_resource);
2165 void wined3d_cs_emit_blt_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *dst_resource,
2166 unsigned int dst_sub_resource_idx, const struct wined3d_box *dst_box, struct wined3d_resource *src_resource,
2167 unsigned int src_sub_resource_idx, const struct wined3d_box *src_box, DWORD flags,
2168 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2170 struct wined3d_cs_blt_sub_resource *op;
2172 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2173 op->opcode = WINED3D_CS_OP_BLT_SUB_RESOURCE;
2174 op->dst_resource = dst_resource;
2175 op->dst_sub_resource_idx = dst_sub_resource_idx;
2176 op->dst_box = *dst_box;
2177 op->src_resource = src_resource;
2178 op->src_sub_resource_idx = src_sub_resource_idx;
2179 op->src_box = *src_box;
2180 op->flags = flags;
2181 if (fx)
2182 op->fx = *fx;
2183 else
2184 memset(&op->fx, 0, sizeof(op->fx));
2185 op->filter = filter;
2187 wined3d_resource_acquire(dst_resource);
2188 if (src_resource)
2189 wined3d_resource_acquire(src_resource);
2191 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2192 if (flags & WINED3D_BLT_SYNCHRONOUS)
2193 cs->ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT);
2196 static void wined3d_cs_exec_update_sub_resource(struct wined3d_cs *cs, const void *data)
2198 const struct wined3d_cs_update_sub_resource *op = data;
2199 struct wined3d_resource *resource = op->resource;
2200 const struct wined3d_box *box = &op->box;
2201 unsigned int width, height, depth, level;
2202 struct wined3d_const_bo_address addr;
2203 struct wined3d_context *context;
2204 struct wined3d_texture *texture;
2206 context = context_acquire(cs->device, NULL, 0);
2208 if (resource->type == WINED3D_RTYPE_BUFFER)
2210 struct wined3d_buffer *buffer = buffer_from_resource(resource);
2212 if (!wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER))
2214 ERR("Failed to load buffer location.\n");
2215 goto done;
2218 wined3d_buffer_upload_data(buffer, context, box, op->data.data);
2219 wined3d_buffer_invalidate_location(buffer, ~WINED3D_LOCATION_BUFFER);
2220 goto done;
2223 texture = wined3d_texture_from_resource(resource);
2225 level = op->sub_resource_idx % texture->level_count;
2226 width = wined3d_texture_get_level_width(texture, level);
2227 height = wined3d_texture_get_level_height(texture, level);
2228 depth = wined3d_texture_get_level_depth(texture, level);
2230 addr.buffer_object = 0;
2231 addr.addr = op->data.data;
2233 /* Only load the sub-resource for partial updates. */
2234 if (!box->left && !box->top && !box->front
2235 && box->right == width && box->bottom == height && box->back == depth)
2236 wined3d_texture_prepare_texture(texture, context, FALSE);
2237 else
2238 wined3d_texture_load_location(texture, op->sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2239 wined3d_texture_bind_and_dirtify(texture, context, FALSE);
2241 wined3d_texture_upload_data(texture, op->sub_resource_idx, context,
2242 box, &addr, op->data.row_pitch, op->data.slice_pitch);
2244 wined3d_texture_validate_location(texture, op->sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2245 wined3d_texture_invalidate_location(texture, op->sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2247 done:
2248 context_release(context);
2250 wined3d_resource_release(resource);
2253 void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource,
2254 unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch,
2255 unsigned int slice_pitch)
2257 struct wined3d_cs_update_sub_resource *op;
2259 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2260 op->opcode = WINED3D_CS_OP_UPDATE_SUB_RESOURCE;
2261 op->resource = resource;
2262 op->sub_resource_idx = sub_resource_idx;
2263 op->box = *box;
2264 op->data.row_pitch = row_pitch;
2265 op->data.slice_pitch = slice_pitch;
2266 op->data.data = data;
2268 wined3d_resource_acquire(resource);
2270 cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2271 /* The data pointer may go away, so we need to wait until it is read.
2272 * Copying the data may be faster if it's small. */
2273 cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2276 static void wined3d_cs_exec_add_dirty_texture_region(struct wined3d_cs *cs, const void *data)
2278 const struct wined3d_cs_add_dirty_texture_region *op = data;
2279 struct wined3d_texture *texture = op->texture;
2280 unsigned int sub_resource_idx, i;
2281 struct wined3d_context *context;
2283 context = context_acquire(cs->device, NULL, 0);
2284 sub_resource_idx = op->layer * texture->level_count;
2285 for (i = 0; i < texture->level_count; ++i, ++sub_resource_idx)
2287 if (wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding))
2288 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
2289 else
2290 ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
2292 context_release(context);
2294 wined3d_resource_release(&texture->resource);
2297 void wined3d_cs_emit_add_dirty_texture_region(struct wined3d_cs *cs,
2298 struct wined3d_texture *texture, unsigned int layer)
2300 struct wined3d_cs_add_dirty_texture_region *op;
2302 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2303 op->opcode = WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION;
2304 op->texture = texture;
2305 op->layer = layer;
2307 wined3d_resource_acquire(&texture->resource);
2309 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2312 static void wined3d_cs_exec_clear_unordered_access_view(struct wined3d_cs *cs, const void *data)
2314 const struct wined3d_cs_clear_unordered_access_view *op = data;
2315 struct wined3d_unordered_access_view *view = op->view;
2316 struct wined3d_context *context;
2318 context = context_acquire(cs->device, NULL, 0);
2319 wined3d_unordered_access_view_clear_uint(view, &op->clear_value, context);
2320 context_release(context);
2322 wined3d_resource_release(view->resource);
2325 void wined3d_cs_emit_clear_unordered_access_view_uint(struct wined3d_cs *cs,
2326 struct wined3d_unordered_access_view *view, const struct wined3d_uvec4 *clear_value)
2328 struct wined3d_cs_clear_unordered_access_view *op;
2330 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2331 op->opcode = WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW;
2332 op->view = view;
2333 op->clear_value = *clear_value;
2335 wined3d_resource_acquire(view->resource);
2337 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2340 static void wined3d_cs_exec_copy_uav_counter(struct wined3d_cs *cs, const void *data)
2342 const struct wined3d_cs_copy_uav_counter *op = data;
2343 struct wined3d_unordered_access_view *view = op->view;
2344 struct wined3d_context *context;
2346 context = context_acquire(cs->device, NULL, 0);
2347 wined3d_unordered_access_view_copy_counter(view, op->buffer, op->offset, context);
2348 context_release(context);
2350 wined3d_resource_release(&op->buffer->resource);
2353 void wined3d_cs_emit_copy_uav_counter(struct wined3d_cs *cs, struct wined3d_buffer *dst_buffer,
2354 unsigned int offset, struct wined3d_unordered_access_view *uav)
2356 struct wined3d_cs_copy_uav_counter *op;
2358 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2359 op->opcode = WINED3D_CS_OP_COPY_UAV_COUNTER;
2360 op->buffer = dst_buffer;
2361 op->offset = offset;
2362 op->view = uav;
2364 wined3d_resource_acquire(&dst_buffer->resource);
2366 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2369 static void wined3d_cs_exec_generate_mipmaps(struct wined3d_cs *cs, const void *data)
2371 const struct wined3d_cs_generate_mipmaps *op = data;
2372 struct wined3d_shader_resource_view *view = op->view;
2374 shader_resource_view_generate_mipmaps(view);
2375 wined3d_resource_release(view->resource);
2378 void wined3d_cs_emit_generate_mipmaps(struct wined3d_cs *cs, struct wined3d_shader_resource_view *view)
2380 struct wined3d_cs_generate_mipmaps *op;
2382 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2383 op->opcode = WINED3D_CS_OP_GENERATE_MIPMAPS;
2384 op->view = view;
2386 wined3d_resource_acquire(view->resource);
2388 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2391 static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
2393 struct wined3d_cs_stop *op;
2395 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2396 op->opcode = WINED3D_CS_OP_STOP;
2398 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2399 cs->ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT);
2402 static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
2404 /* WINED3D_CS_OP_NOP */ wined3d_cs_exec_nop,
2405 /* WINED3D_CS_OP_PRESENT */ wined3d_cs_exec_present,
2406 /* WINED3D_CS_OP_CLEAR */ wined3d_cs_exec_clear,
2407 /* WINED3D_CS_OP_DISPATCH */ wined3d_cs_exec_dispatch,
2408 /* WINED3D_CS_OP_DRAW */ wined3d_cs_exec_draw,
2409 /* WINED3D_CS_OP_FLUSH */ wined3d_cs_exec_flush,
2410 /* WINED3D_CS_OP_SET_PREDICATION */ wined3d_cs_exec_set_predication,
2411 /* WINED3D_CS_OP_SET_VIEWPORT */ wined3d_cs_exec_set_viewport,
2412 /* WINED3D_CS_OP_SET_SCISSOR_RECT */ wined3d_cs_exec_set_scissor_rect,
2413 /* WINED3D_CS_OP_SET_RENDERTARGET_VIEW */ wined3d_cs_exec_set_rendertarget_view,
2414 /* WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW */ wined3d_cs_exec_set_depth_stencil_view,
2415 /* WINED3D_CS_OP_SET_VERTEX_DECLARATION */ wined3d_cs_exec_set_vertex_declaration,
2416 /* WINED3D_CS_OP_SET_STREAM_SOURCE */ wined3d_cs_exec_set_stream_source,
2417 /* WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ */ wined3d_cs_exec_set_stream_source_freq,
2418 /* WINED3D_CS_OP_SET_STREAM_OUTPUT */ wined3d_cs_exec_set_stream_output,
2419 /* WINED3D_CS_OP_SET_INDEX_BUFFER */ wined3d_cs_exec_set_index_buffer,
2420 /* WINED3D_CS_OP_SET_CONSTANT_BUFFER */ wined3d_cs_exec_set_constant_buffer,
2421 /* WINED3D_CS_OP_SET_TEXTURE */ wined3d_cs_exec_set_texture,
2422 /* WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW */ wined3d_cs_exec_set_shader_resource_view,
2423 /* WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_set_unordered_access_view,
2424 /* WINED3D_CS_OP_SET_SAMPLER */ wined3d_cs_exec_set_sampler,
2425 /* WINED3D_CS_OP_SET_SHADER */ wined3d_cs_exec_set_shader,
2426 /* WINED3D_CS_OP_SET_BLEND_STATE */ wined3d_cs_exec_set_blend_state,
2427 /* WINED3D_CS_OP_SET_RASTERIZER_STATE */ wined3d_cs_exec_set_rasterizer_state,
2428 /* WINED3D_CS_OP_SET_RENDER_STATE */ wined3d_cs_exec_set_render_state,
2429 /* WINED3D_CS_OP_SET_TEXTURE_STATE */ wined3d_cs_exec_set_texture_state,
2430 /* WINED3D_CS_OP_SET_SAMPLER_STATE */ wined3d_cs_exec_set_sampler_state,
2431 /* WINED3D_CS_OP_SET_TRANSFORM */ wined3d_cs_exec_set_transform,
2432 /* WINED3D_CS_OP_SET_CLIP_PLANE */ wined3d_cs_exec_set_clip_plane,
2433 /* WINED3D_CS_OP_SET_COLOR_KEY */ wined3d_cs_exec_set_color_key,
2434 /* WINED3D_CS_OP_SET_MATERIAL */ wined3d_cs_exec_set_material,
2435 /* WINED3D_CS_OP_SET_LIGHT */ wined3d_cs_exec_set_light,
2436 /* WINED3D_CS_OP_SET_LIGHT_ENABLE */ wined3d_cs_exec_set_light_enable,
2437 /* WINED3D_CS_OP_PUSH_CONSTANTS */ wined3d_cs_exec_push_constants,
2438 /* WINED3D_CS_OP_RESET_STATE */ wined3d_cs_exec_reset_state,
2439 /* WINED3D_CS_OP_CALLBACK */ wined3d_cs_exec_callback,
2440 /* WINED3D_CS_OP_QUERY_ISSUE */ wined3d_cs_exec_query_issue,
2441 /* WINED3D_CS_OP_PRELOAD_RESOURCE */ wined3d_cs_exec_preload_resource,
2442 /* WINED3D_CS_OP_UNLOAD_RESOURCE */ wined3d_cs_exec_unload_resource,
2443 /* WINED3D_CS_OP_MAP */ wined3d_cs_exec_map,
2444 /* WINED3D_CS_OP_UNMAP */ wined3d_cs_exec_unmap,
2445 /* WINED3D_CS_OP_BLT_SUB_RESOURCE */ wined3d_cs_exec_blt_sub_resource,
2446 /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE */ wined3d_cs_exec_update_sub_resource,
2447 /* WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION */ wined3d_cs_exec_add_dirty_texture_region,
2448 /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view,
2449 /* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter,
2450 /* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps,
2453 static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2455 if (size > (cs->data_size - cs->end))
2457 size_t new_size;
2458 void *new_data;
2460 new_size = max(size, cs->data_size * 2);
2461 if (!cs->end)
2462 new_data = HeapReAlloc(GetProcessHeap(), 0, cs->data, new_size);
2463 else
2464 new_data = HeapAlloc(GetProcessHeap(), 0, new_size);
2465 if (!new_data)
2466 return NULL;
2468 cs->data_size = new_size;
2469 cs->start = cs->end = 0;
2470 cs->data = new_data;
2473 cs->end += size;
2475 return (BYTE *)cs->data + cs->start;
2478 static void wined3d_cs_st_submit(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2480 enum wined3d_cs_op opcode;
2481 size_t start;
2482 BYTE *data;
2484 data = cs->data;
2485 start = cs->start;
2486 cs->start = cs->end;
2488 opcode = *(const enum wined3d_cs_op *)&data[start];
2489 if (opcode >= WINED3D_CS_OP_STOP)
2490 ERR("Invalid opcode %#x.\n", opcode);
2491 else
2492 wined3d_cs_op_handlers[opcode](cs, &data[start]);
2494 if (cs->data == data)
2495 cs->start = cs->end = start;
2496 else if (!start)
2497 HeapFree(GetProcessHeap(), 0, data);
2500 static void wined3d_cs_st_finish(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2504 static const struct wined3d_cs_ops wined3d_cs_st_ops =
2506 wined3d_cs_st_require_space,
2507 wined3d_cs_st_submit,
2508 wined3d_cs_st_finish,
2509 wined3d_cs_st_push_constants,
2512 static BOOL wined3d_cs_queue_is_empty(const struct wined3d_cs *cs, const struct wined3d_cs_queue *queue)
2514 wined3d_from_cs(cs);
2515 return *(volatile LONG *)&queue->head == queue->tail;
2518 static void wined3d_cs_queue_submit(struct wined3d_cs_queue *queue, struct wined3d_cs *cs)
2520 struct wined3d_cs_packet *packet;
2521 size_t packet_size;
2523 packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
2524 packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[packet->size]);
2525 InterlockedExchange(&queue->head, (queue->head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1));
2527 if (InterlockedCompareExchange(&cs->waiting_for_event, FALSE, TRUE))
2528 SetEvent(cs->event);
2531 static void wined3d_cs_mt_submit(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2533 if (cs->thread_id == GetCurrentThreadId())
2534 return wined3d_cs_st_submit(cs, queue_id);
2536 wined3d_cs_queue_submit(&cs->queue[queue_id], cs);
2539 static void *wined3d_cs_queue_require_space(struct wined3d_cs_queue *queue, size_t size, struct wined3d_cs *cs)
2541 size_t queue_size = ARRAY_SIZE(queue->data);
2542 size_t header_size, packet_size, remaining;
2543 struct wined3d_cs_packet *packet;
2545 header_size = FIELD_OFFSET(struct wined3d_cs_packet, data[0]);
2546 size = (size + header_size - 1) & ~(header_size - 1);
2547 packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[size]);
2548 if (packet_size >= WINED3D_CS_QUEUE_SIZE)
2550 ERR("Packet size %lu >= queue size %u.\n",
2551 (unsigned long)packet_size, WINED3D_CS_QUEUE_SIZE);
2552 return NULL;
2555 remaining = queue_size - queue->head;
2556 if (remaining < packet_size)
2558 size_t nop_size = remaining - header_size;
2559 struct wined3d_cs_nop *nop;
2561 TRACE("Inserting a nop for %lu + %lu bytes.\n",
2562 (unsigned long)header_size, (unsigned long)nop_size);
2564 nop = wined3d_cs_queue_require_space(queue, nop_size, cs);
2565 if (nop_size)
2566 nop->opcode = WINED3D_CS_OP_NOP;
2568 wined3d_cs_queue_submit(queue, cs);
2569 assert(!queue->head);
2572 for (;;)
2574 LONG tail = *(volatile LONG *)&queue->tail;
2575 LONG head = queue->head;
2576 LONG new_pos;
2578 /* Empty. */
2579 if (head == tail)
2580 break;
2581 new_pos = (head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1);
2582 /* Head ahead of tail. We checked the remaining size above, so we only
2583 * need to make sure we don't make head equal to tail. */
2584 if (head > tail && (new_pos != tail))
2585 break;
2586 /* Tail ahead of head. Make sure the new head is before the tail as
2587 * well. Note that new_pos is 0 when it's at the end of the queue. */
2588 if (new_pos < tail && new_pos)
2589 break;
2591 TRACE("Waiting for free space. Head %u, tail %u, packet size %lu.\n",
2592 head, tail, (unsigned long)packet_size);
2595 packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
2596 packet->size = size;
2597 return packet->data;
2600 static void *wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2602 if (cs->thread_id == GetCurrentThreadId())
2603 return wined3d_cs_st_require_space(cs, size, queue_id);
2605 return wined3d_cs_queue_require_space(&cs->queue[queue_id], size, cs);
2608 static void wined3d_cs_mt_finish(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2610 if (cs->thread_id == GetCurrentThreadId())
2611 return wined3d_cs_st_finish(cs, queue_id);
2613 while (cs->queue[queue_id].head != *(volatile LONG *)&cs->queue[queue_id].tail)
2614 wined3d_pause();
2617 static const struct wined3d_cs_ops wined3d_cs_mt_ops =
2619 wined3d_cs_mt_require_space,
2620 wined3d_cs_mt_submit,
2621 wined3d_cs_mt_finish,
2622 wined3d_cs_mt_push_constants,
2625 static void poll_queries(struct wined3d_cs *cs)
2627 struct wined3d_query *query, *cursor;
2629 LIST_FOR_EACH_ENTRY_SAFE(query, cursor, &cs->query_poll_list, struct wined3d_query, poll_list_entry)
2631 if (!query->query_ops->query_poll(query, 0))
2632 continue;
2634 list_remove(&query->poll_list_entry);
2635 list_init(&query->poll_list_entry);
2636 InterlockedIncrement(&query->counter_retrieved);
2640 static void wined3d_cs_wait_event(struct wined3d_cs *cs)
2642 InterlockedExchange(&cs->waiting_for_event, TRUE);
2644 /* The main thread might have enqueued a command and blocked on it after
2645 * the CS thread decided to enter wined3d_cs_wait_event(), but before
2646 * "waiting_for_event" was set.
2648 * Likewise, we can race with the main thread when resetting
2649 * "waiting_for_event", in which case we would need to call
2650 * WaitForSingleObject() because the main thread called SetEvent(). */
2651 if (!(wined3d_cs_queue_is_empty(cs, &cs->queue[WINED3D_CS_QUEUE_DEFAULT])
2652 && wined3d_cs_queue_is_empty(cs, &cs->queue[WINED3D_CS_QUEUE_MAP]))
2653 && InterlockedCompareExchange(&cs->waiting_for_event, FALSE, TRUE))
2654 return;
2656 WaitForSingleObject(cs->event, INFINITE);
2659 static DWORD WINAPI wined3d_cs_run(void *ctx)
2661 struct wined3d_cs_packet *packet;
2662 struct wined3d_cs_queue *queue;
2663 unsigned int spin_count = 0;
2664 struct wined3d_cs *cs = ctx;
2665 enum wined3d_cs_op opcode;
2666 HMODULE wined3d_module;
2667 unsigned int poll = 0;
2668 LONG tail;
2670 TRACE("Started.\n");
2672 /* Copy the module handle to a local variable to avoid racing with the
2673 * thread freeing "cs" before the FreeLibraryAndExitThread() call. */
2674 wined3d_module = cs->wined3d_module;
2676 list_init(&cs->query_poll_list);
2677 cs->thread_id = GetCurrentThreadId();
2678 for (;;)
2680 if (++poll == WINED3D_CS_QUERY_POLL_INTERVAL)
2682 poll_queries(cs);
2683 poll = 0;
2686 queue = &cs->queue[WINED3D_CS_QUEUE_MAP];
2687 if (wined3d_cs_queue_is_empty(cs, queue))
2689 queue = &cs->queue[WINED3D_CS_QUEUE_DEFAULT];
2690 if (wined3d_cs_queue_is_empty(cs, queue))
2692 if (++spin_count >= WINED3D_CS_SPIN_COUNT && list_empty(&cs->query_poll_list))
2693 wined3d_cs_wait_event(cs);
2694 continue;
2697 spin_count = 0;
2699 tail = queue->tail;
2700 packet = (struct wined3d_cs_packet *)&queue->data[tail];
2701 if (packet->size)
2703 opcode = *(const enum wined3d_cs_op *)packet->data;
2705 if (opcode >= WINED3D_CS_OP_STOP)
2707 if (opcode > WINED3D_CS_OP_STOP)
2708 ERR("Invalid opcode %#x.\n", opcode);
2709 break;
2712 wined3d_cs_op_handlers[opcode](cs, packet->data);
2715 tail += FIELD_OFFSET(struct wined3d_cs_packet, data[packet->size]);
2716 tail &= (WINED3D_CS_QUEUE_SIZE - 1);
2717 InterlockedExchange(&queue->tail, tail);
2720 cs->queue[WINED3D_CS_QUEUE_MAP].tail = cs->queue[WINED3D_CS_QUEUE_MAP].head;
2721 cs->queue[WINED3D_CS_QUEUE_DEFAULT].tail = cs->queue[WINED3D_CS_QUEUE_DEFAULT].head;
2722 TRACE("Stopped.\n");
2723 FreeLibraryAndExitThread(wined3d_module, 0);
2726 struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device)
2728 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2729 struct wined3d_cs *cs;
2731 if (!(cs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cs))))
2732 return NULL;
2734 cs->ops = &wined3d_cs_st_ops;
2735 cs->device = device;
2737 if (!(cs->fb.render_targets = wined3d_calloc(gl_info->limits.buffers, sizeof(*cs->fb.render_targets))))
2739 HeapFree(GetProcessHeap(), 0, cs);
2740 return NULL;
2743 state_init(&cs->state, &cs->fb, gl_info, &device->adapter->d3d_info,
2744 WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT);
2746 cs->data_size = WINED3D_INITIAL_CS_SIZE;
2747 if (!(cs->data = HeapAlloc(GetProcessHeap(), 0, cs->data_size)))
2748 goto fail;
2750 if (wined3d_settings.cs_multithreaded
2751 && !RtlIsCriticalSectionLockedByThread(NtCurrentTeb()->Peb->LoaderLock))
2753 cs->ops = &wined3d_cs_mt_ops;
2755 if (!(cs->event = CreateEventW(NULL, FALSE, FALSE, NULL)))
2757 ERR("Failed to create command stream event.\n");
2758 HeapFree(GetProcessHeap(), 0, cs->data);
2759 goto fail;
2762 if (!(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
2763 (const WCHAR *)wined3d_cs_run, &cs->wined3d_module)))
2765 ERR("Failed to get wined3d module handle.\n");
2766 CloseHandle(cs->event);
2767 HeapFree(GetProcessHeap(), 0, cs->data);
2768 goto fail;
2771 if (!(cs->thread = CreateThread(NULL, 0, wined3d_cs_run, cs, 0, NULL)))
2773 ERR("Failed to create wined3d command stream thread.\n");
2774 FreeLibrary(cs->wined3d_module);
2775 CloseHandle(cs->event);
2776 HeapFree(GetProcessHeap(), 0, cs->data);
2777 goto fail;
2781 return cs;
2783 fail:
2784 state_cleanup(&cs->state);
2785 HeapFree(GetProcessHeap(), 0, cs->fb.render_targets);
2786 HeapFree(GetProcessHeap(), 0, cs);
2787 return NULL;
2790 void wined3d_cs_destroy(struct wined3d_cs *cs)
2792 if (cs->thread)
2794 wined3d_cs_emit_stop(cs);
2795 CloseHandle(cs->thread);
2796 if (!CloseHandle(cs->event))
2797 ERR("Closing event failed.\n");
2800 state_cleanup(&cs->state);
2801 HeapFree(GetProcessHeap(), 0, cs->fb.render_targets);
2802 HeapFree(GetProcessHeap(), 0, cs->data);
2803 HeapFree(GetProcessHeap(), 0, cs);