mmsystem.dll16: Pass through MCI_LIST, MCI_SETAUDIO, and MCI_SETVIDEO.
[wine.git] / dlls / wined3d / cs.c
blobf7c943e98e98e63793fcc3c4e8329aa69ea5535b
1 /*
2 * Copyright 2013 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
21 #include "wined3d_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
25 #define WINED3D_INITIAL_CS_SIZE 4096
27 enum wined3d_cs_op
29 WINED3D_CS_OP_NOP,
30 WINED3D_CS_OP_PRESENT,
31 WINED3D_CS_OP_CLEAR,
32 WINED3D_CS_OP_DISPATCH,
33 WINED3D_CS_OP_DRAW,
34 WINED3D_CS_OP_FLUSH,
35 WINED3D_CS_OP_SET_PREDICATION,
36 WINED3D_CS_OP_SET_VIEWPORT,
37 WINED3D_CS_OP_SET_SCISSOR_RECT,
38 WINED3D_CS_OP_SET_RENDERTARGET_VIEW,
39 WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW,
40 WINED3D_CS_OP_SET_VERTEX_DECLARATION,
41 WINED3D_CS_OP_SET_STREAM_SOURCE,
42 WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ,
43 WINED3D_CS_OP_SET_STREAM_OUTPUT,
44 WINED3D_CS_OP_SET_INDEX_BUFFER,
45 WINED3D_CS_OP_SET_CONSTANT_BUFFER,
46 WINED3D_CS_OP_SET_TEXTURE,
47 WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW,
48 WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW,
49 WINED3D_CS_OP_SET_SAMPLER,
50 WINED3D_CS_OP_SET_SHADER,
51 WINED3D_CS_OP_SET_RASTERIZER_STATE,
52 WINED3D_CS_OP_SET_RENDER_STATE,
53 WINED3D_CS_OP_SET_TEXTURE_STATE,
54 WINED3D_CS_OP_SET_SAMPLER_STATE,
55 WINED3D_CS_OP_SET_TRANSFORM,
56 WINED3D_CS_OP_SET_CLIP_PLANE,
57 WINED3D_CS_OP_SET_COLOR_KEY,
58 WINED3D_CS_OP_SET_MATERIAL,
59 WINED3D_CS_OP_SET_LIGHT,
60 WINED3D_CS_OP_SET_LIGHT_ENABLE,
61 WINED3D_CS_OP_PUSH_CONSTANTS,
62 WINED3D_CS_OP_RESET_STATE,
63 WINED3D_CS_OP_CALLBACK,
64 WINED3D_CS_OP_QUERY_ISSUE,
65 WINED3D_CS_OP_PRELOAD_RESOURCE,
66 WINED3D_CS_OP_UNLOAD_RESOURCE,
67 WINED3D_CS_OP_MAP,
68 WINED3D_CS_OP_UNMAP,
69 WINED3D_CS_OP_BLT_SUB_RESOURCE,
70 WINED3D_CS_OP_UPDATE_SUB_RESOURCE,
71 WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION,
72 WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW,
73 WINED3D_CS_OP_COPY_UAV_COUNTER,
74 WINED3D_CS_OP_STOP,
77 struct wined3d_cs_packet
79 size_t size;
80 BYTE data[1];
83 struct wined3d_cs_nop
85 enum wined3d_cs_op opcode;
88 struct wined3d_cs_present
90 enum wined3d_cs_op opcode;
91 HWND dst_window_override;
92 struct wined3d_swapchain *swapchain;
93 RECT src_rect;
94 RECT dst_rect;
95 DWORD flags;
98 struct wined3d_cs_clear
100 enum wined3d_cs_op opcode;
101 DWORD flags;
102 unsigned int rt_count;
103 struct wined3d_fb_state *fb;
104 RECT draw_rect;
105 struct wined3d_color color;
106 float depth;
107 DWORD stencil;
108 unsigned int rect_count;
109 RECT rects[1];
112 struct wined3d_cs_dispatch
114 enum wined3d_cs_op opcode;
115 struct wined3d_dispatch_parameters parameters;
118 struct wined3d_cs_draw
120 enum wined3d_cs_op opcode;
121 GLenum primitive_type;
122 GLint patch_vertex_count;
123 struct wined3d_draw_parameters parameters;
126 struct wined3d_cs_flush
128 enum wined3d_cs_op opcode;
131 struct wined3d_cs_set_predication
133 enum wined3d_cs_op opcode;
134 struct wined3d_query *predicate;
135 BOOL value;
138 struct wined3d_cs_set_viewport
140 enum wined3d_cs_op opcode;
141 struct wined3d_viewport viewport;
144 struct wined3d_cs_set_scissor_rect
146 enum wined3d_cs_op opcode;
147 RECT rect;
150 struct wined3d_cs_set_rendertarget_view
152 enum wined3d_cs_op opcode;
153 unsigned int view_idx;
154 struct wined3d_rendertarget_view *view;
157 struct wined3d_cs_set_depth_stencil_view
159 enum wined3d_cs_op opcode;
160 struct wined3d_rendertarget_view *view;
163 struct wined3d_cs_set_vertex_declaration
165 enum wined3d_cs_op opcode;
166 struct wined3d_vertex_declaration *declaration;
169 struct wined3d_cs_set_stream_source
171 enum wined3d_cs_op opcode;
172 UINT stream_idx;
173 struct wined3d_buffer *buffer;
174 UINT offset;
175 UINT stride;
178 struct wined3d_cs_set_stream_source_freq
180 enum wined3d_cs_op opcode;
181 UINT stream_idx;
182 UINT frequency;
183 UINT flags;
186 struct wined3d_cs_set_stream_output
188 enum wined3d_cs_op opcode;
189 UINT stream_idx;
190 struct wined3d_buffer *buffer;
191 UINT offset;
194 struct wined3d_cs_set_index_buffer
196 enum wined3d_cs_op opcode;
197 struct wined3d_buffer *buffer;
198 enum wined3d_format_id format_id;
199 unsigned int offset;
202 struct wined3d_cs_set_constant_buffer
204 enum wined3d_cs_op opcode;
205 enum wined3d_shader_type type;
206 UINT cb_idx;
207 struct wined3d_buffer *buffer;
210 struct wined3d_cs_set_texture
212 enum wined3d_cs_op opcode;
213 UINT stage;
214 struct wined3d_texture *texture;
217 struct wined3d_cs_set_color_key
219 enum wined3d_cs_op opcode;
220 struct wined3d_texture *texture;
221 WORD flags;
222 WORD set;
223 struct wined3d_color_key color_key;
226 struct wined3d_cs_set_shader_resource_view
228 enum wined3d_cs_op opcode;
229 enum wined3d_shader_type type;
230 UINT view_idx;
231 struct wined3d_shader_resource_view *view;
234 struct wined3d_cs_set_unordered_access_view
236 enum wined3d_cs_op opcode;
237 enum wined3d_pipeline pipeline;
238 unsigned int view_idx;
239 struct wined3d_unordered_access_view *view;
240 unsigned int initial_count;
243 struct wined3d_cs_set_sampler
245 enum wined3d_cs_op opcode;
246 enum wined3d_shader_type type;
247 UINT sampler_idx;
248 struct wined3d_sampler *sampler;
251 struct wined3d_cs_set_shader
253 enum wined3d_cs_op opcode;
254 enum wined3d_shader_type type;
255 struct wined3d_shader *shader;
258 struct wined3d_cs_set_rasterizer_state
260 enum wined3d_cs_op opcode;
261 struct wined3d_rasterizer_state *state;
264 struct wined3d_cs_set_render_state
266 enum wined3d_cs_op opcode;
267 enum wined3d_render_state state;
268 DWORD value;
271 struct wined3d_cs_set_texture_state
273 enum wined3d_cs_op opcode;
274 UINT stage;
275 enum wined3d_texture_stage_state state;
276 DWORD value;
279 struct wined3d_cs_set_sampler_state
281 enum wined3d_cs_op opcode;
282 UINT sampler_idx;
283 enum wined3d_sampler_state state;
284 DWORD value;
287 struct wined3d_cs_set_transform
289 enum wined3d_cs_op opcode;
290 enum wined3d_transform_state state;
291 struct wined3d_matrix matrix;
294 struct wined3d_cs_set_clip_plane
296 enum wined3d_cs_op opcode;
297 UINT plane_idx;
298 struct wined3d_vec4 plane;
301 struct wined3d_cs_set_material
303 enum wined3d_cs_op opcode;
304 struct wined3d_material material;
307 struct wined3d_cs_set_light
309 enum wined3d_cs_op opcode;
310 struct wined3d_light_info light;
313 struct wined3d_cs_set_light_enable
315 enum wined3d_cs_op opcode;
316 unsigned int idx;
317 BOOL enable;
320 struct wined3d_cs_push_constants
322 enum wined3d_cs_op opcode;
323 enum wined3d_push_constants type;
324 unsigned int start_idx;
325 unsigned int count;
326 BYTE constants[1];
329 struct wined3d_cs_reset_state
331 enum wined3d_cs_op opcode;
334 struct wined3d_cs_callback
336 enum wined3d_cs_op opcode;
337 void (*callback)(void *object);
338 void *object;
341 struct wined3d_cs_query_issue
343 enum wined3d_cs_op opcode;
344 struct wined3d_query *query;
345 DWORD flags;
348 struct wined3d_cs_preload_resource
350 enum wined3d_cs_op opcode;
351 struct wined3d_resource *resource;
354 struct wined3d_cs_unload_resource
356 enum wined3d_cs_op opcode;
357 struct wined3d_resource *resource;
360 struct wined3d_cs_map
362 enum wined3d_cs_op opcode;
363 struct wined3d_resource *resource;
364 unsigned int sub_resource_idx;
365 struct wined3d_map_desc *map_desc;
366 const struct wined3d_box *box;
367 DWORD flags;
368 HRESULT *hr;
371 struct wined3d_cs_unmap
373 enum wined3d_cs_op opcode;
374 struct wined3d_resource *resource;
375 unsigned int sub_resource_idx;
376 HRESULT *hr;
379 struct wined3d_cs_blt_sub_resource
381 enum wined3d_cs_op opcode;
382 struct wined3d_resource *dst_resource;
383 unsigned int dst_sub_resource_idx;
384 struct wined3d_box dst_box;
385 struct wined3d_resource *src_resource;
386 unsigned int src_sub_resource_idx;
387 struct wined3d_box src_box;
388 DWORD flags;
389 struct wined3d_blt_fx fx;
390 enum wined3d_texture_filter_type filter;
393 struct wined3d_cs_update_sub_resource
395 enum wined3d_cs_op opcode;
396 struct wined3d_resource *resource;
397 unsigned int sub_resource_idx;
398 struct wined3d_box box;
399 struct wined3d_sub_resource_data data;
402 struct wined3d_cs_add_dirty_texture_region
404 enum wined3d_cs_op opcode;
405 struct wined3d_texture *texture;
406 unsigned int layer;
409 struct wined3d_cs_clear_unordered_access_view
411 enum wined3d_cs_op opcode;
412 struct wined3d_unordered_access_view *view;
413 struct wined3d_uvec4 clear_value;
416 struct wined3d_cs_copy_uav_counter
418 enum wined3d_cs_op opcode;
419 struct wined3d_buffer *buffer;
420 unsigned int offset;
421 struct wined3d_unordered_access_view *view;
424 struct wined3d_cs_stop
426 enum wined3d_cs_op opcode;
429 static void wined3d_cs_exec_nop(struct wined3d_cs *cs, const void *data)
433 static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data)
435 const struct wined3d_cs_present *op = data;
436 struct wined3d_swapchain *swapchain;
437 unsigned int i;
439 swapchain = op->swapchain;
440 wined3d_swapchain_set_window(swapchain, op->dst_window_override);
442 swapchain->swapchain_ops->swapchain_present(swapchain, &op->src_rect, &op->dst_rect, op->flags);
444 wined3d_resource_release(&swapchain->front_buffer->resource);
445 for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
447 wined3d_resource_release(&swapchain->back_buffers[i]->resource);
450 InterlockedDecrement(&cs->pending_presents);
453 void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain,
454 const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, DWORD flags)
456 struct wined3d_cs_present *op;
457 unsigned int i;
458 LONG pending;
460 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
461 op->opcode = WINED3D_CS_OP_PRESENT;
462 op->dst_window_override = dst_window_override;
463 op->swapchain = swapchain;
464 op->src_rect = *src_rect;
465 op->dst_rect = *dst_rect;
466 op->flags = flags;
468 pending = InterlockedIncrement(&cs->pending_presents);
470 wined3d_resource_acquire(&swapchain->front_buffer->resource);
471 for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
473 wined3d_resource_acquire(&swapchain->back_buffers[i]->resource);
476 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
478 /* Limit input latency by limiting the number of presents that we can get
479 * ahead of the worker thread. We have a constant limit here, but
480 * IDXGIDevice1 allows tuning this. */
481 while (pending > 1)
483 wined3d_pause();
484 pending = InterlockedCompareExchange(&cs->pending_presents, 0, 0);
488 static void wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
490 const struct wined3d_state *state = &cs->state;
491 const struct wined3d_cs_clear *op = data;
492 struct wined3d_device *device;
493 unsigned int i;
494 RECT draw_rect;
496 device = cs->device;
497 wined3d_get_draw_rect(state, &draw_rect);
498 device->blitter->ops->blitter_clear(device->blitter, device, op->rt_count, op->fb,
499 op->rect_count, op->rects, &op->draw_rect, op->flags, &op->color, op->depth, op->stencil);
501 if (op->flags & WINED3DCLEAR_TARGET)
503 for (i = 0; i < op->rt_count; ++i)
505 if (op->fb->render_targets[i])
506 wined3d_resource_release(op->fb->render_targets[i]->resource);
509 if (op->flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
510 wined3d_resource_release(op->fb->depth_stencil->resource);
513 void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects,
514 DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
516 unsigned int rt_count = cs->device->adapter->gl_info.limits.buffers;
517 const struct wined3d_state *state = &cs->device->state;
518 struct wined3d_cs_clear *op;
519 unsigned int i;
521 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_clear, rects[rect_count]),
522 WINED3D_CS_QUEUE_DEFAULT);
523 op->opcode = WINED3D_CS_OP_CLEAR;
524 op->flags = flags;
525 op->rt_count = rt_count;
526 op->fb = &cs->fb;
527 wined3d_get_draw_rect(state, &op->draw_rect);
528 op->color = *color;
529 op->depth = depth;
530 op->stencil = stencil;
531 op->rect_count = rect_count;
532 memcpy(op->rects, rects, sizeof(*rects) * rect_count);
534 if (flags & WINED3DCLEAR_TARGET)
536 for (i = 0; i < rt_count; ++i)
538 if (state->fb->render_targets[i])
539 wined3d_resource_acquire(state->fb->render_targets[i]->resource);
542 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
543 wined3d_resource_acquire(state->fb->depth_stencil->resource);
545 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
548 void wined3d_cs_emit_clear_rendertarget_view(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view,
549 const RECT *rect, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
551 struct wined3d_cs_clear *op;
552 struct
554 struct wined3d_rendertarget_view *rt;
555 struct wined3d_fb_state fb;
556 } *extra;
558 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_clear, rects[1]) + sizeof(*extra),
559 WINED3D_CS_QUEUE_DEFAULT);
560 extra = (void *)&op->rects[1];
561 extra->fb.render_targets = &extra->rt;
562 op->fb = &extra->fb;
564 op->opcode = WINED3D_CS_OP_CLEAR;
565 op->flags = flags;
566 if (flags & WINED3DCLEAR_TARGET)
568 op->rt_count = 1;
569 op->fb->render_targets[0] = view;
570 op->fb->depth_stencil = NULL;
571 op->color = *color;
573 else
575 op->rt_count = 0;
576 op->fb->render_targets[0] = NULL;
577 op->fb->depth_stencil = view;
578 op->depth = depth;
579 op->stencil = stencil;
581 SetRect(&op->draw_rect, 0, 0, view->width, view->height);
582 op->rect_count = 1;
583 op->rects[0] = *rect;
585 wined3d_resource_acquire(view->resource);
587 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
590 static void acquire_shader_resources(const struct wined3d_state *state, unsigned int shader_mask)
592 struct wined3d_shader_sampler_map_entry *entry;
593 struct wined3d_shader_resource_view *view;
594 struct wined3d_shader *shader;
595 unsigned int i, j;
597 for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
599 if (!(shader_mask & (1u << i)))
600 continue;
602 if (!(shader = state->shader[i]))
603 continue;
605 for (j = 0; j < WINED3D_MAX_CBS; ++j)
607 if (state->cb[i][j])
608 wined3d_resource_acquire(&state->cb[i][j]->resource);
611 for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
613 entry = &shader->reg_maps.sampler_map.entries[j];
615 if (!(view = state->shader_resource_view[i][entry->resource_idx]))
616 continue;
618 wined3d_resource_acquire(view->resource);
623 static void release_shader_resources(const struct wined3d_state *state, unsigned int shader_mask)
625 struct wined3d_shader_sampler_map_entry *entry;
626 struct wined3d_shader_resource_view *view;
627 struct wined3d_shader *shader;
628 unsigned int i, j;
630 for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
632 if (!(shader_mask & (1u << i)))
633 continue;
635 if (!(shader = state->shader[i]))
636 continue;
638 for (j = 0; j < WINED3D_MAX_CBS; ++j)
640 if (state->cb[i][j])
641 wined3d_resource_release(&state->cb[i][j]->resource);
644 for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
646 entry = &shader->reg_maps.sampler_map.entries[j];
648 if (!(view = state->shader_resource_view[i][entry->resource_idx]))
649 continue;
651 wined3d_resource_release(view->resource);
656 static void acquire_unordered_access_resources(const struct wined3d_shader *shader,
657 struct wined3d_unordered_access_view * const *views)
659 unsigned int i;
661 if (!shader)
662 return;
664 for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
666 if (!shader->reg_maps.uav_resource_info[i].type)
667 continue;
669 if (!views[i])
670 continue;
672 wined3d_resource_acquire(views[i]->resource);
676 static void release_unordered_access_resources(const struct wined3d_shader *shader,
677 struct wined3d_unordered_access_view * const *views)
679 unsigned int i;
681 if (!shader)
682 return;
684 for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
686 if (!shader->reg_maps.uav_resource_info[i].type)
687 continue;
689 if (!views[i])
690 continue;
692 wined3d_resource_release(views[i]->resource);
696 static void wined3d_cs_exec_dispatch(struct wined3d_cs *cs, const void *data)
698 const struct wined3d_cs_dispatch *op = data;
699 struct wined3d_state *state = &cs->state;
701 dispatch_compute(cs->device, state, &op->parameters);
703 if (op->parameters.indirect)
704 wined3d_resource_release(&op->parameters.u.indirect.buffer->resource);
706 release_shader_resources(state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
707 release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_COMPUTE],
708 state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
711 static void acquire_compute_pipeline_resources(const struct wined3d_state *state)
713 acquire_shader_resources(state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
714 acquire_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_COMPUTE],
715 state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
718 void wined3d_cs_emit_dispatch(struct wined3d_cs *cs,
719 unsigned int group_count_x, unsigned int group_count_y, unsigned int group_count_z)
721 const struct wined3d_state *state = &cs->device->state;
722 struct wined3d_cs_dispatch *op;
724 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
725 op->opcode = WINED3D_CS_OP_DISPATCH;
726 op->parameters.indirect = FALSE;
727 op->parameters.u.direct.group_count_x = group_count_x;
728 op->parameters.u.direct.group_count_y = group_count_y;
729 op->parameters.u.direct.group_count_z = group_count_z;
731 acquire_compute_pipeline_resources(state);
733 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
736 void wined3d_cs_emit_dispatch_indirect(struct wined3d_cs *cs,
737 struct wined3d_buffer *buffer, unsigned int offset)
739 const struct wined3d_state *state = &cs->device->state;
740 struct wined3d_cs_dispatch *op;
742 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
743 op->opcode = WINED3D_CS_OP_DISPATCH;
744 op->parameters.indirect = TRUE;
745 op->parameters.u.indirect.buffer = buffer;
746 op->parameters.u.indirect.offset = offset;
748 acquire_compute_pipeline_resources(state);
749 wined3d_resource_acquire(&buffer->resource);
751 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
754 static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
756 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
757 struct wined3d_state *state = &cs->state;
758 const struct wined3d_cs_draw *op = data;
759 int load_base_vertex_idx;
760 unsigned int i;
762 /* ARB_draw_indirect always supports a base vertex offset. */
763 if (!op->parameters.indirect && !gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
764 load_base_vertex_idx = op->parameters.u.direct.base_vertex_idx;
765 else
766 load_base_vertex_idx = 0;
768 if (state->load_base_vertex_index != load_base_vertex_idx)
770 state->load_base_vertex_index = load_base_vertex_idx;
771 device_invalidate_state(cs->device, STATE_BASEVERTEXINDEX);
774 if (state->gl_primitive_type != op->primitive_type)
776 if (state->gl_primitive_type == GL_POINTS || op->primitive_type == GL_POINTS)
777 device_invalidate_state(cs->device, STATE_POINT_ENABLE);
778 state->gl_primitive_type = op->primitive_type;
780 state->gl_patch_vertices = op->patch_vertex_count;
782 draw_primitive(cs->device, state, &op->parameters);
784 if (op->parameters.indirect)
786 struct wined3d_buffer *buffer = op->parameters.u.indirect.buffer;
787 wined3d_resource_release(&buffer->resource);
790 if (op->parameters.indexed)
791 wined3d_resource_release(&state->index_buffer->resource);
792 for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
794 if (state->streams[i].buffer)
795 wined3d_resource_release(&state->streams[i].buffer->resource);
797 for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
799 if (state->stream_output[i].buffer)
800 wined3d_resource_release(&state->stream_output[i].buffer->resource);
802 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
804 if (state->textures[i])
805 wined3d_resource_release(&state->textures[i]->resource);
807 for (i = 0; i < gl_info->limits.buffers; ++i)
809 if (state->fb->render_targets[i])
810 wined3d_resource_release(state->fb->render_targets[i]->resource);
812 if (state->fb->depth_stencil)
813 wined3d_resource_release(state->fb->depth_stencil->resource);
814 release_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
815 release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL],
816 state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
819 static void acquire_graphics_pipeline_resources(const struct wined3d_state *state,
820 BOOL indexed, const struct wined3d_gl_info *gl_info)
822 unsigned int i;
824 if (indexed)
825 wined3d_resource_acquire(&state->index_buffer->resource);
826 for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
828 if (state->streams[i].buffer)
829 wined3d_resource_acquire(&state->streams[i].buffer->resource);
831 for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
833 if (state->stream_output[i].buffer)
834 wined3d_resource_acquire(&state->stream_output[i].buffer->resource);
836 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
838 if (state->textures[i])
839 wined3d_resource_acquire(&state->textures[i]->resource);
841 for (i = 0; i < gl_info->limits.buffers; ++i)
843 if (state->fb->render_targets[i])
844 wined3d_resource_acquire(state->fb->render_targets[i]->resource);
846 if (state->fb->depth_stencil)
847 wined3d_resource_acquire(state->fb->depth_stencil->resource);
848 acquire_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
849 acquire_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL],
850 state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
853 void wined3d_cs_emit_draw(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
854 int base_vertex_idx, unsigned int start_idx, unsigned int index_count,
855 unsigned int start_instance, unsigned int instance_count, BOOL indexed)
857 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
858 const struct wined3d_state *state = &cs->device->state;
859 struct wined3d_cs_draw *op;
861 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
862 op->opcode = WINED3D_CS_OP_DRAW;
863 op->primitive_type = primitive_type;
864 op->patch_vertex_count = patch_vertex_count;
865 op->parameters.indirect = FALSE;
866 op->parameters.u.direct.base_vertex_idx = base_vertex_idx;
867 op->parameters.u.direct.start_idx = start_idx;
868 op->parameters.u.direct.index_count = index_count;
869 op->parameters.u.direct.start_instance = start_instance;
870 op->parameters.u.direct.instance_count = instance_count;
871 op->parameters.indexed = indexed;
873 acquire_graphics_pipeline_resources(state, indexed, gl_info);
875 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
878 void wined3d_cs_emit_draw_indirect(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
879 struct wined3d_buffer *buffer, unsigned int offset, BOOL indexed)
881 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
882 const struct wined3d_state *state = &cs->device->state;
883 struct wined3d_cs_draw *op;
885 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
886 op->opcode = WINED3D_CS_OP_DRAW;
887 op->primitive_type = primitive_type;
888 op->patch_vertex_count = patch_vertex_count;
889 op->parameters.indirect = TRUE;
890 op->parameters.u.indirect.buffer = buffer;
891 op->parameters.u.indirect.offset = offset;
892 op->parameters.indexed = indexed;
894 acquire_graphics_pipeline_resources(state, indexed, gl_info);
895 wined3d_resource_acquire(&buffer->resource);
897 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
900 static void wined3d_cs_exec_flush(struct wined3d_cs *cs, const void *data)
902 struct wined3d_context *context;
904 context = context_acquire(cs->device, NULL, 0);
905 if (context->valid)
906 context->gl_info->gl_ops.gl.p_glFlush();
907 context_release(context);
910 void wined3d_cs_emit_flush(struct wined3d_cs *cs)
912 struct wined3d_cs_flush *op;
914 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
915 op->opcode = WINED3D_CS_OP_FLUSH;
917 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
918 cs->queries_flushed = TRUE;
921 static void wined3d_cs_exec_set_predication(struct wined3d_cs *cs, const void *data)
923 const struct wined3d_cs_set_predication *op = data;
925 cs->state.predicate = op->predicate;
926 cs->state.predicate_value = op->value;
929 void wined3d_cs_emit_set_predication(struct wined3d_cs *cs, struct wined3d_query *predicate, BOOL value)
931 struct wined3d_cs_set_predication *op;
933 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
934 op->opcode = WINED3D_CS_OP_SET_PREDICATION;
935 op->predicate = predicate;
936 op->value = value;
938 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
941 static void wined3d_cs_exec_set_viewport(struct wined3d_cs *cs, const void *data)
943 const struct wined3d_cs_set_viewport *op = data;
945 cs->state.viewport = op->viewport;
946 device_invalidate_state(cs->device, STATE_VIEWPORT);
949 void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_viewport *viewport)
951 struct wined3d_cs_set_viewport *op;
953 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
954 op->opcode = WINED3D_CS_OP_SET_VIEWPORT;
955 op->viewport = *viewport;
957 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
960 static void wined3d_cs_exec_set_scissor_rect(struct wined3d_cs *cs, const void *data)
962 const struct wined3d_cs_set_scissor_rect *op = data;
964 cs->state.scissor_rect = op->rect;
965 device_invalidate_state(cs->device, STATE_SCISSORRECT);
968 void wined3d_cs_emit_set_scissor_rect(struct wined3d_cs *cs, const RECT *rect)
970 struct wined3d_cs_set_scissor_rect *op;
972 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
973 op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECT;
974 op->rect = *rect;
976 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
979 static void wined3d_cs_exec_set_rendertarget_view(struct wined3d_cs *cs, const void *data)
981 const struct wined3d_cs_set_rendertarget_view *op = data;
983 cs->state.fb->render_targets[op->view_idx] = op->view;
984 device_invalidate_state(cs->device, STATE_FRAMEBUFFER);
987 void wined3d_cs_emit_set_rendertarget_view(struct wined3d_cs *cs, unsigned int view_idx,
988 struct wined3d_rendertarget_view *view)
990 struct wined3d_cs_set_rendertarget_view *op;
992 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
993 op->opcode = WINED3D_CS_OP_SET_RENDERTARGET_VIEW;
994 op->view_idx = view_idx;
995 op->view = view;
997 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1000 static void wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const void *data)
1002 const struct wined3d_cs_set_depth_stencil_view *op = data;
1003 struct wined3d_device *device = cs->device;
1004 struct wined3d_rendertarget_view *prev;
1006 if ((prev = cs->state.fb->depth_stencil))
1008 struct wined3d_surface *prev_surface = wined3d_rendertarget_view_get_surface(prev);
1010 if (prev_surface && (device->swapchains[0]->desc.flags & WINED3D_SWAPCHAIN_DISCARD_DEPTHSTENCIL
1011 || prev_surface->container->flags & WINED3D_TEXTURE_DISCARD))
1013 wined3d_texture_validate_location(prev_surface->container,
1014 prev->sub_resource_idx, WINED3D_LOCATION_DISCARDED);
1018 cs->fb.depth_stencil = op->view;
1020 if (!prev != !op->view)
1022 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
1023 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
1024 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
1025 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
1026 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
1028 else if (prev && (prev->format_flags & WINED3DFMT_FLAG_FLOAT)
1029 != (op->view->format_flags & WINED3DFMT_FLAG_FLOAT))
1031 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
1034 device_invalidate_state(device, STATE_FRAMEBUFFER);
1037 void wined3d_cs_emit_set_depth_stencil_view(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view)
1039 struct wined3d_cs_set_depth_stencil_view *op;
1041 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1042 op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW;
1043 op->view = view;
1045 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1048 static void wined3d_cs_exec_set_vertex_declaration(struct wined3d_cs *cs, const void *data)
1050 const struct wined3d_cs_set_vertex_declaration *op = data;
1052 cs->state.vertex_declaration = op->declaration;
1053 device_invalidate_state(cs->device, STATE_VDECL);
1056 void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs, struct wined3d_vertex_declaration *declaration)
1058 struct wined3d_cs_set_vertex_declaration *op;
1060 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1061 op->opcode = WINED3D_CS_OP_SET_VERTEX_DECLARATION;
1062 op->declaration = declaration;
1064 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1067 static void wined3d_cs_exec_set_stream_source(struct wined3d_cs *cs, const void *data)
1069 const struct wined3d_cs_set_stream_source *op = data;
1070 struct wined3d_stream_state *stream;
1071 struct wined3d_buffer *prev;
1073 stream = &cs->state.streams[op->stream_idx];
1074 prev = stream->buffer;
1075 stream->buffer = op->buffer;
1076 stream->offset = op->offset;
1077 stream->stride = op->stride;
1079 if (op->buffer)
1080 InterlockedIncrement(&op->buffer->resource.bind_count);
1081 if (prev)
1082 InterlockedDecrement(&prev->resource.bind_count);
1084 device_invalidate_state(cs->device, STATE_STREAMSRC);
1087 void wined3d_cs_emit_set_stream_source(struct wined3d_cs *cs, UINT stream_idx,
1088 struct wined3d_buffer *buffer, UINT offset, UINT stride)
1090 struct wined3d_cs_set_stream_source *op;
1092 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1093 op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE;
1094 op->stream_idx = stream_idx;
1095 op->buffer = buffer;
1096 op->offset = offset;
1097 op->stride = stride;
1099 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1102 static void wined3d_cs_exec_set_stream_source_freq(struct wined3d_cs *cs, const void *data)
1104 const struct wined3d_cs_set_stream_source_freq *op = data;
1105 struct wined3d_stream_state *stream;
1107 stream = &cs->state.streams[op->stream_idx];
1108 stream->frequency = op->frequency;
1109 stream->flags = op->flags;
1111 device_invalidate_state(cs->device, STATE_STREAMSRC);
1114 void wined3d_cs_emit_set_stream_source_freq(struct wined3d_cs *cs, UINT stream_idx, UINT frequency, UINT flags)
1116 struct wined3d_cs_set_stream_source_freq *op;
1118 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1119 op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ;
1120 op->stream_idx = stream_idx;
1121 op->frequency = frequency;
1122 op->flags = flags;
1124 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1127 static void wined3d_cs_exec_set_stream_output(struct wined3d_cs *cs, const void *data)
1129 const struct wined3d_cs_set_stream_output *op = data;
1130 struct wined3d_stream_output *stream;
1131 struct wined3d_buffer *prev;
1133 stream = &cs->state.stream_output[op->stream_idx];
1134 prev = stream->buffer;
1135 stream->buffer = op->buffer;
1136 stream->offset = op->offset;
1138 if (op->buffer)
1139 InterlockedIncrement(&op->buffer->resource.bind_count);
1140 if (prev)
1141 InterlockedDecrement(&prev->resource.bind_count);
1143 device_invalidate_state(cs->device, STATE_STREAM_OUTPUT);
1146 void wined3d_cs_emit_set_stream_output(struct wined3d_cs *cs, UINT stream_idx,
1147 struct wined3d_buffer *buffer, UINT offset)
1149 struct wined3d_cs_set_stream_output *op;
1151 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1152 op->opcode = WINED3D_CS_OP_SET_STREAM_OUTPUT;
1153 op->stream_idx = stream_idx;
1154 op->buffer = buffer;
1155 op->offset = offset;
1157 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1160 static void wined3d_cs_exec_set_index_buffer(struct wined3d_cs *cs, const void *data)
1162 const struct wined3d_cs_set_index_buffer *op = data;
1163 struct wined3d_buffer *prev;
1165 prev = cs->state.index_buffer;
1166 cs->state.index_buffer = op->buffer;
1167 cs->state.index_format = op->format_id;
1168 cs->state.index_offset = op->offset;
1170 if (op->buffer)
1171 InterlockedIncrement(&op->buffer->resource.bind_count);
1172 if (prev)
1173 InterlockedDecrement(&prev->resource.bind_count);
1175 device_invalidate_state(cs->device, STATE_INDEXBUFFER);
1178 void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer,
1179 enum wined3d_format_id format_id, unsigned int offset)
1181 struct wined3d_cs_set_index_buffer *op;
1183 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1184 op->opcode = WINED3D_CS_OP_SET_INDEX_BUFFER;
1185 op->buffer = buffer;
1186 op->format_id = format_id;
1187 op->offset = offset;
1189 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1192 static void wined3d_cs_exec_set_constant_buffer(struct wined3d_cs *cs, const void *data)
1194 const struct wined3d_cs_set_constant_buffer *op = data;
1195 struct wined3d_buffer *prev;
1197 prev = cs->state.cb[op->type][op->cb_idx];
1198 cs->state.cb[op->type][op->cb_idx] = op->buffer;
1200 if (op->buffer)
1201 InterlockedIncrement(&op->buffer->resource.bind_count);
1202 if (prev)
1203 InterlockedDecrement(&prev->resource.bind_count);
1205 device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(op->type));
1208 void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_shader_type type,
1209 UINT cb_idx, struct wined3d_buffer *buffer)
1211 struct wined3d_cs_set_constant_buffer *op;
1213 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1214 op->opcode = WINED3D_CS_OP_SET_CONSTANT_BUFFER;
1215 op->type = type;
1216 op->cb_idx = cb_idx;
1217 op->buffer = buffer;
1219 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1222 static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data)
1224 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
1225 const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info;
1226 const struct wined3d_cs_set_texture *op = data;
1227 struct wined3d_texture *prev;
1228 BOOL old_use_color_key = FALSE, new_use_color_key = FALSE;
1230 prev = cs->state.textures[op->stage];
1231 cs->state.textures[op->stage] = op->texture;
1233 if (op->texture)
1235 const struct wined3d_format *new_format = op->texture->resource.format;
1236 const struct wined3d_format *old_format = prev ? prev->resource.format : NULL;
1237 unsigned int old_fmt_flags = prev ? prev->resource.format_flags : 0;
1238 unsigned int new_fmt_flags = op->texture->resource.format_flags;
1240 if (InterlockedIncrement(&op->texture->resource.bind_count) == 1)
1241 op->texture->sampler = op->stage;
1243 if (!prev || op->texture->target != prev->target
1244 || (!is_same_fixup(new_format->color_fixup, old_format->color_fixup)
1245 && !(can_use_texture_swizzle(gl_info, new_format) && can_use_texture_swizzle(gl_info, old_format)))
1246 || (new_fmt_flags & WINED3DFMT_FLAG_SHADOW) != (old_fmt_flags & WINED3DFMT_FLAG_SHADOW))
1247 device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
1249 if (!prev && op->stage < d3d_info->limits.ffp_blend_stages)
1251 /* The source arguments for color and alpha ops have different
1252 * meanings when a NULL texture is bound, so the COLOR_OP and
1253 * ALPHA_OP have to be dirtified. */
1254 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1255 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1258 if (!op->stage && op->texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1259 new_use_color_key = TRUE;
1262 if (prev)
1264 if (InterlockedDecrement(&prev->resource.bind_count) && prev->sampler == op->stage)
1266 unsigned int i;
1268 /* Search for other stages the texture is bound to. Shouldn't
1269 * happen if applications bind textures to a single stage only. */
1270 TRACE("Searching for other stages the texture is bound to.\n");
1271 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
1273 if (cs->state.textures[i] == prev)
1275 TRACE("Texture is also bound to stage %u.\n", i);
1276 prev->sampler = i;
1277 break;
1282 if (!op->texture && op->stage < d3d_info->limits.ffp_blend_stages)
1284 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1285 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1288 if (!op->stage && prev->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1289 old_use_color_key = TRUE;
1292 device_invalidate_state(cs->device, STATE_SAMPLER(op->stage));
1294 if (new_use_color_key != old_use_color_key)
1295 device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1297 if (new_use_color_key)
1298 device_invalidate_state(cs->device, STATE_COLOR_KEY);
1301 void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined3d_texture *texture)
1303 struct wined3d_cs_set_texture *op;
1305 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1306 op->opcode = WINED3D_CS_OP_SET_TEXTURE;
1307 op->stage = stage;
1308 op->texture = texture;
1310 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1313 static void wined3d_cs_exec_set_shader_resource_view(struct wined3d_cs *cs, const void *data)
1315 const struct wined3d_cs_set_shader_resource_view *op = data;
1316 struct wined3d_shader_resource_view *prev;
1318 prev = cs->state.shader_resource_view[op->type][op->view_idx];
1319 cs->state.shader_resource_view[op->type][op->view_idx] = op->view;
1321 if (op->view)
1322 InterlockedIncrement(&op->view->resource->bind_count);
1323 if (prev)
1324 InterlockedDecrement(&prev->resource->bind_count);
1326 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1327 device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1328 else
1329 device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1332 void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3d_shader_type type,
1333 UINT view_idx, struct wined3d_shader_resource_view *view)
1335 struct wined3d_cs_set_shader_resource_view *op;
1337 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1338 op->opcode = WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW;
1339 op->type = type;
1340 op->view_idx = view_idx;
1341 op->view = view;
1343 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1346 static void wined3d_cs_exec_set_unordered_access_view(struct wined3d_cs *cs, const void *data)
1348 const struct wined3d_cs_set_unordered_access_view *op = data;
1349 struct wined3d_unordered_access_view *prev;
1351 prev = cs->state.unordered_access_view[op->pipeline][op->view_idx];
1352 cs->state.unordered_access_view[op->pipeline][op->view_idx] = op->view;
1354 if (op->view)
1355 InterlockedIncrement(&op->view->resource->bind_count);
1356 if (prev)
1357 InterlockedDecrement(&prev->resource->bind_count);
1359 if (op->view && op->initial_count != ~0u)
1360 wined3d_unordered_access_view_set_counter(op->view, op->initial_count);
1362 device_invalidate_state(cs->device, STATE_UNORDERED_ACCESS_VIEW_BINDING(op->pipeline));
1365 void wined3d_cs_emit_set_unordered_access_view(struct wined3d_cs *cs, enum wined3d_pipeline pipeline,
1366 unsigned int view_idx, struct wined3d_unordered_access_view *view, unsigned int initial_count)
1368 struct wined3d_cs_set_unordered_access_view *op;
1370 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1371 op->opcode = WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW;
1372 op->pipeline = pipeline;
1373 op->view_idx = view_idx;
1374 op->view = view;
1375 op->initial_count = initial_count;
1377 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1380 static void wined3d_cs_exec_set_sampler(struct wined3d_cs *cs, const void *data)
1382 const struct wined3d_cs_set_sampler *op = data;
1384 cs->state.sampler[op->type][op->sampler_idx] = op->sampler;
1385 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1386 device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1387 else
1388 device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1391 void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type,
1392 UINT sampler_idx, struct wined3d_sampler *sampler)
1394 struct wined3d_cs_set_sampler *op;
1396 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1397 op->opcode = WINED3D_CS_OP_SET_SAMPLER;
1398 op->type = type;
1399 op->sampler_idx = sampler_idx;
1400 op->sampler = sampler;
1402 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1405 static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
1407 const struct wined3d_cs_set_shader *op = data;
1409 cs->state.shader[op->type] = op->shader;
1410 device_invalidate_state(cs->device, STATE_SHADER(op->type));
1411 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1412 device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1413 else
1414 device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1417 void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader)
1419 struct wined3d_cs_set_shader *op;
1421 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1422 op->opcode = WINED3D_CS_OP_SET_SHADER;
1423 op->type = type;
1424 op->shader = shader;
1426 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1429 static void wined3d_cs_exec_set_rasterizer_state(struct wined3d_cs *cs, const void *data)
1431 const struct wined3d_cs_set_rasterizer_state *op = data;
1433 cs->state.rasterizer_state = op->state;
1434 device_invalidate_state(cs->device, STATE_FRONTFACE);
1437 void wined3d_cs_emit_set_rasterizer_state(struct wined3d_cs *cs,
1438 struct wined3d_rasterizer_state *rasterizer_state)
1440 struct wined3d_cs_set_rasterizer_state *op;
1442 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1443 op->opcode = WINED3D_CS_OP_SET_RASTERIZER_STATE;
1444 op->state = rasterizer_state;
1446 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1449 static void wined3d_cs_exec_set_render_state(struct wined3d_cs *cs, const void *data)
1451 const struct wined3d_cs_set_render_state *op = data;
1453 cs->state.render_states[op->state] = op->value;
1454 device_invalidate_state(cs->device, STATE_RENDER(op->state));
1457 void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render_state state, DWORD value)
1459 struct wined3d_cs_set_render_state *op;
1461 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1462 op->opcode = WINED3D_CS_OP_SET_RENDER_STATE;
1463 op->state = state;
1464 op->value = value;
1466 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1469 static void wined3d_cs_exec_set_texture_state(struct wined3d_cs *cs, const void *data)
1471 const struct wined3d_cs_set_texture_state *op = data;
1473 cs->state.texture_states[op->stage][op->state] = op->value;
1474 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, op->state));
1477 void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage,
1478 enum wined3d_texture_stage_state state, DWORD value)
1480 struct wined3d_cs_set_texture_state *op;
1482 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1483 op->opcode = WINED3D_CS_OP_SET_TEXTURE_STATE;
1484 op->stage = stage;
1485 op->state = state;
1486 op->value = value;
1488 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1491 static void wined3d_cs_exec_set_sampler_state(struct wined3d_cs *cs, const void *data)
1493 const struct wined3d_cs_set_sampler_state *op = data;
1495 cs->state.sampler_states[op->sampler_idx][op->state] = op->value;
1496 device_invalidate_state(cs->device, STATE_SAMPLER(op->sampler_idx));
1499 void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx,
1500 enum wined3d_sampler_state state, DWORD value)
1502 struct wined3d_cs_set_sampler_state *op;
1504 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1505 op->opcode = WINED3D_CS_OP_SET_SAMPLER_STATE;
1506 op->sampler_idx = sampler_idx;
1507 op->state = state;
1508 op->value = value;
1510 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1513 static void wined3d_cs_exec_set_transform(struct wined3d_cs *cs, const void *data)
1515 const struct wined3d_cs_set_transform *op = data;
1517 cs->state.transforms[op->state] = op->matrix;
1518 if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->d3d_info.limits.ffp_vertex_blend_matrices))
1519 device_invalidate_state(cs->device, STATE_TRANSFORM(op->state));
1522 void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform_state state,
1523 const struct wined3d_matrix *matrix)
1525 struct wined3d_cs_set_transform *op;
1527 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1528 op->opcode = WINED3D_CS_OP_SET_TRANSFORM;
1529 op->state = state;
1530 op->matrix = *matrix;
1532 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1535 static void wined3d_cs_exec_set_clip_plane(struct wined3d_cs *cs, const void *data)
1537 const struct wined3d_cs_set_clip_plane *op = data;
1539 cs->state.clip_planes[op->plane_idx] = op->plane;
1540 device_invalidate_state(cs->device, STATE_CLIPPLANE(op->plane_idx));
1543 void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const struct wined3d_vec4 *plane)
1545 struct wined3d_cs_set_clip_plane *op;
1547 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1548 op->opcode = WINED3D_CS_OP_SET_CLIP_PLANE;
1549 op->plane_idx = plane_idx;
1550 op->plane = *plane;
1552 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1555 static void wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *data)
1557 const struct wined3d_cs_set_color_key *op = data;
1558 struct wined3d_texture *texture = op->texture;
1560 if (op->set)
1562 switch (op->flags)
1564 case WINED3D_CKEY_DST_BLT:
1565 texture->async.dst_blt_color_key = op->color_key;
1566 texture->async.color_key_flags |= WINED3D_CKEY_DST_BLT;
1567 break;
1569 case WINED3D_CKEY_DST_OVERLAY:
1570 texture->async.dst_overlay_color_key = op->color_key;
1571 texture->async.color_key_flags |= WINED3D_CKEY_DST_OVERLAY;
1572 break;
1574 case WINED3D_CKEY_SRC_BLT:
1575 if (texture == cs->state.textures[0])
1577 device_invalidate_state(cs->device, STATE_COLOR_KEY);
1578 if (!(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT))
1579 device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1582 texture->async.src_blt_color_key = op->color_key;
1583 texture->async.color_key_flags |= WINED3D_CKEY_SRC_BLT;
1584 break;
1586 case WINED3D_CKEY_SRC_OVERLAY:
1587 texture->async.src_overlay_color_key = op->color_key;
1588 texture->async.color_key_flags |= WINED3D_CKEY_SRC_OVERLAY;
1589 break;
1592 else
1594 switch (op->flags)
1596 case WINED3D_CKEY_DST_BLT:
1597 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_BLT;
1598 break;
1600 case WINED3D_CKEY_DST_OVERLAY:
1601 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_OVERLAY;
1602 break;
1604 case WINED3D_CKEY_SRC_BLT:
1605 if (texture == cs->state.textures[0] && texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1606 device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1608 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_BLT;
1609 break;
1611 case WINED3D_CKEY_SRC_OVERLAY:
1612 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_OVERLAY;
1613 break;
1618 void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture *texture,
1619 WORD flags, const struct wined3d_color_key *color_key)
1621 struct wined3d_cs_set_color_key *op;
1623 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1624 op->opcode = WINED3D_CS_OP_SET_COLOR_KEY;
1625 op->texture = texture;
1626 op->flags = flags;
1627 if (color_key)
1629 op->color_key = *color_key;
1630 op->set = 1;
1632 else
1633 op->set = 0;
1635 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1638 static void wined3d_cs_exec_set_material(struct wined3d_cs *cs, const void *data)
1640 const struct wined3d_cs_set_material *op = data;
1642 cs->state.material = op->material;
1643 device_invalidate_state(cs->device, STATE_MATERIAL);
1646 void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_material *material)
1648 struct wined3d_cs_set_material *op;
1650 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1651 op->opcode = WINED3D_CS_OP_SET_MATERIAL;
1652 op->material = *material;
1654 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1657 static void wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data)
1659 const struct wined3d_cs_set_light *op = data;
1660 struct wined3d_light_info *light_info;
1661 unsigned int light_idx, hash_idx;
1663 light_idx = op->light.OriginalIndex;
1665 if (!(light_info = wined3d_state_get_light(&cs->state, light_idx)))
1667 TRACE("Adding new light.\n");
1668 if (!(light_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*light_info))))
1670 ERR("Failed to allocate light info.\n");
1671 return;
1674 hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1675 list_add_head(&cs->state.light_map[hash_idx], &light_info->entry);
1676 light_info->glIndex = -1;
1677 light_info->OriginalIndex = light_idx;
1680 if (light_info->glIndex != -1)
1682 if (light_info->OriginalParms.type != op->light.OriginalParms.type)
1683 device_invalidate_state(cs->device, STATE_LIGHT_TYPE);
1684 device_invalidate_state(cs->device, STATE_ACTIVELIGHT(light_info->glIndex));
1687 light_info->OriginalParms = op->light.OriginalParms;
1688 light_info->position = op->light.position;
1689 light_info->direction = op->light.direction;
1690 light_info->exponent = op->light.exponent;
1691 light_info->cutoff = op->light.cutoff;
1694 void wined3d_cs_emit_set_light(struct wined3d_cs *cs, const struct wined3d_light_info *light)
1696 struct wined3d_cs_set_light *op;
1698 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1699 op->opcode = WINED3D_CS_OP_SET_LIGHT;
1700 op->light = *light;
1702 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1705 static void wined3d_cs_exec_set_light_enable(struct wined3d_cs *cs, const void *data)
1707 const struct wined3d_cs_set_light_enable *op = data;
1708 struct wined3d_device *device = cs->device;
1709 struct wined3d_light_info *light_info;
1710 int prev_idx;
1712 if (!(light_info = wined3d_state_get_light(&cs->state, op->idx)))
1714 ERR("Light doesn't exist.\n");
1715 return;
1718 prev_idx = light_info->glIndex;
1719 wined3d_state_enable_light(&cs->state, &device->adapter->d3d_info, light_info, op->enable);
1720 if (light_info->glIndex != prev_idx)
1722 device_invalidate_state(device, STATE_LIGHT_TYPE);
1723 device_invalidate_state(device, STATE_ACTIVELIGHT(op->enable ? light_info->glIndex : prev_idx));
1727 void wined3d_cs_emit_set_light_enable(struct wined3d_cs *cs, unsigned int idx, BOOL enable)
1729 struct wined3d_cs_set_light_enable *op;
1731 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1732 op->opcode = WINED3D_CS_OP_SET_LIGHT_ENABLE;
1733 op->idx = idx;
1734 op->enable = enable;
1736 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1739 static const struct
1741 size_t offset;
1742 size_t size;
1743 DWORD mask;
1745 wined3d_cs_push_constant_info[] =
1747 /* WINED3D_PUSH_CONSTANTS_VS_F */
1748 {FIELD_OFFSET(struct wined3d_state, vs_consts_f), sizeof(struct wined3d_vec4), WINED3D_SHADER_CONST_VS_F},
1749 /* WINED3D_PUSH_CONSTANTS_PS_F */
1750 {FIELD_OFFSET(struct wined3d_state, ps_consts_f), sizeof(struct wined3d_vec4), WINED3D_SHADER_CONST_PS_F},
1751 /* WINED3D_PUSH_CONSTANTS_VS_I */
1752 {FIELD_OFFSET(struct wined3d_state, vs_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_VS_I},
1753 /* WINED3D_PUSH_CONSTANTS_PS_I */
1754 {FIELD_OFFSET(struct wined3d_state, ps_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_PS_I},
1755 /* WINED3D_PUSH_CONSTANTS_VS_B */
1756 {FIELD_OFFSET(struct wined3d_state, vs_consts_b), sizeof(BOOL), WINED3D_SHADER_CONST_VS_B},
1757 /* WINED3D_PUSH_CONSTANTS_PS_B */
1758 {FIELD_OFFSET(struct wined3d_state, ps_consts_b), sizeof(BOOL), WINED3D_SHADER_CONST_PS_B},
1761 static void wined3d_cs_st_push_constants(struct wined3d_cs *cs, enum wined3d_push_constants p,
1762 unsigned int start_idx, unsigned int count, const void *constants)
1764 struct wined3d_device *device = cs->device;
1765 unsigned int context_count;
1766 unsigned int i;
1767 size_t offset;
1769 if (p == WINED3D_PUSH_CONSTANTS_VS_F)
1770 device->shader_backend->shader_update_float_vertex_constants(device, start_idx, count);
1771 else if (p == WINED3D_PUSH_CONSTANTS_PS_F)
1772 device->shader_backend->shader_update_float_pixel_constants(device, start_idx, count);
1774 offset = wined3d_cs_push_constant_info[p].offset + start_idx * wined3d_cs_push_constant_info[p].size;
1775 memcpy((BYTE *)&cs->state + offset, constants, count * wined3d_cs_push_constant_info[p].size);
1776 for (i = 0, context_count = device->context_count; i < context_count; ++i)
1778 device->contexts[i]->constant_update_mask |= wined3d_cs_push_constant_info[p].mask;
1782 static void wined3d_cs_exec_push_constants(struct wined3d_cs *cs, const void *data)
1784 const struct wined3d_cs_push_constants *op = data;
1786 wined3d_cs_st_push_constants(cs, op->type, op->start_idx, op->count, op->constants);
1789 static void wined3d_cs_mt_push_constants(struct wined3d_cs *cs, enum wined3d_push_constants p,
1790 unsigned int start_idx, unsigned int count, const void *constants)
1792 struct wined3d_cs_push_constants *op;
1793 size_t size;
1795 size = count * wined3d_cs_push_constant_info[p].size;
1796 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_push_constants, constants[size]),
1797 WINED3D_CS_QUEUE_DEFAULT);
1798 op->opcode = WINED3D_CS_OP_PUSH_CONSTANTS;
1799 op->type = p;
1800 op->start_idx = start_idx;
1801 op->count = count;
1802 memcpy(op->constants, constants, size);
1804 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1807 static void wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data)
1809 struct wined3d_adapter *adapter = cs->device->adapter;
1811 state_cleanup(&cs->state);
1812 memset(&cs->state, 0, sizeof(cs->state));
1813 state_init(&cs->state, &cs->fb, &adapter->gl_info, &adapter->d3d_info,
1814 WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT);
1817 void wined3d_cs_emit_reset_state(struct wined3d_cs *cs)
1819 struct wined3d_cs_reset_state *op;
1821 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1822 op->opcode = WINED3D_CS_OP_RESET_STATE;
1824 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1827 static void wined3d_cs_exec_callback(struct wined3d_cs *cs, const void *data)
1829 const struct wined3d_cs_callback *op = data;
1831 op->callback(op->object);
1834 static void wined3d_cs_emit_callback(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1836 struct wined3d_cs_callback *op;
1838 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1839 op->opcode = WINED3D_CS_OP_CALLBACK;
1840 op->callback = callback;
1841 op->object = object;
1843 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1846 void wined3d_cs_destroy_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1848 wined3d_cs_emit_callback(cs, callback, object);
1851 void wined3d_cs_init_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1853 wined3d_cs_emit_callback(cs, callback, object);
1856 static void wined3d_cs_exec_query_issue(struct wined3d_cs *cs, const void *data)
1858 const struct wined3d_cs_query_issue *op = data;
1859 struct wined3d_query *query = op->query;
1860 BOOL poll;
1862 poll = query->query_ops->query_issue(query, op->flags);
1864 if (!cs->thread)
1865 return;
1867 if (poll && list_empty(&query->poll_list_entry))
1869 list_add_tail(&cs->query_poll_list, &query->poll_list_entry);
1870 return;
1873 /* This can happen if occlusion queries are restarted. This discards the
1874 * old result, since polling it could result in a GL error. */
1875 if ((op->flags & WINED3DISSUE_BEGIN) && !poll && !list_empty(&query->poll_list_entry))
1877 list_remove(&query->poll_list_entry);
1878 list_init(&query->poll_list_entry);
1879 InterlockedIncrement(&query->counter_retrieved);
1880 return;
1883 /* This can happen when an occlusion query is ended without being started,
1884 * in which case we don't want to poll, but still have to counter-balance
1885 * the increment of the main counter.
1887 * This can also happen if an event query is re-issued before the first
1888 * fence was reached. In this case the query is already in the list and
1889 * the poll function will check the new fence. We have to counter-balance
1890 * the discarded increment. */
1891 if (op->flags & WINED3DISSUE_END)
1892 InterlockedIncrement(&query->counter_retrieved);
1895 void wined3d_cs_emit_query_issue(struct wined3d_cs *cs, struct wined3d_query *query, DWORD flags)
1897 struct wined3d_cs_query_issue *op;
1899 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1900 op->opcode = WINED3D_CS_OP_QUERY_ISSUE;
1901 op->query = query;
1902 op->flags = flags;
1904 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1905 cs->queries_flushed = FALSE;
1908 static void wined3d_cs_exec_preload_resource(struct wined3d_cs *cs, const void *data)
1910 const struct wined3d_cs_preload_resource *op = data;
1911 struct wined3d_resource *resource = op->resource;
1913 resource->resource_ops->resource_preload(resource);
1914 wined3d_resource_release(resource);
1917 void wined3d_cs_emit_preload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
1919 struct wined3d_cs_preload_resource *op;
1921 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1922 op->opcode = WINED3D_CS_OP_PRELOAD_RESOURCE;
1923 op->resource = resource;
1925 wined3d_resource_acquire(resource);
1927 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1930 static void wined3d_cs_exec_unload_resource(struct wined3d_cs *cs, const void *data)
1932 const struct wined3d_cs_unload_resource *op = data;
1933 struct wined3d_resource *resource = op->resource;
1935 resource->resource_ops->resource_unload(resource);
1936 wined3d_resource_release(resource);
1939 void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
1941 struct wined3d_cs_unload_resource *op;
1943 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1944 op->opcode = WINED3D_CS_OP_UNLOAD_RESOURCE;
1945 op->resource = resource;
1947 wined3d_resource_acquire(resource);
1949 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1952 static void wined3d_cs_exec_map(struct wined3d_cs *cs, const void *data)
1954 const struct wined3d_cs_map *op = data;
1955 struct wined3d_resource *resource = op->resource;
1957 *op->hr = resource->resource_ops->resource_sub_resource_map(resource,
1958 op->sub_resource_idx, op->map_desc, op->box, op->flags);
1961 HRESULT wined3d_cs_map(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx,
1962 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, unsigned int flags)
1964 struct wined3d_cs_map *op;
1965 HRESULT hr;
1967 /* Mapping resources from the worker thread isn't an issue by itself, but
1968 * increasing the map count would be visible to applications. */
1969 wined3d_not_from_cs(cs);
1971 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
1972 op->opcode = WINED3D_CS_OP_MAP;
1973 op->resource = resource;
1974 op->sub_resource_idx = sub_resource_idx;
1975 op->map_desc = map_desc;
1976 op->box = box;
1977 op->flags = flags;
1978 op->hr = &hr;
1980 cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
1981 cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
1983 return hr;
1986 static void wined3d_cs_exec_unmap(struct wined3d_cs *cs, const void *data)
1988 const struct wined3d_cs_unmap *op = data;
1989 struct wined3d_resource *resource = op->resource;
1991 *op->hr = resource->resource_ops->resource_sub_resource_unmap(resource, op->sub_resource_idx);
1994 HRESULT wined3d_cs_unmap(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx)
1996 struct wined3d_cs_unmap *op;
1997 HRESULT hr;
1999 wined3d_not_from_cs(cs);
2001 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2002 op->opcode = WINED3D_CS_OP_UNMAP;
2003 op->resource = resource;
2004 op->sub_resource_idx = sub_resource_idx;
2005 op->hr = &hr;
2007 cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2008 cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2010 return hr;
2013 static void wined3d_cs_exec_blt_sub_resource(struct wined3d_cs *cs, const void *data)
2015 const struct wined3d_cs_blt_sub_resource *op = data;
2017 if (op->dst_resource->type == WINED3D_RTYPE_BUFFER)
2019 wined3d_buffer_copy(buffer_from_resource(op->dst_resource), op->dst_box.left,
2020 buffer_from_resource(op->src_resource), op->src_box.left,
2021 op->src_box.right - op->src_box.left);
2023 else if (op->dst_resource->type == WINED3D_RTYPE_TEXTURE_2D)
2025 struct wined3d_surface *dst_surface, *src_surface;
2026 struct wined3d_texture *dst_texture, *src_texture;
2027 RECT dst_rect, src_rect;
2029 dst_texture = texture_from_resource(op->dst_resource);
2030 src_texture = texture_from_resource(op->src_resource);
2031 dst_surface = dst_texture->sub_resources[op->dst_sub_resource_idx].u.surface;
2032 src_surface = src_texture->sub_resources[op->src_sub_resource_idx].u.surface;
2033 SetRect(&dst_rect, op->dst_box.left, op->dst_box.top, op->dst_box.right, op->dst_box.bottom);
2034 SetRect(&src_rect, op->src_box.left, op->src_box.top, op->src_box.right, op->src_box.bottom);
2036 if (FAILED(wined3d_surface_blt(dst_surface, &dst_rect, src_surface,
2037 &src_rect, op->flags, &op->fx, op->filter)))
2038 FIXME("Blit failed.\n");
2040 else if (op->dst_resource->type == WINED3D_RTYPE_TEXTURE_3D)
2042 struct wined3d_texture *src_texture, *dst_texture;
2043 unsigned int level, update_w, update_h, update_d;
2044 unsigned int row_pitch, slice_pitch;
2045 struct wined3d_context *context;
2046 struct wined3d_bo_address addr;
2048 if (op->flags & ~WINED3D_BLT_RAW)
2050 FIXME("Flags %#x not implemented for %s resources.\n",
2051 op->flags, debug_d3dresourcetype(op->dst_resource->type));
2052 goto error;
2055 if (!(op->flags & WINED3D_BLT_RAW) && op->src_resource->format != op->dst_resource->format)
2057 FIXME("Format conversion not implemented for %s resources.\n",
2058 debug_d3dresourcetype(op->dst_resource->type));
2059 goto error;
2062 update_w = op->dst_box.right - op->dst_box.left;
2063 update_h = op->dst_box.bottom - op->dst_box.top;
2064 update_d = op->dst_box.back - op->dst_box.front;
2065 if (op->src_box.right - op->src_box.left != update_w
2066 || op->src_box.bottom - op->src_box.top != update_h
2067 || op->src_box.back - op->src_box.front != update_d)
2069 FIXME("Stretching not implemented for %s resources.\n",
2070 debug_d3dresourcetype(op->dst_resource->type));
2071 goto error;
2074 if (op->src_box.left || op->src_box.top || op->src_box.front)
2076 FIXME("Source box %s not supported for %s resources.\n",
2077 debug_box(&op->src_box), debug_d3dresourcetype(op->dst_resource->type));
2078 goto error;
2081 dst_texture = texture_from_resource(op->dst_resource);
2082 src_texture = texture_from_resource(op->src_resource);
2084 context = context_acquire(cs->device, NULL, 0);
2086 if (!wined3d_texture_load_location(src_texture, op->src_sub_resource_idx,
2087 context, src_texture->resource.map_binding))
2089 ERR("Failed to load source sub-resource into %s.\n",
2090 wined3d_debug_location(src_texture->resource.map_binding));
2091 context_release(context);
2092 goto error;
2095 level = op->dst_sub_resource_idx % dst_texture->level_count;
2096 if (update_w == wined3d_texture_get_level_width(dst_texture, level)
2097 && update_h == wined3d_texture_get_level_height(dst_texture, level)
2098 && update_d == wined3d_texture_get_level_depth(dst_texture, level))
2100 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
2102 else if (!wined3d_texture_load_location(dst_texture, op->dst_sub_resource_idx,
2103 context, WINED3D_LOCATION_TEXTURE_RGB))
2105 ERR("Failed to load destination sub-resource.\n");
2106 context_release(context);
2107 goto error;
2110 wined3d_texture_get_memory(src_texture, op->src_sub_resource_idx, &addr, src_texture->resource.map_binding);
2111 wined3d_texture_get_pitch(src_texture, op->src_sub_resource_idx % src_texture->level_count,
2112 &row_pitch, &slice_pitch);
2114 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
2115 wined3d_texture_upload_data(dst_texture, op->dst_sub_resource_idx, context, &op->dst_box,
2116 wined3d_const_bo_address(&addr), row_pitch, slice_pitch);
2117 wined3d_texture_validate_location(dst_texture, op->dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2118 wined3d_texture_invalidate_location(dst_texture, op->dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2120 context_release(context);
2122 else
2124 FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(op->dst_resource->type));
2127 error:
2128 if (op->src_resource)
2129 wined3d_resource_release(op->src_resource);
2130 wined3d_resource_release(op->dst_resource);
2133 void wined3d_cs_emit_blt_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *dst_resource,
2134 unsigned int dst_sub_resource_idx, const struct wined3d_box *dst_box, struct wined3d_resource *src_resource,
2135 unsigned int src_sub_resource_idx, const struct wined3d_box *src_box, DWORD flags,
2136 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2138 struct wined3d_cs_blt_sub_resource *op;
2140 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2141 op->opcode = WINED3D_CS_OP_BLT_SUB_RESOURCE;
2142 op->dst_resource = dst_resource;
2143 op->dst_sub_resource_idx = dst_sub_resource_idx;
2144 op->dst_box = *dst_box;
2145 op->src_resource = src_resource;
2146 op->src_sub_resource_idx = src_sub_resource_idx;
2147 op->src_box = *src_box;
2148 op->flags = flags;
2149 if (fx)
2150 op->fx = *fx;
2151 else
2152 memset(&op->fx, 0, sizeof(op->fx));
2153 op->filter = filter;
2155 wined3d_resource_acquire(dst_resource);
2156 if (src_resource)
2157 wined3d_resource_acquire(src_resource);
2159 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2160 if (flags & WINED3D_BLT_SYNCHRONOUS)
2161 cs->ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT);
2164 static void wined3d_cs_exec_update_sub_resource(struct wined3d_cs *cs, const void *data)
2166 const struct wined3d_cs_update_sub_resource *op = data;
2167 const struct wined3d_box *box = &op->box;
2168 unsigned int width, height, depth, level;
2169 struct wined3d_const_bo_address addr;
2170 struct wined3d_context *context;
2171 struct wined3d_texture *texture;
2173 if (op->resource->type == WINED3D_RTYPE_BUFFER)
2175 struct wined3d_buffer *buffer = buffer_from_resource(op->resource);
2177 context = context_acquire(op->resource->device, NULL, 0);
2178 if (!wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER))
2180 ERR("Failed to load buffer location.\n");
2181 context_release(context);
2182 goto done;
2185 wined3d_buffer_upload_data(buffer, context, box, op->data.data);
2186 wined3d_buffer_invalidate_location(buffer, ~WINED3D_LOCATION_BUFFER);
2187 context_release(context);
2188 goto done;
2191 texture = wined3d_texture_from_resource(op->resource);
2193 level = op->sub_resource_idx % texture->level_count;
2194 width = wined3d_texture_get_level_width(texture, level);
2195 height = wined3d_texture_get_level_height(texture, level);
2196 depth = wined3d_texture_get_level_depth(texture, level);
2198 addr.buffer_object = 0;
2199 addr.addr = op->data.data;
2201 context = context_acquire(op->resource->device, NULL, 0);
2203 /* Only load the sub-resource for partial updates. */
2204 if (!box->left && !box->top && !box->front
2205 && box->right == width && box->bottom == height && box->back == depth)
2206 wined3d_texture_prepare_texture(texture, context, FALSE);
2207 else
2208 wined3d_texture_load_location(texture, op->sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2209 wined3d_texture_bind_and_dirtify(texture, context, FALSE);
2211 wined3d_texture_upload_data(texture, op->sub_resource_idx, context,
2212 box, &addr, op->data.row_pitch, op->data.slice_pitch);
2214 context_release(context);
2216 wined3d_texture_validate_location(texture, op->sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2217 wined3d_texture_invalidate_location(texture, op->sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2219 done:
2220 wined3d_resource_release(op->resource);
2223 void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource,
2224 unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch,
2225 unsigned int slice_pitch)
2227 struct wined3d_cs_update_sub_resource *op;
2229 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2230 op->opcode = WINED3D_CS_OP_UPDATE_SUB_RESOURCE;
2231 op->resource = resource;
2232 op->sub_resource_idx = sub_resource_idx;
2233 op->box = *box;
2234 op->data.row_pitch = row_pitch;
2235 op->data.slice_pitch = slice_pitch;
2236 op->data.data = data;
2238 wined3d_resource_acquire(resource);
2240 cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2241 /* The data pointer may go away, so we need to wait until it is read.
2242 * Copying the data may be faster if it's small. */
2243 cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2246 static void wined3d_cs_exec_add_dirty_texture_region(struct wined3d_cs *cs, const void *data)
2248 const struct wined3d_cs_add_dirty_texture_region *op = data;
2249 struct wined3d_texture *texture = op->texture;
2250 unsigned int sub_resource_idx, i;
2251 struct wined3d_context *context;
2253 context = context_acquire(cs->device, NULL, 0);
2254 sub_resource_idx = op->layer * texture->level_count;
2255 for (i = 0; i < texture->level_count; ++i, ++sub_resource_idx)
2257 if (wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding))
2258 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
2259 else
2260 ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
2262 context_release(context);
2264 wined3d_resource_release(&texture->resource);
2267 void wined3d_cs_emit_add_dirty_texture_region(struct wined3d_cs *cs,
2268 struct wined3d_texture *texture, unsigned int layer)
2270 struct wined3d_cs_add_dirty_texture_region *op;
2272 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2273 op->opcode = WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION;
2274 op->texture = texture;
2275 op->layer = layer;
2277 wined3d_resource_acquire(&texture->resource);
2279 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2282 static void wined3d_cs_exec_clear_unordered_access_view(struct wined3d_cs *cs, const void *data)
2284 const struct wined3d_cs_clear_unordered_access_view *op = data;
2285 struct wined3d_unordered_access_view *view = op->view;
2286 struct wined3d_context *context;
2288 context = context_acquire(cs->device, NULL, 0);
2289 wined3d_unordered_access_view_clear_uint(view, &op->clear_value, context);
2290 context_release(context);
2292 wined3d_resource_release(view->resource);
2295 void wined3d_cs_emit_clear_unordered_access_view_uint(struct wined3d_cs *cs,
2296 struct wined3d_unordered_access_view *view, const struct wined3d_uvec4 *clear_value)
2298 struct wined3d_cs_clear_unordered_access_view *op;
2300 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2301 op->opcode = WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW;
2302 op->view = view;
2303 op->clear_value = *clear_value;
2305 wined3d_resource_acquire(view->resource);
2307 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2310 static void wined3d_cs_exec_copy_uav_counter(struct wined3d_cs *cs, const void *data)
2312 const struct wined3d_cs_copy_uav_counter *op = data;
2313 struct wined3d_unordered_access_view *view = op->view;
2314 struct wined3d_context *context;
2316 context = context_acquire(cs->device, NULL, 0);
2317 wined3d_unordered_access_view_copy_counter(view, op->buffer, op->offset, context);
2318 context_release(context);
2320 wined3d_resource_release(&op->buffer->resource);
2323 void wined3d_cs_emit_copy_uav_counter(struct wined3d_cs *cs, struct wined3d_buffer *dst_buffer,
2324 unsigned int offset, struct wined3d_unordered_access_view *uav)
2326 struct wined3d_cs_copy_uav_counter *op;
2328 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2329 op->opcode = WINED3D_CS_OP_COPY_UAV_COUNTER;
2330 op->buffer = dst_buffer;
2331 op->offset = offset;
2332 op->view = uav;
2334 wined3d_resource_acquire(&dst_buffer->resource);
2336 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2339 static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
2341 struct wined3d_cs_stop *op;
2343 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2344 op->opcode = WINED3D_CS_OP_STOP;
2346 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2347 cs->ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT);
2350 static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
2352 /* WINED3D_CS_OP_NOP */ wined3d_cs_exec_nop,
2353 /* WINED3D_CS_OP_PRESENT */ wined3d_cs_exec_present,
2354 /* WINED3D_CS_OP_CLEAR */ wined3d_cs_exec_clear,
2355 /* WINED3D_CS_OP_DISPATCH */ wined3d_cs_exec_dispatch,
2356 /* WINED3D_CS_OP_DRAW */ wined3d_cs_exec_draw,
2357 /* WINED3D_CS_OP_FLUSH */ wined3d_cs_exec_flush,
2358 /* WINED3D_CS_OP_SET_PREDICATION */ wined3d_cs_exec_set_predication,
2359 /* WINED3D_CS_OP_SET_VIEWPORT */ wined3d_cs_exec_set_viewport,
2360 /* WINED3D_CS_OP_SET_SCISSOR_RECT */ wined3d_cs_exec_set_scissor_rect,
2361 /* WINED3D_CS_OP_SET_RENDERTARGET_VIEW */ wined3d_cs_exec_set_rendertarget_view,
2362 /* WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW */ wined3d_cs_exec_set_depth_stencil_view,
2363 /* WINED3D_CS_OP_SET_VERTEX_DECLARATION */ wined3d_cs_exec_set_vertex_declaration,
2364 /* WINED3D_CS_OP_SET_STREAM_SOURCE */ wined3d_cs_exec_set_stream_source,
2365 /* WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ */ wined3d_cs_exec_set_stream_source_freq,
2366 /* WINED3D_CS_OP_SET_STREAM_OUTPUT */ wined3d_cs_exec_set_stream_output,
2367 /* WINED3D_CS_OP_SET_INDEX_BUFFER */ wined3d_cs_exec_set_index_buffer,
2368 /* WINED3D_CS_OP_SET_CONSTANT_BUFFER */ wined3d_cs_exec_set_constant_buffer,
2369 /* WINED3D_CS_OP_SET_TEXTURE */ wined3d_cs_exec_set_texture,
2370 /* WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW */ wined3d_cs_exec_set_shader_resource_view,
2371 /* WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_set_unordered_access_view,
2372 /* WINED3D_CS_OP_SET_SAMPLER */ wined3d_cs_exec_set_sampler,
2373 /* WINED3D_CS_OP_SET_SHADER */ wined3d_cs_exec_set_shader,
2374 /* WINED3D_CS_OP_SET_RASTERIZER_STATE */ wined3d_cs_exec_set_rasterizer_state,
2375 /* WINED3D_CS_OP_SET_RENDER_STATE */ wined3d_cs_exec_set_render_state,
2376 /* WINED3D_CS_OP_SET_TEXTURE_STATE */ wined3d_cs_exec_set_texture_state,
2377 /* WINED3D_CS_OP_SET_SAMPLER_STATE */ wined3d_cs_exec_set_sampler_state,
2378 /* WINED3D_CS_OP_SET_TRANSFORM */ wined3d_cs_exec_set_transform,
2379 /* WINED3D_CS_OP_SET_CLIP_PLANE */ wined3d_cs_exec_set_clip_plane,
2380 /* WINED3D_CS_OP_SET_COLOR_KEY */ wined3d_cs_exec_set_color_key,
2381 /* WINED3D_CS_OP_SET_MATERIAL */ wined3d_cs_exec_set_material,
2382 /* WINED3D_CS_OP_SET_LIGHT */ wined3d_cs_exec_set_light,
2383 /* WINED3D_CS_OP_SET_LIGHT_ENABLE */ wined3d_cs_exec_set_light_enable,
2384 /* WINED3D_CS_OP_PUSH_CONSTANTS */ wined3d_cs_exec_push_constants,
2385 /* WINED3D_CS_OP_RESET_STATE */ wined3d_cs_exec_reset_state,
2386 /* WINED3D_CS_OP_CALLBACK */ wined3d_cs_exec_callback,
2387 /* WINED3D_CS_OP_QUERY_ISSUE */ wined3d_cs_exec_query_issue,
2388 /* WINED3D_CS_OP_PRELOAD_RESOURCE */ wined3d_cs_exec_preload_resource,
2389 /* WINED3D_CS_OP_UNLOAD_RESOURCE */ wined3d_cs_exec_unload_resource,
2390 /* WINED3D_CS_OP_MAP */ wined3d_cs_exec_map,
2391 /* WINED3D_CS_OP_UNMAP */ wined3d_cs_exec_unmap,
2392 /* WINED3D_CS_OP_BLT_SUB_RESOURCE */ wined3d_cs_exec_blt_sub_resource,
2393 /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE */ wined3d_cs_exec_update_sub_resource,
2394 /* WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION */ wined3d_cs_exec_add_dirty_texture_region,
2395 /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view,
2396 /* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter,
2399 static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2401 if (size > (cs->data_size - cs->end))
2403 size_t new_size;
2404 void *new_data;
2406 new_size = max(size, cs->data_size * 2);
2407 if (!cs->end)
2408 new_data = HeapReAlloc(GetProcessHeap(), 0, cs->data, new_size);
2409 else
2410 new_data = HeapAlloc(GetProcessHeap(), 0, new_size);
2411 if (!new_data)
2412 return NULL;
2414 cs->data_size = new_size;
2415 cs->start = cs->end = 0;
2416 cs->data = new_data;
2419 cs->end += size;
2421 return (BYTE *)cs->data + cs->start;
2424 static void wined3d_cs_st_submit(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2426 enum wined3d_cs_op opcode;
2427 size_t start;
2428 BYTE *data;
2430 data = cs->data;
2431 start = cs->start;
2432 cs->start = cs->end;
2434 opcode = *(const enum wined3d_cs_op *)&data[start];
2435 if (opcode >= WINED3D_CS_OP_STOP)
2436 ERR("Invalid opcode %#x.\n", opcode);
2437 else
2438 wined3d_cs_op_handlers[opcode](cs, &data[start]);
2440 if (cs->data == data)
2441 cs->start = cs->end = start;
2442 else if (!start)
2443 HeapFree(GetProcessHeap(), 0, data);
2446 static void wined3d_cs_st_finish(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2450 static const struct wined3d_cs_ops wined3d_cs_st_ops =
2452 wined3d_cs_st_require_space,
2453 wined3d_cs_st_submit,
2454 wined3d_cs_st_finish,
2455 wined3d_cs_st_push_constants,
2458 static BOOL wined3d_cs_queue_is_empty(const struct wined3d_cs *cs, const struct wined3d_cs_queue *queue)
2460 wined3d_from_cs(cs);
2461 return *(volatile LONG *)&queue->head == queue->tail;
2464 static void wined3d_cs_queue_submit(struct wined3d_cs_queue *queue, struct wined3d_cs *cs)
2466 struct wined3d_cs_packet *packet;
2467 size_t packet_size;
2469 packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
2470 packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[packet->size]);
2471 InterlockedExchange(&queue->head, (queue->head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1));
2473 if (InterlockedCompareExchange(&cs->waiting_for_event, FALSE, TRUE))
2474 SetEvent(cs->event);
2477 static void wined3d_cs_mt_submit(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2479 if (cs->thread_id == GetCurrentThreadId())
2480 return wined3d_cs_st_submit(cs, queue_id);
2482 wined3d_cs_queue_submit(&cs->queue[queue_id], cs);
2485 static void *wined3d_cs_queue_require_space(struct wined3d_cs_queue *queue, size_t size, struct wined3d_cs *cs)
2487 size_t queue_size = ARRAY_SIZE(queue->data);
2488 size_t header_size, packet_size, remaining;
2489 struct wined3d_cs_packet *packet;
2491 header_size = FIELD_OFFSET(struct wined3d_cs_packet, data[0]);
2492 size = (size + header_size - 1) & ~(header_size - 1);
2493 packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[size]);
2494 if (packet_size >= WINED3D_CS_QUEUE_SIZE)
2496 ERR("Packet size %lu >= queue size %u.\n",
2497 (unsigned long)packet_size, WINED3D_CS_QUEUE_SIZE);
2498 return NULL;
2501 remaining = queue_size - queue->head;
2502 if (remaining < packet_size)
2504 size_t nop_size = remaining - header_size;
2505 struct wined3d_cs_nop *nop;
2507 TRACE("Inserting a nop for %lu + %lu bytes.\n",
2508 (unsigned long)header_size, (unsigned long)nop_size);
2510 nop = wined3d_cs_queue_require_space(queue, nop_size, cs);
2511 if (nop_size)
2512 nop->opcode = WINED3D_CS_OP_NOP;
2514 wined3d_cs_queue_submit(queue, cs);
2515 assert(!queue->head);
2518 for (;;)
2520 LONG tail = *(volatile LONG *)&queue->tail;
2521 LONG head = queue->head;
2522 LONG new_pos;
2524 /* Empty. */
2525 if (head == tail)
2526 break;
2527 new_pos = (head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1);
2528 /* Head ahead of tail. We checked the remaining size above, so we only
2529 * need to make sure we don't make head equal to tail. */
2530 if (head > tail && (new_pos != tail))
2531 break;
2532 /* Tail ahead of head. Make sure the new head is before the tail as
2533 * well. Note that new_pos is 0 when it's at the end of the queue. */
2534 if (new_pos < tail && new_pos)
2535 break;
2537 TRACE("Waiting for free space. Head %u, tail %u, packet size %lu.\n",
2538 head, tail, (unsigned long)packet_size);
2541 packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
2542 packet->size = size;
2543 return packet->data;
2546 static void *wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2548 if (cs->thread_id == GetCurrentThreadId())
2549 return wined3d_cs_st_require_space(cs, size, queue_id);
2551 return wined3d_cs_queue_require_space(&cs->queue[queue_id], size, cs);
2554 static void wined3d_cs_mt_finish(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2556 if (cs->thread_id == GetCurrentThreadId())
2557 return wined3d_cs_st_finish(cs, queue_id);
2559 while (cs->queue[queue_id].head != *(volatile LONG *)&cs->queue[queue_id].tail)
2560 wined3d_pause();
2563 static const struct wined3d_cs_ops wined3d_cs_mt_ops =
2565 wined3d_cs_mt_require_space,
2566 wined3d_cs_mt_submit,
2567 wined3d_cs_mt_finish,
2568 wined3d_cs_mt_push_constants,
2571 static void poll_queries(struct wined3d_cs *cs)
2573 struct wined3d_query *query, *cursor;
2575 LIST_FOR_EACH_ENTRY_SAFE(query, cursor, &cs->query_poll_list, struct wined3d_query, poll_list_entry)
2577 if (!query->query_ops->query_poll(query, 0))
2578 continue;
2580 list_remove(&query->poll_list_entry);
2581 list_init(&query->poll_list_entry);
2582 InterlockedIncrement(&query->counter_retrieved);
2586 static void wined3d_cs_wait_event(struct wined3d_cs *cs)
2588 InterlockedExchange(&cs->waiting_for_event, TRUE);
2590 /* The main thread might have enqueued a command and blocked on it after
2591 * the CS thread decided to enter wined3d_cs_wait_event(), but before
2592 * "waiting_for_event" was set.
2594 * Likewise, we can race with the main thread when resetting
2595 * "waiting_for_event", in which case we would need to call
2596 * WaitForSingleObject() because the main thread called SetEvent(). */
2597 if (!(wined3d_cs_queue_is_empty(cs, &cs->queue[WINED3D_CS_QUEUE_DEFAULT])
2598 && wined3d_cs_queue_is_empty(cs, &cs->queue[WINED3D_CS_QUEUE_MAP]))
2599 && InterlockedCompareExchange(&cs->waiting_for_event, FALSE, TRUE))
2600 return;
2602 WaitForSingleObject(cs->event, INFINITE);
2605 static DWORD WINAPI wined3d_cs_run(void *ctx)
2607 struct wined3d_cs_packet *packet;
2608 struct wined3d_cs_queue *queue;
2609 unsigned int spin_count = 0;
2610 struct wined3d_cs *cs = ctx;
2611 enum wined3d_cs_op opcode;
2612 HMODULE wined3d_module;
2613 unsigned int poll = 0;
2614 LONG tail;
2616 TRACE("Started.\n");
2618 /* Copy the module handle to a local variable to avoid racing with the
2619 * thread freeing "cs" before the FreeLibraryAndExitThread() call. */
2620 wined3d_module = cs->wined3d_module;
2622 list_init(&cs->query_poll_list);
2623 cs->thread_id = GetCurrentThreadId();
2624 for (;;)
2626 if (++poll == WINED3D_CS_QUERY_POLL_INTERVAL)
2628 poll_queries(cs);
2629 poll = 0;
2632 queue = &cs->queue[WINED3D_CS_QUEUE_MAP];
2633 if (wined3d_cs_queue_is_empty(cs, queue))
2635 queue = &cs->queue[WINED3D_CS_QUEUE_DEFAULT];
2636 if (wined3d_cs_queue_is_empty(cs, queue))
2638 if (++spin_count >= WINED3D_CS_SPIN_COUNT && list_empty(&cs->query_poll_list))
2639 wined3d_cs_wait_event(cs);
2640 continue;
2643 spin_count = 0;
2645 tail = queue->tail;
2646 packet = (struct wined3d_cs_packet *)&queue->data[tail];
2647 if (packet->size)
2649 opcode = *(const enum wined3d_cs_op *)packet->data;
2651 if (opcode >= WINED3D_CS_OP_STOP)
2653 if (opcode > WINED3D_CS_OP_STOP)
2654 ERR("Invalid opcode %#x.\n", opcode);
2655 break;
2658 wined3d_cs_op_handlers[opcode](cs, packet->data);
2661 tail += FIELD_OFFSET(struct wined3d_cs_packet, data[packet->size]);
2662 tail &= (WINED3D_CS_QUEUE_SIZE - 1);
2663 InterlockedExchange(&queue->tail, tail);
2666 cs->queue[WINED3D_CS_QUEUE_MAP].tail = cs->queue[WINED3D_CS_QUEUE_MAP].head;
2667 cs->queue[WINED3D_CS_QUEUE_DEFAULT].tail = cs->queue[WINED3D_CS_QUEUE_DEFAULT].head;
2668 TRACE("Stopped.\n");
2669 FreeLibraryAndExitThread(wined3d_module, 0);
2672 struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device)
2674 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2675 struct wined3d_cs *cs;
2677 if (!(cs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cs))))
2678 return NULL;
2680 cs->ops = &wined3d_cs_st_ops;
2681 cs->device = device;
2683 if (!(cs->fb.render_targets = wined3d_calloc(gl_info->limits.buffers, sizeof(*cs->fb.render_targets))))
2685 HeapFree(GetProcessHeap(), 0, cs);
2686 return NULL;
2689 state_init(&cs->state, &cs->fb, gl_info, &device->adapter->d3d_info,
2690 WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT);
2692 cs->data_size = WINED3D_INITIAL_CS_SIZE;
2693 if (!(cs->data = HeapAlloc(GetProcessHeap(), 0, cs->data_size)))
2694 goto fail;
2696 if (wined3d_settings.cs_multithreaded
2697 && !RtlIsCriticalSectionLockedByThread(NtCurrentTeb()->Peb->LoaderLock))
2699 cs->ops = &wined3d_cs_mt_ops;
2701 if (!(cs->event = CreateEventW(NULL, FALSE, FALSE, NULL)))
2703 ERR("Failed to create command stream event.\n");
2704 HeapFree(GetProcessHeap(), 0, cs->data);
2705 goto fail;
2708 if (!(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
2709 (const WCHAR *)wined3d_cs_run, &cs->wined3d_module)))
2711 ERR("Failed to get wined3d module handle.\n");
2712 CloseHandle(cs->event);
2713 HeapFree(GetProcessHeap(), 0, cs->data);
2714 goto fail;
2717 if (!(cs->thread = CreateThread(NULL, 0, wined3d_cs_run, cs, 0, NULL)))
2719 ERR("Failed to create wined3d command stream thread.\n");
2720 FreeLibrary(cs->wined3d_module);
2721 CloseHandle(cs->event);
2722 HeapFree(GetProcessHeap(), 0, cs->data);
2723 goto fail;
2727 return cs;
2729 fail:
2730 state_cleanup(&cs->state);
2731 HeapFree(GetProcessHeap(), 0, cs->fb.render_targets);
2732 HeapFree(GetProcessHeap(), 0, cs);
2733 return NULL;
2736 void wined3d_cs_destroy(struct wined3d_cs *cs)
2738 if (cs->thread)
2740 wined3d_cs_emit_stop(cs);
2741 CloseHandle(cs->thread);
2742 if (!CloseHandle(cs->event))
2743 ERR("Closing event failed.\n");
2746 state_cleanup(&cs->state);
2747 HeapFree(GetProcessHeap(), 0, cs->fb.render_targets);
2748 HeapFree(GetProcessHeap(), 0, cs->data);
2749 HeapFree(GetProcessHeap(), 0, cs);