wined3d: Store the blend factor as a struct wined3d_color.
[wine.git] / dlls / wined3d / cs.c
blobfc3e47e3298764d4b1e910b565d0f4b5403562f6
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_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,
79 struct wined3d_cs_packet
81 size_t size;
82 BYTE data[1];
85 struct wined3d_cs_nop
87 enum wined3d_cs_op opcode;
90 struct wined3d_cs_present
92 enum wined3d_cs_op opcode;
93 HWND dst_window_override;
94 struct wined3d_swapchain *swapchain;
95 RECT src_rect;
96 RECT dst_rect;
97 unsigned int swap_interval;
98 DWORD flags;
101 struct wined3d_cs_clear
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];
115 struct wined3d_cs_dispatch
117 enum wined3d_cs_op opcode;
118 struct wined3d_dispatch_parameters parameters;
121 struct wined3d_cs_draw
123 enum wined3d_cs_op opcode;
124 GLenum primitive_type;
125 GLint patch_vertex_count;
126 struct wined3d_draw_parameters parameters;
129 struct wined3d_cs_flush
131 enum wined3d_cs_op opcode;
134 struct wined3d_cs_set_predication
136 enum wined3d_cs_op opcode;
137 struct wined3d_query *predicate;
138 BOOL value;
141 struct wined3d_cs_set_viewports
143 enum wined3d_cs_op opcode;
144 unsigned int viewport_count;
145 struct wined3d_viewport viewports[1];
148 struct wined3d_cs_set_scissor_rects
150 enum wined3d_cs_op opcode;
151 unsigned int rect_count;
152 RECT rects[1];
155 struct wined3d_cs_set_rendertarget_view
157 enum wined3d_cs_op opcode;
158 unsigned int view_idx;
159 struct wined3d_rendertarget_view *view;
162 struct wined3d_cs_set_depth_stencil_view
164 enum wined3d_cs_op opcode;
165 struct wined3d_rendertarget_view *view;
168 struct wined3d_cs_set_vertex_declaration
170 enum wined3d_cs_op opcode;
171 struct wined3d_vertex_declaration *declaration;
174 struct wined3d_cs_set_stream_source
176 enum wined3d_cs_op opcode;
177 UINT stream_idx;
178 struct wined3d_buffer *buffer;
179 UINT offset;
180 UINT stride;
183 struct wined3d_cs_set_stream_source_freq
185 enum wined3d_cs_op opcode;
186 UINT stream_idx;
187 UINT frequency;
188 UINT flags;
191 struct wined3d_cs_set_stream_output
193 enum wined3d_cs_op opcode;
194 UINT stream_idx;
195 struct wined3d_buffer *buffer;
196 UINT offset;
199 struct wined3d_cs_set_index_buffer
201 enum wined3d_cs_op opcode;
202 struct wined3d_buffer *buffer;
203 enum wined3d_format_id format_id;
204 unsigned int offset;
207 struct wined3d_cs_set_constant_buffer
209 enum wined3d_cs_op opcode;
210 enum wined3d_shader_type type;
211 UINT cb_idx;
212 struct wined3d_buffer *buffer;
215 struct wined3d_cs_set_texture
217 enum wined3d_cs_op opcode;
218 UINT stage;
219 struct wined3d_texture *texture;
222 struct wined3d_cs_set_color_key
224 enum wined3d_cs_op opcode;
225 struct wined3d_texture *texture;
226 WORD flags;
227 WORD set;
228 struct wined3d_color_key color_key;
231 struct wined3d_cs_set_shader_resource_view
233 enum wined3d_cs_op opcode;
234 enum wined3d_shader_type type;
235 UINT view_idx;
236 struct wined3d_shader_resource_view *view;
239 struct wined3d_cs_set_unordered_access_view
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;
248 struct wined3d_cs_set_sampler
250 enum wined3d_cs_op opcode;
251 enum wined3d_shader_type type;
252 UINT sampler_idx;
253 struct wined3d_sampler *sampler;
256 struct wined3d_cs_set_shader
258 enum wined3d_cs_op opcode;
259 enum wined3d_shader_type type;
260 struct wined3d_shader *shader;
263 struct wined3d_cs_set_blend_state
265 enum wined3d_cs_op opcode;
266 struct wined3d_blend_state *state;
267 struct wined3d_color factor;
270 struct wined3d_cs_set_rasterizer_state
272 enum wined3d_cs_op opcode;
273 struct wined3d_rasterizer_state *state;
276 struct wined3d_cs_set_render_state
278 enum wined3d_cs_op opcode;
279 enum wined3d_render_state state;
280 DWORD value;
283 struct wined3d_cs_set_texture_state
285 enum wined3d_cs_op opcode;
286 UINT stage;
287 enum wined3d_texture_stage_state state;
288 DWORD value;
291 struct wined3d_cs_set_sampler_state
293 enum wined3d_cs_op opcode;
294 UINT sampler_idx;
295 enum wined3d_sampler_state state;
296 DWORD value;
299 struct wined3d_cs_set_transform
301 enum wined3d_cs_op opcode;
302 enum wined3d_transform_state state;
303 struct wined3d_matrix matrix;
306 struct wined3d_cs_set_clip_plane
308 enum wined3d_cs_op opcode;
309 UINT plane_idx;
310 struct wined3d_vec4 plane;
313 struct wined3d_cs_set_material
315 enum wined3d_cs_op opcode;
316 struct wined3d_material material;
319 struct wined3d_cs_set_light
321 enum wined3d_cs_op opcode;
322 struct wined3d_light_info light;
325 struct wined3d_cs_set_light_enable
327 enum wined3d_cs_op opcode;
328 unsigned int idx;
329 BOOL enable;
332 struct wined3d_cs_push_constants
334 enum wined3d_cs_op opcode;
335 enum wined3d_push_constants type;
336 unsigned int start_idx;
337 unsigned int count;
338 BYTE constants[1];
341 struct wined3d_cs_reset_state
343 enum wined3d_cs_op opcode;
346 struct wined3d_cs_callback
348 enum wined3d_cs_op opcode;
349 void (*callback)(void *object);
350 void *object;
353 struct wined3d_cs_query_issue
355 enum wined3d_cs_op opcode;
356 struct wined3d_query *query;
357 DWORD flags;
360 struct wined3d_cs_preload_resource
362 enum wined3d_cs_op opcode;
363 struct wined3d_resource *resource;
366 struct wined3d_cs_unload_resource
368 enum wined3d_cs_op opcode;
369 struct wined3d_resource *resource;
372 struct wined3d_cs_map
374 enum wined3d_cs_op opcode;
375 struct wined3d_resource *resource;
376 unsigned int sub_resource_idx;
377 struct wined3d_map_desc *map_desc;
378 const struct wined3d_box *box;
379 DWORD flags;
380 HRESULT *hr;
383 struct wined3d_cs_unmap
385 enum wined3d_cs_op opcode;
386 struct wined3d_resource *resource;
387 unsigned int sub_resource_idx;
388 HRESULT *hr;
391 struct wined3d_cs_blt_sub_resource
393 enum wined3d_cs_op opcode;
394 struct wined3d_resource *dst_resource;
395 unsigned int dst_sub_resource_idx;
396 struct wined3d_box dst_box;
397 struct wined3d_resource *src_resource;
398 unsigned int src_sub_resource_idx;
399 struct wined3d_box src_box;
400 DWORD flags;
401 struct wined3d_blt_fx fx;
402 enum wined3d_texture_filter_type filter;
405 struct wined3d_cs_update_sub_resource
407 enum wined3d_cs_op opcode;
408 struct wined3d_resource *resource;
409 unsigned int sub_resource_idx;
410 struct wined3d_box box;
411 struct wined3d_sub_resource_data data;
414 struct wined3d_cs_add_dirty_texture_region
416 enum wined3d_cs_op opcode;
417 struct wined3d_texture *texture;
418 unsigned int layer;
421 struct wined3d_cs_clear_unordered_access_view
423 enum wined3d_cs_op opcode;
424 struct wined3d_unordered_access_view *view;
425 struct wined3d_uvec4 clear_value;
428 struct wined3d_cs_copy_uav_counter
430 enum wined3d_cs_op opcode;
431 struct wined3d_buffer *buffer;
432 unsigned int offset;
433 struct wined3d_unordered_access_view *view;
436 struct wined3d_cs_generate_mipmaps
438 enum wined3d_cs_op opcode;
439 struct wined3d_shader_resource_view *view;
442 struct wined3d_cs_stop
444 enum wined3d_cs_op opcode;
447 static const char *debug_cs_op(enum wined3d_cs_op op)
449 switch (op)
451 #define WINED3D_TO_STR(type) case type: return #type
452 WINED3D_TO_STR(WINED3D_CS_OP_NOP);
453 WINED3D_TO_STR(WINED3D_CS_OP_PRESENT);
454 WINED3D_TO_STR(WINED3D_CS_OP_CLEAR);
455 WINED3D_TO_STR(WINED3D_CS_OP_DISPATCH);
456 WINED3D_TO_STR(WINED3D_CS_OP_DRAW);
457 WINED3D_TO_STR(WINED3D_CS_OP_FLUSH);
458 WINED3D_TO_STR(WINED3D_CS_OP_SET_PREDICATION);
459 WINED3D_TO_STR(WINED3D_CS_OP_SET_VIEWPORTS);
460 WINED3D_TO_STR(WINED3D_CS_OP_SET_SCISSOR_RECTS);
461 WINED3D_TO_STR(WINED3D_CS_OP_SET_RENDERTARGET_VIEW);
462 WINED3D_TO_STR(WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW);
463 WINED3D_TO_STR(WINED3D_CS_OP_SET_VERTEX_DECLARATION);
464 WINED3D_TO_STR(WINED3D_CS_OP_SET_STREAM_SOURCE);
465 WINED3D_TO_STR(WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ);
466 WINED3D_TO_STR(WINED3D_CS_OP_SET_STREAM_OUTPUT);
467 WINED3D_TO_STR(WINED3D_CS_OP_SET_INDEX_BUFFER);
468 WINED3D_TO_STR(WINED3D_CS_OP_SET_CONSTANT_BUFFER);
469 WINED3D_TO_STR(WINED3D_CS_OP_SET_TEXTURE);
470 WINED3D_TO_STR(WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW);
471 WINED3D_TO_STR(WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW);
472 WINED3D_TO_STR(WINED3D_CS_OP_SET_SAMPLER);
473 WINED3D_TO_STR(WINED3D_CS_OP_SET_SHADER);
474 WINED3D_TO_STR(WINED3D_CS_OP_SET_BLEND_STATE);
475 WINED3D_TO_STR(WINED3D_CS_OP_SET_RASTERIZER_STATE);
476 WINED3D_TO_STR(WINED3D_CS_OP_SET_RENDER_STATE);
477 WINED3D_TO_STR(WINED3D_CS_OP_SET_TEXTURE_STATE);
478 WINED3D_TO_STR(WINED3D_CS_OP_SET_SAMPLER_STATE);
479 WINED3D_TO_STR(WINED3D_CS_OP_SET_TRANSFORM);
480 WINED3D_TO_STR(WINED3D_CS_OP_SET_CLIP_PLANE);
481 WINED3D_TO_STR(WINED3D_CS_OP_SET_COLOR_KEY);
482 WINED3D_TO_STR(WINED3D_CS_OP_SET_MATERIAL);
483 WINED3D_TO_STR(WINED3D_CS_OP_SET_LIGHT);
484 WINED3D_TO_STR(WINED3D_CS_OP_SET_LIGHT_ENABLE);
485 WINED3D_TO_STR(WINED3D_CS_OP_PUSH_CONSTANTS);
486 WINED3D_TO_STR(WINED3D_CS_OP_RESET_STATE);
487 WINED3D_TO_STR(WINED3D_CS_OP_CALLBACK);
488 WINED3D_TO_STR(WINED3D_CS_OP_QUERY_ISSUE);
489 WINED3D_TO_STR(WINED3D_CS_OP_PRELOAD_RESOURCE);
490 WINED3D_TO_STR(WINED3D_CS_OP_UNLOAD_RESOURCE);
491 WINED3D_TO_STR(WINED3D_CS_OP_MAP);
492 WINED3D_TO_STR(WINED3D_CS_OP_UNMAP);
493 WINED3D_TO_STR(WINED3D_CS_OP_BLT_SUB_RESOURCE);
494 WINED3D_TO_STR(WINED3D_CS_OP_UPDATE_SUB_RESOURCE);
495 WINED3D_TO_STR(WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION);
496 WINED3D_TO_STR(WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW);
497 WINED3D_TO_STR(WINED3D_CS_OP_COPY_UAV_COUNTER);
498 WINED3D_TO_STR(WINED3D_CS_OP_GENERATE_MIPMAPS);
499 WINED3D_TO_STR(WINED3D_CS_OP_STOP);
500 #undef WINED3D_TO_STR
501 default:
502 return wine_dbg_sprintf("UNKNOWN_OP(%#x)", op);
506 static void wined3d_cs_exec_nop(struct wined3d_cs *cs, const void *data)
510 static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data)
512 const struct wined3d_cs_present *op = data;
513 struct wined3d_swapchain *swapchain;
514 unsigned int i;
516 swapchain = op->swapchain;
517 wined3d_swapchain_set_window(swapchain, op->dst_window_override);
518 wined3d_swapchain_set_swap_interval(swapchain, op->swap_interval);
520 swapchain->swapchain_ops->swapchain_present(swapchain, &op->src_rect, &op->dst_rect, op->flags);
522 wined3d_resource_release(&swapchain->front_buffer->resource);
523 for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
525 wined3d_resource_release(&swapchain->back_buffers[i]->resource);
528 InterlockedDecrement(&cs->pending_presents);
531 void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain,
532 const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
533 unsigned int swap_interval, DWORD flags)
535 struct wined3d_cs_present *op;
536 unsigned int i;
537 LONG pending;
539 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
540 op->opcode = WINED3D_CS_OP_PRESENT;
541 op->dst_window_override = dst_window_override;
542 op->swapchain = swapchain;
543 op->src_rect = *src_rect;
544 op->dst_rect = *dst_rect;
545 op->swap_interval = swap_interval;
546 op->flags = flags;
548 pending = InterlockedIncrement(&cs->pending_presents);
550 wined3d_resource_acquire(&swapchain->front_buffer->resource);
551 for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
553 wined3d_resource_acquire(&swapchain->back_buffers[i]->resource);
556 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
558 /* Limit input latency by limiting the number of presents that we can get
559 * ahead of the worker thread. */
560 while (pending >= swapchain->max_frame_latency)
562 wined3d_pause();
563 pending = InterlockedCompareExchange(&cs->pending_presents, 0, 0);
567 static void wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
569 const struct wined3d_cs_clear *op = data;
570 struct wined3d_device *device;
571 unsigned int i;
573 device = cs->device;
574 device->blitter->ops->blitter_clear(device->blitter, device, op->rt_count, op->fb,
575 op->rect_count, op->rects, &op->draw_rect, op->flags, &op->color, op->depth, op->stencil);
577 if (op->flags & WINED3DCLEAR_TARGET)
579 for (i = 0; i < op->rt_count; ++i)
581 if (op->fb->render_targets[i])
582 wined3d_resource_release(op->fb->render_targets[i]->resource);
585 if (op->flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
586 wined3d_resource_release(op->fb->depth_stencil->resource);
589 void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects,
590 DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
592 unsigned int rt_count = cs->device->adapter->d3d_info.limits.max_rt_count;
593 const struct wined3d_state *state = &cs->device->state;
594 const struct wined3d_viewport *vp = &state->viewports[0];
595 struct wined3d_rendertarget_view *view;
596 struct wined3d_cs_clear *op;
597 RECT view_rect;
598 unsigned int i;
600 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_clear, rects[rect_count]),
601 WINED3D_CS_QUEUE_DEFAULT);
602 op->opcode = WINED3D_CS_OP_CLEAR;
603 op->flags = flags;
604 if (flags & WINED3DCLEAR_TARGET)
605 op->rt_count = rt_count;
606 else
607 op->rt_count = 0;
608 op->fb = &cs->fb;
609 SetRect(&op->draw_rect, vp->x, vp->y, vp->x + vp->width, vp->y + vp->height);
610 if (state->render_states[WINED3D_RS_SCISSORTESTENABLE])
611 IntersectRect(&op->draw_rect, &op->draw_rect, &state->scissor_rects[0]);
612 op->color = *color;
613 op->depth = depth;
614 op->stencil = stencil;
615 op->rect_count = rect_count;
616 memcpy(op->rects, rects, sizeof(*rects) * rect_count);
618 if (flags & WINED3DCLEAR_TARGET)
620 for (i = 0; i < rt_count; ++i)
622 if ((view = state->fb->render_targets[i]))
624 SetRect(&view_rect, 0, 0, view->width, view->height);
625 IntersectRect(&op->draw_rect, &op->draw_rect, &view_rect);
626 wined3d_resource_acquire(view->resource);
630 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
632 view = state->fb->depth_stencil;
633 SetRect(&view_rect, 0, 0, view->width, view->height);
634 IntersectRect(&op->draw_rect, &op->draw_rect, &view_rect);
635 wined3d_resource_acquire(view->resource);
638 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
641 void wined3d_cs_emit_clear_rendertarget_view(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view,
642 const RECT *rect, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
644 struct wined3d_cs_clear *op;
645 size_t size;
647 size = FIELD_OFFSET(struct wined3d_cs_clear, rects[1]) + sizeof(struct wined3d_fb_state);
648 op = cs->ops->require_space(cs, size, WINED3D_CS_QUEUE_DEFAULT);
649 op->fb = (void *)&op->rects[1];
651 op->opcode = WINED3D_CS_OP_CLEAR;
652 op->flags = flags;
653 if (flags & WINED3DCLEAR_TARGET)
655 op->rt_count = 1;
656 op->fb->render_targets[0] = view;
657 op->fb->depth_stencil = NULL;
658 op->color = *color;
660 else
662 op->rt_count = 0;
663 op->fb->render_targets[0] = NULL;
664 op->fb->depth_stencil = view;
665 op->depth = depth;
666 op->stencil = stencil;
668 SetRect(&op->draw_rect, 0, 0, view->width, view->height);
669 op->rect_count = 1;
670 op->rects[0] = *rect;
672 wined3d_resource_acquire(view->resource);
674 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
675 if (flags & WINED3DCLEAR_SYNCHRONOUS)
676 cs->ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT);
679 static void acquire_shader_resources(const struct wined3d_state *state, unsigned int shader_mask)
681 struct wined3d_shader_sampler_map_entry *entry;
682 struct wined3d_shader_resource_view *view;
683 struct wined3d_shader *shader;
684 unsigned int i, j;
686 for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
688 if (!(shader_mask & (1u << i)))
689 continue;
691 if (!(shader = state->shader[i]))
692 continue;
694 for (j = 0; j < WINED3D_MAX_CBS; ++j)
696 if (state->cb[i][j])
697 wined3d_resource_acquire(&state->cb[i][j]->resource);
700 for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
702 entry = &shader->reg_maps.sampler_map.entries[j];
704 if (!(view = state->shader_resource_view[i][entry->resource_idx]))
705 continue;
707 wined3d_resource_acquire(view->resource);
712 static void release_shader_resources(const struct wined3d_state *state, unsigned int shader_mask)
714 struct wined3d_shader_sampler_map_entry *entry;
715 struct wined3d_shader_resource_view *view;
716 struct wined3d_shader *shader;
717 unsigned int i, j;
719 for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
721 if (!(shader_mask & (1u << i)))
722 continue;
724 if (!(shader = state->shader[i]))
725 continue;
727 for (j = 0; j < WINED3D_MAX_CBS; ++j)
729 if (state->cb[i][j])
730 wined3d_resource_release(&state->cb[i][j]->resource);
733 for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
735 entry = &shader->reg_maps.sampler_map.entries[j];
737 if (!(view = state->shader_resource_view[i][entry->resource_idx]))
738 continue;
740 wined3d_resource_release(view->resource);
745 static void acquire_unordered_access_resources(const struct wined3d_shader *shader,
746 struct wined3d_unordered_access_view * const *views)
748 unsigned int i;
750 if (!shader)
751 return;
753 for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
755 if (!shader->reg_maps.uav_resource_info[i].type)
756 continue;
758 if (!views[i])
759 continue;
761 wined3d_resource_acquire(views[i]->resource);
765 static void release_unordered_access_resources(const struct wined3d_shader *shader,
766 struct wined3d_unordered_access_view * const *views)
768 unsigned int i;
770 if (!shader)
771 return;
773 for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
775 if (!shader->reg_maps.uav_resource_info[i].type)
776 continue;
778 if (!views[i])
779 continue;
781 wined3d_resource_release(views[i]->resource);
785 static void wined3d_cs_exec_dispatch(struct wined3d_cs *cs, const void *data)
787 const struct wined3d_cs_dispatch *op = data;
788 struct wined3d_state *state = &cs->state;
790 dispatch_compute(cs->device, state, &op->parameters);
792 if (op->parameters.indirect)
793 wined3d_resource_release(&op->parameters.u.indirect.buffer->resource);
795 release_shader_resources(state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
796 release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_COMPUTE],
797 state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
800 static void acquire_compute_pipeline_resources(const struct wined3d_state *state)
802 acquire_shader_resources(state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
803 acquire_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_COMPUTE],
804 state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
807 void wined3d_cs_emit_dispatch(struct wined3d_cs *cs,
808 unsigned int group_count_x, unsigned int group_count_y, unsigned int group_count_z)
810 const struct wined3d_state *state = &cs->device->state;
811 struct wined3d_cs_dispatch *op;
813 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
814 op->opcode = WINED3D_CS_OP_DISPATCH;
815 op->parameters.indirect = FALSE;
816 op->parameters.u.direct.group_count_x = group_count_x;
817 op->parameters.u.direct.group_count_y = group_count_y;
818 op->parameters.u.direct.group_count_z = group_count_z;
820 acquire_compute_pipeline_resources(state);
822 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
825 void wined3d_cs_emit_dispatch_indirect(struct wined3d_cs *cs,
826 struct wined3d_buffer *buffer, unsigned int offset)
828 const struct wined3d_state *state = &cs->device->state;
829 struct wined3d_cs_dispatch *op;
831 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
832 op->opcode = WINED3D_CS_OP_DISPATCH;
833 op->parameters.indirect = TRUE;
834 op->parameters.u.indirect.buffer = buffer;
835 op->parameters.u.indirect.offset = offset;
837 acquire_compute_pipeline_resources(state);
838 wined3d_resource_acquire(&buffer->resource);
840 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
843 static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
845 const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info;
846 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
847 const struct wined3d_shader *geometry_shader;
848 struct wined3d_state *state = &cs->state;
849 const struct wined3d_cs_draw *op = data;
850 int load_base_vertex_idx;
851 unsigned int i;
853 /* ARB_draw_indirect always supports a base vertex offset. */
854 if (!op->parameters.indirect && !gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
855 load_base_vertex_idx = op->parameters.u.direct.base_vertex_idx;
856 else
857 load_base_vertex_idx = 0;
859 if (state->load_base_vertex_index != load_base_vertex_idx)
861 state->load_base_vertex_index = load_base_vertex_idx;
862 device_invalidate_state(cs->device, STATE_BASEVERTEXINDEX);
865 if (state->gl_primitive_type != op->primitive_type)
867 if ((geometry_shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY]) && !geometry_shader->function)
868 device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_GEOMETRY));
869 if (state->gl_primitive_type == GL_POINTS || op->primitive_type == GL_POINTS)
870 device_invalidate_state(cs->device, STATE_POINT_ENABLE);
871 state->gl_primitive_type = op->primitive_type;
873 state->gl_patch_vertices = op->patch_vertex_count;
875 draw_primitive(cs->device, state, &op->parameters);
877 if (op->parameters.indirect)
879 struct wined3d_buffer *buffer = op->parameters.u.indirect.buffer;
880 wined3d_resource_release(&buffer->resource);
883 if (op->parameters.indexed)
884 wined3d_resource_release(&state->index_buffer->resource);
885 for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
887 if (state->streams[i].buffer)
888 wined3d_resource_release(&state->streams[i].buffer->resource);
890 for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
892 if (state->stream_output[i].buffer)
893 wined3d_resource_release(&state->stream_output[i].buffer->resource);
895 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
897 if (state->textures[i])
898 wined3d_resource_release(&state->textures[i]->resource);
900 for (i = 0; i < d3d_info->limits.max_rt_count; ++i)
902 if (state->fb->render_targets[i])
903 wined3d_resource_release(state->fb->render_targets[i]->resource);
905 if (state->fb->depth_stencil)
906 wined3d_resource_release(state->fb->depth_stencil->resource);
907 release_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
908 release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL],
909 state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
912 static void acquire_graphics_pipeline_resources(const struct wined3d_state *state,
913 BOOL indexed, const struct wined3d_d3d_info *d3d_info)
915 unsigned int i;
917 if (indexed)
918 wined3d_resource_acquire(&state->index_buffer->resource);
919 for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
921 if (state->streams[i].buffer)
922 wined3d_resource_acquire(&state->streams[i].buffer->resource);
924 for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
926 if (state->stream_output[i].buffer)
927 wined3d_resource_acquire(&state->stream_output[i].buffer->resource);
929 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
931 if (state->textures[i])
932 wined3d_resource_acquire(&state->textures[i]->resource);
934 for (i = 0; i < d3d_info->limits.max_rt_count; ++i)
936 if (state->fb->render_targets[i])
937 wined3d_resource_acquire(state->fb->render_targets[i]->resource);
939 if (state->fb->depth_stencil)
940 wined3d_resource_acquire(state->fb->depth_stencil->resource);
941 acquire_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
942 acquire_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL],
943 state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
946 void wined3d_cs_emit_draw(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
947 int base_vertex_idx, unsigned int start_idx, unsigned int index_count,
948 unsigned int start_instance, unsigned int instance_count, BOOL indexed)
950 const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info;
951 const struct wined3d_state *state = &cs->device->state;
952 struct wined3d_cs_draw *op;
954 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
955 op->opcode = WINED3D_CS_OP_DRAW;
956 op->primitive_type = primitive_type;
957 op->patch_vertex_count = patch_vertex_count;
958 op->parameters.indirect = FALSE;
959 op->parameters.u.direct.base_vertex_idx = base_vertex_idx;
960 op->parameters.u.direct.start_idx = start_idx;
961 op->parameters.u.direct.index_count = index_count;
962 op->parameters.u.direct.start_instance = start_instance;
963 op->parameters.u.direct.instance_count = instance_count;
964 op->parameters.indexed = indexed;
966 acquire_graphics_pipeline_resources(state, indexed, d3d_info);
968 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
971 void wined3d_cs_emit_draw_indirect(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
972 struct wined3d_buffer *buffer, unsigned int offset, BOOL indexed)
974 const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info;
975 const struct wined3d_state *state = &cs->device->state;
976 struct wined3d_cs_draw *op;
978 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
979 op->opcode = WINED3D_CS_OP_DRAW;
980 op->primitive_type = primitive_type;
981 op->patch_vertex_count = patch_vertex_count;
982 op->parameters.indirect = TRUE;
983 op->parameters.u.indirect.buffer = buffer;
984 op->parameters.u.indirect.offset = offset;
985 op->parameters.indexed = indexed;
987 acquire_graphics_pipeline_resources(state, indexed, d3d_info);
988 wined3d_resource_acquire(&buffer->resource);
990 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
993 static void wined3d_cs_exec_flush(struct wined3d_cs *cs, const void *data)
995 struct wined3d_context *context;
997 context = context_acquire(cs->device, NULL, 0);
998 if (context->valid)
999 context->gl_info->gl_ops.gl.p_glFlush();
1000 context_release(context);
1003 void wined3d_cs_emit_flush(struct wined3d_cs *cs)
1005 struct wined3d_cs_flush *op;
1007 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1008 op->opcode = WINED3D_CS_OP_FLUSH;
1010 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1011 cs->queries_flushed = TRUE;
1014 static void wined3d_cs_exec_set_predication(struct wined3d_cs *cs, const void *data)
1016 const struct wined3d_cs_set_predication *op = data;
1018 cs->state.predicate = op->predicate;
1019 cs->state.predicate_value = op->value;
1022 void wined3d_cs_emit_set_predication(struct wined3d_cs *cs, struct wined3d_query *predicate, BOOL value)
1024 struct wined3d_cs_set_predication *op;
1026 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1027 op->opcode = WINED3D_CS_OP_SET_PREDICATION;
1028 op->predicate = predicate;
1029 op->value = value;
1031 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1034 static void wined3d_cs_exec_set_viewports(struct wined3d_cs *cs, const void *data)
1036 const struct wined3d_cs_set_viewports *op = data;
1038 if (op->viewport_count)
1039 memcpy(cs->state.viewports, op->viewports, op->viewport_count * sizeof(*op->viewports));
1040 else
1041 memset(cs->state.viewports, 0, sizeof(*cs->state.viewports));
1042 cs->state.viewport_count = op->viewport_count;
1043 device_invalidate_state(cs->device, STATE_VIEWPORT);
1046 void wined3d_cs_emit_set_viewports(struct wined3d_cs *cs, unsigned int viewport_count,
1047 const struct wined3d_viewport *viewports)
1049 struct wined3d_cs_set_viewports *op;
1051 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_set_viewports, viewports[viewport_count]),
1052 WINED3D_CS_QUEUE_DEFAULT);
1053 op->opcode = WINED3D_CS_OP_SET_VIEWPORTS;
1054 memcpy(op->viewports, viewports, viewport_count * sizeof(*viewports));
1055 op->viewport_count = viewport_count;
1057 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1060 static void wined3d_cs_exec_set_scissor_rects(struct wined3d_cs *cs, const void *data)
1062 const struct wined3d_cs_set_scissor_rects *op = data;
1064 if (op->rect_count)
1065 memcpy(cs->state.scissor_rects, op->rects, op->rect_count * sizeof(*op->rects));
1066 else
1067 SetRectEmpty(cs->state.scissor_rects);
1068 cs->state.scissor_rect_count = op->rect_count;
1069 device_invalidate_state(cs->device, STATE_SCISSORRECT);
1072 void wined3d_cs_emit_set_scissor_rects(struct wined3d_cs *cs, unsigned int rect_count, const RECT *rects)
1074 struct wined3d_cs_set_scissor_rects *op;
1076 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_set_scissor_rects, rects[rect_count]),
1077 WINED3D_CS_QUEUE_DEFAULT);
1078 op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECTS;
1079 memcpy(op->rects, rects, rect_count * sizeof(*rects));
1080 op->rect_count = rect_count;
1082 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1085 static void wined3d_cs_exec_set_rendertarget_view(struct wined3d_cs *cs, const void *data)
1087 const struct wined3d_cs_set_rendertarget_view *op = data;
1088 BOOL prev_alpha_swizzle, curr_alpha_swizzle;
1089 struct wined3d_rendertarget_view *prev;
1091 prev = cs->state.fb->render_targets[op->view_idx];
1092 cs->fb.render_targets[op->view_idx] = op->view;
1093 device_invalidate_state(cs->device, STATE_FRAMEBUFFER);
1095 prev_alpha_swizzle = prev && prev->format->id == WINED3DFMT_A8_UNORM;
1096 curr_alpha_swizzle = op->view && op->view->format->id == WINED3DFMT_A8_UNORM;
1097 if (prev_alpha_swizzle != curr_alpha_swizzle)
1098 device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
1101 void wined3d_cs_emit_set_rendertarget_view(struct wined3d_cs *cs, unsigned int view_idx,
1102 struct wined3d_rendertarget_view *view)
1104 struct wined3d_cs_set_rendertarget_view *op;
1106 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1107 op->opcode = WINED3D_CS_OP_SET_RENDERTARGET_VIEW;
1108 op->view_idx = view_idx;
1109 op->view = view;
1111 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1114 static void wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const void *data)
1116 const struct wined3d_cs_set_depth_stencil_view *op = data;
1117 struct wined3d_device *device = cs->device;
1118 struct wined3d_rendertarget_view *prev;
1120 if ((prev = cs->state.fb->depth_stencil) && prev->resource->type != WINED3D_RTYPE_BUFFER)
1122 struct wined3d_texture *prev_texture = texture_from_resource(prev->resource);
1124 if (device->swapchains[0]->desc.flags & WINED3D_SWAPCHAIN_DISCARD_DEPTHSTENCIL
1125 || prev_texture->flags & WINED3D_TEXTURE_DISCARD)
1126 wined3d_texture_validate_location(prev_texture,
1127 prev->sub_resource_idx, WINED3D_LOCATION_DISCARDED);
1130 cs->fb.depth_stencil = op->view;
1132 if (!prev != !op->view)
1134 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
1135 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
1136 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
1137 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
1138 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
1140 else if (prev && prev->format->depth_bias_scale != op->view->format->depth_bias_scale)
1142 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
1145 device_invalidate_state(device, STATE_FRAMEBUFFER);
1148 void wined3d_cs_emit_set_depth_stencil_view(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view)
1150 struct wined3d_cs_set_depth_stencil_view *op;
1152 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1153 op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW;
1154 op->view = view;
1156 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1159 static void wined3d_cs_exec_set_vertex_declaration(struct wined3d_cs *cs, const void *data)
1161 const struct wined3d_cs_set_vertex_declaration *op = data;
1163 cs->state.vertex_declaration = op->declaration;
1164 device_invalidate_state(cs->device, STATE_VDECL);
1167 void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs, struct wined3d_vertex_declaration *declaration)
1169 struct wined3d_cs_set_vertex_declaration *op;
1171 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1172 op->opcode = WINED3D_CS_OP_SET_VERTEX_DECLARATION;
1173 op->declaration = declaration;
1175 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1178 static void wined3d_cs_exec_set_stream_source(struct wined3d_cs *cs, const void *data)
1180 const struct wined3d_cs_set_stream_source *op = data;
1181 struct wined3d_stream_state *stream;
1182 struct wined3d_buffer *prev;
1184 stream = &cs->state.streams[op->stream_idx];
1185 prev = stream->buffer;
1186 stream->buffer = op->buffer;
1187 stream->offset = op->offset;
1188 stream->stride = op->stride;
1190 if (op->buffer)
1191 InterlockedIncrement(&op->buffer->resource.bind_count);
1192 if (prev)
1193 InterlockedDecrement(&prev->resource.bind_count);
1195 device_invalidate_state(cs->device, STATE_STREAMSRC);
1198 void wined3d_cs_emit_set_stream_source(struct wined3d_cs *cs, UINT stream_idx,
1199 struct wined3d_buffer *buffer, UINT offset, UINT stride)
1201 struct wined3d_cs_set_stream_source *op;
1203 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1204 op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE;
1205 op->stream_idx = stream_idx;
1206 op->buffer = buffer;
1207 op->offset = offset;
1208 op->stride = stride;
1210 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1213 static void wined3d_cs_exec_set_stream_source_freq(struct wined3d_cs *cs, const void *data)
1215 const struct wined3d_cs_set_stream_source_freq *op = data;
1216 struct wined3d_stream_state *stream;
1218 stream = &cs->state.streams[op->stream_idx];
1219 stream->frequency = op->frequency;
1220 stream->flags = op->flags;
1222 device_invalidate_state(cs->device, STATE_STREAMSRC);
1225 void wined3d_cs_emit_set_stream_source_freq(struct wined3d_cs *cs, UINT stream_idx, UINT frequency, UINT flags)
1227 struct wined3d_cs_set_stream_source_freq *op;
1229 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1230 op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ;
1231 op->stream_idx = stream_idx;
1232 op->frequency = frequency;
1233 op->flags = flags;
1235 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1238 static void wined3d_cs_exec_set_stream_output(struct wined3d_cs *cs, const void *data)
1240 const struct wined3d_cs_set_stream_output *op = data;
1241 struct wined3d_stream_output *stream;
1242 struct wined3d_buffer *prev;
1244 stream = &cs->state.stream_output[op->stream_idx];
1245 prev = stream->buffer;
1246 stream->buffer = op->buffer;
1247 stream->offset = op->offset;
1249 if (op->buffer)
1250 InterlockedIncrement(&op->buffer->resource.bind_count);
1251 if (prev)
1252 InterlockedDecrement(&prev->resource.bind_count);
1254 device_invalidate_state(cs->device, STATE_STREAM_OUTPUT);
1257 void wined3d_cs_emit_set_stream_output(struct wined3d_cs *cs, UINT stream_idx,
1258 struct wined3d_buffer *buffer, UINT offset)
1260 struct wined3d_cs_set_stream_output *op;
1262 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1263 op->opcode = WINED3D_CS_OP_SET_STREAM_OUTPUT;
1264 op->stream_idx = stream_idx;
1265 op->buffer = buffer;
1266 op->offset = offset;
1268 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1271 static void wined3d_cs_exec_set_index_buffer(struct wined3d_cs *cs, const void *data)
1273 const struct wined3d_cs_set_index_buffer *op = data;
1274 struct wined3d_buffer *prev;
1276 prev = cs->state.index_buffer;
1277 cs->state.index_buffer = op->buffer;
1278 cs->state.index_format = op->format_id;
1279 cs->state.index_offset = op->offset;
1281 if (op->buffer)
1282 InterlockedIncrement(&op->buffer->resource.bind_count);
1283 if (prev)
1284 InterlockedDecrement(&prev->resource.bind_count);
1286 device_invalidate_state(cs->device, STATE_INDEXBUFFER);
1289 void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer,
1290 enum wined3d_format_id format_id, unsigned int offset)
1292 struct wined3d_cs_set_index_buffer *op;
1294 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1295 op->opcode = WINED3D_CS_OP_SET_INDEX_BUFFER;
1296 op->buffer = buffer;
1297 op->format_id = format_id;
1298 op->offset = offset;
1300 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1303 static void wined3d_cs_exec_set_constant_buffer(struct wined3d_cs *cs, const void *data)
1305 const struct wined3d_cs_set_constant_buffer *op = data;
1306 struct wined3d_buffer *prev;
1308 prev = cs->state.cb[op->type][op->cb_idx];
1309 cs->state.cb[op->type][op->cb_idx] = op->buffer;
1311 if (op->buffer)
1312 InterlockedIncrement(&op->buffer->resource.bind_count);
1313 if (prev)
1314 InterlockedDecrement(&prev->resource.bind_count);
1316 device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(op->type));
1319 void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_shader_type type,
1320 UINT cb_idx, struct wined3d_buffer *buffer)
1322 struct wined3d_cs_set_constant_buffer *op;
1324 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1325 op->opcode = WINED3D_CS_OP_SET_CONSTANT_BUFFER;
1326 op->type = type;
1327 op->cb_idx = cb_idx;
1328 op->buffer = buffer;
1330 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1333 static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data)
1335 const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
1336 const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info;
1337 const struct wined3d_cs_set_texture *op = data;
1338 struct wined3d_texture *prev;
1339 BOOL old_use_color_key = FALSE, new_use_color_key = FALSE;
1341 prev = cs->state.textures[op->stage];
1342 cs->state.textures[op->stage] = op->texture;
1344 if (op->texture)
1346 const struct wined3d_format *new_format = op->texture->resource.format;
1347 const struct wined3d_format *old_format = prev ? prev->resource.format : NULL;
1348 unsigned int old_fmt_flags = prev ? prev->resource.format_flags : 0;
1349 unsigned int new_fmt_flags = op->texture->resource.format_flags;
1351 if (InterlockedIncrement(&op->texture->resource.bind_count) == 1)
1352 op->texture->sampler = op->stage;
1354 if (!prev || op->texture->target != prev->target
1355 || (!is_same_fixup(new_format->color_fixup, old_format->color_fixup)
1356 && !(can_use_texture_swizzle(gl_info, new_format) && can_use_texture_swizzle(gl_info, old_format)))
1357 || (new_fmt_flags & WINED3DFMT_FLAG_SHADOW) != (old_fmt_flags & WINED3DFMT_FLAG_SHADOW))
1358 device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
1360 if (!prev && op->stage < d3d_info->limits.ffp_blend_stages)
1362 /* The source arguments for color and alpha ops have different
1363 * meanings when a NULL texture is bound, so the COLOR_OP and
1364 * ALPHA_OP have to be dirtified. */
1365 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1366 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1369 if (!op->stage && op->texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1370 new_use_color_key = TRUE;
1373 if (prev)
1375 if (InterlockedDecrement(&prev->resource.bind_count) && prev->sampler == op->stage)
1377 unsigned int i;
1379 /* Search for other stages the texture is bound to. Shouldn't
1380 * happen if applications bind textures to a single stage only. */
1381 TRACE("Searching for other stages the texture is bound to.\n");
1382 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
1384 if (cs->state.textures[i] == prev)
1386 TRACE("Texture is also bound to stage %u.\n", i);
1387 prev->sampler = i;
1388 break;
1393 if (!op->texture && op->stage < d3d_info->limits.ffp_blend_stages)
1395 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1396 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1399 if (!op->stage && prev->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1400 old_use_color_key = TRUE;
1403 device_invalidate_state(cs->device, STATE_SAMPLER(op->stage));
1405 if (new_use_color_key != old_use_color_key)
1406 device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1408 if (new_use_color_key)
1409 device_invalidate_state(cs->device, STATE_COLOR_KEY);
1412 void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined3d_texture *texture)
1414 struct wined3d_cs_set_texture *op;
1416 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1417 op->opcode = WINED3D_CS_OP_SET_TEXTURE;
1418 op->stage = stage;
1419 op->texture = texture;
1421 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1424 static void wined3d_cs_exec_set_shader_resource_view(struct wined3d_cs *cs, const void *data)
1426 const struct wined3d_cs_set_shader_resource_view *op = data;
1427 struct wined3d_shader_resource_view *prev;
1429 prev = cs->state.shader_resource_view[op->type][op->view_idx];
1430 cs->state.shader_resource_view[op->type][op->view_idx] = op->view;
1432 if (op->view)
1433 InterlockedIncrement(&op->view->resource->bind_count);
1434 if (prev)
1435 InterlockedDecrement(&prev->resource->bind_count);
1437 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1438 device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1439 else
1440 device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1443 void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3d_shader_type type,
1444 UINT view_idx, struct wined3d_shader_resource_view *view)
1446 struct wined3d_cs_set_shader_resource_view *op;
1448 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1449 op->opcode = WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW;
1450 op->type = type;
1451 op->view_idx = view_idx;
1452 op->view = view;
1454 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1457 static void wined3d_cs_exec_set_unordered_access_view(struct wined3d_cs *cs, const void *data)
1459 const struct wined3d_cs_set_unordered_access_view *op = data;
1460 struct wined3d_unordered_access_view *prev;
1462 prev = cs->state.unordered_access_view[op->pipeline][op->view_idx];
1463 cs->state.unordered_access_view[op->pipeline][op->view_idx] = op->view;
1465 if (op->view)
1466 InterlockedIncrement(&op->view->resource->bind_count);
1467 if (prev)
1468 InterlockedDecrement(&prev->resource->bind_count);
1470 if (op->view && op->initial_count != ~0u)
1471 wined3d_unordered_access_view_set_counter(op->view, op->initial_count);
1473 device_invalidate_state(cs->device, STATE_UNORDERED_ACCESS_VIEW_BINDING(op->pipeline));
1476 void wined3d_cs_emit_set_unordered_access_view(struct wined3d_cs *cs, enum wined3d_pipeline pipeline,
1477 unsigned int view_idx, struct wined3d_unordered_access_view *view, unsigned int initial_count)
1479 struct wined3d_cs_set_unordered_access_view *op;
1481 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1482 op->opcode = WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW;
1483 op->pipeline = pipeline;
1484 op->view_idx = view_idx;
1485 op->view = view;
1486 op->initial_count = initial_count;
1488 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1491 static void wined3d_cs_exec_set_sampler(struct wined3d_cs *cs, const void *data)
1493 const struct wined3d_cs_set_sampler *op = data;
1495 cs->state.sampler[op->type][op->sampler_idx] = op->sampler;
1496 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1497 device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1498 else
1499 device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1502 void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type,
1503 UINT sampler_idx, struct wined3d_sampler *sampler)
1505 struct wined3d_cs_set_sampler *op;
1507 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1508 op->opcode = WINED3D_CS_OP_SET_SAMPLER;
1509 op->type = type;
1510 op->sampler_idx = sampler_idx;
1511 op->sampler = sampler;
1513 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1516 static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
1518 const struct wined3d_cs_set_shader *op = data;
1520 cs->state.shader[op->type] = op->shader;
1521 device_invalidate_state(cs->device, STATE_SHADER(op->type));
1522 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1523 device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1524 else
1525 device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1528 void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader)
1530 struct wined3d_cs_set_shader *op;
1532 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1533 op->opcode = WINED3D_CS_OP_SET_SHADER;
1534 op->type = type;
1535 op->shader = shader;
1537 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1540 static void wined3d_cs_exec_set_blend_state(struct wined3d_cs *cs, const void *data)
1542 const struct wined3d_cs_set_blend_state *op = data;
1543 struct wined3d_state *state = &cs->state;
1545 if (state->blend_state != op->state)
1547 state->blend_state = op->state;
1548 device_invalidate_state(cs->device, STATE_BLEND);
1550 state->blend_factor = op->factor;
1551 device_invalidate_state(cs->device, STATE_BLEND_FACTOR);
1554 void wined3d_cs_emit_set_blend_state(struct wined3d_cs *cs, struct wined3d_blend_state *state,
1555 const struct wined3d_color *blend_factor)
1557 struct wined3d_cs_set_blend_state *op;
1559 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1560 op->opcode = WINED3D_CS_OP_SET_BLEND_STATE;
1561 op->state = state;
1562 op->factor = *blend_factor;
1564 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1567 static void wined3d_cs_exec_set_rasterizer_state(struct wined3d_cs *cs, const void *data)
1569 const struct wined3d_cs_set_rasterizer_state *op = data;
1571 cs->state.rasterizer_state = op->state;
1572 device_invalidate_state(cs->device, STATE_RASTERIZER);
1575 void wined3d_cs_emit_set_rasterizer_state(struct wined3d_cs *cs,
1576 struct wined3d_rasterizer_state *rasterizer_state)
1578 struct wined3d_cs_set_rasterizer_state *op;
1580 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1581 op->opcode = WINED3D_CS_OP_SET_RASTERIZER_STATE;
1582 op->state = rasterizer_state;
1584 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1587 static void wined3d_cs_exec_set_render_state(struct wined3d_cs *cs, const void *data)
1589 const struct wined3d_cs_set_render_state *op = data;
1591 cs->state.render_states[op->state] = op->value;
1592 device_invalidate_state(cs->device, STATE_RENDER(op->state));
1595 void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render_state state, DWORD value)
1597 struct wined3d_cs_set_render_state *op;
1599 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1600 op->opcode = WINED3D_CS_OP_SET_RENDER_STATE;
1601 op->state = state;
1602 op->value = value;
1604 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1607 static void wined3d_cs_exec_set_texture_state(struct wined3d_cs *cs, const void *data)
1609 const struct wined3d_cs_set_texture_state *op = data;
1611 cs->state.texture_states[op->stage][op->state] = op->value;
1612 device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, op->state));
1615 void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage,
1616 enum wined3d_texture_stage_state state, DWORD value)
1618 struct wined3d_cs_set_texture_state *op;
1620 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1621 op->opcode = WINED3D_CS_OP_SET_TEXTURE_STATE;
1622 op->stage = stage;
1623 op->state = state;
1624 op->value = value;
1626 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1629 static void wined3d_cs_exec_set_sampler_state(struct wined3d_cs *cs, const void *data)
1631 const struct wined3d_cs_set_sampler_state *op = data;
1633 cs->state.sampler_states[op->sampler_idx][op->state] = op->value;
1634 device_invalidate_state(cs->device, STATE_SAMPLER(op->sampler_idx));
1637 void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx,
1638 enum wined3d_sampler_state state, DWORD value)
1640 struct wined3d_cs_set_sampler_state *op;
1642 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1643 op->opcode = WINED3D_CS_OP_SET_SAMPLER_STATE;
1644 op->sampler_idx = sampler_idx;
1645 op->state = state;
1646 op->value = value;
1648 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1651 static void wined3d_cs_exec_set_transform(struct wined3d_cs *cs, const void *data)
1653 const struct wined3d_cs_set_transform *op = data;
1655 cs->state.transforms[op->state] = op->matrix;
1656 if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->d3d_info.limits.ffp_vertex_blend_matrices))
1657 device_invalidate_state(cs->device, STATE_TRANSFORM(op->state));
1660 void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform_state state,
1661 const struct wined3d_matrix *matrix)
1663 struct wined3d_cs_set_transform *op;
1665 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1666 op->opcode = WINED3D_CS_OP_SET_TRANSFORM;
1667 op->state = state;
1668 op->matrix = *matrix;
1670 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1673 static void wined3d_cs_exec_set_clip_plane(struct wined3d_cs *cs, const void *data)
1675 const struct wined3d_cs_set_clip_plane *op = data;
1677 cs->state.clip_planes[op->plane_idx] = op->plane;
1678 device_invalidate_state(cs->device, STATE_CLIPPLANE(op->plane_idx));
1681 void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const struct wined3d_vec4 *plane)
1683 struct wined3d_cs_set_clip_plane *op;
1685 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1686 op->opcode = WINED3D_CS_OP_SET_CLIP_PLANE;
1687 op->plane_idx = plane_idx;
1688 op->plane = *plane;
1690 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1693 static void wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *data)
1695 const struct wined3d_cs_set_color_key *op = data;
1696 struct wined3d_texture *texture = op->texture;
1698 if (op->set)
1700 switch (op->flags)
1702 case WINED3D_CKEY_DST_BLT:
1703 texture->async.dst_blt_color_key = op->color_key;
1704 texture->async.color_key_flags |= WINED3D_CKEY_DST_BLT;
1705 break;
1707 case WINED3D_CKEY_DST_OVERLAY:
1708 texture->async.dst_overlay_color_key = op->color_key;
1709 texture->async.color_key_flags |= WINED3D_CKEY_DST_OVERLAY;
1710 break;
1712 case WINED3D_CKEY_SRC_BLT:
1713 if (texture == cs->state.textures[0])
1715 device_invalidate_state(cs->device, STATE_COLOR_KEY);
1716 if (!(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT))
1717 device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1720 texture->async.src_blt_color_key = op->color_key;
1721 texture->async.color_key_flags |= WINED3D_CKEY_SRC_BLT;
1722 break;
1724 case WINED3D_CKEY_SRC_OVERLAY:
1725 texture->async.src_overlay_color_key = op->color_key;
1726 texture->async.color_key_flags |= WINED3D_CKEY_SRC_OVERLAY;
1727 break;
1730 else
1732 switch (op->flags)
1734 case WINED3D_CKEY_DST_BLT:
1735 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_BLT;
1736 break;
1738 case WINED3D_CKEY_DST_OVERLAY:
1739 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_OVERLAY;
1740 break;
1742 case WINED3D_CKEY_SRC_BLT:
1743 if (texture == cs->state.textures[0] && texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1744 device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1746 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_BLT;
1747 break;
1749 case WINED3D_CKEY_SRC_OVERLAY:
1750 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_OVERLAY;
1751 break;
1756 void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture *texture,
1757 WORD flags, const struct wined3d_color_key *color_key)
1759 struct wined3d_cs_set_color_key *op;
1761 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1762 op->opcode = WINED3D_CS_OP_SET_COLOR_KEY;
1763 op->texture = texture;
1764 op->flags = flags;
1765 if (color_key)
1767 op->color_key = *color_key;
1768 op->set = 1;
1770 else
1771 op->set = 0;
1773 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1776 static void wined3d_cs_exec_set_material(struct wined3d_cs *cs, const void *data)
1778 const struct wined3d_cs_set_material *op = data;
1780 cs->state.material = op->material;
1781 device_invalidate_state(cs->device, STATE_MATERIAL);
1784 void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_material *material)
1786 struct wined3d_cs_set_material *op;
1788 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1789 op->opcode = WINED3D_CS_OP_SET_MATERIAL;
1790 op->material = *material;
1792 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1795 static void wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data)
1797 const struct wined3d_cs_set_light *op = data;
1798 struct wined3d_light_info *light_info;
1799 unsigned int light_idx, hash_idx;
1801 light_idx = op->light.OriginalIndex;
1803 if (!(light_info = wined3d_state_get_light(&cs->state, light_idx)))
1805 TRACE("Adding new light.\n");
1806 if (!(light_info = heap_alloc_zero(sizeof(*light_info))))
1808 ERR("Failed to allocate light info.\n");
1809 return;
1812 hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1813 list_add_head(&cs->state.light_map[hash_idx], &light_info->entry);
1814 light_info->glIndex = -1;
1815 light_info->OriginalIndex = light_idx;
1818 if (light_info->glIndex != -1)
1820 if (light_info->OriginalParms.type != op->light.OriginalParms.type)
1821 device_invalidate_state(cs->device, STATE_LIGHT_TYPE);
1822 device_invalidate_state(cs->device, STATE_ACTIVELIGHT(light_info->glIndex));
1825 light_info->OriginalParms = op->light.OriginalParms;
1826 light_info->position = op->light.position;
1827 light_info->direction = op->light.direction;
1828 light_info->exponent = op->light.exponent;
1829 light_info->cutoff = op->light.cutoff;
1832 void wined3d_cs_emit_set_light(struct wined3d_cs *cs, const struct wined3d_light_info *light)
1834 struct wined3d_cs_set_light *op;
1836 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1837 op->opcode = WINED3D_CS_OP_SET_LIGHT;
1838 op->light = *light;
1840 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1843 static void wined3d_cs_exec_set_light_enable(struct wined3d_cs *cs, const void *data)
1845 const struct wined3d_cs_set_light_enable *op = data;
1846 struct wined3d_device *device = cs->device;
1847 struct wined3d_light_info *light_info;
1848 int prev_idx;
1850 if (!(light_info = wined3d_state_get_light(&cs->state, op->idx)))
1852 ERR("Light doesn't exist.\n");
1853 return;
1856 prev_idx = light_info->glIndex;
1857 wined3d_state_enable_light(&cs->state, &device->adapter->d3d_info, light_info, op->enable);
1858 if (light_info->glIndex != prev_idx)
1860 device_invalidate_state(device, STATE_LIGHT_TYPE);
1861 device_invalidate_state(device, STATE_ACTIVELIGHT(op->enable ? light_info->glIndex : prev_idx));
1865 void wined3d_cs_emit_set_light_enable(struct wined3d_cs *cs, unsigned int idx, BOOL enable)
1867 struct wined3d_cs_set_light_enable *op;
1869 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1870 op->opcode = WINED3D_CS_OP_SET_LIGHT_ENABLE;
1871 op->idx = idx;
1872 op->enable = enable;
1874 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1877 static const struct
1879 size_t offset;
1880 size_t size;
1881 DWORD mask;
1883 wined3d_cs_push_constant_info[] =
1885 /* WINED3D_PUSH_CONSTANTS_VS_F */
1886 {FIELD_OFFSET(struct wined3d_state, vs_consts_f), sizeof(struct wined3d_vec4), WINED3D_SHADER_CONST_VS_F},
1887 /* WINED3D_PUSH_CONSTANTS_PS_F */
1888 {FIELD_OFFSET(struct wined3d_state, ps_consts_f), sizeof(struct wined3d_vec4), WINED3D_SHADER_CONST_PS_F},
1889 /* WINED3D_PUSH_CONSTANTS_VS_I */
1890 {FIELD_OFFSET(struct wined3d_state, vs_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_VS_I},
1891 /* WINED3D_PUSH_CONSTANTS_PS_I */
1892 {FIELD_OFFSET(struct wined3d_state, ps_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_PS_I},
1893 /* WINED3D_PUSH_CONSTANTS_VS_B */
1894 {FIELD_OFFSET(struct wined3d_state, vs_consts_b), sizeof(BOOL), WINED3D_SHADER_CONST_VS_B},
1895 /* WINED3D_PUSH_CONSTANTS_PS_B */
1896 {FIELD_OFFSET(struct wined3d_state, ps_consts_b), sizeof(BOOL), WINED3D_SHADER_CONST_PS_B},
1899 static void wined3d_cs_st_push_constants(struct wined3d_cs *cs, enum wined3d_push_constants p,
1900 unsigned int start_idx, unsigned int count, const void *constants)
1902 struct wined3d_device *device = cs->device;
1903 unsigned int context_count;
1904 unsigned int i;
1905 size_t offset;
1907 if (p == WINED3D_PUSH_CONSTANTS_VS_F)
1908 device->shader_backend->shader_update_float_vertex_constants(device, start_idx, count);
1909 else if (p == WINED3D_PUSH_CONSTANTS_PS_F)
1910 device->shader_backend->shader_update_float_pixel_constants(device, start_idx, count);
1912 offset = wined3d_cs_push_constant_info[p].offset + start_idx * wined3d_cs_push_constant_info[p].size;
1913 memcpy((BYTE *)&cs->state + offset, constants, count * wined3d_cs_push_constant_info[p].size);
1914 for (i = 0, context_count = device->context_count; i < context_count; ++i)
1916 device->contexts[i]->constant_update_mask |= wined3d_cs_push_constant_info[p].mask;
1920 static void wined3d_cs_exec_push_constants(struct wined3d_cs *cs, const void *data)
1922 const struct wined3d_cs_push_constants *op = data;
1924 wined3d_cs_st_push_constants(cs, op->type, op->start_idx, op->count, op->constants);
1927 static void wined3d_cs_mt_push_constants(struct wined3d_cs *cs, enum wined3d_push_constants p,
1928 unsigned int start_idx, unsigned int count, const void *constants)
1930 struct wined3d_cs_push_constants *op;
1931 size_t size;
1933 size = count * wined3d_cs_push_constant_info[p].size;
1934 op = cs->ops->require_space(cs, FIELD_OFFSET(struct wined3d_cs_push_constants, constants[size]),
1935 WINED3D_CS_QUEUE_DEFAULT);
1936 op->opcode = WINED3D_CS_OP_PUSH_CONSTANTS;
1937 op->type = p;
1938 op->start_idx = start_idx;
1939 op->count = count;
1940 memcpy(op->constants, constants, size);
1942 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1945 static void wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data)
1947 struct wined3d_adapter *adapter = cs->device->adapter;
1949 state_cleanup(&cs->state);
1950 memset(&cs->state, 0, sizeof(cs->state));
1951 state_init(&cs->state, &cs->fb, &adapter->d3d_info, WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT);
1954 void wined3d_cs_emit_reset_state(struct wined3d_cs *cs)
1956 struct wined3d_cs_reset_state *op;
1958 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1959 op->opcode = WINED3D_CS_OP_RESET_STATE;
1961 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1964 static void wined3d_cs_exec_callback(struct wined3d_cs *cs, const void *data)
1966 const struct wined3d_cs_callback *op = data;
1968 op->callback(op->object);
1971 static void wined3d_cs_emit_callback(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1973 struct wined3d_cs_callback *op;
1975 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1976 op->opcode = WINED3D_CS_OP_CALLBACK;
1977 op->callback = callback;
1978 op->object = object;
1980 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
1983 void wined3d_cs_destroy_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1985 wined3d_cs_emit_callback(cs, callback, object);
1988 void wined3d_cs_init_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
1990 wined3d_cs_emit_callback(cs, callback, object);
1993 static void wined3d_cs_exec_query_issue(struct wined3d_cs *cs, const void *data)
1995 const struct wined3d_cs_query_issue *op = data;
1996 struct wined3d_query *query = op->query;
1997 BOOL poll;
1999 poll = query->query_ops->query_issue(query, op->flags);
2001 if (!cs->thread)
2002 return;
2004 if (poll && list_empty(&query->poll_list_entry))
2006 if (query->buffer_object)
2007 InterlockedIncrement(&query->counter_retrieved);
2008 else
2009 list_add_tail(&cs->query_poll_list, &query->poll_list_entry);
2010 return;
2013 /* This can happen if occlusion queries are restarted. This discards the
2014 * old result, since polling it could result in a GL error. */
2015 if ((op->flags & WINED3DISSUE_BEGIN) && !poll && !list_empty(&query->poll_list_entry))
2017 list_remove(&query->poll_list_entry);
2018 list_init(&query->poll_list_entry);
2019 InterlockedIncrement(&query->counter_retrieved);
2020 return;
2023 /* This can happen when an occlusion query is ended without being started,
2024 * in which case we don't want to poll, but still have to counter-balance
2025 * the increment of the main counter.
2027 * This can also happen if an event query is re-issued before the first
2028 * fence was reached. In this case the query is already in the list and
2029 * the poll function will check the new fence. We have to counter-balance
2030 * the discarded increment. */
2031 if (op->flags & WINED3DISSUE_END)
2032 InterlockedIncrement(&query->counter_retrieved);
2035 void wined3d_cs_emit_query_issue(struct wined3d_cs *cs, struct wined3d_query *query, DWORD flags)
2037 struct wined3d_cs_query_issue *op;
2039 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2040 op->opcode = WINED3D_CS_OP_QUERY_ISSUE;
2041 op->query = query;
2042 op->flags = flags;
2044 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2045 cs->queries_flushed = FALSE;
2048 static void wined3d_cs_exec_preload_resource(struct wined3d_cs *cs, const void *data)
2050 const struct wined3d_cs_preload_resource *op = data;
2051 struct wined3d_resource *resource = op->resource;
2053 resource->resource_ops->resource_preload(resource);
2054 wined3d_resource_release(resource);
2057 void wined3d_cs_emit_preload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
2059 struct wined3d_cs_preload_resource *op;
2061 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2062 op->opcode = WINED3D_CS_OP_PRELOAD_RESOURCE;
2063 op->resource = resource;
2065 wined3d_resource_acquire(resource);
2067 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2070 static void wined3d_cs_exec_unload_resource(struct wined3d_cs *cs, const void *data)
2072 const struct wined3d_cs_unload_resource *op = data;
2073 struct wined3d_resource *resource = op->resource;
2075 resource->resource_ops->resource_unload(resource);
2076 wined3d_resource_release(resource);
2079 void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
2081 struct wined3d_cs_unload_resource *op;
2083 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2084 op->opcode = WINED3D_CS_OP_UNLOAD_RESOURCE;
2085 op->resource = resource;
2087 wined3d_resource_acquire(resource);
2089 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2092 static void wined3d_cs_exec_map(struct wined3d_cs *cs, const void *data)
2094 const struct wined3d_cs_map *op = data;
2095 struct wined3d_resource *resource = op->resource;
2097 *op->hr = resource->resource_ops->resource_sub_resource_map(resource,
2098 op->sub_resource_idx, op->map_desc, op->box, op->flags);
2101 HRESULT wined3d_cs_map(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx,
2102 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, unsigned int flags)
2104 struct wined3d_cs_map *op;
2105 HRESULT hr;
2107 /* Mapping resources from the worker thread isn't an issue by itself, but
2108 * increasing the map count would be visible to applications. */
2109 wined3d_not_from_cs(cs);
2111 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2112 op->opcode = WINED3D_CS_OP_MAP;
2113 op->resource = resource;
2114 op->sub_resource_idx = sub_resource_idx;
2115 op->map_desc = map_desc;
2116 op->box = box;
2117 op->flags = flags;
2118 op->hr = &hr;
2120 cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2121 cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2123 return hr;
2126 static void wined3d_cs_exec_unmap(struct wined3d_cs *cs, const void *data)
2128 const struct wined3d_cs_unmap *op = data;
2129 struct wined3d_resource *resource = op->resource;
2131 *op->hr = resource->resource_ops->resource_sub_resource_unmap(resource, op->sub_resource_idx);
2134 HRESULT wined3d_cs_unmap(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx)
2136 struct wined3d_cs_unmap *op;
2137 HRESULT hr;
2139 wined3d_not_from_cs(cs);
2141 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2142 op->opcode = WINED3D_CS_OP_UNMAP;
2143 op->resource = resource;
2144 op->sub_resource_idx = sub_resource_idx;
2145 op->hr = &hr;
2147 cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2148 cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2150 return hr;
2153 static void wined3d_cs_exec_blt_sub_resource(struct wined3d_cs *cs, const void *data)
2155 const struct wined3d_cs_blt_sub_resource *op = data;
2157 if (op->dst_resource->type == WINED3D_RTYPE_BUFFER)
2159 wined3d_buffer_copy(buffer_from_resource(op->dst_resource), op->dst_box.left,
2160 buffer_from_resource(op->src_resource), op->src_box.left,
2161 op->src_box.right - op->src_box.left);
2163 else if (op->dst_resource->type == WINED3D_RTYPE_TEXTURE_3D)
2165 struct wined3d_texture *src_texture, *dst_texture;
2166 unsigned int level, update_w, update_h, update_d;
2167 unsigned int row_pitch, slice_pitch;
2168 struct wined3d_context *context;
2169 struct wined3d_bo_address addr;
2171 if (op->flags & ~WINED3D_BLT_RAW)
2173 FIXME("Flags %#x not implemented for %s resources.\n",
2174 op->flags, debug_d3dresourcetype(op->dst_resource->type));
2175 goto error;
2178 if (!(op->flags & WINED3D_BLT_RAW) && op->src_resource->format != op->dst_resource->format)
2180 FIXME("Format conversion not implemented for %s resources.\n",
2181 debug_d3dresourcetype(op->dst_resource->type));
2182 goto error;
2185 update_w = op->dst_box.right - op->dst_box.left;
2186 update_h = op->dst_box.bottom - op->dst_box.top;
2187 update_d = op->dst_box.back - op->dst_box.front;
2188 if (op->src_box.right - op->src_box.left != update_w
2189 || op->src_box.bottom - op->src_box.top != update_h
2190 || op->src_box.back - op->src_box.front != update_d)
2192 FIXME("Stretching not implemented for %s resources.\n",
2193 debug_d3dresourcetype(op->dst_resource->type));
2194 goto error;
2197 dst_texture = texture_from_resource(op->dst_resource);
2198 src_texture = texture_from_resource(op->src_resource);
2200 context = context_acquire(cs->device, NULL, 0);
2202 if (!wined3d_texture_load_location(src_texture, op->src_sub_resource_idx,
2203 context, src_texture->resource.map_binding))
2205 ERR("Failed to load source sub-resource into %s.\n",
2206 wined3d_debug_location(src_texture->resource.map_binding));
2207 context_release(context);
2208 goto error;
2211 level = op->dst_sub_resource_idx % dst_texture->level_count;
2212 if (update_w == wined3d_texture_get_level_width(dst_texture, level)
2213 && update_h == wined3d_texture_get_level_height(dst_texture, level)
2214 && update_d == wined3d_texture_get_level_depth(dst_texture, level))
2216 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
2218 else if (!wined3d_texture_load_location(dst_texture, op->dst_sub_resource_idx,
2219 context, WINED3D_LOCATION_TEXTURE_RGB))
2221 ERR("Failed to load destination sub-resource.\n");
2222 context_release(context);
2223 goto error;
2226 wined3d_texture_get_memory(src_texture, op->src_sub_resource_idx, &addr, src_texture->resource.map_binding);
2227 wined3d_texture_get_pitch(src_texture, op->src_sub_resource_idx % src_texture->level_count,
2228 &row_pitch, &slice_pitch);
2230 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
2231 wined3d_texture_upload_data(dst_texture, op->dst_sub_resource_idx, context,
2232 dst_texture->resource.format, &op->src_box, wined3d_const_bo_address(&addr),
2233 row_pitch, slice_pitch, op->dst_box.left, op->dst_box.top, op->dst_box.front, FALSE);
2234 wined3d_texture_validate_location(dst_texture, op->dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2235 wined3d_texture_invalidate_location(dst_texture, op->dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2237 context_release(context);
2239 else
2241 if (FAILED(texture2d_blt(texture_from_resource(op->dst_resource), op->dst_sub_resource_idx,
2242 &op->dst_box, texture_from_resource(op->src_resource), op->src_sub_resource_idx,
2243 &op->src_box, op->flags, &op->fx, op->filter)))
2244 FIXME("Blit failed.\n");
2247 error:
2248 if (op->src_resource)
2249 wined3d_resource_release(op->src_resource);
2250 wined3d_resource_release(op->dst_resource);
2253 void wined3d_cs_emit_blt_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *dst_resource,
2254 unsigned int dst_sub_resource_idx, const struct wined3d_box *dst_box, struct wined3d_resource *src_resource,
2255 unsigned int src_sub_resource_idx, const struct wined3d_box *src_box, DWORD flags,
2256 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2258 struct wined3d_cs_blt_sub_resource *op;
2260 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2261 op->opcode = WINED3D_CS_OP_BLT_SUB_RESOURCE;
2262 op->dst_resource = dst_resource;
2263 op->dst_sub_resource_idx = dst_sub_resource_idx;
2264 op->dst_box = *dst_box;
2265 op->src_resource = src_resource;
2266 op->src_sub_resource_idx = src_sub_resource_idx;
2267 op->src_box = *src_box;
2268 op->flags = flags;
2269 if (fx)
2270 op->fx = *fx;
2271 else
2272 memset(&op->fx, 0, sizeof(op->fx));
2273 op->filter = filter;
2275 wined3d_resource_acquire(dst_resource);
2276 if (src_resource)
2277 wined3d_resource_acquire(src_resource);
2279 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2280 if (flags & WINED3D_BLT_SYNCHRONOUS)
2281 cs->ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT);
2284 static void wined3d_cs_exec_update_sub_resource(struct wined3d_cs *cs, const void *data)
2286 const struct wined3d_cs_update_sub_resource *op = data;
2287 struct wined3d_resource *resource = op->resource;
2288 const struct wined3d_box *box = &op->box;
2289 unsigned int width, height, depth, level;
2290 struct wined3d_const_bo_address addr;
2291 struct wined3d_context *context;
2292 struct wined3d_texture *texture;
2293 struct wined3d_box src_box;
2295 context = context_acquire(cs->device, NULL, 0);
2297 if (resource->type == WINED3D_RTYPE_BUFFER)
2299 struct wined3d_buffer *buffer = buffer_from_resource(resource);
2301 if (!wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER))
2303 ERR("Failed to load buffer location.\n");
2304 goto done;
2307 wined3d_buffer_upload_data(buffer, context, box, op->data.data);
2308 wined3d_buffer_invalidate_location(buffer, ~WINED3D_LOCATION_BUFFER);
2309 goto done;
2312 texture = wined3d_texture_from_resource(resource);
2314 level = op->sub_resource_idx % texture->level_count;
2315 width = wined3d_texture_get_level_width(texture, level);
2316 height = wined3d_texture_get_level_height(texture, level);
2317 depth = wined3d_texture_get_level_depth(texture, level);
2319 addr.buffer_object = 0;
2320 addr.addr = op->data.data;
2322 /* Only load the sub-resource for partial updates. */
2323 if (!box->left && !box->top && !box->front
2324 && box->right == width && box->bottom == height && box->back == depth)
2325 wined3d_texture_prepare_texture(texture, context, FALSE);
2326 else
2327 wined3d_texture_load_location(texture, op->sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
2328 wined3d_texture_bind_and_dirtify(texture, context, FALSE);
2330 wined3d_box_set(&src_box, 0, 0, box->right - box->left, box->bottom - box->top, 0, box->back - box->front);
2331 wined3d_texture_upload_data(texture, op->sub_resource_idx, context, texture->resource.format, &src_box,
2332 &addr, op->data.row_pitch, op->data.slice_pitch, box->left, box->top, box->front, FALSE);
2334 wined3d_texture_validate_location(texture, op->sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2335 wined3d_texture_invalidate_location(texture, op->sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2337 done:
2338 context_release(context);
2340 wined3d_resource_release(resource);
2343 void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource,
2344 unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch,
2345 unsigned int slice_pitch)
2347 struct wined3d_cs_update_sub_resource *op;
2349 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2350 op->opcode = WINED3D_CS_OP_UPDATE_SUB_RESOURCE;
2351 op->resource = resource;
2352 op->sub_resource_idx = sub_resource_idx;
2353 op->box = *box;
2354 op->data.row_pitch = row_pitch;
2355 op->data.slice_pitch = slice_pitch;
2356 op->data.data = data;
2358 wined3d_resource_acquire(resource);
2360 cs->ops->submit(cs, WINED3D_CS_QUEUE_MAP);
2361 /* The data pointer may go away, so we need to wait until it is read.
2362 * Copying the data may be faster if it's small. */
2363 cs->ops->finish(cs, WINED3D_CS_QUEUE_MAP);
2366 static void wined3d_cs_exec_add_dirty_texture_region(struct wined3d_cs *cs, const void *data)
2368 const struct wined3d_cs_add_dirty_texture_region *op = data;
2369 struct wined3d_texture *texture = op->texture;
2370 unsigned int sub_resource_idx, i;
2371 struct wined3d_context *context;
2373 context = context_acquire(cs->device, NULL, 0);
2374 sub_resource_idx = op->layer * texture->level_count;
2375 for (i = 0; i < texture->level_count; ++i, ++sub_resource_idx)
2377 if (wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding))
2378 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
2379 else
2380 ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
2382 context_release(context);
2384 wined3d_resource_release(&texture->resource);
2387 void wined3d_cs_emit_add_dirty_texture_region(struct wined3d_cs *cs,
2388 struct wined3d_texture *texture, unsigned int layer)
2390 struct wined3d_cs_add_dirty_texture_region *op;
2392 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2393 op->opcode = WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION;
2394 op->texture = texture;
2395 op->layer = layer;
2397 wined3d_resource_acquire(&texture->resource);
2399 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2402 static void wined3d_cs_exec_clear_unordered_access_view(struct wined3d_cs *cs, const void *data)
2404 const struct wined3d_cs_clear_unordered_access_view *op = data;
2405 struct wined3d_unordered_access_view *view = op->view;
2406 struct wined3d_context *context;
2408 context = context_acquire(cs->device, NULL, 0);
2409 wined3d_unordered_access_view_clear_uint(view, &op->clear_value, context);
2410 context_release(context);
2412 wined3d_resource_release(view->resource);
2415 void wined3d_cs_emit_clear_unordered_access_view_uint(struct wined3d_cs *cs,
2416 struct wined3d_unordered_access_view *view, const struct wined3d_uvec4 *clear_value)
2418 struct wined3d_cs_clear_unordered_access_view *op;
2420 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2421 op->opcode = WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW;
2422 op->view = view;
2423 op->clear_value = *clear_value;
2425 wined3d_resource_acquire(view->resource);
2427 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2430 static void wined3d_cs_exec_copy_uav_counter(struct wined3d_cs *cs, const void *data)
2432 const struct wined3d_cs_copy_uav_counter *op = data;
2433 struct wined3d_unordered_access_view *view = op->view;
2434 struct wined3d_context *context;
2436 context = context_acquire(cs->device, NULL, 0);
2437 wined3d_unordered_access_view_copy_counter(view, op->buffer, op->offset, context);
2438 context_release(context);
2440 wined3d_resource_release(&op->buffer->resource);
2443 void wined3d_cs_emit_copy_uav_counter(struct wined3d_cs *cs, struct wined3d_buffer *dst_buffer,
2444 unsigned int offset, struct wined3d_unordered_access_view *uav)
2446 struct wined3d_cs_copy_uav_counter *op;
2448 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2449 op->opcode = WINED3D_CS_OP_COPY_UAV_COUNTER;
2450 op->buffer = dst_buffer;
2451 op->offset = offset;
2452 op->view = uav;
2454 wined3d_resource_acquire(&dst_buffer->resource);
2456 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2459 static void wined3d_cs_exec_generate_mipmaps(struct wined3d_cs *cs, const void *data)
2461 const struct wined3d_cs_generate_mipmaps *op = data;
2462 struct wined3d_shader_resource_view *view = op->view;
2464 shader_resource_view_generate_mipmaps(view);
2465 wined3d_resource_release(view->resource);
2468 void wined3d_cs_emit_generate_mipmaps(struct wined3d_cs *cs, struct wined3d_shader_resource_view *view)
2470 struct wined3d_cs_generate_mipmaps *op;
2472 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2473 op->opcode = WINED3D_CS_OP_GENERATE_MIPMAPS;
2474 op->view = view;
2476 wined3d_resource_acquire(view->resource);
2478 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2481 static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
2483 struct wined3d_cs_stop *op;
2485 op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2486 op->opcode = WINED3D_CS_OP_STOP;
2488 cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
2489 cs->ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT);
2492 static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
2494 /* WINED3D_CS_OP_NOP */ wined3d_cs_exec_nop,
2495 /* WINED3D_CS_OP_PRESENT */ wined3d_cs_exec_present,
2496 /* WINED3D_CS_OP_CLEAR */ wined3d_cs_exec_clear,
2497 /* WINED3D_CS_OP_DISPATCH */ wined3d_cs_exec_dispatch,
2498 /* WINED3D_CS_OP_DRAW */ wined3d_cs_exec_draw,
2499 /* WINED3D_CS_OP_FLUSH */ wined3d_cs_exec_flush,
2500 /* WINED3D_CS_OP_SET_PREDICATION */ wined3d_cs_exec_set_predication,
2501 /* WINED3D_CS_OP_SET_VIEWPORTS */ wined3d_cs_exec_set_viewports,
2502 /* WINED3D_CS_OP_SET_SCISSOR_RECTS */ wined3d_cs_exec_set_scissor_rects,
2503 /* WINED3D_CS_OP_SET_RENDERTARGET_VIEW */ wined3d_cs_exec_set_rendertarget_view,
2504 /* WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW */ wined3d_cs_exec_set_depth_stencil_view,
2505 /* WINED3D_CS_OP_SET_VERTEX_DECLARATION */ wined3d_cs_exec_set_vertex_declaration,
2506 /* WINED3D_CS_OP_SET_STREAM_SOURCE */ wined3d_cs_exec_set_stream_source,
2507 /* WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ */ wined3d_cs_exec_set_stream_source_freq,
2508 /* WINED3D_CS_OP_SET_STREAM_OUTPUT */ wined3d_cs_exec_set_stream_output,
2509 /* WINED3D_CS_OP_SET_INDEX_BUFFER */ wined3d_cs_exec_set_index_buffer,
2510 /* WINED3D_CS_OP_SET_CONSTANT_BUFFER */ wined3d_cs_exec_set_constant_buffer,
2511 /* WINED3D_CS_OP_SET_TEXTURE */ wined3d_cs_exec_set_texture,
2512 /* WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW */ wined3d_cs_exec_set_shader_resource_view,
2513 /* WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_set_unordered_access_view,
2514 /* WINED3D_CS_OP_SET_SAMPLER */ wined3d_cs_exec_set_sampler,
2515 /* WINED3D_CS_OP_SET_SHADER */ wined3d_cs_exec_set_shader,
2516 /* WINED3D_CS_OP_SET_BLEND_STATE */ wined3d_cs_exec_set_blend_state,
2517 /* WINED3D_CS_OP_SET_RASTERIZER_STATE */ wined3d_cs_exec_set_rasterizer_state,
2518 /* WINED3D_CS_OP_SET_RENDER_STATE */ wined3d_cs_exec_set_render_state,
2519 /* WINED3D_CS_OP_SET_TEXTURE_STATE */ wined3d_cs_exec_set_texture_state,
2520 /* WINED3D_CS_OP_SET_SAMPLER_STATE */ wined3d_cs_exec_set_sampler_state,
2521 /* WINED3D_CS_OP_SET_TRANSFORM */ wined3d_cs_exec_set_transform,
2522 /* WINED3D_CS_OP_SET_CLIP_PLANE */ wined3d_cs_exec_set_clip_plane,
2523 /* WINED3D_CS_OP_SET_COLOR_KEY */ wined3d_cs_exec_set_color_key,
2524 /* WINED3D_CS_OP_SET_MATERIAL */ wined3d_cs_exec_set_material,
2525 /* WINED3D_CS_OP_SET_LIGHT */ wined3d_cs_exec_set_light,
2526 /* WINED3D_CS_OP_SET_LIGHT_ENABLE */ wined3d_cs_exec_set_light_enable,
2527 /* WINED3D_CS_OP_PUSH_CONSTANTS */ wined3d_cs_exec_push_constants,
2528 /* WINED3D_CS_OP_RESET_STATE */ wined3d_cs_exec_reset_state,
2529 /* WINED3D_CS_OP_CALLBACK */ wined3d_cs_exec_callback,
2530 /* WINED3D_CS_OP_QUERY_ISSUE */ wined3d_cs_exec_query_issue,
2531 /* WINED3D_CS_OP_PRELOAD_RESOURCE */ wined3d_cs_exec_preload_resource,
2532 /* WINED3D_CS_OP_UNLOAD_RESOURCE */ wined3d_cs_exec_unload_resource,
2533 /* WINED3D_CS_OP_MAP */ wined3d_cs_exec_map,
2534 /* WINED3D_CS_OP_UNMAP */ wined3d_cs_exec_unmap,
2535 /* WINED3D_CS_OP_BLT_SUB_RESOURCE */ wined3d_cs_exec_blt_sub_resource,
2536 /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE */ wined3d_cs_exec_update_sub_resource,
2537 /* WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION */ wined3d_cs_exec_add_dirty_texture_region,
2538 /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view,
2539 /* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter,
2540 /* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps,
2543 static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2545 if (size > (cs->data_size - cs->end))
2547 size_t new_size;
2548 void *new_data;
2550 new_size = max(size, cs->data_size * 2);
2551 if (!cs->end)
2552 new_data = heap_realloc(cs->data, new_size);
2553 else
2554 new_data = heap_alloc(new_size);
2555 if (!new_data)
2556 return NULL;
2558 cs->data_size = new_size;
2559 cs->start = cs->end = 0;
2560 cs->data = new_data;
2563 cs->end += size;
2565 return (BYTE *)cs->data + cs->start;
2568 static void wined3d_cs_st_submit(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2570 enum wined3d_cs_op opcode;
2571 size_t start;
2572 BYTE *data;
2574 data = cs->data;
2575 start = cs->start;
2576 cs->start = cs->end;
2578 opcode = *(const enum wined3d_cs_op *)&data[start];
2579 if (opcode >= WINED3D_CS_OP_STOP)
2580 ERR("Invalid opcode %#x.\n", opcode);
2581 else
2582 wined3d_cs_op_handlers[opcode](cs, &data[start]);
2584 if (cs->data == data)
2585 cs->start = cs->end = start;
2586 else if (!start)
2587 heap_free(data);
2590 static void wined3d_cs_st_finish(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2594 static const struct wined3d_cs_ops wined3d_cs_st_ops =
2596 wined3d_cs_st_require_space,
2597 wined3d_cs_st_submit,
2598 wined3d_cs_st_finish,
2599 wined3d_cs_st_push_constants,
2602 static BOOL wined3d_cs_queue_is_empty(const struct wined3d_cs *cs, const struct wined3d_cs_queue *queue)
2604 wined3d_from_cs(cs);
2605 return *(volatile LONG *)&queue->head == queue->tail;
2608 static void wined3d_cs_queue_submit(struct wined3d_cs_queue *queue, struct wined3d_cs *cs)
2610 struct wined3d_cs_packet *packet;
2611 size_t packet_size;
2613 packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
2614 packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[packet->size]);
2615 InterlockedExchange(&queue->head, (queue->head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1));
2617 if (InterlockedCompareExchange(&cs->waiting_for_event, FALSE, TRUE))
2618 SetEvent(cs->event);
2621 static void wined3d_cs_mt_submit(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2623 if (cs->thread_id == GetCurrentThreadId())
2624 return wined3d_cs_st_submit(cs, queue_id);
2626 wined3d_cs_queue_submit(&cs->queue[queue_id], cs);
2629 static void *wined3d_cs_queue_require_space(struct wined3d_cs_queue *queue, size_t size, struct wined3d_cs *cs)
2631 size_t queue_size = ARRAY_SIZE(queue->data);
2632 size_t header_size, packet_size, remaining;
2633 struct wined3d_cs_packet *packet;
2635 header_size = FIELD_OFFSET(struct wined3d_cs_packet, data[0]);
2636 size = (size + header_size - 1) & ~(header_size - 1);
2637 packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[size]);
2638 if (packet_size >= WINED3D_CS_QUEUE_SIZE)
2640 ERR("Packet size %lu >= queue size %u.\n",
2641 (unsigned long)packet_size, WINED3D_CS_QUEUE_SIZE);
2642 return NULL;
2645 remaining = queue_size - queue->head;
2646 if (remaining < packet_size)
2648 size_t nop_size = remaining - header_size;
2649 struct wined3d_cs_nop *nop;
2651 TRACE("Inserting a nop for %lu + %lu bytes.\n",
2652 (unsigned long)header_size, (unsigned long)nop_size);
2654 nop = wined3d_cs_queue_require_space(queue, nop_size, cs);
2655 if (nop_size)
2656 nop->opcode = WINED3D_CS_OP_NOP;
2658 wined3d_cs_queue_submit(queue, cs);
2659 assert(!queue->head);
2662 for (;;)
2664 LONG tail = *(volatile LONG *)&queue->tail;
2665 LONG head = queue->head;
2666 LONG new_pos;
2668 /* Empty. */
2669 if (head == tail)
2670 break;
2671 new_pos = (head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1);
2672 /* Head ahead of tail. We checked the remaining size above, so we only
2673 * need to make sure we don't make head equal to tail. */
2674 if (head > tail && (new_pos != tail))
2675 break;
2676 /* Tail ahead of head. Make sure the new head is before the tail as
2677 * well. Note that new_pos is 0 when it's at the end of the queue. */
2678 if (new_pos < tail && new_pos)
2679 break;
2681 TRACE("Waiting for free space. Head %u, tail %u, packet size %lu.\n",
2682 head, tail, (unsigned long)packet_size);
2685 packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
2686 packet->size = size;
2687 return packet->data;
2690 static void *wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
2692 if (cs->thread_id == GetCurrentThreadId())
2693 return wined3d_cs_st_require_space(cs, size, queue_id);
2695 return wined3d_cs_queue_require_space(&cs->queue[queue_id], size, cs);
2698 static void wined3d_cs_mt_finish(struct wined3d_cs *cs, enum wined3d_cs_queue_id queue_id)
2700 if (cs->thread_id == GetCurrentThreadId())
2701 return wined3d_cs_st_finish(cs, queue_id);
2703 while (cs->queue[queue_id].head != *(volatile LONG *)&cs->queue[queue_id].tail)
2704 wined3d_pause();
2707 static const struct wined3d_cs_ops wined3d_cs_mt_ops =
2709 wined3d_cs_mt_require_space,
2710 wined3d_cs_mt_submit,
2711 wined3d_cs_mt_finish,
2712 wined3d_cs_mt_push_constants,
2715 static void poll_queries(struct wined3d_cs *cs)
2717 struct wined3d_query *query, *cursor;
2719 LIST_FOR_EACH_ENTRY_SAFE(query, cursor, &cs->query_poll_list, struct wined3d_query, poll_list_entry)
2721 if (!query->query_ops->query_poll(query, 0))
2722 continue;
2724 list_remove(&query->poll_list_entry);
2725 list_init(&query->poll_list_entry);
2726 InterlockedIncrement(&query->counter_retrieved);
2730 static void wined3d_cs_wait_event(struct wined3d_cs *cs)
2732 InterlockedExchange(&cs->waiting_for_event, TRUE);
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.
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;
2746 WaitForSingleObject(cs->event, INFINITE);
2749 static DWORD WINAPI wined3d_cs_run(void *ctx)
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;
2760 TRACE("Started.\n");
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;
2766 list_init(&cs->query_poll_list);
2767 cs->thread_id = GetCurrentThreadId();
2768 for (;;)
2770 if (++poll == WINED3D_CS_QUERY_POLL_INTERVAL)
2772 poll_queries(cs);
2773 poll = 0;
2776 queue = &cs->queue[WINED3D_CS_QUEUE_MAP];
2777 if (wined3d_cs_queue_is_empty(cs, queue))
2779 queue = &cs->queue[WINED3D_CS_QUEUE_DEFAULT];
2780 if (wined3d_cs_queue_is_empty(cs, queue))
2782 if (++spin_count >= WINED3D_CS_SPIN_COUNT && list_empty(&cs->query_poll_list))
2783 wined3d_cs_wait_event(cs);
2784 continue;
2787 spin_count = 0;
2789 tail = queue->tail;
2790 packet = (struct wined3d_cs_packet *)&queue->data[tail];
2791 if (packet->size)
2793 opcode = *(const enum wined3d_cs_op *)packet->data;
2795 TRACE("Executing %s.\n", debug_cs_op(opcode));
2796 if (opcode >= WINED3D_CS_OP_STOP)
2798 if (opcode > WINED3D_CS_OP_STOP)
2799 ERR("Invalid opcode %#x.\n", opcode);
2800 break;
2803 wined3d_cs_op_handlers[opcode](cs, packet->data);
2804 TRACE("%s executed.\n", debug_cs_op(opcode));
2807 tail += FIELD_OFFSET(struct wined3d_cs_packet, data[packet->size]);
2808 tail &= (WINED3D_CS_QUEUE_SIZE - 1);
2809 InterlockedExchange(&queue->tail, tail);
2812 cs->queue[WINED3D_CS_QUEUE_MAP].tail = cs->queue[WINED3D_CS_QUEUE_MAP].head;
2813 cs->queue[WINED3D_CS_QUEUE_DEFAULT].tail = cs->queue[WINED3D_CS_QUEUE_DEFAULT].head;
2814 TRACE("Stopped.\n");
2815 FreeLibraryAndExitThread(wined3d_module, 0);
2818 struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device)
2820 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
2821 struct wined3d_cs *cs;
2823 if (!(cs = heap_alloc_zero(sizeof(*cs))))
2824 return NULL;
2826 cs->ops = &wined3d_cs_st_ops;
2827 cs->device = device;
2829 state_init(&cs->state, &cs->fb, d3d_info, WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT);
2831 cs->data_size = WINED3D_INITIAL_CS_SIZE;
2832 if (!(cs->data = heap_alloc(cs->data_size)))
2833 goto fail;
2835 if (wined3d_settings.cs_multithreaded
2836 && !RtlIsCriticalSectionLockedByThread(NtCurrentTeb()->Peb->LoaderLock))
2838 cs->ops = &wined3d_cs_mt_ops;
2840 if (!(cs->event = CreateEventW(NULL, FALSE, FALSE, NULL)))
2842 ERR("Failed to create command stream event.\n");
2843 heap_free(cs->data);
2844 goto fail;
2847 if (!(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
2848 (const WCHAR *)wined3d_cs_run, &cs->wined3d_module)))
2850 ERR("Failed to get wined3d module handle.\n");
2851 CloseHandle(cs->event);
2852 heap_free(cs->data);
2853 goto fail;
2856 if (!(cs->thread = CreateThread(NULL, 0, wined3d_cs_run, cs, 0, NULL)))
2858 ERR("Failed to create wined3d command stream thread.\n");
2859 FreeLibrary(cs->wined3d_module);
2860 CloseHandle(cs->event);
2861 heap_free(cs->data);
2862 goto fail;
2866 return cs;
2868 fail:
2869 state_cleanup(&cs->state);
2870 heap_free(cs);
2871 return NULL;
2874 void wined3d_cs_destroy(struct wined3d_cs *cs)
2876 if (cs->thread)
2878 wined3d_cs_emit_stop(cs);
2879 CloseHandle(cs->thread);
2880 if (!CloseHandle(cs->event))
2881 ERR("Closing event failed.\n");
2884 state_cleanup(&cs->state);
2885 heap_free(cs->data);
2886 heap_free(cs);