xref: /reactos/dll/directx/wine/wined3d/cs.c (revision 4567e13e)
1 /*
2  * Copyright 2013 Henri Verbeet for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18 
19 #include "config.h"
20 #include "wine/port.h"
21 #include "wined3d_private.h"
22 
23 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
24 
25 #define WINED3D_INITIAL_CS_SIZE 4096
26 
27 enum wined3d_cs_op
28 {
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_VIEWPORTS,
37     WINED3D_CS_OP_SET_SCISSOR_RECTS,
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,
77 };
78 
79 struct wined3d_cs_packet
80 {
81     size_t size;
82     BYTE data[1];
83 };
84 
85 struct wined3d_cs_nop
86 {
87     enum wined3d_cs_op opcode;
88 };
89 
90 struct wined3d_cs_present
91 {
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     unsigned int swap_interval;
98     DWORD flags;
99 };
100 
101 struct wined3d_cs_clear
102 {
103     enum wined3d_cs_op opcode;
104     DWORD flags;
105     unsigned int rt_count;
106     struct wined3d_fb_state *fb;
107     RECT draw_rect;
108     struct wined3d_color color;
109     float depth;
110     DWORD stencil;
111     unsigned int rect_count;
112     RECT rects[1];
113 };
114 
115 struct wined3d_cs_dispatch
116 {
117     enum wined3d_cs_op opcode;
118     struct wined3d_dispatch_parameters parameters;
119 };
120 
121 struct wined3d_cs_draw
122 {
123     enum wined3d_cs_op opcode;
124     GLenum primitive_type;
125     GLint patch_vertex_count;
126     struct wined3d_draw_parameters parameters;
127 };
128 
129 struct wined3d_cs_flush
130 {
131     enum wined3d_cs_op opcode;
132 };
133 
134 struct wined3d_cs_set_predication
135 {
136     enum wined3d_cs_op opcode;
137     struct wined3d_query *predicate;
138     BOOL value;
139 };
140 
141 struct wined3d_cs_set_viewports
142 {
143     enum wined3d_cs_op opcode;
144     unsigned int viewport_count;
145     struct wined3d_viewport viewports[1];
146 };
147 
148 struct wined3d_cs_set_scissor_rects
149 {
150     enum wined3d_cs_op opcode;
151     unsigned int rect_count;
152     RECT rects[1];
153 };
154 
155 struct wined3d_cs_set_rendertarget_view
156 {
157     enum wined3d_cs_op opcode;
158     unsigned int view_idx;
159     struct wined3d_rendertarget_view *view;
160 };
161 
162 struct wined3d_cs_set_depth_stencil_view
163 {
164     enum wined3d_cs_op opcode;
165     struct wined3d_rendertarget_view *view;
166 };
167 
168 struct wined3d_cs_set_vertex_declaration
169 {
170     enum wined3d_cs_op opcode;
171     struct wined3d_vertex_declaration *declaration;
172 };
173 
174 struct wined3d_cs_set_stream_source
175 {
176     enum wined3d_cs_op opcode;
177     UINT stream_idx;
178     struct wined3d_buffer *buffer;
179     UINT offset;
180     UINT stride;
181 };
182 
183 struct wined3d_cs_set_stream_source_freq
184 {
185     enum wined3d_cs_op opcode;
186     UINT stream_idx;
187     UINT frequency;
188     UINT flags;
189 };
190 
191 struct wined3d_cs_set_stream_output
192 {
193     enum wined3d_cs_op opcode;
194     UINT stream_idx;
195     struct wined3d_buffer *buffer;
196     UINT offset;
197 };
198 
199 struct wined3d_cs_set_index_buffer
200 {
201     enum wined3d_cs_op opcode;
202     struct wined3d_buffer *buffer;
203     enum wined3d_format_id format_id;
204     unsigned int offset;
205 };
206 
207 struct wined3d_cs_set_constant_buffer
208 {
209     enum wined3d_cs_op opcode;
210     enum wined3d_shader_type type;
211     UINT cb_idx;
212     struct wined3d_buffer *buffer;
213 };
214 
215 struct wined3d_cs_set_texture
216 {
217     enum wined3d_cs_op opcode;
218     UINT stage;
219     struct wined3d_texture *texture;
220 };
221 
222 struct wined3d_cs_set_color_key
223 {
224     enum wined3d_cs_op opcode;
225     struct wined3d_texture *texture;
226     WORD flags;
227     WORD set;
228     struct wined3d_color_key color_key;
229 };
230 
231 struct wined3d_cs_set_shader_resource_view
232 {
233     enum wined3d_cs_op opcode;
234     enum wined3d_shader_type type;
235     UINT view_idx;
236     struct wined3d_shader_resource_view *view;
237 };
238 
239 struct wined3d_cs_set_unordered_access_view
240 {
241     enum wined3d_cs_op opcode;
242     enum wined3d_pipeline pipeline;
243     unsigned int view_idx;
244     struct wined3d_unordered_access_view *view;
245     unsigned int initial_count;
246 };
247 
248 struct wined3d_cs_set_sampler
249 {
250     enum wined3d_cs_op opcode;
251     enum wined3d_shader_type type;
252     UINT sampler_idx;
253     struct wined3d_sampler *sampler;
254 };
255 
256 struct wined3d_cs_set_shader
257 {
258     enum wined3d_cs_op opcode;
259     enum wined3d_shader_type type;
260     struct wined3d_shader *shader;
261 };
262 
263 struct wined3d_cs_set_blend_state
264 {
265     enum wined3d_cs_op opcode;
266     struct wined3d_blend_state *state;
267 };
268 
269 struct wined3d_cs_set_rasterizer_state
270 {
271     enum wined3d_cs_op opcode;
272     struct wined3d_rasterizer_state *state;
273 };
274 
275 struct wined3d_cs_set_render_state
276 {
277     enum wined3d_cs_op opcode;
278     enum wined3d_render_state state;
279     DWORD value;
280 };
281 
282 struct wined3d_cs_set_texture_state
283 {
284     enum wined3d_cs_op opcode;
285     UINT stage;
286     enum wined3d_texture_stage_state state;
287     DWORD value;
288 };
289 
290 struct wined3d_cs_set_sampler_state
291 {
292     enum wined3d_cs_op opcode;
293     UINT sampler_idx;
294     enum wined3d_sampler_state state;
295     DWORD value;
296 };
297 
298 struct wined3d_cs_set_transform
299 {
300     enum wined3d_cs_op opcode;
301     enum wined3d_transform_state state;
302     struct wined3d_matrix matrix;
303 };
304 
305 struct wined3d_cs_set_clip_plane
306 {
307     enum wined3d_cs_op opcode;
308     UINT plane_idx;
309     struct wined3d_vec4 plane;
310 };
311 
312 struct wined3d_cs_set_material
313 {
314     enum wined3d_cs_op opcode;
315     struct wined3d_material material;
316 };
317 
318 struct wined3d_cs_set_light
319 {
320     enum wined3d_cs_op opcode;
321     struct wined3d_light_info light;
322 };
323 
324 struct wined3d_cs_set_light_enable
325 {
326     enum wined3d_cs_op opcode;
327     unsigned int idx;
328     BOOL enable;
329 };
330 
331 struct wined3d_cs_push_constants
332 {
333     enum wined3d_cs_op opcode;
334     enum wined3d_push_constants type;
335     unsigned int start_idx;
336     unsigned int count;
337     BYTE constants[1];
338 };
339 
340 struct wined3d_cs_reset_state
341 {
342     enum wined3d_cs_op opcode;
343 };
344 
345 struct wined3d_cs_callback
346 {
347     enum wined3d_cs_op opcode;
348     void (*callback)(void *object);
349     void *object;
350 };
351 
352 struct wined3d_cs_query_issue
353 {
354     enum wined3d_cs_op opcode;
355     struct wined3d_query *query;
356     DWORD flags;
357 };
358 
359 struct wined3d_cs_preload_resource
360 {
361     enum wined3d_cs_op opcode;
362     struct wined3d_resource *resource;
363 };
364 
365 struct wined3d_cs_unload_resource
366 {
367     enum wined3d_cs_op opcode;
368     struct wined3d_resource *resource;
369 };
370 
371 struct wined3d_cs_map
372 {
373     enum wined3d_cs_op opcode;
374     struct wined3d_resource *resource;
375     unsigned int sub_resource_idx;
376     struct wined3d_map_desc *map_desc;
377     const struct wined3d_box *box;
378     DWORD flags;
379     HRESULT *hr;
380 };
381 
382 struct wined3d_cs_unmap
383 {
384     enum wined3d_cs_op opcode;
385     struct wined3d_resource *resource;
386     unsigned int sub_resource_idx;
387     HRESULT *hr;
388 };
389 
390 struct wined3d_cs_blt_sub_resource
391 {
392     enum wined3d_cs_op opcode;
393     struct wined3d_resource *dst_resource;
394     unsigned int dst_sub_resource_idx;
395     struct wined3d_box dst_box;
396     struct wined3d_resource *src_resource;
397     unsigned int src_sub_resource_idx;
398     struct wined3d_box src_box;
399     DWORD flags;
400     struct wined3d_blt_fx fx;
401     enum wined3d_texture_filter_type filter;
402 };
403 
404 struct wined3d_cs_update_sub_resource
405 {
406     enum wined3d_cs_op opcode;
407     struct wined3d_resource *resource;
408     unsigned int sub_resource_idx;
409     struct wined3d_box box;
410     struct wined3d_sub_resource_data data;
411     BYTE copy_data[1];
412 };
413 
414 struct wined3d_cs_add_dirty_texture_region
415 {
416     enum wined3d_cs_op opcode;
417     struct wined3d_texture *texture;
418     unsigned int layer;
419 };
420 
421 struct wined3d_cs_clear_unordered_access_view
422 {
423     enum wined3d_cs_op opcode;
424     struct wined3d_unordered_access_view *view;
425     struct wined3d_uvec4 clear_value;
426 };
427 
428 struct wined3d_cs_copy_uav_counter
429 {
430     enum wined3d_cs_op opcode;
431     struct wined3d_buffer *buffer;
432     unsigned int offset;
433     struct wined3d_unordered_access_view *view;
434 };
435 
436 struct wined3d_cs_generate_mipmaps
437 {
438     enum wined3d_cs_op opcode;
439     struct wined3d_shader_resource_view *view;
440 };
441 
442 struct wined3d_cs_stop
443 {
444     enum wined3d_cs_op opcode;
445 };
446 
447 static void wined3d_cs_exec_nop(struct wined3d_cs *cs, const void *data)
448 {
449 }
450 
451 static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data)
452 {
453     const struct wined3d_cs_present *op = data;
454     struct wined3d_swapchain *swapchain;
455     unsigned int i;
456 
457     swapchain = op->swapchain;
458     wined3d_swapchain_set_window(swapchain, op->dst_window_override);
459     wined3d_swapchain_set_swap_interval(swapchain, op->swap_interval);
460 
461     swapchain->swapchain_ops->swapchain_present(swapchain, &op->src_rect, &op->dst_rect, op->flags);
462 
463     wined3d_resource_release(&swapchain->front_buffer->resource);
464     for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
465     {
466         wined3d_resource_release(&swapchain->back_buffers[i]->resource);
467     }
468 
469     InterlockedDecrement(&cs->pending_presents);
470 }
471 
472 void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain,
473         const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
474         unsigned int swap_interval, DWORD flags)
475 {
476     struct wined3d_cs_present *op;
477     unsigned int i;
478     LONG pending;
479 
480     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
481     op->opcode = WINED3D_CS_OP_PRESENT;
482     op->dst_window_override = dst_window_override;
483     op->swapchain = swapchain;
484     op->src_rect = *src_rect;
485     op->dst_rect = *dst_rect;
486     op->swap_interval = swap_interval;
487     op->flags = flags;
488 
489     pending = InterlockedIncrement(&cs->pending_presents);
490 
491     wined3d_resource_acquire(&swapchain->front_buffer->resource);
492     for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
493     {
494         wined3d_resource_acquire(&swapchain->back_buffers[i]->resource);
495     }
496 
497     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
498 
499     /* Limit input latency by limiting the number of presents that we can get
500      * ahead of the worker thread. */
501     while (pending >= swapchain->max_frame_latency)
502     {
503         wined3d_pause();
504         pending = InterlockedCompareExchange(&cs->pending_presents, 0, 0);
505     }
506 }
507 
508 static void wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
509 {
510     const struct wined3d_cs_clear *op = data;
511     struct wined3d_device *device;
512     unsigned int i;
513 
514     device = cs->device;
515     device->blitter->ops->blitter_clear(device->blitter, device, op->rt_count, op->fb,
516             op->rect_count, op->rects, &op->draw_rect, op->flags, &op->color, op->depth, op->stencil);
517 
518     if (op->flags & WINED3DCLEAR_TARGET)
519     {
520         for (i = 0; i < op->rt_count; ++i)
521         {
522             if (op->fb->render_targets[i])
523                 wined3d_resource_release(op->fb->render_targets[i]->resource);
524         }
525     }
526     if (op->flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
527         wined3d_resource_release(op->fb->depth_stencil->resource);
528 }
529 
530 void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects,
531         DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
532 {
533     unsigned int rt_count = cs->device->adapter->gl_info.limits.buffers;
534     const struct wined3d_state *state = &cs->device->state;
535     const struct wined3d_viewport *vp = &state->viewports[0];
536     struct wined3d_rendertarget_view *view;
537     struct wined3d_cs_clear *op;
538     RECT view_rect;
539     unsigned int i;
540 
541     op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_clear, rects[rect_count]),
542             WINED3D_CS_QUEUE_DEFAULT);
543     op->opcode = WINED3D_CS_OP_CLEAR;
544     op->flags = flags;
545     if (flags & WINED3DCLEAR_TARGET)
546         op->rt_count = rt_count;
547     else
548         op->rt_count = 0;
549     op->fb = &cs->fb;
550     SetRect(&op->draw_rect, vp->x, vp->y, vp->x + vp->width, vp->y + vp->height);
551     if (state->render_states[WINED3D_RS_SCISSORTESTENABLE])
552         IntersectRect(&op->draw_rect, &op->draw_rect, &state->scissor_rects[0]);
553     op->color = *color;
554     op->depth = depth;
555     op->stencil = stencil;
556     op->rect_count = rect_count;
557     memcpy(op->rects, rects, sizeof(*rects) * rect_count);
558 
559     if (flags & WINED3DCLEAR_TARGET)
560     {
561         for (i = 0; i < rt_count; ++i)
562         {
563             if ((view = state->fb->render_targets[i]))
564             {
565                 SetRect(&view_rect, 0, 0, view->width, view->height);
566                 IntersectRect(&op->draw_rect, &op->draw_rect, &view_rect);
567                 wined3d_resource_acquire(view->resource);
568             }
569         }
570     }
571     if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
572     {
573         view = state->fb->depth_stencil;
574         SetRect(&view_rect, 0, 0, view->width, view->height);
575         IntersectRect(&op->draw_rect, &op->draw_rect, &view_rect);
576         wined3d_resource_acquire(view->resource);
577     }
578 
579     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
580 }
581 
582 void wined3d_cs_emit_clear_rendertarget_view(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view,
583         const RECT *rect, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
584 {
585     struct wined3d_cs_clear *op;
586     size_t size;
587 
588     size = FIELD_OFFSET(struct wined3d_cs_clear, rects[1]) + sizeof(struct wined3d_fb_state);
589     op = cs->ops->require_space(cs, size, WINED3D_CS_QUEUE_DEFAULT);
590     op->fb = (void *)&op->rects[1];
591 
592     op->opcode = WINED3D_CS_OP_CLEAR;
593     op->flags = flags;
594     if (flags & WINED3DCLEAR_TARGET)
595     {
596         op->rt_count = 1;
597         op->fb->render_targets[0] = view;
598         op->fb->depth_stencil = NULL;
599         op->color = *color;
600     }
601     else
602     {
603         op->rt_count = 0;
604         op->fb->render_targets[0] = NULL;
605         op->fb->depth_stencil = view;
606         op->depth = depth;
607         op->stencil = stencil;
608     }
609     SetRect(&op->draw_rect, 0, 0, view->width, view->height);
610     op->rect_count = 1;
611     op->rects[0] = *rect;
612 
613     wined3d_resource_acquire(view->resource);
614 
615     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
616 }
617 
618 static void acquire_shader_resources(const struct wined3d_state *state, unsigned int shader_mask)
619 {
620     struct wined3d_shader_sampler_map_entry *entry;
621     struct wined3d_shader_resource_view *view;
622     struct wined3d_shader *shader;
623     unsigned int i, j;
624 
625     for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
626     {
627         if (!(shader_mask & (1u << i)))
628             continue;
629 
630         if (!(shader = state->shader[i]))
631             continue;
632 
633         for (j = 0; j < WINED3D_MAX_CBS; ++j)
634         {
635             if (state->cb[i][j])
636                 wined3d_resource_acquire(&state->cb[i][j]->resource);
637         }
638 
639         for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
640         {
641             entry = &shader->reg_maps.sampler_map.entries[j];
642 
643             if (!(view = state->shader_resource_view[i][entry->resource_idx]))
644                 continue;
645 
646             wined3d_resource_acquire(view->resource);
647         }
648     }
649 }
650 
651 static void release_shader_resources(const struct wined3d_state *state, unsigned int shader_mask)
652 {
653     struct wined3d_shader_sampler_map_entry *entry;
654     struct wined3d_shader_resource_view *view;
655     struct wined3d_shader *shader;
656     unsigned int i, j;
657 
658     for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
659     {
660         if (!(shader_mask & (1u << i)))
661             continue;
662 
663         if (!(shader = state->shader[i]))
664             continue;
665 
666         for (j = 0; j < WINED3D_MAX_CBS; ++j)
667         {
668             if (state->cb[i][j])
669                 wined3d_resource_release(&state->cb[i][j]->resource);
670         }
671 
672         for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
673         {
674             entry = &shader->reg_maps.sampler_map.entries[j];
675 
676             if (!(view = state->shader_resource_view[i][entry->resource_idx]))
677                 continue;
678 
679             wined3d_resource_release(view->resource);
680         }
681     }
682 }
683 
684 static void acquire_unordered_access_resources(const struct wined3d_shader *shader,
685         struct wined3d_unordered_access_view * const *views)
686 {
687     unsigned int i;
688 
689     if (!shader)
690         return;
691 
692     for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
693     {
694         if (!shader->reg_maps.uav_resource_info[i].type)
695             continue;
696 
697         if (!views[i])
698             continue;
699 
700         wined3d_resource_acquire(views[i]->resource);
701     }
702 }
703 
704 static void release_unordered_access_resources(const struct wined3d_shader *shader,
705         struct wined3d_unordered_access_view * const *views)
706 {
707     unsigned int i;
708 
709     if (!shader)
710         return;
711 
712     for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
713     {
714         if (!shader->reg_maps.uav_resource_info[i].type)
715             continue;
716 
717         if (!views[i])
718             continue;
719 
720         wined3d_resource_release(views[i]->resource);
721     }
722 }
723 
724 static void wined3d_cs_exec_dispatch(struct wined3d_cs *cs, const void *data)
725 {
726     const struct wined3d_cs_dispatch *op = data;
727     struct wined3d_state *state = &cs->state;
728 
729     dispatch_compute(cs->device, state, &op->parameters);
730 
731     if (op->parameters.indirect)
732         wined3d_resource_release(&op->parameters.u.indirect.buffer->resource);
733 
734     release_shader_resources(state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
735     release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_COMPUTE],
736             state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
737 }
738 
739 static void acquire_compute_pipeline_resources(const struct wined3d_state *state)
740 {
741     acquire_shader_resources(state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
742     acquire_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_COMPUTE],
743             state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
744 }
745 
746 void wined3d_cs_emit_dispatch(struct wined3d_cs *cs,
747         unsigned int group_count_x, unsigned int group_count_y, unsigned int group_count_z)
748 {
749     const struct wined3d_state *state = &cs->device->state;
750     struct wined3d_cs_dispatch *op;
751 
752     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
753     op->opcode = WINED3D_CS_OP_DISPATCH;
754     op->parameters.indirect = FALSE;
755     op->parameters.u.direct.group_count_x = group_count_x;
756     op->parameters.u.direct.group_count_y = group_count_y;
757     op->parameters.u.direct.group_count_z = group_count_z;
758 
759     acquire_compute_pipeline_resources(state);
760 
761     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
762 }
763 
764 void wined3d_cs_emit_dispatch_indirect(struct wined3d_cs *cs,
765         struct wined3d_buffer *buffer, unsigned int offset)
766 {
767     const struct wined3d_state *state = &cs->device->state;
768     struct wined3d_cs_dispatch *op;
769 
770     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
771     op->opcode = WINED3D_CS_OP_DISPATCH;
772     op->parameters.indirect = TRUE;
773     op->parameters.u.indirect.buffer = buffer;
774     op->parameters.u.indirect.offset = offset;
775 
776     acquire_compute_pipeline_resources(state);
777     wined3d_resource_acquire(&buffer->resource);
778 
779     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
780 }
781 
782 static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
783 {
784     const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
785     const struct wined3d_shader *geometry_shader;
786     struct wined3d_state *state = &cs->state;
787     const struct wined3d_cs_draw *op = data;
788     int load_base_vertex_idx;
789     unsigned int i;
790 
791     /* ARB_draw_indirect always supports a base vertex offset. */
792     if (!op->parameters.indirect && !gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
793         load_base_vertex_idx = op->parameters.u.direct.base_vertex_idx;
794     else
795         load_base_vertex_idx = 0;
796 
797     if (state->load_base_vertex_index != load_base_vertex_idx)
798     {
799         state->load_base_vertex_index = load_base_vertex_idx;
800         device_invalidate_state(cs->device, STATE_BASEVERTEXINDEX);
801     }
802 
803     if (state->gl_primitive_type != op->primitive_type)
804     {
805         if ((geometry_shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY]) && !geometry_shader->function)
806             device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_GEOMETRY));
807         if (state->gl_primitive_type == GL_POINTS || op->primitive_type == GL_POINTS)
808             device_invalidate_state(cs->device, STATE_POINT_ENABLE);
809         state->gl_primitive_type = op->primitive_type;
810     }
811     state->gl_patch_vertices = op->patch_vertex_count;
812 
813     draw_primitive(cs->device, state, &op->parameters);
814 
815     if (op->parameters.indirect)
816     {
817         struct wined3d_buffer *buffer = op->parameters.u.indirect.buffer;
818         wined3d_resource_release(&buffer->resource);
819     }
820 
821     if (op->parameters.indexed)
822         wined3d_resource_release(&state->index_buffer->resource);
823     for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
824     {
825         if (state->streams[i].buffer)
826             wined3d_resource_release(&state->streams[i].buffer->resource);
827     }
828     for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
829     {
830         if (state->stream_output[i].buffer)
831             wined3d_resource_release(&state->stream_output[i].buffer->resource);
832     }
833     for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
834     {
835         if (state->textures[i])
836             wined3d_resource_release(&state->textures[i]->resource);
837     }
838     for (i = 0; i < gl_info->limits.buffers; ++i)
839     {
840         if (state->fb->render_targets[i])
841             wined3d_resource_release(state->fb->render_targets[i]->resource);
842     }
843     if (state->fb->depth_stencil)
844         wined3d_resource_release(state->fb->depth_stencil->resource);
845     release_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
846     release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL],
847             state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
848 }
849 
850 static void acquire_graphics_pipeline_resources(const struct wined3d_state *state,
851         BOOL indexed, const struct wined3d_gl_info *gl_info)
852 {
853     unsigned int i;
854 
855     if (indexed)
856         wined3d_resource_acquire(&state->index_buffer->resource);
857     for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
858     {
859         if (state->streams[i].buffer)
860             wined3d_resource_acquire(&state->streams[i].buffer->resource);
861     }
862     for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
863     {
864         if (state->stream_output[i].buffer)
865             wined3d_resource_acquire(&state->stream_output[i].buffer->resource);
866     }
867     for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
868     {
869         if (state->textures[i])
870             wined3d_resource_acquire(&state->textures[i]->resource);
871     }
872     for (i = 0; i < gl_info->limits.buffers; ++i)
873     {
874         if (state->fb->render_targets[i])
875             wined3d_resource_acquire(state->fb->render_targets[i]->resource);
876     }
877     if (state->fb->depth_stencil)
878         wined3d_resource_acquire(state->fb->depth_stencil->resource);
879     acquire_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
880     acquire_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL],
881             state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
882 }
883 
884 void wined3d_cs_emit_draw(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
885         int base_vertex_idx, unsigned int start_idx, unsigned int index_count,
886         unsigned int start_instance, unsigned int instance_count, BOOL indexed)
887 {
888     const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
889     const struct wined3d_state *state = &cs->device->state;
890     struct wined3d_cs_draw *op;
891 
892     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
893     op->opcode = WINED3D_CS_OP_DRAW;
894     op->primitive_type = primitive_type;
895     op->patch_vertex_count = patch_vertex_count;
896     op->parameters.indirect = FALSE;
897     op->parameters.u.direct.base_vertex_idx = base_vertex_idx;
898     op->parameters.u.direct.start_idx = start_idx;
899     op->parameters.u.direct.index_count = index_count;
900     op->parameters.u.direct.start_instance = start_instance;
901     op->parameters.u.direct.instance_count = instance_count;
902     op->parameters.indexed = indexed;
903 
904     acquire_graphics_pipeline_resources(state, indexed, gl_info);
905 
906     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
907 }
908 
909 void wined3d_cs_emit_draw_indirect(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
910         struct wined3d_buffer *buffer, unsigned int offset, BOOL indexed)
911 {
912     const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
913     const struct wined3d_state *state = &cs->device->state;
914     struct wined3d_cs_draw *op;
915 
916     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
917     op->opcode = WINED3D_CS_OP_DRAW;
918     op->primitive_type = primitive_type;
919     op->patch_vertex_count = patch_vertex_count;
920     op->parameters.indirect = TRUE;
921     op->parameters.u.indirect.buffer = buffer;
922     op->parameters.u.indirect.offset = offset;
923     op->parameters.indexed = indexed;
924 
925     acquire_graphics_pipeline_resources(state, indexed, gl_info);
926     wined3d_resource_acquire(&buffer->resource);
927 
928     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
929 }
930 
931 static void wined3d_cs_exec_flush(struct wined3d_cs *cs, const void *data)
932 {
933     struct wined3d_context *context;
934 
935     context = context_acquire(cs->device, NULL, 0);
936     if (context->valid)
937         context->gl_info->gl_ops.gl.p_glFlush();
938     context_release(context);
939 }
940 
941 void wined3d_cs_emit_flush(struct wined3d_cs *cs)
942 {
943     struct wined3d_cs_flush *op;
944 
945     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
946     op->opcode = WINED3D_CS_OP_FLUSH;
947 
948     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
949     cs->queries_flushed = TRUE;
950 }
951 
952 static void wined3d_cs_exec_set_predication(struct wined3d_cs *cs, const void *data)
953 {
954     const struct wined3d_cs_set_predication *op = data;
955 
956     cs->state.predicate = op->predicate;
957     cs->state.predicate_value = op->value;
958 }
959 
960 void wined3d_cs_emit_set_predication(struct wined3d_cs *cs, struct wined3d_query *predicate, BOOL value)
961 {
962     struct wined3d_cs_set_predication *op;
963 
964     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
965     op->opcode = WINED3D_CS_OP_SET_PREDICATION;
966     op->predicate = predicate;
967     op->value = value;
968 
969     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
970 }
971 
972 static void wined3d_cs_exec_set_viewports(struct wined3d_cs *cs, const void *data)
973 {
974     const struct wined3d_cs_set_viewports *op = data;
975 
976     if (op->viewport_count)
977         memcpy(cs->state.viewports, op->viewports, op->viewport_count * sizeof(*op->viewports));
978     else
979         memset(cs->state.viewports, 0, sizeof(*cs->state.viewports));
980     cs->state.viewport_count = op->viewport_count;
981     device_invalidate_state(cs->device, STATE_VIEWPORT);
982 }
983 
984 void wined3d_cs_emit_set_viewports(struct wined3d_cs *cs, unsigned int viewport_count,
985         const struct wined3d_viewport *viewports)
986 {
987     struct wined3d_cs_set_viewports *op;
988 
989     op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_set_viewports, viewports[viewport_count]),
990             WINED3D_CS_QUEUE_DEFAULT);
991     op->opcode = WINED3D_CS_OP_SET_VIEWPORTS;
992     memcpy(op->viewports, viewports, viewport_count * sizeof(*viewports));
993     op->viewport_count = viewport_count;
994 
995     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
996 }
997 
998 static void wined3d_cs_exec_set_scissor_rects(struct wined3d_cs *cs, const void *data)
999 {
1000     const struct wined3d_cs_set_scissor_rects *op = data;
1001 
1002     if (op->rect_count)
1003         memcpy(cs->state.scissor_rects, op->rects, op->rect_count * sizeof(*op->rects));
1004     else
1005         SetRectEmpty(cs->state.scissor_rects);
1006     cs->state.scissor_rect_count = op->rect_count;
1007     device_invalidate_state(cs->device, STATE_SCISSORRECT);
1008 }
1009 
1010 void wined3d_cs_emit_set_scissor_rects(struct wined3d_cs *cs, unsigned int rect_count, const RECT *rects)
1011 {
1012     struct wined3d_cs_set_scissor_rects *op;
1013 
1014     op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_set_scissor_rects, rects[rect_count]),
1015             WINED3D_CS_QUEUE_DEFAULT);
1016     op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECTS;
1017     memcpy(op->rects, rects, rect_count * sizeof(*rects));
1018     op->rect_count = rect_count;
1019 
1020     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1021 }
1022 
1023 static void wined3d_cs_exec_set_rendertarget_view(struct wined3d_cs *cs, const void *data)
1024 {
1025     const struct wined3d_cs_set_rendertarget_view *op = data;
1026 
1027     cs->fb.render_targets[op->view_idx] = op->view;
1028     device_invalidate_state(cs->device, STATE_FRAMEBUFFER);
1029 }
1030 
1031 void wined3d_cs_emit_set_rendertarget_view(struct wined3d_cs *cs, unsigned int view_idx,
1032         struct wined3d_rendertarget_view *view)
1033 {
1034     struct wined3d_cs_set_rendertarget_view *op;
1035 
1036     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1037     op->opcode = WINED3D_CS_OP_SET_RENDERTARGET_VIEW;
1038     op->view_idx = view_idx;
1039     op->view = view;
1040 
1041     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1042 }
1043 
1044 static void wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const void *data)
1045 {
1046     const struct wined3d_cs_set_depth_stencil_view *op = data;
1047     struct wined3d_device *device = cs->device;
1048     struct wined3d_rendertarget_view *prev;
1049 
1050     if ((prev = cs->state.fb->depth_stencil) && prev->resource->type != WINED3D_RTYPE_BUFFER)
1051     {
1052         struct wined3d_texture *prev_texture = texture_from_resource(prev->resource);
1053 
1054         if (device->swapchains[0]->desc.flags & WINED3D_SWAPCHAIN_DISCARD_DEPTHSTENCIL
1055                 || prev_texture->flags & WINED3D_TEXTURE_DISCARD)
1056             wined3d_texture_validate_location(prev_texture,
1057                     prev->sub_resource_idx, WINED3D_LOCATION_DISCARDED);
1058     }
1059 
1060     cs->fb.depth_stencil = op->view;
1061 
1062     if (!prev != !op->view)
1063     {
1064         /* Swapping NULL / non NULL depth stencil affects the depth and tests */
1065         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
1066         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
1067         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
1068         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
1069         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIASCLAMP));
1070     }
1071     else if (prev && prev->format->depth_bias_scale != op->view->format->depth_bias_scale)
1072     {
1073         device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
1074     }
1075 
1076     device_invalidate_state(device, STATE_FRAMEBUFFER);
1077 }
1078 
1079 void wined3d_cs_emit_set_depth_stencil_view(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view)
1080 {
1081     struct wined3d_cs_set_depth_stencil_view *op;
1082 
1083     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1084     op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW;
1085     op->view = view;
1086 
1087     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1088 }
1089 
1090 static void wined3d_cs_exec_set_vertex_declaration(struct wined3d_cs *cs, const void *data)
1091 {
1092     const struct wined3d_cs_set_vertex_declaration *op = data;
1093 
1094     cs->state.vertex_declaration = op->declaration;
1095     device_invalidate_state(cs->device, STATE_VDECL);
1096 }
1097 
1098 void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs, struct wined3d_vertex_declaration *declaration)
1099 {
1100     struct wined3d_cs_set_vertex_declaration *op;
1101 
1102     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1103     op->opcode = WINED3D_CS_OP_SET_VERTEX_DECLARATION;
1104     op->declaration = declaration;
1105 
1106     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1107 }
1108 
1109 static void wined3d_cs_exec_set_stream_source(struct wined3d_cs *cs, const void *data)
1110 {
1111     const struct wined3d_cs_set_stream_source *op = data;
1112     struct wined3d_stream_state *stream;
1113     struct wined3d_buffer *prev;
1114 
1115     stream = &cs->state.streams[op->stream_idx];
1116     prev = stream->buffer;
1117     stream->buffer = op->buffer;
1118     stream->offset = op->offset;
1119     stream->stride = op->stride;
1120 
1121     if (op->buffer)
1122         InterlockedIncrement(&op->buffer->resource.bind_count);
1123     if (prev)
1124         InterlockedDecrement(&prev->resource.bind_count);
1125 
1126     device_invalidate_state(cs->device, STATE_STREAMSRC);
1127 }
1128 
1129 void wined3d_cs_emit_set_stream_source(struct wined3d_cs *cs, UINT stream_idx,
1130         struct wined3d_buffer *buffer, UINT offset, UINT stride)
1131 {
1132     struct wined3d_cs_set_stream_source *op;
1133 
1134     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1135     op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE;
1136     op->stream_idx = stream_idx;
1137     op->buffer = buffer;
1138     op->offset = offset;
1139     op->stride = stride;
1140 
1141     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1142 }
1143 
1144 static void wined3d_cs_exec_set_stream_source_freq(struct wined3d_cs *cs, const void *data)
1145 {
1146     const struct wined3d_cs_set_stream_source_freq *op = data;
1147     struct wined3d_stream_state *stream;
1148 
1149     stream = &cs->state.streams[op->stream_idx];
1150     stream->frequency = op->frequency;
1151     stream->flags = op->flags;
1152 
1153     device_invalidate_state(cs->device, STATE_STREAMSRC);
1154 }
1155 
1156 void wined3d_cs_emit_set_stream_source_freq(struct wined3d_cs *cs, UINT stream_idx, UINT frequency, UINT flags)
1157 {
1158     struct wined3d_cs_set_stream_source_freq *op;
1159 
1160     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1161     op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ;
1162     op->stream_idx = stream_idx;
1163     op->frequency = frequency;
1164     op->flags = flags;
1165 
1166     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1167 }
1168 
1169 static void wined3d_cs_exec_set_stream_output(struct wined3d_cs *cs, const void *data)
1170 {
1171     const struct wined3d_cs_set_stream_output *op = data;
1172     struct wined3d_stream_output *stream;
1173     struct wined3d_buffer *prev;
1174 
1175     stream = &cs->state.stream_output[op->stream_idx];
1176     prev = stream->buffer;
1177     stream->buffer = op->buffer;
1178     stream->offset = op->offset;
1179 
1180     if (op->buffer)
1181         InterlockedIncrement(&op->buffer->resource.bind_count);
1182     if (prev)
1183         InterlockedDecrement(&prev->resource.bind_count);
1184 
1185     device_invalidate_state(cs->device, STATE_STREAM_OUTPUT);
1186 }
1187 
1188 void wined3d_cs_emit_set_stream_output(struct wined3d_cs *cs, UINT stream_idx,
1189         struct wined3d_buffer *buffer, UINT offset)
1190 {
1191     struct wined3d_cs_set_stream_output *op;
1192 
1193     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1194     op->opcode = WINED3D_CS_OP_SET_STREAM_OUTPUT;
1195     op->stream_idx = stream_idx;
1196     op->buffer = buffer;
1197     op->offset = offset;
1198 
1199     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1200 }
1201 
1202 static void wined3d_cs_exec_set_index_buffer(struct wined3d_cs *cs, const void *data)
1203 {
1204     const struct wined3d_cs_set_index_buffer *op = data;
1205     struct wined3d_buffer *prev;
1206 
1207     prev = cs->state.index_buffer;
1208     cs->state.index_buffer = op->buffer;
1209     cs->state.index_format = op->format_id;
1210     cs->state.index_offset = op->offset;
1211 
1212     if (op->buffer)
1213         InterlockedIncrement(&op->buffer->resource.bind_count);
1214     if (prev)
1215         InterlockedDecrement(&prev->resource.bind_count);
1216 
1217     device_invalidate_state(cs->device, STATE_INDEXBUFFER);
1218 }
1219 
1220 void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer,
1221         enum wined3d_format_id format_id, unsigned int offset)
1222 {
1223     struct wined3d_cs_set_index_buffer *op;
1224 
1225     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1226     op->opcode = WINED3D_CS_OP_SET_INDEX_BUFFER;
1227     op->buffer = buffer;
1228     op->format_id = format_id;
1229     op->offset = offset;
1230 
1231     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1232 }
1233 
1234 static void wined3d_cs_exec_set_constant_buffer(struct wined3d_cs *cs, const void *data)
1235 {
1236     const struct wined3d_cs_set_constant_buffer *op = data;
1237     struct wined3d_buffer *prev;
1238 
1239     prev = cs->state.cb[op->type][op->cb_idx];
1240     cs->state.cb[op->type][op->cb_idx] = op->buffer;
1241 
1242     if (op->buffer)
1243         InterlockedIncrement(&op->buffer->resource.bind_count);
1244     if (prev)
1245         InterlockedDecrement(&prev->resource.bind_count);
1246 
1247     device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(op->type));
1248 }
1249 
1250 void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_shader_type type,
1251         UINT cb_idx, struct wined3d_buffer *buffer)
1252 {
1253     struct wined3d_cs_set_constant_buffer *op;
1254 
1255     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1256     op->opcode = WINED3D_CS_OP_SET_CONSTANT_BUFFER;
1257     op->type = type;
1258     op->cb_idx = cb_idx;
1259     op->buffer = buffer;
1260 
1261     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1262 }
1263 
1264 static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data)
1265 {
1266     const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
1267     const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info;
1268     const struct wined3d_cs_set_texture *op = data;
1269     struct wined3d_texture *prev;
1270     BOOL old_use_color_key = FALSE, new_use_color_key = FALSE;
1271 
1272     prev = cs->state.textures[op->stage];
1273     cs->state.textures[op->stage] = op->texture;
1274 
1275     if (op->texture)
1276     {
1277         const struct wined3d_format *new_format = op->texture->resource.format;
1278         const struct wined3d_format *old_format = prev ? prev->resource.format : NULL;
1279         unsigned int old_fmt_flags = prev ? prev->resource.format_flags : 0;
1280         unsigned int new_fmt_flags = op->texture->resource.format_flags;
1281 
1282         if (InterlockedIncrement(&op->texture->resource.bind_count) == 1)
1283             op->texture->sampler = op->stage;
1284 
1285         if (!prev || op->texture->target != prev->target
1286                 || (!is_same_fixup(new_format->color_fixup, old_format->color_fixup)
1287                 && !(can_use_texture_swizzle(gl_info, new_format) && can_use_texture_swizzle(gl_info, old_format)))
1288                 || (new_fmt_flags & WINED3DFMT_FLAG_SHADOW) != (old_fmt_flags & WINED3DFMT_FLAG_SHADOW))
1289             device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
1290 
1291         if (!prev && op->stage < d3d_info->limits.ffp_blend_stages)
1292         {
1293             /* The source arguments for color and alpha ops have different
1294              * meanings when a NULL texture is bound, so the COLOR_OP and
1295              * ALPHA_OP have to be dirtified. */
1296             device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1297             device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1298         }
1299 
1300         if (!op->stage && op->texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1301             new_use_color_key = TRUE;
1302     }
1303 
1304     if (prev)
1305     {
1306         if (InterlockedDecrement(&prev->resource.bind_count) && prev->sampler == op->stage)
1307         {
1308             unsigned int i;
1309 
1310             /* Search for other stages the texture is bound to. Shouldn't
1311              * happen if applications bind textures to a single stage only. */
1312             TRACE("Searching for other stages the texture is bound to.\n");
1313             for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
1314             {
1315                 if (cs->state.textures[i] == prev)
1316                 {
1317                     TRACE("Texture is also bound to stage %u.\n", i);
1318                     prev->sampler = i;
1319                     break;
1320                 }
1321             }
1322         }
1323 
1324         if (!op->texture && op->stage < d3d_info->limits.ffp_blend_stages)
1325         {
1326             device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1327             device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1328         }
1329 
1330         if (!op->stage && prev->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1331             old_use_color_key = TRUE;
1332     }
1333 
1334     device_invalidate_state(cs->device, STATE_SAMPLER(op->stage));
1335 
1336     if (new_use_color_key != old_use_color_key)
1337         device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1338 
1339     if (new_use_color_key)
1340         device_invalidate_state(cs->device, STATE_COLOR_KEY);
1341 }
1342 
1343 void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined3d_texture *texture)
1344 {
1345     struct wined3d_cs_set_texture *op;
1346 
1347     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1348     op->opcode = WINED3D_CS_OP_SET_TEXTURE;
1349     op->stage = stage;
1350     op->texture = texture;
1351 
1352     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1353 }
1354 
1355 static void wined3d_cs_exec_set_shader_resource_view(struct wined3d_cs *cs, const void *data)
1356 {
1357     const struct wined3d_cs_set_shader_resource_view *op = data;
1358     struct wined3d_shader_resource_view *prev;
1359 
1360     prev = cs->state.shader_resource_view[op->type][op->view_idx];
1361     cs->state.shader_resource_view[op->type][op->view_idx] = op->view;
1362 
1363     if (op->view)
1364         InterlockedIncrement(&op->view->resource->bind_count);
1365     if (prev)
1366         InterlockedDecrement(&prev->resource->bind_count);
1367 
1368     if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1369         device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1370     else
1371         device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1372 }
1373 
1374 void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3d_shader_type type,
1375         UINT view_idx, struct wined3d_shader_resource_view *view)
1376 {
1377     struct wined3d_cs_set_shader_resource_view *op;
1378 
1379     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1380     op->opcode = WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW;
1381     op->type = type;
1382     op->view_idx = view_idx;
1383     op->view = view;
1384 
1385     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1386 }
1387 
1388 static void wined3d_cs_exec_set_unordered_access_view(struct wined3d_cs *cs, const void *data)
1389 {
1390     const struct wined3d_cs_set_unordered_access_view *op = data;
1391     struct wined3d_unordered_access_view *prev;
1392 
1393     prev = cs->state.unordered_access_view[op->pipeline][op->view_idx];
1394     cs->state.unordered_access_view[op->pipeline][op->view_idx] = op->view;
1395 
1396     if (op->view)
1397         InterlockedIncrement(&op->view->resource->bind_count);
1398     if (prev)
1399         InterlockedDecrement(&prev->resource->bind_count);
1400 
1401     if (op->view && op->initial_count != ~0u)
1402         wined3d_unordered_access_view_set_counter(op->view, op->initial_count);
1403 
1404     device_invalidate_state(cs->device, STATE_UNORDERED_ACCESS_VIEW_BINDING(op->pipeline));
1405 }
1406 
1407 void wined3d_cs_emit_set_unordered_access_view(struct wined3d_cs *cs, enum wined3d_pipeline pipeline,
1408         unsigned int view_idx, struct wined3d_unordered_access_view *view, unsigned int initial_count)
1409 {
1410     struct wined3d_cs_set_unordered_access_view *op;
1411 
1412     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1413     op->opcode = WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW;
1414     op->pipeline = pipeline;
1415     op->view_idx = view_idx;
1416     op->view = view;
1417     op->initial_count = initial_count;
1418 
1419     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1420 }
1421 
1422 static void wined3d_cs_exec_set_sampler(struct wined3d_cs *cs, const void *data)
1423 {
1424     const struct wined3d_cs_set_sampler *op = data;
1425 
1426     cs->state.sampler[op->type][op->sampler_idx] = op->sampler;
1427     if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1428         device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1429     else
1430         device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1431 }
1432 
1433 void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type,
1434         UINT sampler_idx, struct wined3d_sampler *sampler)
1435 {
1436     struct wined3d_cs_set_sampler *op;
1437 
1438     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1439     op->opcode = WINED3D_CS_OP_SET_SAMPLER;
1440     op->type = type;
1441     op->sampler_idx = sampler_idx;
1442     op->sampler = sampler;
1443 
1444     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1445 }
1446 
1447 static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
1448 {
1449     const struct wined3d_cs_set_shader *op = data;
1450 
1451     cs->state.shader[op->type] = op->shader;
1452     device_invalidate_state(cs->device, STATE_SHADER(op->type));
1453     if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1454         device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1455     else
1456         device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1457 }
1458 
1459 void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader)
1460 {
1461     struct wined3d_cs_set_shader *op;
1462 
1463     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1464     op->opcode = WINED3D_CS_OP_SET_SHADER;
1465     op->type = type;
1466     op->shader = shader;
1467 
1468     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1469 }
1470 
1471 static void wined3d_cs_exec_set_blend_state(struct wined3d_cs *cs, const void *data)
1472 {
1473     const struct wined3d_cs_set_blend_state *op = data;
1474 
1475     cs->state.blend_state = op->state;
1476     device_invalidate_state(cs->device, STATE_BLEND);
1477 }
1478 
1479 void wined3d_cs_emit_set_blend_state(struct wined3d_cs *cs, struct wined3d_blend_state *state)
1480 {
1481     struct wined3d_cs_set_blend_state *op;
1482 
1483     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1484     op->opcode = WINED3D_CS_OP_SET_BLEND_STATE;
1485     op->state = state;
1486 
1487     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1488 }
1489 
1490 static void wined3d_cs_exec_set_rasterizer_state(struct wined3d_cs *cs, const void *data)
1491 {
1492     const struct wined3d_cs_set_rasterizer_state *op = data;
1493 
1494     cs->state.rasterizer_state = op->state;
1495     device_invalidate_state(cs->device, STATE_RASTERIZER);
1496 }
1497 
1498 void wined3d_cs_emit_set_rasterizer_state(struct wined3d_cs *cs,
1499         struct wined3d_rasterizer_state *rasterizer_state)
1500 {
1501     struct wined3d_cs_set_rasterizer_state *op;
1502 
1503     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1504     op->opcode = WINED3D_CS_OP_SET_RASTERIZER_STATE;
1505     op->state = rasterizer_state;
1506 
1507     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1508 }
1509 
1510 static void wined3d_cs_exec_set_render_state(struct wined3d_cs *cs, const void *data)
1511 {
1512     const struct wined3d_cs_set_render_state *op = data;
1513 
1514     cs->state.render_states[op->state] = op->value;
1515     device_invalidate_state(cs->device, STATE_RENDER(op->state));
1516 }
1517 
1518 void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render_state state, DWORD value)
1519 {
1520     struct wined3d_cs_set_render_state *op;
1521 
1522     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1523     op->opcode = WINED3D_CS_OP_SET_RENDER_STATE;
1524     op->state = state;
1525     op->value = value;
1526 
1527     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1528 }
1529 
1530 static void wined3d_cs_exec_set_texture_state(struct wined3d_cs *cs, const void *data)
1531 {
1532     const struct wined3d_cs_set_texture_state *op = data;
1533 
1534     cs->state.texture_states[op->stage][op->state] = op->value;
1535     device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, op->state));
1536 }
1537 
1538 void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage,
1539         enum wined3d_texture_stage_state state, DWORD value)
1540 {
1541     struct wined3d_cs_set_texture_state *op;
1542 
1543     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1544     op->opcode = WINED3D_CS_OP_SET_TEXTURE_STATE;
1545     op->stage = stage;
1546     op->state = state;
1547     op->value = value;
1548 
1549     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1550 }
1551 
1552 static void wined3d_cs_exec_set_sampler_state(struct wined3d_cs *cs, const void *data)
1553 {
1554     const struct wined3d_cs_set_sampler_state *op = data;
1555 
1556     cs->state.sampler_states[op->sampler_idx][op->state] = op->value;
1557     device_invalidate_state(cs->device, STATE_SAMPLER(op->sampler_idx));
1558 }
1559 
1560 void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx,
1561         enum wined3d_sampler_state state, DWORD value)
1562 {
1563     struct wined3d_cs_set_sampler_state *op;
1564 
1565     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1566     op->opcode = WINED3D_CS_OP_SET_SAMPLER_STATE;
1567     op->sampler_idx = sampler_idx;
1568     op->state = state;
1569     op->value = value;
1570 
1571     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1572 }
1573 
1574 static void wined3d_cs_exec_set_transform(struct wined3d_cs *cs, const void *data)
1575 {
1576     const struct wined3d_cs_set_transform *op = data;
1577 
1578     cs->state.transforms[op->state] = op->matrix;
1579     if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->d3d_info.limits.ffp_vertex_blend_matrices))
1580         device_invalidate_state(cs->device, STATE_TRANSFORM(op->state));
1581 }
1582 
1583 void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform_state state,
1584         const struct wined3d_matrix *matrix)
1585 {
1586     struct wined3d_cs_set_transform *op;
1587 
1588     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1589     op->opcode = WINED3D_CS_OP_SET_TRANSFORM;
1590     op->state = state;
1591     op->matrix = *matrix;
1592 
1593     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1594 }
1595 
1596 static void wined3d_cs_exec_set_clip_plane(struct wined3d_cs *cs, const void *data)
1597 {
1598     const struct wined3d_cs_set_clip_plane *op = data;
1599 
1600     cs->state.clip_planes[op->plane_idx] = op->plane;
1601     device_invalidate_state(cs->device, STATE_CLIPPLANE(op->plane_idx));
1602 }
1603 
1604 void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const struct wined3d_vec4 *plane)
1605 {
1606     struct wined3d_cs_set_clip_plane *op;
1607 
1608     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1609     op->opcode = WINED3D_CS_OP_SET_CLIP_PLANE;
1610     op->plane_idx = plane_idx;
1611     op->plane = *plane;
1612 
1613     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1614 }
1615 
1616 static void wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *data)
1617 {
1618     const struct wined3d_cs_set_color_key *op = data;
1619     struct wined3d_texture *texture = op->texture;
1620 
1621     if (op->set)
1622     {
1623         switch (op->flags)
1624         {
1625             case WINED3D_CKEY_DST_BLT:
1626                 texture->async.dst_blt_color_key = op->color_key;
1627                 texture->async.color_key_flags |= WINED3D_CKEY_DST_BLT;
1628                 break;
1629 
1630             case WINED3D_CKEY_DST_OVERLAY:
1631                 texture->async.dst_overlay_color_key = op->color_key;
1632                 texture->async.color_key_flags |= WINED3D_CKEY_DST_OVERLAY;
1633                 break;
1634 
1635             case WINED3D_CKEY_SRC_BLT:
1636                 if (texture == cs->state.textures[0])
1637                 {
1638                     device_invalidate_state(cs->device, STATE_COLOR_KEY);
1639                     if (!(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT))
1640                         device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1641                 }
1642 
1643                 texture->async.src_blt_color_key = op->color_key;
1644                 texture->async.color_key_flags |= WINED3D_CKEY_SRC_BLT;
1645                 break;
1646 
1647             case WINED3D_CKEY_SRC_OVERLAY:
1648                 texture->async.src_overlay_color_key = op->color_key;
1649                 texture->async.color_key_flags |= WINED3D_CKEY_SRC_OVERLAY;
1650                 break;
1651         }
1652     }
1653     else
1654     {
1655         switch (op->flags)
1656         {
1657             case WINED3D_CKEY_DST_BLT:
1658                 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_BLT;
1659                 break;
1660 
1661             case WINED3D_CKEY_DST_OVERLAY:
1662                 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_OVERLAY;
1663                 break;
1664 
1665             case WINED3D_CKEY_SRC_BLT:
1666                 if (texture == cs->state.textures[0] && texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1667                     device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1668 
1669                 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_BLT;
1670                 break;
1671 
1672             case WINED3D_CKEY_SRC_OVERLAY:
1673                 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_OVERLAY;
1674                 break;
1675         }
1676     }
1677 }
1678 
1679 void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture *texture,
1680         WORD flags, const struct wined3d_color_key *color_key)
1681 {
1682     struct wined3d_cs_set_color_key *op;
1683 
1684     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1685     op->opcode = WINED3D_CS_OP_SET_COLOR_KEY;
1686     op->texture = texture;
1687     op->flags = flags;
1688     if (color_key)
1689     {
1690         op->color_key = *color_key;
1691         op->set = 1;
1692     }
1693     else
1694         op->set = 0;
1695 
1696     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1697 }
1698 
1699 static void wined3d_cs_exec_set_material(struct wined3d_cs *cs, const void *data)
1700 {
1701     const struct wined3d_cs_set_material *op = data;
1702 
1703     cs->state.material = op->material;
1704     device_invalidate_state(cs->device, STATE_MATERIAL);
1705 }
1706 
1707 void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_material *material)
1708 {
1709     struct wined3d_cs_set_material *op;
1710 
1711     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1712     op->opcode = WINED3D_CS_OP_SET_MATERIAL;
1713     op->material = *material;
1714 
1715     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1716 }
1717 
1718 static void wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data)
1719 {
1720     const struct wined3d_cs_set_light *op = data;
1721     struct wined3d_light_info *light_info;
1722     unsigned int light_idx, hash_idx;
1723 
1724     light_idx = op->light.OriginalIndex;
1725 
1726     if (!(light_info = wined3d_state_get_light(&cs->state, light_idx)))
1727     {
1728         TRACE("Adding new light.\n");
1729         if (!(light_info = heap_alloc_zero(sizeof(*light_info))))
1730         {
1731             ERR("Failed to allocate light info.\n");
1732             return;
1733         }
1734 
1735         hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1736         list_add_head(&cs->state.light_map[hash_idx], &light_info->entry);
1737         light_info->glIndex = -1;
1738         light_info->OriginalIndex = light_idx;
1739     }
1740 
1741     if (light_info->glIndex != -1)
1742     {
1743         if (light_info->OriginalParms.type != op->light.OriginalParms.type)
1744             device_invalidate_state(cs->device, STATE_LIGHT_TYPE);
1745         device_invalidate_state(cs->device, STATE_ACTIVELIGHT(light_info->glIndex));
1746     }
1747 
1748     light_info->OriginalParms = op->light.OriginalParms;
1749     light_info->position = op->light.position;
1750     light_info->direction = op->light.direction;
1751     light_info->exponent = op->light.exponent;
1752     light_info->cutoff = op->light.cutoff;
1753 }
1754 
1755 void wined3d_cs_emit_set_light(struct wined3d_cs *cs, const struct wined3d_light_info *light)
1756 {
1757     struct wined3d_cs_set_light *op;
1758 
1759     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1760     op->opcode = WINED3D_CS_OP_SET_LIGHT;
1761     op->light = *light;
1762 
1763     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1764 }
1765 
1766 static void wined3d_cs_exec_set_light_enable(struct wined3d_cs *cs, const void *data)
1767 {
1768     const struct wined3d_cs_set_light_enable *op = data;
1769     struct wined3d_device *device = cs->device;
1770     struct wined3d_light_info *light_info;
1771     int prev_idx;
1772 
1773     if (!(light_info = wined3d_state_get_light(&cs->state, op->idx)))
1774     {
1775         ERR("Light doesn't exist.\n");
1776         return;
1777     }
1778 
1779     prev_idx = light_info->glIndex;
1780     wined3d_state_enable_light(&cs->state, &device->adapter->d3d_info, light_info, op->enable);
1781     if (light_info->glIndex != prev_idx)
1782     {
1783         device_invalidate_state(device, STATE_LIGHT_TYPE);
1784         device_invalidate_state(device, STATE_ACTIVELIGHT(op->enable ? light_info->glIndex : prev_idx));
1785     }
1786 }
1787 
1788 void wined3d_cs_emit_set_light_enable(struct wined3d_cs *cs, unsigned int idx, BOOL enable)
1789 {
1790     struct wined3d_cs_set_light_enable *op;
1791 
1792     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1793     op->opcode = WINED3D_CS_OP_SET_LIGHT_ENABLE;
1794     op->idx = idx;
1795     op->enable = enable;
1796 
1797     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1798 }
1799 
1800 static const struct
1801 {
1802     size_t offset;
1803     size_t size;
1804     DWORD mask;
1805 }
1806 wined3d_cs_push_constant_info[] =
1807 {
1808     /* WINED3D_PUSH_CONSTANTS_VS_F */
1809     {FIELD_OFFSET(struct wined3d_state, vs_consts_f), sizeof(struct wined3d_vec4),  WINED3D_SHADER_CONST_VS_F},
1810     /* WINED3D_PUSH_CONSTANTS_PS_F */
1811     {FIELD_OFFSET(struct wined3d_state, ps_consts_f), sizeof(struct wined3d_vec4),  WINED3D_SHADER_CONST_PS_F},
1812     /* WINED3D_PUSH_CONSTANTS_VS_I */
1813     {FIELD_OFFSET(struct wined3d_state, vs_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_VS_I},
1814     /* WINED3D_PUSH_CONSTANTS_PS_I */
1815     {FIELD_OFFSET(struct wined3d_state, ps_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_PS_I},
1816     /* WINED3D_PUSH_CONSTANTS_VS_B */
1817     {FIELD_OFFSET(struct wined3d_state, vs_consts_b), sizeof(BOOL),                 WINED3D_SHADER_CONST_VS_B},
1818     /* WINED3D_PUSH_CONSTANTS_PS_B */
1819     {FIELD_OFFSET(struct wined3d_state, ps_consts_b), sizeof(BOOL),                 WINED3D_SHADER_CONST_PS_B},
1820 };
1821 
1822 static void wined3d_cs_st_push_constants(struct wined3d_cs *cs, enum wined3d_push_constants p,
1823         unsigned int start_idx, unsigned int count, const void *constants)
1824 {
1825     struct wined3d_device *device = cs->device;
1826     unsigned int context_count;
1827     unsigned int i;
1828     size_t offset;
1829 
1830     if (p == WINED3D_PUSH_CONSTANTS_VS_F)
1831         device->shader_backend->shader_update_float_vertex_constants(device, start_idx, count);
1832     else if (p == WINED3D_PUSH_CONSTANTS_PS_F)
1833         device->shader_backend->shader_update_float_pixel_constants(device, start_idx, count);
1834 
1835     offset = wined3d_cs_push_constant_info[p].offset + start_idx * wined3d_cs_push_constant_info[p].size;
1836     memcpy((BYTE *)&cs->state + offset, constants, count * wined3d_cs_push_constant_info[p].size);
1837     for (i = 0, context_count = device->context_count; i < context_count; ++i)
1838     {
1839         device->contexts[i]->constant_update_mask |= wined3d_cs_push_constant_info[p].mask;
1840     }
1841 }
1842 
1843 static void wined3d_cs_exec_push_constants(struct wined3d_cs *cs, const void *data)
1844 {
1845     const struct wined3d_cs_push_constants *op = data;
1846 
1847     wined3d_cs_st_push_constants(cs, op->type, op->start_idx, op->count, op->constants);
1848 }
1849 
1850 static void wined3d_cs_mt_push_constants(struct wined3d_cs *cs, enum wined3d_push_constants p,
1851         unsigned int start_idx, unsigned int count, const void *constants)
1852 {
1853     struct wined3d_cs_push_constants *op;
1854     size_t size;
1855 
1856     size = count * wined3d_cs_push_constant_info[p].size;
1857     op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_push_constants, constants[size]),
1858             WINED3D_CS_QUEUE_DEFAULT);
1859     op->opcode = WINED3D_CS_OP_PUSH_CONSTANTS;
1860     op->type = p;
1861     op->start_idx = start_idx;
1862     op->count = count;
1863     memcpy(op->constants, constants, size);
1864 
1865     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1866 }
1867 
1868 static void wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data)
1869 {
1870     struct wined3d_adapter *adapter = cs->device->adapter;
1871 
1872     state_cleanup(&cs->state);
1873     memset(&cs->state, 0, sizeof(cs->state));
1874     state_init(&cs->state, &cs->fb, &adapter->gl_info, &adapter->d3d_info,
1875             WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT);
1876 }
1877 
1878 void wined3d_cs_emit_reset_state(struct wined3d_cs *cs)
1879 {
1880     struct wined3d_cs_reset_state *op;
1881 
1882     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1883     op->opcode = WINED3D_CS_OP_RESET_STATE;
1884 
1885     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1886 }
1887 
1888 static void wined3d_cs_exec_callback(struct wined3d_cs *cs, const void *data)
1889 {
1890     const struct wined3d_cs_callback *op = data;
1891 
1892     op->callback(op->object);
1893 }
1894 
1895 static void wined3d_cs_emit_callback(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1896 {
1897     struct wined3d_cs_callback *op;
1898 
1899     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1900     op->opcode = WINED3D_CS_OP_CALLBACK;
1901     op->callback = callback;
1902     op->object = object;
1903 
1904     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1905 }
1906 
1907 void wined3d_cs_destroy_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1908 {
1909     wined3d_cs_emit_callback(cs, callback, object);
1910 }
1911 
1912 void wined3d_cs_init_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1913 {
1914     wined3d_cs_emit_callback(cs, callback, object);
1915 }
1916 
1917 static void wined3d_cs_exec_query_issue(struct wined3d_cs *cs, const void *data)
1918 {
1919     const struct wined3d_cs_query_issue *op = data;
1920     struct wined3d_query *query = op->query;
1921     BOOL poll;
1922 
1923     poll = query->query_ops->query_issue(query, op->flags);
1924 
1925     if (!cs->thread)
1926         return;
1927 
1928     if (poll && list_empty(&query->poll_list_entry))
1929     {
1930         list_add_tail(&cs->query_poll_list, &query->poll_list_entry);
1931         return;
1932     }
1933 
1934     /* This can happen if occlusion queries are restarted. This discards the
1935      * old result, since polling it could result in a GL error. */
1936     if ((op->flags & WINED3DISSUE_BEGIN) && !poll && !list_empty(&query->poll_list_entry))
1937     {
1938         list_remove(&query->poll_list_entry);
1939         list_init(&query->poll_list_entry);
1940         InterlockedIncrement(&query->counter_retrieved);
1941         return;
1942     }
1943 
1944     /* This can happen when an occlusion query is ended without being started,
1945      * in which case we don't want to poll, but still have to counter-balance
1946      * the increment of the main counter.
1947      *
1948      * This can also happen if an event query is re-issued before the first
1949      * fence was reached. In this case the query is already in the list and
1950      * the poll function will check the new fence. We have to counter-balance
1951      * the discarded increment. */
1952     if (op->flags & WINED3DISSUE_END)
1953         InterlockedIncrement(&query->counter_retrieved);
1954 }
1955 
1956 void wined3d_cs_emit_query_issue(struct wined3d_cs *cs, struct wined3d_query *query, DWORD flags)
1957 {
1958     struct wined3d_cs_query_issue *op;
1959 
1960     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1961     op->opcode = WINED3D_CS_OP_QUERY_ISSUE;
1962     op->query = query;
1963     op->flags = flags;
1964 
1965     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1966     cs->queries_flushed = FALSE;
1967 }
1968 
1969 static void wined3d_cs_exec_preload_resource(struct wined3d_cs *cs, const void *data)
1970 {
1971     const struct wined3d_cs_preload_resource *op = data;
1972     struct wined3d_resource *resource = op->resource;
1973 
1974     resource->resource_ops->resource_preload(resource);
1975     wined3d_resource_release(resource);
1976 }
1977 
1978 void wined3d_cs_emit_preload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
1979 {
1980     struct wined3d_cs_preload_resource *op;
1981 
1982     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1983     op->opcode = WINED3D_CS_OP_PRELOAD_RESOURCE;
1984     op->resource = resource;
1985 
1986     wined3d_resource_acquire(resource);
1987 
1988     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1989 }
1990 
1991 static void wined3d_cs_exec_unload_resource(struct wined3d_cs *cs, const void *data)
1992 {
1993     const struct wined3d_cs_unload_resource *op = data;
1994     struct wined3d_resource *resource = op->resource;
1995 
1996     resource->resource_ops->resource_unload(resource);
1997     wined3d_resource_release(resource);
1998 }
1999 
2000 void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
2001 {
2002     struct wined3d_cs_unload_resource *op;
2003 
2004     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2005     op->opcode = WINED3D_CS_OP_UNLOAD_RESOURCE;
2006     op->resource = resource;
2007 
2008     wined3d_resource_acquire(resource);
2009 
2010     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2011 }
2012 
2013 static void wined3d_cs_exec_map(struct wined3d_cs *cs, const void *data)
2014 {
2015     const struct wined3d_cs_map *op = data;
2016     struct wined3d_resource *resource = op->resource;
2017 
2018     *op->hr = resource->resource_ops->resource_sub_resource_map(resource,
2019             op->sub_resource_idx, op->map_desc, op->box, op->flags);
2020 }
2021 
2022 HRESULT wined3d_cs_map(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx,
2023         struct wined3d_map_desc *map_desc, const struct wined3d_box *box, unsigned int flags)
2024 {
2025     struct wined3d_cs_map *op;
2026     HRESULT hr;
2027 
2028     /* Mapping resources from the worker thread isn't an issue by itself, but
2029      * increasing the map count would be visible to applications. */
2030     wined3d_not_from_cs(cs);
2031 
2032     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2033     op->opcode = WINED3D_CS_OP_MAP;
2034     op->resource = resource;
2035     op->sub_resource_idx = sub_resource_idx;
2036     op->map_desc = map_desc;
2037     op->box = box;
2038     op->flags = flags;
2039     op->hr = &hr;
2040 
2041     cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2042     cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2043 
2044     return hr;
2045 }
2046 
2047 static void wined3d_cs_exec_unmap(struct wined3d_cs *cs, const void *data)
2048 {
2049     const struct wined3d_cs_unmap *op = data;
2050     struct wined3d_resource *resource = op->resource;
2051 
2052     *op->hr = resource->resource_ops->resource_sub_resource_unmap(resource, op->sub_resource_idx);
2053 }
2054 
2055 HRESULT wined3d_cs_unmap(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx)
2056 {
2057     struct wined3d_cs_unmap *op;
2058     HRESULT hr;
2059 
2060     wined3d_not_from_cs(cs);
2061 
2062     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2063     op->opcode = WINED3D_CS_OP_UNMAP;
2064     op->resource = resource;
2065     op->sub_resource_idx = sub_resource_idx;
2066     op->hr = &hr;
2067 
2068     cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2069     cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2070 
2071     return hr;
2072 }
2073 
2074 static void wined3d_cs_exec_blt_sub_resource(struct wined3d_cs *cs, const void *data)
2075 {
2076     const struct wined3d_cs_blt_sub_resource *op = data;
2077 
2078     if (op->dst_resource->type == WINED3D_RTYPE_BUFFER)
2079     {
2080         wined3d_buffer_copy(buffer_from_resource(op->dst_resource), op->dst_box.left,
2081                 buffer_from_resource(op->src_resource), op->src_box.left,
2082                 op->src_box.right - op->src_box.left);
2083     }
2084     else if (op->dst_resource->type == WINED3D_RTYPE_TEXTURE_3D)
2085     {
2086         struct wined3d_texture *src_texture, *dst_texture;
2087         unsigned int level, update_w, update_h, update_d;
2088         unsigned int row_pitch, slice_pitch;
2089         struct wined3d_context *context;
2090         struct wined3d_bo_address addr;
2091 
2092         if (op->flags & ~WINED3D_BLT_RAW)
2093         {
2094             FIXME("Flags %#x not implemented for %s resources.\n",
2095                     op->flags, debug_d3dresourcetype(op->dst_resource->type));
2096             goto error;
2097         }
2098 
2099         if (!(op->flags & WINED3D_BLT_RAW) && op->src_resource->format != op->dst_resource->format)
2100         {
2101             FIXME("Format conversion not implemented for %s resources.\n",
2102                     debug_d3dresourcetype(op->dst_resource->type));
2103             goto error;
2104         }
2105 
2106         update_w = op->dst_box.right - op->dst_box.left;
2107         update_h = op->dst_box.bottom - op->dst_box.top;
2108         update_d = op->dst_box.back - op->dst_box.front;
2109         if (op->src_box.right - op->src_box.left != update_w
2110                 || op->src_box.bottom - op->src_box.top != update_h
2111                 || op->src_box.back - op->src_box.front != update_d)
2112         {
2113             FIXME("Stretching not implemented for %s resources.\n",
2114                     debug_d3dresourcetype(op->dst_resource->type));
2115             goto error;
2116         }
2117 
2118         dst_texture = texture_from_resource(op->dst_resource);
2119         src_texture = texture_from_resource(op->src_resource);
2120 
2121         context = context_acquire(cs->device, NULL, 0);
2122 
2123         if (!wined3d_texture_load_location(src_texture, op->src_sub_resource_idx,
2124                 context, src_texture->resource.map_binding))
2125         {
2126             ERR("Failed to load source sub-resource into %s.\n",
2127                     wined3d_debug_location(src_texture->resource.map_binding));
2128             context_release(context);
2129             goto error;
2130         }
2131 
2132         level = op->dst_sub_resource_idx % dst_texture->level_count;
2133         if (update_w == wined3d_texture_get_level_width(dst_texture, level)
2134                 && update_h == wined3d_texture_get_level_height(dst_texture, level)
2135                 && update_d == wined3d_texture_get_level_depth(dst_texture, level))
2136         {
2137             wined3d_texture_prepare_texture(dst_texture, context, FALSE);
2138         }
2139         else if (!wined3d_texture_load_location(dst_texture, op->dst_sub_resource_idx,
2140                 context, WINED3D_LOCATION_TEXTURE_RGB))
2141         {
2142             ERR("Failed to load destination sub-resource.\n");
2143             context_release(context);
2144             goto error;
2145         }
2146 
2147         wined3d_texture_get_memory(src_texture, op->src_sub_resource_idx, &addr, src_texture->resource.map_binding);
2148         wined3d_texture_get_pitch(src_texture, op->src_sub_resource_idx % src_texture->level_count,
2149                 &row_pitch, &slice_pitch);
2150 
2151         wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
2152         wined3d_texture_upload_data(dst_texture, op->dst_sub_resource_idx, context,
2153                 dst_texture->resource.format, &op->src_box, wined3d_const_bo_address(&addr),
2154                 row_pitch, slice_pitch, op->dst_box.left, op->dst_box.top, op->dst_box.front, FALSE);
2155         wined3d_texture_validate_location(dst_texture, op->dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2156         wined3d_texture_invalidate_location(dst_texture, op->dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2157 
2158         context_release(context);
2159     }
2160     else
2161     {
2162         if (FAILED(texture2d_blt(texture_from_resource(op->dst_resource), op->dst_sub_resource_idx,
2163                 &op->dst_box, texture_from_resource(op->src_resource), op->src_sub_resource_idx,
2164                 &op->src_box, op->flags, &op->fx, op->filter)))
2165             FIXME("Blit failed.\n");
2166     }
2167 
2168 error:
2169     if (op->src_resource)
2170         wined3d_resource_release(op->src_resource);
2171     wined3d_resource_release(op->dst_resource);
2172 }
2173 
2174 void wined3d_cs_emit_blt_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *dst_resource,
2175         unsigned int dst_sub_resource_idx, const struct wined3d_box *dst_box, struct wined3d_resource *src_resource,
2176         unsigned int src_sub_resource_idx, const struct wined3d_box *src_box, DWORD flags,
2177         const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2178 {
2179     struct wined3d_cs_blt_sub_resource *op;
2180 
2181     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2182     op->opcode = WINED3D_CS_OP_BLT_SUB_RESOURCE;
2183     op->dst_resource = dst_resource;
2184     op->dst_sub_resource_idx = dst_sub_resource_idx;
2185     op->dst_box = *dst_box;
2186     op->src_resource = src_resource;
2187     op->src_sub_resource_idx = src_sub_resource_idx;
2188     op->src_box = *src_box;
2189     op->flags = flags;
2190     if (fx)
2191         op->fx = *fx;
2192     else
2193         memset(&op->fx, 0, sizeof(op->fx));
2194     op->filter = filter;
2195 
2196     wined3d_resource_acquire(dst_resource);
2197     if (src_resource)
2198         wined3d_resource_acquire(src_resource);
2199 
2200     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2201     if (flags & WINED3D_BLT_SYNCHRONOUS)
2202         cs->ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT);
2203 }
2204 
2205 static void wined3d_cs_exec_update_sub_resource(struct wined3d_cs *cs, const void *data)
2206 {
2207     const struct wined3d_cs_update_sub_resource *op = data;
2208     struct wined3d_resource *resource = op->resource;
2209     const struct wined3d_box *box = &op->box;
2210     unsigned int width, height, depth, level;
2211     struct wined3d_const_bo_address addr;
2212     struct wined3d_context *context;
2213     struct wined3d_texture *texture;
2214     struct wined3d_box src_box;
2215 
2216     context = context_acquire(cs->device, NULL, 0);
2217 
2218     if (resource->type == WINED3D_RTYPE_BUFFER)
2219     {
2220         struct wined3d_buffer *buffer = buffer_from_resource(resource);
2221 
2222         if (!wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER))
2223         {
2224             ERR("Failed to load buffer location.\n");
2225             goto done;
2226         }
2227 
2228         wined3d_buffer_upload_data(buffer, context, box, op->data.data);
2229         wined3d_buffer_invalidate_location(buffer, ~WINED3D_LOCATION_BUFFER);
2230         goto done;
2231     }
2232 
2233     texture = wined3d_texture_from_resource(resource);
2234 
2235     level = op->sub_resource_idx % texture->level_count;
2236     width = wined3d_texture_get_level_width(texture, level);
2237     height = wined3d_texture_get_level_height(texture, level);
2238     depth = wined3d_texture_get_level_depth(texture, level);
2239 
2240     addr.buffer_object = 0;
2241     addr.addr = op->data.data;
2242 
2243     /* Only load the sub-resource for partial updates. */
2244     if (!box->left && !box->top && !box->front
2245             && box->right == width && box->bottom == height && box->back == depth)
2246         wined3d_texture_prepare_texture(texture, context, FALSE);
2247     else
2248         wined3d_texture_load_location(texture, op->sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2249     wined3d_texture_bind_and_dirtify(texture, context, FALSE);
2250 
2251     wined3d_box_set(&src_box, 0, 0, box->right - box->left, box->bottom - box->top, 0, box->back - box->front);
2252     wined3d_texture_upload_data(texture, op->sub_resource_idx, context, texture->resource.format, &src_box,
2253             &addr, op->data.row_pitch, op->data.slice_pitch, box->left, box->top, box->front, FALSE);
2254 
2255     wined3d_texture_validate_location(texture, op->sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2256     wined3d_texture_invalidate_location(texture, op->sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2257 
2258 done:
2259     context_release(context);
2260 
2261     wined3d_resource_release(resource);
2262 }
2263 
2264 void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource,
2265         unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch,
2266         unsigned int slice_pitch)
2267 {
2268     struct wined3d_cs_update_sub_resource *op;
2269     size_t data_size, size;
2270 
2271     if (resource->type != WINED3D_RTYPE_BUFFER && resource->format_flags & WINED3DFMT_FLAG_BLOCKS)
2272         goto no_async;
2273 
2274     data_size = 0;
2275     switch (resource->type)
2276     {
2277         case WINED3D_RTYPE_TEXTURE_3D:
2278             data_size += (box->back - box->front - 1) * slice_pitch;
2279             /* fall-through */
2280         case WINED3D_RTYPE_TEXTURE_2D:
2281             data_size += (box->bottom - box->top - 1) * row_pitch;
2282             /* fall-through */
2283         case WINED3D_RTYPE_TEXTURE_1D:
2284             data_size += (box->right - box->left) * resource->format->byte_count;
2285             break;
2286         case WINED3D_RTYPE_BUFFER:
2287             data_size = box->right - box->left;
2288             break;
2289         case WINED3D_RTYPE_NONE:
2290             return;
2291     }
2292 
2293     size = FIELD_OFFSET(struct wined3d_cs_update_sub_resource, copy_data[data_size]);
2294     if (!cs->ops->check_space(cs, size, WINED3D_CS_QUEUE_DEFAULT))
2295         goto no_async;
2296 
2297     op = cs->ops->require_space(cs, size, WINED3D_CS_QUEUE_DEFAULT);
2298     op->opcode = WINED3D_CS_OP_UPDATE_SUB_RESOURCE;
2299     op->resource = resource;
2300     op->sub_resource_idx = sub_resource_idx;
2301     op->box = *box;
2302     op->data.row_pitch = row_pitch;
2303     op->data.slice_pitch = slice_pitch;
2304     op->data.data = op->copy_data;
2305     memcpy(op->copy_data, data, data_size);
2306 
2307     wined3d_resource_acquire(resource);
2308 
2309     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2310     return;
2311 
2312 no_async:
2313     wined3d_resource_wait_idle(resource);
2314 
2315     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2316     op->opcode = WINED3D_CS_OP_UPDATE_SUB_RESOURCE;
2317     op->resource = resource;
2318     op->sub_resource_idx = sub_resource_idx;
2319     op->box = *box;
2320     op->data.row_pitch = row_pitch;
2321     op->data.slice_pitch = slice_pitch;
2322     op->data.data = data;
2323 
2324     wined3d_resource_acquire(resource);
2325 
2326     cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2327     cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2328 }
2329 
2330 static void wined3d_cs_exec_add_dirty_texture_region(struct wined3d_cs *cs, const void *data)
2331 {
2332     const struct wined3d_cs_add_dirty_texture_region *op = data;
2333     struct wined3d_texture *texture = op->texture;
2334     unsigned int sub_resource_idx, i;
2335     struct wined3d_context *context;
2336 
2337     context = context_acquire(cs->device, NULL, 0);
2338     sub_resource_idx = op->layer * texture->level_count;
2339     for (i = 0; i < texture->level_count; ++i, ++sub_resource_idx)
2340     {
2341         if (wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding))
2342             wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
2343         else
2344             ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
2345     }
2346     context_release(context);
2347 
2348     wined3d_resource_release(&texture->resource);
2349 }
2350 
2351 void wined3d_cs_emit_add_dirty_texture_region(struct wined3d_cs *cs,
2352         struct wined3d_texture *texture, unsigned int layer)
2353 {
2354     struct wined3d_cs_add_dirty_texture_region *op;
2355 
2356     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2357     op->opcode = WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION;
2358     op->texture = texture;
2359     op->layer = layer;
2360 
2361     wined3d_resource_acquire(&texture->resource);
2362 
2363     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2364 }
2365 
2366 static void wined3d_cs_exec_clear_unordered_access_view(struct wined3d_cs *cs, const void *data)
2367 {
2368     const struct wined3d_cs_clear_unordered_access_view *op = data;
2369     struct wined3d_unordered_access_view *view = op->view;
2370     struct wined3d_context *context;
2371 
2372     context = context_acquire(cs->device, NULL, 0);
2373     wined3d_unordered_access_view_clear_uint(view, &op->clear_value, context);
2374     context_release(context);
2375 
2376     wined3d_resource_release(view->resource);
2377 }
2378 
2379 void wined3d_cs_emit_clear_unordered_access_view_uint(struct wined3d_cs *cs,
2380         struct wined3d_unordered_access_view *view, const struct wined3d_uvec4 *clear_value)
2381 {
2382     struct wined3d_cs_clear_unordered_access_view *op;
2383 
2384     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2385     op->opcode = WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW;
2386     op->view = view;
2387     op->clear_value = *clear_value;
2388 
2389     wined3d_resource_acquire(view->resource);
2390 
2391     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2392 }
2393 
2394 static void wined3d_cs_exec_copy_uav_counter(struct wined3d_cs *cs, const void *data)
2395 {
2396     const struct wined3d_cs_copy_uav_counter *op = data;
2397     struct wined3d_unordered_access_view *view = op->view;
2398     struct wined3d_context *context;
2399 
2400     context = context_acquire(cs->device, NULL, 0);
2401     wined3d_unordered_access_view_copy_counter(view, op->buffer, op->offset, context);
2402     context_release(context);
2403 
2404     wined3d_resource_release(&op->buffer->resource);
2405     wined3d_resource_release(view->resource);
2406 }
2407 
2408 void wined3d_cs_emit_copy_uav_counter(struct wined3d_cs *cs, struct wined3d_buffer *dst_buffer,
2409         unsigned int offset, struct wined3d_unordered_access_view *uav)
2410 {
2411     struct wined3d_cs_copy_uav_counter *op;
2412 
2413     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2414     op->opcode = WINED3D_CS_OP_COPY_UAV_COUNTER;
2415     op->buffer = dst_buffer;
2416     op->offset = offset;
2417     op->view = uav;
2418 
2419     wined3d_resource_acquire(&dst_buffer->resource);
2420     wined3d_resource_acquire(uav->resource);
2421 
2422     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2423 }
2424 
2425 static void wined3d_cs_exec_generate_mipmaps(struct wined3d_cs *cs, const void *data)
2426 {
2427     const struct wined3d_cs_generate_mipmaps *op = data;
2428     struct wined3d_shader_resource_view *view = op->view;
2429 
2430     shader_resource_view_generate_mipmaps(view);
2431     wined3d_resource_release(view->resource);
2432 }
2433 
2434 void wined3d_cs_emit_generate_mipmaps(struct wined3d_cs *cs, struct wined3d_shader_resource_view *view)
2435 {
2436     struct wined3d_cs_generate_mipmaps *op;
2437 
2438     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2439     op->opcode = WINED3D_CS_OP_GENERATE_MIPMAPS;
2440     op->view = view;
2441 
2442     wined3d_resource_acquire(view->resource);
2443 
2444     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2445 }
2446 
2447 static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
2448 {
2449     struct wined3d_cs_stop *op;
2450 
2451     op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2452     op->opcode = WINED3D_CS_OP_STOP;
2453 
2454     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2455     cs->ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT);
2456 }
2457 
2458 static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
2459 {
2460     /* WINED3D_CS_OP_NOP                         */ wined3d_cs_exec_nop,
2461     /* WINED3D_CS_OP_PRESENT                     */ wined3d_cs_exec_present,
2462     /* WINED3D_CS_OP_CLEAR                       */ wined3d_cs_exec_clear,
2463     /* WINED3D_CS_OP_DISPATCH                    */ wined3d_cs_exec_dispatch,
2464     /* WINED3D_CS_OP_DRAW                        */ wined3d_cs_exec_draw,
2465     /* WINED3D_CS_OP_FLUSH                       */ wined3d_cs_exec_flush,
2466     /* WINED3D_CS_OP_SET_PREDICATION             */ wined3d_cs_exec_set_predication,
2467     /* WINED3D_CS_OP_SET_VIEWPORTS               */ wined3d_cs_exec_set_viewports,
2468     /* WINED3D_CS_OP_SET_SCISSOR_RECTS           */ wined3d_cs_exec_set_scissor_rects,
2469     /* WINED3D_CS_OP_SET_RENDERTARGET_VIEW       */ wined3d_cs_exec_set_rendertarget_view,
2470     /* WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW      */ wined3d_cs_exec_set_depth_stencil_view,
2471     /* WINED3D_CS_OP_SET_VERTEX_DECLARATION      */ wined3d_cs_exec_set_vertex_declaration,
2472     /* WINED3D_CS_OP_SET_STREAM_SOURCE           */ wined3d_cs_exec_set_stream_source,
2473     /* WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ      */ wined3d_cs_exec_set_stream_source_freq,
2474     /* WINED3D_CS_OP_SET_STREAM_OUTPUT           */ wined3d_cs_exec_set_stream_output,
2475     /* WINED3D_CS_OP_SET_INDEX_BUFFER            */ wined3d_cs_exec_set_index_buffer,
2476     /* WINED3D_CS_OP_SET_CONSTANT_BUFFER         */ wined3d_cs_exec_set_constant_buffer,
2477     /* WINED3D_CS_OP_SET_TEXTURE                 */ wined3d_cs_exec_set_texture,
2478     /* WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW    */ wined3d_cs_exec_set_shader_resource_view,
2479     /* WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW   */ wined3d_cs_exec_set_unordered_access_view,
2480     /* WINED3D_CS_OP_SET_SAMPLER                 */ wined3d_cs_exec_set_sampler,
2481     /* WINED3D_CS_OP_SET_SHADER                  */ wined3d_cs_exec_set_shader,
2482     /* WINED3D_CS_OP_SET_BLEND_STATE             */ wined3d_cs_exec_set_blend_state,
2483     /* WINED3D_CS_OP_SET_RASTERIZER_STATE        */ wined3d_cs_exec_set_rasterizer_state,
2484     /* WINED3D_CS_OP_SET_RENDER_STATE            */ wined3d_cs_exec_set_render_state,
2485     /* WINED3D_CS_OP_SET_TEXTURE_STATE           */ wined3d_cs_exec_set_texture_state,
2486     /* WINED3D_CS_OP_SET_SAMPLER_STATE           */ wined3d_cs_exec_set_sampler_state,
2487     /* WINED3D_CS_OP_SET_TRANSFORM               */ wined3d_cs_exec_set_transform,
2488     /* WINED3D_CS_OP_SET_CLIP_PLANE              */ wined3d_cs_exec_set_clip_plane,
2489     /* WINED3D_CS_OP_SET_COLOR_KEY               */ wined3d_cs_exec_set_color_key,
2490     /* WINED3D_CS_OP_SET_MATERIAL                */ wined3d_cs_exec_set_material,
2491     /* WINED3D_CS_OP_SET_LIGHT                   */ wined3d_cs_exec_set_light,
2492     /* WINED3D_CS_OP_SET_LIGHT_ENABLE            */ wined3d_cs_exec_set_light_enable,
2493     /* WINED3D_CS_OP_PUSH_CONSTANTS              */ wined3d_cs_exec_push_constants,
2494     /* WINED3D_CS_OP_RESET_STATE                 */ wined3d_cs_exec_reset_state,
2495     /* WINED3D_CS_OP_CALLBACK                    */ wined3d_cs_exec_callback,
2496     /* WINED3D_CS_OP_QUERY_ISSUE                 */ wined3d_cs_exec_query_issue,
2497     /* WINED3D_CS_OP_PRELOAD_RESOURCE            */ wined3d_cs_exec_preload_resource,
2498     /* WINED3D_CS_OP_UNLOAD_RESOURCE             */ wined3d_cs_exec_unload_resource,
2499     /* WINED3D_CS_OP_MAP                         */ wined3d_cs_exec_map,
2500     /* WINED3D_CS_OP_UNMAP                       */ wined3d_cs_exec_unmap,
2501     /* WINED3D_CS_OP_BLT_SUB_RESOURCE            */ wined3d_cs_exec_blt_sub_resource,
2502     /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE         */ wined3d_cs_exec_update_sub_resource,
2503     /* WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION    */ wined3d_cs_exec_add_dirty_texture_region,
2504     /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view,
2505     /* WINED3D_CS_OP_COPY_UAV_COUNTER            */ wined3d_cs_exec_copy_uav_counter,
2506     /* WINED3D_CS_OP_GENERATE_MIPMAPS            */ wined3d_cs_exec_generate_mipmaps,
2507 };
2508 
2509 static BOOL wined3d_cs_st_check_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2510 {
2511     return TRUE;
2512 }
2513 
2514 static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2515 {
2516     if (size > (cs->data_size - cs->end))
2517     {
2518         size_t new_size;
2519         void *new_data;
2520 
2521         new_size = max(size, cs->data_size * 2);
2522         if (!cs->end)
2523             new_data = heap_realloc(cs->data, new_size);
2524         else
2525             new_data = heap_alloc(new_size);
2526         if (!new_data)
2527             return NULL;
2528 
2529         cs->data_size = new_size;
2530         cs->start = cs->end = 0;
2531         cs->data = new_data;
2532     }
2533 
2534     cs->end += size;
2535 
2536     return (BYTE *)cs->data + cs->start;
2537 }
2538 
2539 static void wined3d_cs_st_submit(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2540 {
2541     enum wined3d_cs_op opcode;
2542     size_t start;
2543     BYTE *data;
2544 
2545     data = cs->data;
2546     start = cs->start;
2547     cs->start = cs->end;
2548 
2549     opcode = *(const enum wined3d_cs_op *)&data[start];
2550     if (opcode >= WINED3D_CS_OP_STOP)
2551         ERR("Invalid opcode %#x.\n", opcode);
2552     else
2553         wined3d_cs_op_handlers[opcode](cs, &data[start]);
2554 
2555     if (cs->data == data)
2556         cs->start = cs->end = start;
2557     else if (!start)
2558         heap_free(data);
2559 }
2560 
2561 static void wined3d_cs_st_finish(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2562 {
2563 }
2564 
2565 static const struct wined3d_cs_ops wined3d_cs_st_ops =
2566 {
2567     wined3d_cs_st_check_space,
2568     wined3d_cs_st_require_space,
2569     wined3d_cs_st_submit,
2570     wined3d_cs_st_finish,
2571     wined3d_cs_st_push_constants,
2572 };
2573 
2574 static BOOL wined3d_cs_queue_is_empty(const struct wined3d_cs *cs, const struct wined3d_cs_queue *queue)
2575 {
2576     wined3d_from_cs(cs);
2577     return *(volatile LONG *)&queue->head == queue->tail;
2578 }
2579 
2580 static void wined3d_cs_queue_submit(struct wined3d_cs_queue *queue, struct wined3d_cs *cs)
2581 {
2582     struct wined3d_cs_packet *packet;
2583     size_t packet_size;
2584 
2585     packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
2586     packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[packet->size]);
2587     InterlockedExchange(&queue->head, (queue->head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1));
2588 
2589     if (InterlockedCompareExchange(&cs->waiting_for_event, FALSE, TRUE))
2590         SetEvent(cs->event);
2591 }
2592 
2593 static void wined3d_cs_mt_submit(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2594 {
2595     if (cs->thread_id == GetCurrentThreadId())
2596     {
2597         wined3d_cs_st_submit(cs, queue_id);
2598         return;
2599     }
2600 
2601     wined3d_cs_queue_submit(&cs->queue[queue_id], cs);
2602 }
2603 
2604 static BOOL wined3d_cs_queue_check_space(struct wined3d_cs_queue *queue, size_t size)
2605 {
2606     size_t queue_size = ARRAY_SIZE(queue->data);
2607     size_t header_size, packet_size, remaining;
2608 
2609     header_size = FIELD_OFFSET(struct wined3d_cs_packet, data[0]);
2610     size = (size + header_size - 1) & ~(header_size - 1);
2611     packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[size]);
2612 
2613     remaining = queue_size - queue->head;
2614     return (remaining >= packet_size);
2615 }
2616 
2617 static void *wined3d_cs_queue_require_space(struct wined3d_cs_queue *queue, size_t size, struct wined3d_cs *cs)
2618 {
2619     size_t queue_size = ARRAY_SIZE(queue->data);
2620     size_t header_size, packet_size, remaining;
2621     struct wined3d_cs_packet *packet;
2622 
2623     header_size = FIELD_OFFSET(struct wined3d_cs_packet, data[0]);
2624     size = (size + header_size - 1) & ~(header_size - 1);
2625     packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[size]);
2626     if (packet_size >= WINED3D_CS_QUEUE_SIZE)
2627     {
2628         ERR("Packet size %lu >= queue size %u.\n",
2629                 (unsigned long)packet_size, WINED3D_CS_QUEUE_SIZE);
2630         return NULL;
2631     }
2632 
2633     remaining = queue_size - queue->head;
2634     if (remaining < packet_size)
2635     {
2636         size_t nop_size = remaining - header_size;
2637         struct wined3d_cs_nop *nop;
2638 
2639         TRACE("Inserting a nop for %lu + %lu bytes.\n",
2640                 (unsigned long)header_size, (unsigned long)nop_size);
2641 
2642         nop = wined3d_cs_queue_require_space(queue, nop_size, cs);
2643         if (nop_size)
2644             nop->opcode = WINED3D_CS_OP_NOP;
2645 
2646         wined3d_cs_queue_submit(queue, cs);
2647         assert(!queue->head);
2648     }
2649 
2650     for (;;)
2651     {
2652         LONG tail = *(volatile LONG *)&queue->tail;
2653         LONG head = queue->head;
2654         LONG new_pos;
2655 
2656         /* Empty. */
2657         if (head == tail)
2658             break;
2659         new_pos = (head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1);
2660         /* Head ahead of tail. We checked the remaining size above, so we only
2661          * need to make sure we don't make head equal to tail. */
2662         if (head > tail && (new_pos != tail))
2663             break;
2664         /* Tail ahead of head. Make sure the new head is before the tail as
2665          * well. Note that new_pos is 0 when it's at the end of the queue. */
2666         if (new_pos < tail && new_pos)
2667             break;
2668 
2669         TRACE("Waiting for free space. Head %u, tail %u, packet size %lu.\n",
2670                 head, tail, (unsigned long)packet_size);
2671     }
2672 
2673     packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
2674     packet->size = size;
2675     return packet->data;
2676 }
2677 
2678 static BOOL wined3d_cs_mt_check_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2679 {
2680     if (cs->thread_id == GetCurrentThreadId())
2681         return wined3d_cs_st_check_space(cs, size, queue_id);
2682 
2683     return wined3d_cs_queue_check_space(&cs->queue[queue_id], size);
2684 }
2685 
2686 static void *wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2687 {
2688     if (cs->thread_id == GetCurrentThreadId())
2689         return wined3d_cs_st_require_space(cs, size, queue_id);
2690 
2691     return wined3d_cs_queue_require_space(&cs->queue[queue_id], size, cs);
2692 }
2693 
2694 static void wined3d_cs_mt_finish(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2695 {
2696     if (cs->thread_id == GetCurrentThreadId())
2697     {
2698         wined3d_cs_st_finish(cs, queue_id);
2699         return;
2700     }
2701 
2702     while (cs->queue[queue_id].head != *(volatile LONG *)&cs->queue[queue_id].tail)
2703         wined3d_pause();
2704 }
2705 
2706 static const struct wined3d_cs_ops wined3d_cs_mt_ops =
2707 {
2708     wined3d_cs_mt_check_space,
2709     wined3d_cs_mt_require_space,
2710     wined3d_cs_mt_submit,
2711     wined3d_cs_mt_finish,
2712     wined3d_cs_mt_push_constants,
2713 };
2714 
2715 static void poll_queries(struct wined3d_cs *cs)
2716 {
2717     struct wined3d_query *query, *cursor;
2718 
2719     LIST_FOR_EACH_ENTRY_SAFE(query, cursor, &cs->query_poll_list, struct wined3d_query, poll_list_entry)
2720     {
2721         if (!query->query_ops->query_poll(query, 0))
2722             continue;
2723 
2724         list_remove(&query->poll_list_entry);
2725         list_init(&query->poll_list_entry);
2726         InterlockedIncrement(&query->counter_retrieved);
2727     }
2728 }
2729 
2730 static void wined3d_cs_wait_event(struct wined3d_cs *cs)
2731 {
2732     InterlockedExchange(&cs->waiting_for_event, TRUE);
2733 
2734     /* The main thread might have enqueued a command and blocked on it after
2735      * the CS thread decided to enter wined3d_cs_wait_event(), but before
2736      * "waiting_for_event" was set.
2737      *
2738      * Likewise, we can race with the main thread when resetting
2739      * "waiting_for_event", in which case we would need to call
2740      * WaitForSingleObject() because the main thread called SetEvent(). */
2741     if (!(wined3d_cs_queue_is_empty(cs, &cs->queue[WINED3D_CS_QUEUE_DEFAULT])
2742             && wined3d_cs_queue_is_empty(cs, &cs->queue[WINED3D_CS_QUEUE_MAP]))
2743             && InterlockedCompareExchange(&cs->waiting_for_event, FALSE, TRUE))
2744         return;
2745 
2746     WaitForSingleObject(cs->event, INFINITE);
2747 }
2748 
2749 static DWORD WINAPI wined3d_cs_run(void *ctx)
2750 {
2751     struct wined3d_cs_packet *packet;
2752     struct wined3d_cs_queue *queue;
2753     unsigned int spin_count = 0;
2754     struct wined3d_cs *cs = ctx;
2755     enum wined3d_cs_op opcode;
2756     HMODULE wined3d_module;
2757     unsigned int poll = 0;
2758     LONG tail;
2759 
2760     TRACE("Started.\n");
2761 
2762     /* Copy the module handle to a local variable to avoid racing with the
2763      * thread freeing "cs" before the FreeLibraryAndExitThread() call. */
2764     wined3d_module = cs->wined3d_module;
2765 
2766     list_init(&cs->query_poll_list);
2767     cs->thread_id = GetCurrentThreadId();
2768     for (;;)
2769     {
2770         if (++poll == WINED3D_CS_QUERY_POLL_INTERVAL)
2771         {
2772             poll_queries(cs);
2773             poll = 0;
2774         }
2775 
2776         queue = &cs->queue[WINED3D_CS_QUEUE_MAP];
2777         if (wined3d_cs_queue_is_empty(cs, queue))
2778         {
2779             queue = &cs->queue[WINED3D_CS_QUEUE_DEFAULT];
2780             if (wined3d_cs_queue_is_empty(cs, queue))
2781             {
2782                 if (++spin_count >= WINED3D_CS_SPIN_COUNT && list_empty(&cs->query_poll_list))
2783                     wined3d_cs_wait_event(cs);
2784                 continue;
2785             }
2786         }
2787         spin_count = 0;
2788 
2789         tail = queue->tail;
2790         packet = (struct wined3d_cs_packet *)&queue->data[tail];
2791         if (packet->size)
2792         {
2793             opcode = *(const enum wined3d_cs_op *)packet->data;
2794 
2795             if (opcode >= WINED3D_CS_OP_STOP)
2796             {
2797                 if (opcode > WINED3D_CS_OP_STOP)
2798                     ERR("Invalid opcode %#x.\n", opcode);
2799                 break;
2800             }
2801 
2802             wined3d_cs_op_handlers[opcode](cs, packet->data);
2803         }
2804 
2805         tail += FIELD_OFFSET(struct wined3d_cs_packet, data[packet->size]);
2806         tail &= (WINED3D_CS_QUEUE_SIZE - 1);
2807         InterlockedExchange(&queue->tail, tail);
2808     }
2809 
2810     cs->queue[WINED3D_CS_QUEUE_MAP].tail = cs->queue[WINED3D_CS_QUEUE_MAP].head;
2811     cs->queue[WINED3D_CS_QUEUE_DEFAULT].tail = cs->queue[WINED3D_CS_QUEUE_DEFAULT].head;
2812     TRACE("Stopped.\n");
2813     FreeLibraryAndExitThread(wined3d_module, 0);
2814 }
2815 
2816 struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device)
2817 {
2818     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2819     struct wined3d_cs *cs;
2820 
2821     if (!(cs = heap_alloc_zero(sizeof(*cs))))
2822         return NULL;
2823 
2824     cs->ops = &wined3d_cs_st_ops;
2825     cs->device = device;
2826 
2827     state_init(&cs->state, &cs->fb, gl_info, &device->adapter->d3d_info,
2828             WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT);
2829 
2830     cs->data_size = WINED3D_INITIAL_CS_SIZE;
2831     if (!(cs->data = heap_alloc(cs->data_size)))
2832         goto fail;
2833 
2834     if (wined3d_settings.cs_multithreaded
2835             && !RtlIsCriticalSectionLockedByThread(NtCurrentTeb()->Peb->LoaderLock))
2836     {
2837         cs->ops = &wined3d_cs_mt_ops;
2838 
2839         if (!(cs->event = CreateEventW(NULL, FALSE, FALSE, NULL)))
2840         {
2841             ERR("Failed to create command stream event.\n");
2842             heap_free(cs->data);
2843             goto fail;
2844         }
2845 
2846         if (!(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
2847                 (const WCHAR *)wined3d_cs_run, &cs->wined3d_module)))
2848         {
2849             ERR("Failed to get wined3d module handle.\n");
2850             CloseHandle(cs->event);
2851             heap_free(cs->data);
2852             goto fail;
2853         }
2854 
2855         if (!(cs->thread = CreateThread(NULL, 0, wined3d_cs_run, cs, 0, NULL)))
2856         {
2857             ERR("Failed to create wined3d command stream thread.\n");
2858             FreeLibrary(cs->wined3d_module);
2859             CloseHandle(cs->event);
2860             heap_free(cs->data);
2861             goto fail;
2862         }
2863     }
2864 
2865     return cs;
2866 
2867 fail:
2868     state_cleanup(&cs->state);
2869     heap_free(cs);
2870     return NULL;
2871 }
2872 
2873 void wined3d_cs_destroy(struct wined3d_cs *cs)
2874 {
2875     if (cs->thread)
2876     {
2877         wined3d_cs_emit_stop(cs);
2878         CloseHandle(cs->thread);
2879         if (!CloseHandle(cs->event))
2880             ERR("Closing event failed.\n");
2881     }
2882 
2883     state_cleanup(&cs->state);
2884     heap_free(cs->data);
2885     heap_free(cs);
2886 }
2887