wined3d: Introduce a wined3d_texture_update_sub_resource() helper.
[wine.git] / dlls / wined3d / cs.c
blobf294be290919f39b7e37629a8753a6469d819ac9
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 "wined3d_private.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
23 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
24 WINE_DECLARE_DEBUG_CHANNEL(d3d_sync);
25 WINE_DECLARE_DEBUG_CHANNEL(fps);
27 #define WINED3D_INITIAL_CS_SIZE 4096
29 struct wined3d_deferred_upload
31 struct wined3d_resource *resource;
32 unsigned int sub_resource_idx;
33 uint8_t *sysmem;
34 struct wined3d_box box;
35 uint32_t upload_flags;
38 struct wined3d_deferred_query_issue
40 struct wined3d_query *query;
41 unsigned int flags;
44 struct wined3d_command_list
46 LONG refcount;
48 struct wined3d_device *device;
50 SIZE_T data_size;
51 void *data;
53 HANDLE upload_heap;
54 SIZE_T resource_count;
55 struct wined3d_resource **resources;
57 SIZE_T upload_count;
58 struct wined3d_deferred_upload *uploads;
60 /* List of command lists queued for execution on this command list. We might
61 * be the only thing holding a pointer to another command list, so we need
62 * to hold a reference here (and in wined3d_deferred_context) as well. */
63 SIZE_T command_list_count;
64 struct wined3d_command_list **command_lists;
66 SIZE_T query_count;
67 struct wined3d_deferred_query_issue *queries;
70 static void discard_client_address(struct wined3d_resource *resource)
72 struct wined3d_client_resource *client = &resource->client;
74 client->addr.buffer_object = CLIENT_BO_DISCARDED;
75 client->addr.addr = NULL;
78 static void invalidate_client_address(struct wined3d_resource *resource)
80 struct wined3d_client_resource *client = &resource->client;
82 memset(&client->addr, 0, sizeof(client->addr));
85 enum wined3d_cs_op
87 WINED3D_CS_OP_NOP,
88 WINED3D_CS_OP_PRESENT,
89 WINED3D_CS_OP_CLEAR,
90 WINED3D_CS_OP_DISPATCH,
91 WINED3D_CS_OP_DRAW,
92 WINED3D_CS_OP_FLUSH,
93 WINED3D_CS_OP_SET_PREDICATION,
94 WINED3D_CS_OP_SET_VIEWPORTS,
95 WINED3D_CS_OP_SET_SCISSOR_RECTS,
96 WINED3D_CS_OP_SET_RENDERTARGET_VIEWS,
97 WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW,
98 WINED3D_CS_OP_SET_VERTEX_DECLARATION,
99 WINED3D_CS_OP_SET_STREAM_SOURCES,
100 WINED3D_CS_OP_SET_STREAM_OUTPUTS,
101 WINED3D_CS_OP_SET_INDEX_BUFFER,
102 WINED3D_CS_OP_SET_CONSTANT_BUFFERS,
103 WINED3D_CS_OP_SET_TEXTURE,
104 WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEWS,
105 WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEWS,
106 WINED3D_CS_OP_SET_SAMPLERS,
107 WINED3D_CS_OP_SET_SHADER,
108 WINED3D_CS_OP_SET_BLEND_STATE,
109 WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE,
110 WINED3D_CS_OP_SET_RASTERIZER_STATE,
111 WINED3D_CS_OP_SET_RENDER_STATE,
112 WINED3D_CS_OP_SET_TEXTURE_STATE,
113 WINED3D_CS_OP_SET_SAMPLER_STATE,
114 WINED3D_CS_OP_SET_TRANSFORM,
115 WINED3D_CS_OP_SET_CLIP_PLANE,
116 WINED3D_CS_OP_SET_COLOR_KEY,
117 WINED3D_CS_OP_SET_MATERIAL,
118 WINED3D_CS_OP_SET_LIGHT,
119 WINED3D_CS_OP_SET_LIGHT_ENABLE,
120 WINED3D_CS_OP_SET_FEATURE_LEVEL,
121 WINED3D_CS_OP_PUSH_CONSTANTS,
122 WINED3D_CS_OP_RESET_STATE,
123 WINED3D_CS_OP_CALLBACK,
124 WINED3D_CS_OP_QUERY_ISSUE,
125 WINED3D_CS_OP_PRELOAD_RESOURCE,
126 WINED3D_CS_OP_UNLOAD_RESOURCE,
127 WINED3D_CS_OP_MAP,
128 WINED3D_CS_OP_UNMAP,
129 WINED3D_CS_OP_MAP_BO_ADDRESS,
130 WINED3D_CS_OP_BLT_SUB_RESOURCE,
131 WINED3D_CS_OP_UPDATE_SUB_RESOURCE,
132 WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION,
133 WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW,
134 WINED3D_CS_OP_COPY_UAV_COUNTER,
135 WINED3D_CS_OP_GENERATE_MIPMAPS,
136 WINED3D_CS_OP_EXECUTE_COMMAND_LIST,
137 WINED3D_CS_OP_STOP,
140 struct wined3d_cs_packet
142 size_t size;
143 BYTE data[1];
146 struct wined3d_cs_nop
148 enum wined3d_cs_op opcode;
151 struct wined3d_cs_present
153 enum wined3d_cs_op opcode;
154 HWND dst_window_override;
155 struct wined3d_swapchain *swapchain;
156 RECT src_rect;
157 RECT dst_rect;
158 unsigned int swap_interval;
159 DWORD flags;
162 struct wined3d_cs_clear
164 enum wined3d_cs_op opcode;
165 DWORD flags;
166 unsigned int rt_count;
167 struct wined3d_fb_state fb;
168 RECT draw_rect;
169 struct wined3d_color color;
170 float depth;
171 DWORD stencil;
172 unsigned int rect_count;
173 RECT rects[1];
176 struct wined3d_cs_dispatch
178 enum wined3d_cs_op opcode;
179 struct wined3d_dispatch_parameters parameters;
182 struct wined3d_cs_draw
184 enum wined3d_cs_op opcode;
185 enum wined3d_primitive_type primitive_type;
186 GLint patch_vertex_count;
187 struct wined3d_draw_parameters parameters;
190 struct wined3d_cs_flush
192 enum wined3d_cs_op opcode;
195 struct wined3d_cs_set_predication
197 enum wined3d_cs_op opcode;
198 struct wined3d_query *predicate;
199 BOOL value;
202 struct wined3d_cs_set_viewports
204 enum wined3d_cs_op opcode;
205 unsigned int viewport_count;
206 struct wined3d_viewport viewports[1];
209 struct wined3d_cs_set_scissor_rects
211 enum wined3d_cs_op opcode;
212 unsigned int rect_count;
213 RECT rects[1];
216 struct wined3d_cs_set_rendertarget_views
218 enum wined3d_cs_op opcode;
219 unsigned int start_idx;
220 unsigned int count;
221 struct wined3d_rendertarget_view *views[1];
224 struct wined3d_cs_set_depth_stencil_view
226 enum wined3d_cs_op opcode;
227 struct wined3d_rendertarget_view *view;
230 struct wined3d_cs_set_vertex_declaration
232 enum wined3d_cs_op opcode;
233 struct wined3d_vertex_declaration *declaration;
236 struct wined3d_cs_set_stream_sources
238 enum wined3d_cs_op opcode;
239 unsigned int start_idx;
240 unsigned int count;
241 struct wined3d_stream_state streams[1];
244 struct wined3d_cs_set_stream_outputs
246 enum wined3d_cs_op opcode;
247 struct wined3d_stream_output outputs[WINED3D_MAX_STREAM_OUTPUT_BUFFERS];
250 struct wined3d_cs_set_index_buffer
252 enum wined3d_cs_op opcode;
253 struct wined3d_buffer *buffer;
254 enum wined3d_format_id format_id;
255 unsigned int offset;
258 struct wined3d_cs_set_constant_buffers
260 enum wined3d_cs_op opcode;
261 enum wined3d_shader_type type;
262 unsigned int start_idx;
263 unsigned int count;
264 struct wined3d_constant_buffer_state buffers[1];
267 struct wined3d_cs_set_texture
269 enum wined3d_cs_op opcode;
270 UINT stage;
271 struct wined3d_texture *texture;
274 struct wined3d_cs_set_color_key
276 enum wined3d_cs_op opcode;
277 struct wined3d_texture *texture;
278 WORD flags;
279 WORD set;
280 struct wined3d_color_key color_key;
283 struct wined3d_cs_set_shader_resource_views
285 enum wined3d_cs_op opcode;
286 enum wined3d_shader_type type;
287 unsigned int start_idx;
288 unsigned int count;
289 struct wined3d_shader_resource_view *views[1];
292 struct wined3d_cs_set_unordered_access_views
294 enum wined3d_cs_op opcode;
295 enum wined3d_pipeline pipeline;
296 unsigned int start_idx;
297 unsigned int count;
298 struct
300 struct wined3d_unordered_access_view *view;
301 unsigned int initial_count;
302 } uavs[1];
305 struct wined3d_cs_set_samplers
307 enum wined3d_cs_op opcode;
308 enum wined3d_shader_type type;
309 unsigned int start_idx;
310 unsigned int count;
311 struct wined3d_sampler *samplers[1];
314 struct wined3d_cs_set_shader
316 enum wined3d_cs_op opcode;
317 enum wined3d_shader_type type;
318 struct wined3d_shader *shader;
321 struct wined3d_cs_set_blend_state
323 enum wined3d_cs_op opcode;
324 struct wined3d_blend_state *state;
325 struct wined3d_color factor;
326 unsigned int sample_mask;
329 struct wined3d_cs_set_depth_stencil_state
331 enum wined3d_cs_op opcode;
332 struct wined3d_depth_stencil_state *state;
333 unsigned int stencil_ref;
336 struct wined3d_cs_set_rasterizer_state
338 enum wined3d_cs_op opcode;
339 struct wined3d_rasterizer_state *state;
342 struct wined3d_cs_set_render_state
344 enum wined3d_cs_op opcode;
345 enum wined3d_render_state state;
346 DWORD value;
349 struct wined3d_cs_set_texture_state
351 enum wined3d_cs_op opcode;
352 UINT stage;
353 enum wined3d_texture_stage_state state;
354 DWORD value;
357 struct wined3d_cs_set_sampler_state
359 enum wined3d_cs_op opcode;
360 UINT sampler_idx;
361 enum wined3d_sampler_state state;
362 DWORD value;
365 struct wined3d_cs_set_transform
367 enum wined3d_cs_op opcode;
368 enum wined3d_transform_state state;
369 struct wined3d_matrix matrix;
372 struct wined3d_cs_set_clip_plane
374 enum wined3d_cs_op opcode;
375 UINT plane_idx;
376 struct wined3d_vec4 plane;
379 struct wined3d_cs_set_material
381 enum wined3d_cs_op opcode;
382 struct wined3d_material material;
385 struct wined3d_cs_set_light
387 enum wined3d_cs_op opcode;
388 struct wined3d_light_info light;
391 struct wined3d_cs_set_light_enable
393 enum wined3d_cs_op opcode;
394 unsigned int idx;
395 BOOL enable;
398 struct wined3d_cs_set_feature_level
400 enum wined3d_cs_op opcode;
401 enum wined3d_feature_level level;
404 struct wined3d_cs_push_constants
406 enum wined3d_cs_op opcode;
407 enum wined3d_push_constants type;
408 unsigned int start_idx;
409 unsigned int count;
410 BYTE constants[1];
413 struct wined3d_cs_reset_state
415 enum wined3d_cs_op opcode;
416 bool invalidate;
419 struct wined3d_cs_callback
421 enum wined3d_cs_op opcode;
422 void (*callback)(void *object);
423 void *object;
426 struct wined3d_cs_query_issue
428 enum wined3d_cs_op opcode;
429 struct wined3d_query *query;
430 DWORD flags;
433 struct wined3d_cs_preload_resource
435 enum wined3d_cs_op opcode;
436 struct wined3d_resource *resource;
439 struct wined3d_cs_unload_resource
441 enum wined3d_cs_op opcode;
442 struct wined3d_resource *resource;
445 struct wined3d_cs_map
447 enum wined3d_cs_op opcode;
448 struct wined3d_resource *resource;
449 unsigned int sub_resource_idx;
450 void **map_ptr;
451 const struct wined3d_box *box;
452 DWORD flags;
453 HRESULT *hr;
456 struct wined3d_cs_unmap
458 enum wined3d_cs_op opcode;
459 struct wined3d_resource *resource;
460 unsigned int sub_resource_idx;
461 HRESULT *hr;
464 struct wined3d_cs_map_bo_address
466 enum wined3d_cs_op opcode;
467 struct wined3d_bo_address addr;
468 size_t size;
469 uint32_t flags;
472 struct wined3d_cs_blt_sub_resource
474 enum wined3d_cs_op opcode;
475 struct wined3d_resource *dst_resource;
476 unsigned int dst_sub_resource_idx;
477 struct wined3d_box dst_box;
478 struct wined3d_resource *src_resource;
479 unsigned int src_sub_resource_idx;
480 struct wined3d_box src_box;
481 DWORD flags;
482 struct wined3d_blt_fx fx;
483 enum wined3d_texture_filter_type filter;
486 struct wined3d_cs_update_sub_resource
488 enum wined3d_cs_op opcode;
489 struct wined3d_resource *resource;
490 unsigned int sub_resource_idx;
491 struct wined3d_box box;
492 struct upload_bo bo;
493 unsigned int row_pitch, slice_pitch;
496 struct wined3d_cs_add_dirty_texture_region
498 enum wined3d_cs_op opcode;
499 struct wined3d_texture *texture;
500 unsigned int layer;
503 struct wined3d_cs_clear_unordered_access_view
505 enum wined3d_cs_op opcode;
506 struct wined3d_unordered_access_view *view;
507 struct wined3d_uvec4 clear_value;
508 bool fp;
511 struct wined3d_cs_copy_uav_counter
513 enum wined3d_cs_op opcode;
514 struct wined3d_buffer *buffer;
515 unsigned int offset;
516 struct wined3d_unordered_access_view *view;
519 struct wined3d_cs_generate_mipmaps
521 enum wined3d_cs_op opcode;
522 struct wined3d_shader_resource_view *view;
525 struct wined3d_cs_execute_command_list
527 enum wined3d_cs_op opcode;
528 struct wined3d_command_list *list;
531 struct wined3d_cs_stop
533 enum wined3d_cs_op opcode;
536 static inline void *wined3d_device_context_require_space(struct wined3d_device_context *context,
537 size_t size, enum wined3d_cs_queue_id queue_id)
539 return context->ops->require_space(context, size, queue_id);
542 static inline void wined3d_device_context_submit(struct wined3d_device_context *context,
543 enum wined3d_cs_queue_id queue_id)
545 context->ops->submit(context, queue_id);
548 static inline void wined3d_device_context_finish(struct wined3d_device_context *context,
549 enum wined3d_cs_queue_id queue_id)
551 context->ops->finish(context, queue_id);
554 static inline void wined3d_device_context_acquire_resource(struct wined3d_device_context *context,
555 struct wined3d_resource *resource)
557 context->ops->acquire_resource(context, resource);
560 static struct wined3d_cs *wined3d_cs_from_context(struct wined3d_device_context *context)
562 return CONTAINING_RECORD(context, struct wined3d_cs, c);
565 static const char *debug_cs_op(enum wined3d_cs_op op)
567 switch (op)
569 #define WINED3D_TO_STR(type) case type: return #type
570 WINED3D_TO_STR(WINED3D_CS_OP_NOP);
571 WINED3D_TO_STR(WINED3D_CS_OP_PRESENT);
572 WINED3D_TO_STR(WINED3D_CS_OP_CLEAR);
573 WINED3D_TO_STR(WINED3D_CS_OP_DISPATCH);
574 WINED3D_TO_STR(WINED3D_CS_OP_DRAW);
575 WINED3D_TO_STR(WINED3D_CS_OP_FLUSH);
576 WINED3D_TO_STR(WINED3D_CS_OP_SET_PREDICATION);
577 WINED3D_TO_STR(WINED3D_CS_OP_SET_VIEWPORTS);
578 WINED3D_TO_STR(WINED3D_CS_OP_SET_SCISSOR_RECTS);
579 WINED3D_TO_STR(WINED3D_CS_OP_SET_RENDERTARGET_VIEWS);
580 WINED3D_TO_STR(WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW);
581 WINED3D_TO_STR(WINED3D_CS_OP_SET_VERTEX_DECLARATION);
582 WINED3D_TO_STR(WINED3D_CS_OP_SET_STREAM_SOURCES);
583 WINED3D_TO_STR(WINED3D_CS_OP_SET_STREAM_OUTPUTS);
584 WINED3D_TO_STR(WINED3D_CS_OP_SET_INDEX_BUFFER);
585 WINED3D_TO_STR(WINED3D_CS_OP_SET_CONSTANT_BUFFERS);
586 WINED3D_TO_STR(WINED3D_CS_OP_SET_TEXTURE);
587 WINED3D_TO_STR(WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEWS);
588 WINED3D_TO_STR(WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEWS);
589 WINED3D_TO_STR(WINED3D_CS_OP_SET_SAMPLERS);
590 WINED3D_TO_STR(WINED3D_CS_OP_SET_SHADER);
591 WINED3D_TO_STR(WINED3D_CS_OP_SET_BLEND_STATE);
592 WINED3D_TO_STR(WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE);
593 WINED3D_TO_STR(WINED3D_CS_OP_SET_RASTERIZER_STATE);
594 WINED3D_TO_STR(WINED3D_CS_OP_SET_RENDER_STATE);
595 WINED3D_TO_STR(WINED3D_CS_OP_SET_TEXTURE_STATE);
596 WINED3D_TO_STR(WINED3D_CS_OP_SET_SAMPLER_STATE);
597 WINED3D_TO_STR(WINED3D_CS_OP_SET_TRANSFORM);
598 WINED3D_TO_STR(WINED3D_CS_OP_SET_CLIP_PLANE);
599 WINED3D_TO_STR(WINED3D_CS_OP_SET_COLOR_KEY);
600 WINED3D_TO_STR(WINED3D_CS_OP_SET_MATERIAL);
601 WINED3D_TO_STR(WINED3D_CS_OP_SET_LIGHT);
602 WINED3D_TO_STR(WINED3D_CS_OP_SET_LIGHT_ENABLE);
603 WINED3D_TO_STR(WINED3D_CS_OP_SET_FEATURE_LEVEL);
604 WINED3D_TO_STR(WINED3D_CS_OP_PUSH_CONSTANTS);
605 WINED3D_TO_STR(WINED3D_CS_OP_RESET_STATE);
606 WINED3D_TO_STR(WINED3D_CS_OP_CALLBACK);
607 WINED3D_TO_STR(WINED3D_CS_OP_QUERY_ISSUE);
608 WINED3D_TO_STR(WINED3D_CS_OP_PRELOAD_RESOURCE);
609 WINED3D_TO_STR(WINED3D_CS_OP_UNLOAD_RESOURCE);
610 WINED3D_TO_STR(WINED3D_CS_OP_MAP);
611 WINED3D_TO_STR(WINED3D_CS_OP_UNMAP);
612 WINED3D_TO_STR(WINED3D_CS_OP_MAP_BO_ADDRESS);
613 WINED3D_TO_STR(WINED3D_CS_OP_BLT_SUB_RESOURCE);
614 WINED3D_TO_STR(WINED3D_CS_OP_UPDATE_SUB_RESOURCE);
615 WINED3D_TO_STR(WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION);
616 WINED3D_TO_STR(WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW);
617 WINED3D_TO_STR(WINED3D_CS_OP_COPY_UAV_COUNTER);
618 WINED3D_TO_STR(WINED3D_CS_OP_GENERATE_MIPMAPS);
619 WINED3D_TO_STR(WINED3D_CS_OP_EXECUTE_COMMAND_LIST);
620 WINED3D_TO_STR(WINED3D_CS_OP_STOP);
621 #undef WINED3D_TO_STR
623 return wine_dbg_sprintf("UNKNOWN_OP(%#x)", op);
626 static struct wined3d_cs_packet *wined3d_next_cs_packet(const uint8_t *data, SIZE_T *offset)
628 struct wined3d_cs_packet *packet = (struct wined3d_cs_packet *)&data[*offset];
630 *offset += offsetof(struct wined3d_cs_packet, data[packet->size]);
632 return packet;
635 static void wined3d_cs_exec_nop(struct wined3d_cs *cs, const void *data)
639 static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data)
641 struct wined3d_texture *logo_texture, *cursor_texture, *back_buffer;
642 struct wined3d_rendertarget_view *dsv = cs->state.fb.depth_stencil;
643 const struct wined3d_cs_present *op = data;
644 const struct wined3d_swapchain_desc *desc;
645 struct wined3d_swapchain *swapchain;
646 unsigned int i;
648 swapchain = op->swapchain;
649 desc = &swapchain->state.desc;
650 back_buffer = swapchain->back_buffers[0];
651 wined3d_swapchain_set_window(swapchain, op->dst_window_override);
653 if ((logo_texture = swapchain->device->logo_texture))
655 RECT rect = {0, 0, logo_texture->resource.width, logo_texture->resource.height};
657 /* Blit the logo into the upper left corner of the back-buffer. */
658 wined3d_device_context_blt(&cs->c, back_buffer, 0, &rect, logo_texture, 0,
659 &rect, WINED3D_BLT_SRC_CKEY, NULL, WINED3D_TEXF_POINT);
662 if ((cursor_texture = swapchain->device->cursor_texture)
663 && swapchain->device->bCursorVisible && !swapchain->device->hardwareCursor)
665 RECT dst_rect =
667 swapchain->device->xScreenSpace - swapchain->device->xHotSpot,
668 swapchain->device->yScreenSpace - swapchain->device->yHotSpot,
669 swapchain->device->xScreenSpace + swapchain->device->cursorWidth - swapchain->device->xHotSpot,
670 swapchain->device->yScreenSpace + swapchain->device->cursorHeight - swapchain->device->yHotSpot,
672 RECT src_rect =
674 0, 0, cursor_texture->resource.width, cursor_texture->resource.height
676 const RECT clip_rect = {0, 0, back_buffer->resource.width, back_buffer->resource.height};
678 TRACE("Rendering the software cursor.\n");
680 if (desc->windowed)
681 MapWindowPoints(NULL, swapchain->win_handle, (POINT *)&dst_rect, 2);
682 if (wined3d_clip_blit(&clip_rect, &dst_rect, &src_rect))
683 wined3d_device_context_blt(&cs->c, back_buffer, 0, &dst_rect, cursor_texture, 0,
684 &src_rect, WINED3D_BLT_ALPHA_TEST, NULL, WINED3D_TEXF_POINT);
687 swapchain->swapchain_ops->swapchain_present(swapchain, &op->src_rect, &op->dst_rect, op->swap_interval, op->flags);
689 /* Discard buffers if the swap effect allows it. */
690 back_buffer = swapchain->back_buffers[desc->backbuffer_count - 1];
691 if (desc->swap_effect == WINED3D_SWAP_EFFECT_DISCARD || desc->swap_effect == WINED3D_SWAP_EFFECT_FLIP_DISCARD)
692 wined3d_texture_validate_location(back_buffer, 0, WINED3D_LOCATION_DISCARDED);
694 if (dsv && dsv->resource->type != WINED3D_RTYPE_BUFFER)
696 struct wined3d_texture *ds = texture_from_resource(dsv->resource);
698 if ((desc->flags & WINED3D_SWAPCHAIN_DISCARD_DEPTHSTENCIL || ds->flags & WINED3D_TEXTURE_DISCARD))
699 wined3d_rendertarget_view_validate_location(dsv, WINED3D_LOCATION_DISCARDED);
702 if (TRACE_ON(fps))
704 DWORD time = GetTickCount();
705 ++swapchain->frames;
707 /* every 1.5 seconds */
708 if (time - swapchain->prev_time > 1500)
710 TRACE_(fps)("%p @ approx %.2ffps\n",
711 swapchain, 1000.0 * swapchain->frames / (time - swapchain->prev_time));
712 swapchain->prev_time = time;
713 swapchain->frames = 0;
717 wined3d_resource_release(&swapchain->front_buffer->resource);
718 for (i = 0; i < desc->backbuffer_count; ++i)
720 wined3d_resource_release(&swapchain->back_buffers[i]->resource);
723 InterlockedDecrement(&cs->pending_presents);
726 void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain,
727 const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
728 unsigned int swap_interval, DWORD flags)
730 struct wined3d_cs_present *op;
731 unsigned int i;
732 LONG pending;
734 op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
735 op->opcode = WINED3D_CS_OP_PRESENT;
736 op->dst_window_override = dst_window_override;
737 op->swapchain = swapchain;
738 op->src_rect = *src_rect;
739 op->dst_rect = *dst_rect;
740 op->swap_interval = swap_interval;
741 op->flags = flags;
743 pending = InterlockedIncrement(&cs->pending_presents);
745 wined3d_resource_acquire(&swapchain->front_buffer->resource);
746 for (i = 0; i < swapchain->state.desc.backbuffer_count; ++i)
748 wined3d_resource_acquire(&swapchain->back_buffers[i]->resource);
751 wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT);
753 /* Limit input latency by limiting the number of presents that we can get
754 * ahead of the worker thread. */
755 while (pending >= swapchain->max_frame_latency)
757 YieldProcessor();
758 pending = InterlockedCompareExchange(&cs->pending_presents, 0, 0);
762 static void wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
764 struct wined3d_device *device = cs->c.device;
765 const struct wined3d_cs_clear *op = data;
766 unsigned int i;
768 device->blitter->ops->blitter_clear(device->blitter, device, op->rt_count, &op->fb,
769 op->rect_count, op->rects, &op->draw_rect, op->flags, &op->color, op->depth, op->stencil);
771 if (op->flags & WINED3DCLEAR_TARGET)
773 for (i = 0; i < op->rt_count; ++i)
775 if (op->fb.render_targets[i])
776 wined3d_resource_release(op->fb.render_targets[i]->resource);
779 if (op->flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
780 wined3d_resource_release(op->fb.depth_stencil->resource);
783 void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects,
784 DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
786 const struct wined3d_state *state = cs->c.state;
787 const struct wined3d_viewport *vp = &state->viewports[0];
788 struct wined3d_rendertarget_view *view;
789 struct wined3d_cs_clear *op;
790 unsigned int rt_count, i;
792 rt_count = flags & WINED3DCLEAR_TARGET ? cs->c.device->adapter->d3d_info.limits.max_rt_count : 0;
794 op = wined3d_device_context_require_space(&cs->c, FIELD_OFFSET(struct wined3d_cs_clear, rects[rect_count]),
795 WINED3D_CS_QUEUE_DEFAULT);
796 op->opcode = WINED3D_CS_OP_CLEAR;
797 op->flags = flags & (WINED3DCLEAR_TARGET | WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
798 op->rt_count = rt_count;
799 op->fb = state->fb;
800 SetRect(&op->draw_rect, vp->x, vp->y, vp->x + vp->width, vp->y + vp->height);
801 if (state->rasterizer_state && state->rasterizer_state->desc.scissor)
802 IntersectRect(&op->draw_rect, &op->draw_rect, &state->scissor_rects[0]);
803 op->color = *color;
804 op->depth = depth;
805 op->stencil = stencil;
806 op->rect_count = rect_count;
807 memcpy(op->rects, rects, sizeof(*rects) * rect_count);
809 for (i = 0; i < rt_count; ++i)
811 if ((view = state->fb.render_targets[i]))
812 wined3d_resource_acquire(view->resource);
814 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
816 view = state->fb.depth_stencil;
817 wined3d_resource_acquire(view->resource);
820 wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT);
823 void wined3d_device_context_emit_clear_rendertarget_view(struct wined3d_device_context *context,
824 struct wined3d_rendertarget_view *view, const RECT *rect, unsigned int flags,
825 const struct wined3d_color *color, float depth, unsigned int stencil)
827 struct wined3d_cs_clear *op;
828 size_t size;
830 size = FIELD_OFFSET(struct wined3d_cs_clear, rects[1]);
831 op = wined3d_device_context_require_space(context, size, WINED3D_CS_QUEUE_DEFAULT);
833 op->opcode = WINED3D_CS_OP_CLEAR;
834 op->flags = flags & (WINED3DCLEAR_TARGET | WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
835 if (flags & WINED3DCLEAR_TARGET)
837 op->rt_count = 1;
838 op->fb.render_targets[0] = view;
839 op->fb.depth_stencil = NULL;
840 op->color = *color;
842 else
844 op->rt_count = 0;
845 op->fb.render_targets[0] = NULL;
846 op->fb.depth_stencil = view;
847 op->depth = depth;
848 op->stencil = stencil;
850 SetRect(&op->draw_rect, 0, 0, view->width, view->height);
851 op->rect_count = 1;
852 op->rects[0] = *rect;
854 wined3d_device_context_acquire_resource(context, view->resource);
856 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
857 if (flags & WINED3DCLEAR_SYNCHRONOUS)
858 wined3d_device_context_finish(context, WINED3D_CS_QUEUE_DEFAULT);
861 static void acquire_shader_resources(struct wined3d_device_context *context, unsigned int shader_mask)
863 const struct wined3d_state *state = context->state;
864 struct wined3d_shader_sampler_map_entry *entry;
865 struct wined3d_shader_resource_view *view;
866 struct wined3d_shader *shader;
867 unsigned int i, j;
869 for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
871 if (!(shader_mask & (1u << i)))
872 continue;
874 if (!(shader = state->shader[i]))
875 continue;
877 for (j = 0; j < WINED3D_MAX_CBS; ++j)
879 if (state->cb[i][j].buffer)
880 wined3d_device_context_acquire_resource(context, &state->cb[i][j].buffer->resource);
883 for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
885 entry = &shader->reg_maps.sampler_map.entries[j];
887 if (!(view = state->shader_resource_view[i][entry->resource_idx]))
888 continue;
890 wined3d_device_context_acquire_resource(context, view->resource);
895 static void release_shader_resources(const struct wined3d_state *state, unsigned int shader_mask)
897 struct wined3d_shader_sampler_map_entry *entry;
898 struct wined3d_shader_resource_view *view;
899 struct wined3d_shader *shader;
900 unsigned int i, j;
902 for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
904 if (!(shader_mask & (1u << i)))
905 continue;
907 if (!(shader = state->shader[i]))
908 continue;
910 for (j = 0; j < WINED3D_MAX_CBS; ++j)
912 if (state->cb[i][j].buffer)
913 wined3d_resource_release(&state->cb[i][j].buffer->resource);
916 for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
918 entry = &shader->reg_maps.sampler_map.entries[j];
920 if (!(view = state->shader_resource_view[i][entry->resource_idx]))
921 continue;
923 wined3d_resource_release(view->resource);
928 static void acquire_unordered_access_resources(struct wined3d_device_context *context,
929 const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
931 unsigned int i;
933 if (!shader)
934 return;
936 for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
938 if (!shader->reg_maps.uav_resource_info[i].type)
939 continue;
941 if (!views[i])
942 continue;
944 wined3d_device_context_acquire_resource(context, views[i]->resource);
948 static void release_unordered_access_resources(const struct wined3d_shader *shader,
949 struct wined3d_unordered_access_view * const *views)
951 unsigned int i;
953 if (!shader)
954 return;
956 for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
958 if (!shader->reg_maps.uav_resource_info[i].type)
959 continue;
961 if (!views[i])
962 continue;
964 wined3d_resource_release(views[i]->resource);
968 static void wined3d_cs_exec_dispatch(struct wined3d_cs *cs, const void *data)
970 const struct wined3d_cs_dispatch *op = data;
971 struct wined3d_state *state = &cs->state;
973 if (!state->shader[WINED3D_SHADER_TYPE_COMPUTE])
974 WARN("No compute shader bound, skipping dispatch.\n");
975 else
976 cs->c.device->adapter->adapter_ops->adapter_dispatch_compute(cs->c.device, state, &op->parameters);
978 if (op->parameters.indirect)
979 wined3d_resource_release(&op->parameters.u.indirect.buffer->resource);
981 release_shader_resources(state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
982 release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_COMPUTE],
983 state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
986 static void acquire_compute_pipeline_resources(struct wined3d_device_context *context)
988 const struct wined3d_state *state = context->state;
990 acquire_shader_resources(context, 1u << WINED3D_SHADER_TYPE_COMPUTE);
991 acquire_unordered_access_resources(context, state->shader[WINED3D_SHADER_TYPE_COMPUTE],
992 state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
995 void CDECL wined3d_device_context_dispatch(struct wined3d_device_context *context,
996 unsigned int group_count_x, unsigned int group_count_y, unsigned int group_count_z)
998 struct wined3d_cs_dispatch *op;
1000 wined3d_device_context_lock(context);
1001 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1002 op->opcode = WINED3D_CS_OP_DISPATCH;
1003 op->parameters.indirect = FALSE;
1004 op->parameters.u.direct.group_count_x = group_count_x;
1005 op->parameters.u.direct.group_count_y = group_count_y;
1006 op->parameters.u.direct.group_count_z = group_count_z;
1008 acquire_compute_pipeline_resources(context);
1010 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1011 wined3d_device_context_unlock(context);
1014 void CDECL wined3d_device_context_dispatch_indirect(struct wined3d_device_context *context,
1015 struct wined3d_buffer *buffer, unsigned int offset)
1017 struct wined3d_cs_dispatch *op;
1019 wined3d_device_context_lock(context);
1020 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1021 op->opcode = WINED3D_CS_OP_DISPATCH;
1022 op->parameters.indirect = TRUE;
1023 op->parameters.u.indirect.buffer = buffer;
1024 op->parameters.u.indirect.offset = offset;
1026 acquire_compute_pipeline_resources(context);
1027 wined3d_device_context_acquire_resource(context, &buffer->resource);
1029 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1030 wined3d_device_context_unlock(context);
1033 static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
1035 const struct wined3d_d3d_info *d3d_info = &cs->c.device->adapter->d3d_info;
1036 const struct wined3d_shader *geometry_shader;
1037 struct wined3d_device *device = cs->c.device;
1038 int base_vertex_idx, load_base_vertex_idx;
1039 struct wined3d_state *state = &cs->state;
1040 const struct wined3d_cs_draw *op = data;
1041 unsigned int i;
1043 base_vertex_idx = 0;
1044 if (!op->parameters.indirect)
1046 const struct wined3d_direct_draw_parameters *direct = &op->parameters.u.direct;
1048 if (op->parameters.indexed && d3d_info->draw_base_vertex_offset)
1049 base_vertex_idx = direct->base_vertex_idx;
1050 else if (!op->parameters.indexed)
1051 base_vertex_idx = direct->start_idx;
1054 /* ARB_draw_indirect always supports a base vertex offset. */
1055 if (!op->parameters.indirect && !d3d_info->draw_base_vertex_offset)
1056 load_base_vertex_idx = op->parameters.u.direct.base_vertex_idx;
1057 else
1058 load_base_vertex_idx = 0;
1060 if (state->base_vertex_index != base_vertex_idx)
1062 state->base_vertex_index = base_vertex_idx;
1063 for (i = 0; i < device->context_count; ++i)
1064 device->contexts[i]->constant_update_mask |= WINED3D_SHADER_CONST_BASE_VERTEX_ID;
1067 if (state->load_base_vertex_index != load_base_vertex_idx)
1069 state->load_base_vertex_index = load_base_vertex_idx;
1070 device_invalidate_state(cs->c.device, STATE_BASEVERTEXINDEX);
1073 if (state->primitive_type != op->primitive_type)
1075 if ((geometry_shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY]) && !geometry_shader->function)
1076 device_invalidate_state(cs->c.device, STATE_SHADER(WINED3D_SHADER_TYPE_GEOMETRY));
1077 if (state->primitive_type == WINED3D_PT_POINTLIST || op->primitive_type == WINED3D_PT_POINTLIST)
1078 device_invalidate_state(cs->c.device, STATE_POINT_ENABLE);
1079 state->primitive_type = op->primitive_type;
1081 state->patch_vertex_count = op->patch_vertex_count;
1083 cs->c.device->adapter->adapter_ops->adapter_draw_primitive(cs->c.device, state, &op->parameters);
1085 if (op->parameters.indirect)
1087 struct wined3d_buffer *buffer = op->parameters.u.indirect.buffer;
1088 wined3d_resource_release(&buffer->resource);
1091 if (op->parameters.indexed)
1092 wined3d_resource_release(&state->index_buffer->resource);
1093 for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
1095 if (state->streams[i].buffer)
1096 wined3d_resource_release(&state->streams[i].buffer->resource);
1098 for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
1100 if (state->stream_output[i].buffer)
1101 wined3d_resource_release(&state->stream_output[i].buffer->resource);
1103 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
1105 if (state->textures[i])
1106 wined3d_resource_release(&state->textures[i]->resource);
1108 for (i = 0; i < d3d_info->limits.max_rt_count; ++i)
1110 if (state->fb.render_targets[i])
1111 wined3d_resource_release(state->fb.render_targets[i]->resource);
1113 if (state->fb.depth_stencil)
1114 wined3d_resource_release(state->fb.depth_stencil->resource);
1115 release_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
1116 release_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL],
1117 state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
1120 static void acquire_graphics_pipeline_resources(struct wined3d_device_context *context,
1121 BOOL indexed, const struct wined3d_d3d_info *d3d_info)
1123 const struct wined3d_state *state = context->state;
1124 unsigned int i;
1126 if (indexed)
1127 wined3d_device_context_acquire_resource(context, &state->index_buffer->resource);
1128 for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
1130 if (state->streams[i].buffer)
1131 wined3d_device_context_acquire_resource(context, &state->streams[i].buffer->resource);
1133 for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
1135 if (state->stream_output[i].buffer)
1136 wined3d_device_context_acquire_resource(context, &state->stream_output[i].buffer->resource);
1138 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
1140 if (state->textures[i])
1141 wined3d_device_context_acquire_resource(context, &state->textures[i]->resource);
1143 for (i = 0; i < d3d_info->limits.max_rt_count; ++i)
1145 if (state->fb.render_targets[i])
1146 wined3d_device_context_acquire_resource(context, state->fb.render_targets[i]->resource);
1148 if (state->fb.depth_stencil)
1149 wined3d_device_context_acquire_resource(context, state->fb.depth_stencil->resource);
1150 acquire_shader_resources(context, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
1151 acquire_unordered_access_resources(context, state->shader[WINED3D_SHADER_TYPE_PIXEL],
1152 state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
1155 void wined3d_device_context_emit_draw(struct wined3d_device_context *context,
1156 enum wined3d_primitive_type primitive_type, unsigned int patch_vertex_count, int base_vertex_idx,
1157 unsigned int start_idx, unsigned int index_count, unsigned int start_instance, unsigned int instance_count,
1158 bool indexed)
1160 const struct wined3d_d3d_info *d3d_info = &context->device->adapter->d3d_info;
1161 struct wined3d_cs_draw *op;
1163 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1164 op->opcode = WINED3D_CS_OP_DRAW;
1165 op->primitive_type = primitive_type;
1166 op->patch_vertex_count = patch_vertex_count;
1167 op->parameters.indirect = FALSE;
1168 op->parameters.u.direct.base_vertex_idx = base_vertex_idx;
1169 op->parameters.u.direct.start_idx = start_idx;
1170 op->parameters.u.direct.index_count = index_count;
1171 op->parameters.u.direct.start_instance = start_instance;
1172 op->parameters.u.direct.instance_count = instance_count;
1173 op->parameters.indexed = indexed;
1175 acquire_graphics_pipeline_resources(context, indexed, d3d_info);
1177 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1180 void CDECL wined3d_device_context_draw_indirect(struct wined3d_device_context *context,
1181 struct wined3d_buffer *buffer, unsigned int offset, bool indexed)
1183 const struct wined3d_d3d_info *d3d_info = &context->device->adapter->d3d_info;
1184 const struct wined3d_state *state = context->state;
1185 struct wined3d_cs_draw *op;
1187 wined3d_device_context_lock(context);
1188 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1189 op->opcode = WINED3D_CS_OP_DRAW;
1190 op->primitive_type = state->primitive_type;
1191 op->patch_vertex_count = state->patch_vertex_count;
1192 op->parameters.indirect = TRUE;
1193 op->parameters.u.indirect.buffer = buffer;
1194 op->parameters.u.indirect.offset = offset;
1195 op->parameters.indexed = indexed;
1197 acquire_graphics_pipeline_resources(context, indexed, d3d_info);
1198 wined3d_device_context_acquire_resource(context, &buffer->resource);
1200 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1201 wined3d_device_context_unlock(context);
1204 static void wined3d_cs_exec_flush(struct wined3d_cs *cs, const void *data)
1206 struct wined3d_context *context;
1208 context = context_acquire(cs->c.device, NULL, 0);
1209 cs->c.device->adapter->adapter_ops->adapter_flush_context(context);
1210 context_release(context);
1213 static void wined3d_cs_flush(struct wined3d_device_context *context)
1215 struct wined3d_cs *cs = wined3d_cs_from_context(context);
1216 struct wined3d_cs_flush *op;
1218 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1219 op->opcode = WINED3D_CS_OP_FLUSH;
1221 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1222 cs->queries_flushed = TRUE;
1225 static void wined3d_cs_exec_set_predication(struct wined3d_cs *cs, const void *data)
1227 const struct wined3d_cs_set_predication *op = data;
1229 cs->state.predicate = op->predicate;
1230 cs->state.predicate_value = op->value;
1233 void wined3d_device_context_emit_set_predication(struct wined3d_device_context *context,
1234 struct wined3d_query *predicate, BOOL value)
1236 struct wined3d_cs_set_predication *op;
1238 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1239 op->opcode = WINED3D_CS_OP_SET_PREDICATION;
1240 op->predicate = predicate;
1241 op->value = value;
1243 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1246 static void wined3d_cs_exec_set_viewports(struct wined3d_cs *cs, const void *data)
1248 const struct wined3d_cs_set_viewports *op = data;
1250 if (op->viewport_count)
1251 memcpy(cs->state.viewports, op->viewports, op->viewport_count * sizeof(*op->viewports));
1252 else
1253 memset(cs->state.viewports, 0, sizeof(*cs->state.viewports));
1254 cs->state.viewport_count = op->viewport_count;
1255 device_invalidate_state(cs->c.device, STATE_VIEWPORT);
1258 void wined3d_device_context_emit_set_viewports(struct wined3d_device_context *context, unsigned int viewport_count,
1259 const struct wined3d_viewport *viewports)
1261 struct wined3d_cs_set_viewports *op;
1263 op = wined3d_device_context_require_space(context,
1264 FIELD_OFFSET(struct wined3d_cs_set_viewports,viewports[viewport_count]), WINED3D_CS_QUEUE_DEFAULT);
1265 op->opcode = WINED3D_CS_OP_SET_VIEWPORTS;
1266 memcpy(op->viewports, viewports, viewport_count * sizeof(*viewports));
1267 op->viewport_count = viewport_count;
1269 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1272 static void wined3d_cs_exec_set_scissor_rects(struct wined3d_cs *cs, const void *data)
1274 const struct wined3d_cs_set_scissor_rects *op = data;
1276 if (op->rect_count)
1277 memcpy(cs->state.scissor_rects, op->rects, op->rect_count * sizeof(*op->rects));
1278 else
1279 SetRectEmpty(cs->state.scissor_rects);
1280 cs->state.scissor_rect_count = op->rect_count;
1281 device_invalidate_state(cs->c.device, STATE_SCISSORRECT);
1284 void wined3d_device_context_emit_set_scissor_rects(struct wined3d_device_context *context,
1285 unsigned int rect_count, const RECT *rects)
1287 struct wined3d_cs_set_scissor_rects *op;
1289 op = wined3d_device_context_require_space(context, FIELD_OFFSET(struct wined3d_cs_set_scissor_rects, rects[rect_count]),
1290 WINED3D_CS_QUEUE_DEFAULT);
1291 op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECTS;
1292 memcpy(op->rects, rects, rect_count * sizeof(*rects));
1293 op->rect_count = rect_count;
1295 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1298 static void wined3d_cs_exec_set_rendertarget_views(struct wined3d_cs *cs, const void *data)
1300 const struct wined3d_cs_set_rendertarget_views *op = data;
1301 struct wined3d_device *device = cs->c.device;
1302 unsigned int i;
1304 for (i = 0; i < op->count; ++i)
1306 struct wined3d_rendertarget_view *prev = cs->state.fb.render_targets[op->start_idx + i];
1307 struct wined3d_rendertarget_view *view = op->views[i];
1308 bool prev_alpha_swizzle, curr_alpha_swizzle;
1309 bool prev_srgb_write, curr_srgb_write;
1311 cs->state.fb.render_targets[op->start_idx + i] = view;
1313 prev_alpha_swizzle = prev && prev->format->id == WINED3DFMT_A8_UNORM;
1314 curr_alpha_swizzle = view && view->format->id == WINED3DFMT_A8_UNORM;
1315 if (prev_alpha_swizzle != curr_alpha_swizzle)
1316 device_invalidate_state(device, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
1318 if (!(device->adapter->d3d_info.wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
1319 || cs->state.render_states[WINED3D_RS_SRGBWRITEENABLE])
1321 prev_srgb_write = prev && prev->format_flags & WINED3DFMT_FLAG_SRGB_WRITE;
1322 curr_srgb_write = view && view->format_flags & WINED3DFMT_FLAG_SRGB_WRITE;
1323 if (prev_srgb_write != curr_srgb_write)
1324 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
1328 device_invalidate_state(device, STATE_FRAMEBUFFER);
1331 void wined3d_device_context_emit_set_rendertarget_views(struct wined3d_device_context *context,
1332 unsigned int start_idx, unsigned int count, struct wined3d_rendertarget_view *const *views)
1334 struct wined3d_cs_set_rendertarget_views *op;
1336 op = wined3d_device_context_require_space(context,
1337 offsetof(struct wined3d_cs_set_rendertarget_views, views[count]), WINED3D_CS_QUEUE_DEFAULT);
1338 op->opcode = WINED3D_CS_OP_SET_RENDERTARGET_VIEWS;
1339 op->start_idx = start_idx;
1340 op->count = count;
1341 memcpy(op->views, views, count * sizeof(*views));
1343 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1346 static void wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const void *data)
1348 const struct wined3d_cs_set_depth_stencil_view *op = data;
1349 struct wined3d_device *device = cs->c.device;
1350 struct wined3d_rendertarget_view *prev;
1352 if ((prev = cs->state.fb.depth_stencil) && prev->resource->type != WINED3D_RTYPE_BUFFER)
1354 struct wined3d_texture *prev_texture = texture_from_resource(prev->resource);
1356 if (device->swapchains[0]->state.desc.flags & WINED3D_SWAPCHAIN_DISCARD_DEPTHSTENCIL
1357 || prev_texture->flags & WINED3D_TEXTURE_DISCARD)
1358 wined3d_texture_validate_location(prev_texture,
1359 prev->sub_resource_idx, WINED3D_LOCATION_DISCARDED);
1362 cs->state.fb.depth_stencil = op->view;
1364 if (!prev != !op->view)
1366 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
1367 device_invalidate_state(device, STATE_DEPTH_STENCIL);
1368 device_invalidate_state(device, STATE_STENCIL_REF);
1369 device_invalidate_state(device, STATE_RASTERIZER);
1371 else if (prev)
1373 if (prev->format->depth_bias_scale != op->view->format->depth_bias_scale)
1374 device_invalidate_state(device, STATE_RASTERIZER);
1375 if (prev->format->stencil_size != op->view->format->stencil_size)
1376 device_invalidate_state(device, STATE_STENCIL_REF);
1379 device_invalidate_state(device, STATE_FRAMEBUFFER);
1382 void wined3d_device_context_emit_set_depth_stencil_view(struct wined3d_device_context *context,
1383 struct wined3d_rendertarget_view *view)
1385 struct wined3d_cs_set_depth_stencil_view *op;
1387 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1388 op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW;
1389 op->view = view;
1391 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1394 static void wined3d_cs_exec_set_vertex_declaration(struct wined3d_cs *cs, const void *data)
1396 const struct wined3d_cs_set_vertex_declaration *op = data;
1398 cs->state.vertex_declaration = op->declaration;
1399 device_invalidate_state(cs->c.device, STATE_VDECL);
1402 void wined3d_device_context_emit_set_vertex_declaration(struct wined3d_device_context *context,
1403 struct wined3d_vertex_declaration *declaration)
1405 struct wined3d_cs_set_vertex_declaration *op;
1407 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1408 op->opcode = WINED3D_CS_OP_SET_VERTEX_DECLARATION;
1409 op->declaration = declaration;
1411 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1414 static void wined3d_cs_exec_set_stream_sources(struct wined3d_cs *cs, const void *data)
1416 const struct wined3d_cs_set_stream_sources *op = data;
1417 unsigned int i;
1419 for (i = 0; i < op->count; ++i)
1421 struct wined3d_buffer *prev = cs->state.streams[op->start_idx + i].buffer;
1422 struct wined3d_buffer *buffer = op->streams[i].buffer;
1424 if (buffer)
1425 InterlockedIncrement(&buffer->resource.bind_count);
1426 if (prev)
1427 InterlockedDecrement(&prev->resource.bind_count);
1430 memcpy(&cs->state.streams[op->start_idx], op->streams, op->count * sizeof(*op->streams));
1431 device_invalidate_state(cs->c.device, STATE_STREAMSRC);
1434 void wined3d_device_context_emit_set_stream_sources(struct wined3d_device_context *context,
1435 unsigned int start_idx, unsigned int count, const struct wined3d_stream_state *streams)
1437 struct wined3d_cs_set_stream_sources *op;
1439 op = wined3d_device_context_require_space(context,
1440 offsetof(struct wined3d_cs_set_stream_sources, streams[count]), WINED3D_CS_QUEUE_DEFAULT);
1441 op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCES;
1442 op->start_idx = start_idx;
1443 op->count = count;
1444 memcpy(op->streams, streams, count * sizeof(*streams));
1446 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1449 static void wined3d_cs_exec_set_stream_outputs(struct wined3d_cs *cs, const void *data)
1451 const struct wined3d_cs_set_stream_outputs *op = data;
1452 unsigned int i;
1454 for (i = 0; i < WINED3D_MAX_STREAM_OUTPUT_BUFFERS; ++i)
1456 struct wined3d_buffer *prev = cs->state.stream_output[i].buffer;
1457 struct wined3d_buffer *buffer = op->outputs[i].buffer;
1459 if (buffer)
1460 InterlockedIncrement(&buffer->resource.bind_count);
1461 if (prev)
1462 InterlockedDecrement(&prev->resource.bind_count);
1465 memcpy(cs->state.stream_output, op->outputs, sizeof(op->outputs));
1466 device_invalidate_state(cs->c.device, STATE_STREAM_OUTPUT);
1469 void wined3d_device_context_emit_set_stream_outputs(struct wined3d_device_context *context,
1470 const struct wined3d_stream_output outputs[WINED3D_MAX_STREAM_OUTPUT_BUFFERS])
1472 struct wined3d_cs_set_stream_outputs *op;
1474 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1475 op->opcode = WINED3D_CS_OP_SET_STREAM_OUTPUTS;
1476 memcpy(op->outputs, outputs, sizeof(op->outputs));
1478 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1481 static void wined3d_cs_exec_set_index_buffer(struct wined3d_cs *cs, const void *data)
1483 const struct wined3d_cs_set_index_buffer *op = data;
1484 struct wined3d_buffer *prev;
1486 prev = cs->state.index_buffer;
1487 cs->state.index_buffer = op->buffer;
1488 cs->state.index_format = op->format_id;
1489 cs->state.index_offset = op->offset;
1491 if (op->buffer)
1492 InterlockedIncrement(&op->buffer->resource.bind_count);
1493 if (prev)
1494 InterlockedDecrement(&prev->resource.bind_count);
1496 device_invalidate_state(cs->c.device, STATE_INDEXBUFFER);
1499 void wined3d_device_context_emit_set_index_buffer(struct wined3d_device_context *context, struct wined3d_buffer *buffer,
1500 enum wined3d_format_id format_id, unsigned int offset)
1502 struct wined3d_cs_set_index_buffer *op;
1504 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1505 op->opcode = WINED3D_CS_OP_SET_INDEX_BUFFER;
1506 op->buffer = buffer;
1507 op->format_id = format_id;
1508 op->offset = offset;
1510 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1513 static void wined3d_cs_exec_set_constant_buffers(struct wined3d_cs *cs, const void *data)
1515 const struct wined3d_cs_set_constant_buffers *op = data;
1516 unsigned int i;
1518 for (i = 0; i < op->count; ++i)
1520 struct wined3d_buffer *prev = cs->state.cb[op->type][op->start_idx + i].buffer;
1521 struct wined3d_buffer *buffer = op->buffers[i].buffer;
1523 cs->state.cb[op->type][op->start_idx + i] = op->buffers[i];
1525 if (buffer)
1526 InterlockedIncrement(&buffer->resource.bind_count);
1527 if (prev)
1528 InterlockedDecrement(&prev->resource.bind_count);
1531 device_invalidate_state(cs->c.device, STATE_CONSTANT_BUFFER(op->type));
1534 void wined3d_device_context_emit_set_constant_buffers(struct wined3d_device_context *context,
1535 enum wined3d_shader_type type, unsigned int start_idx, unsigned int count,
1536 const struct wined3d_constant_buffer_state *buffers)
1538 struct wined3d_cs_set_constant_buffers *op;
1540 op = wined3d_device_context_require_space(context, offsetof(struct wined3d_cs_set_constant_buffers, buffers[count]),
1541 WINED3D_CS_QUEUE_DEFAULT);
1542 op->opcode = WINED3D_CS_OP_SET_CONSTANT_BUFFERS;
1543 op->type = type;
1544 op->start_idx = start_idx;
1545 op->count = count;
1546 memcpy(op->buffers, buffers, count * sizeof(*buffers));
1548 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1551 static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data)
1553 const struct wined3d_d3d_info *d3d_info = &cs->c.device->adapter->d3d_info;
1554 const struct wined3d_cs_set_texture *op = data;
1555 struct wined3d_texture *prev;
1556 BOOL old_use_color_key = FALSE, new_use_color_key = FALSE;
1558 prev = cs->state.textures[op->stage];
1559 cs->state.textures[op->stage] = op->texture;
1561 if (op->texture)
1563 const struct wined3d_format *new_format = op->texture->resource.format;
1564 const struct wined3d_format *old_format = prev ? prev->resource.format : NULL;
1565 unsigned int old_fmt_flags = prev ? prev->resource.format_flags : 0;
1566 unsigned int new_fmt_flags = op->texture->resource.format_flags;
1568 if (InterlockedIncrement(&op->texture->resource.bind_count) == 1)
1569 op->texture->sampler = op->stage;
1571 if (!prev || wined3d_texture_gl(op->texture)->target != wined3d_texture_gl(prev)->target
1572 || (!is_same_fixup(new_format->color_fixup, old_format->color_fixup)
1573 && !(can_use_texture_swizzle(d3d_info, new_format) && can_use_texture_swizzle(d3d_info, old_format)))
1574 || (new_fmt_flags & WINED3DFMT_FLAG_SHADOW) != (old_fmt_flags & WINED3DFMT_FLAG_SHADOW))
1575 device_invalidate_state(cs->c.device, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
1577 if (!prev && op->stage < d3d_info->limits.ffp_blend_stages)
1579 /* The source arguments for color and alpha ops have different
1580 * meanings when a NULL texture is bound, so the COLOR_OP and
1581 * ALPHA_OP have to be dirtified. */
1582 device_invalidate_state(cs->c.device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1583 device_invalidate_state(cs->c.device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1586 if (!op->stage && op->texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1587 new_use_color_key = TRUE;
1590 if (prev)
1592 if (InterlockedDecrement(&prev->resource.bind_count) && prev->sampler == op->stage)
1594 unsigned int i;
1596 /* Search for other stages the texture is bound to. Shouldn't
1597 * happen if applications bind textures to a single stage only. */
1598 TRACE("Searching for other stages the texture is bound to.\n");
1599 for (i = 0; i < WINED3D_MAX_COMBINED_SAMPLERS; ++i)
1601 if (cs->state.textures[i] == prev)
1603 TRACE("Texture is also bound to stage %u.\n", i);
1604 prev->sampler = i;
1605 break;
1610 if (!op->texture && op->stage < d3d_info->limits.ffp_blend_stages)
1612 device_invalidate_state(cs->c.device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
1613 device_invalidate_state(cs->c.device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
1616 if (!op->stage && prev->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
1617 old_use_color_key = TRUE;
1620 device_invalidate_state(cs->c.device, STATE_SAMPLER(op->stage));
1622 if (new_use_color_key != old_use_color_key)
1623 device_invalidate_state(cs->c.device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
1625 if (new_use_color_key)
1626 device_invalidate_state(cs->c.device, STATE_COLOR_KEY);
1629 void wined3d_device_context_emit_set_texture(struct wined3d_device_context *context, unsigned int stage,
1630 struct wined3d_texture *texture)
1632 struct wined3d_cs_set_texture *op;
1634 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1635 op->opcode = WINED3D_CS_OP_SET_TEXTURE;
1636 op->stage = stage;
1637 op->texture = texture;
1639 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1642 static void wined3d_cs_exec_set_shader_resource_views(struct wined3d_cs *cs, const void *data)
1644 const struct wined3d_cs_set_shader_resource_views *op = data;
1645 unsigned int i;
1647 for (i = 0; i < op->count; ++i)
1649 struct wined3d_shader_resource_view *prev = cs->state.shader_resource_view[op->type][op->start_idx + i];
1650 struct wined3d_shader_resource_view *view = op->views[i];
1652 cs->state.shader_resource_view[op->type][op->start_idx + i] = view;
1654 if (view)
1655 InterlockedIncrement(&view->resource->bind_count);
1656 if (prev)
1657 InterlockedDecrement(&prev->resource->bind_count);
1660 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1661 device_invalidate_state(cs->c.device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1662 else
1663 device_invalidate_state(cs->c.device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1666 void wined3d_device_context_emit_set_shader_resource_views(struct wined3d_device_context *context,
1667 enum wined3d_shader_type type, unsigned int start_idx, unsigned int count,
1668 struct wined3d_shader_resource_view *const *views)
1670 struct wined3d_cs_set_shader_resource_views *op;
1672 op = wined3d_device_context_require_space(context,
1673 offsetof(struct wined3d_cs_set_shader_resource_views, views[count]), WINED3D_CS_QUEUE_DEFAULT);
1674 op->opcode = WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEWS;
1675 op->type = type;
1676 op->start_idx = start_idx;
1677 op->count = count;
1678 memcpy(op->views, views, count * sizeof(*views));
1680 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1683 static void wined3d_cs_exec_set_unordered_access_views(struct wined3d_cs *cs, const void *data)
1685 const struct wined3d_cs_set_unordered_access_views *op = data;
1686 unsigned int i;
1688 for (i = 0; i < op->count; ++i)
1690 struct wined3d_unordered_access_view *prev = cs->state.unordered_access_view[op->pipeline][op->start_idx + i];
1691 struct wined3d_unordered_access_view *view = op->uavs[i].view;
1692 unsigned int initial_count = op->uavs[i].initial_count;
1694 cs->state.unordered_access_view[op->pipeline][op->start_idx + i] = view;
1696 if (view)
1697 InterlockedIncrement(&view->resource->bind_count);
1698 if (prev)
1699 InterlockedDecrement(&prev->resource->bind_count);
1701 if (view && initial_count != ~0u)
1702 wined3d_unordered_access_view_set_counter(view, initial_count);
1705 device_invalidate_state(cs->c.device, STATE_UNORDERED_ACCESS_VIEW_BINDING(op->pipeline));
1708 void wined3d_device_context_emit_set_unordered_access_views(struct wined3d_device_context *context,
1709 enum wined3d_pipeline pipeline, unsigned int start_idx, unsigned int count,
1710 struct wined3d_unordered_access_view *const *views, const unsigned int *initial_counts)
1712 struct wined3d_cs_set_unordered_access_views *op;
1713 unsigned int i;
1715 op = wined3d_device_context_require_space(context,
1716 offsetof(struct wined3d_cs_set_unordered_access_views, uavs[count]), WINED3D_CS_QUEUE_DEFAULT);
1717 op->opcode = WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEWS;
1718 op->pipeline = pipeline;
1719 op->start_idx = start_idx;
1720 op->count = count;
1721 for (i = 0; i < count; ++i)
1723 op->uavs[i].view = views[i];
1724 op->uavs[i].initial_count = initial_counts ? initial_counts[i] : ~0u;
1727 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1730 static void wined3d_cs_exec_set_samplers(struct wined3d_cs *cs, const void *data)
1732 const struct wined3d_cs_set_samplers *op = data;
1733 unsigned int i;
1735 for (i = 0; i < op->count; ++i)
1736 cs->state.sampler[op->type][op->start_idx + i] = op->samplers[i];
1738 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1739 device_invalidate_state(cs->c.device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1740 else
1741 device_invalidate_state(cs->c.device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1744 void wined3d_device_context_emit_set_samplers(struct wined3d_device_context *context, enum wined3d_shader_type type,
1745 unsigned int start_idx, unsigned int count, struct wined3d_sampler *const *samplers)
1747 struct wined3d_cs_set_samplers *op;
1749 op = wined3d_device_context_require_space(context, offsetof(struct wined3d_cs_set_samplers, samplers[count]),
1750 WINED3D_CS_QUEUE_DEFAULT);
1751 op->opcode = WINED3D_CS_OP_SET_SAMPLERS;
1752 op->type = type;
1753 op->start_idx = start_idx;
1754 op->count = count;
1755 memcpy(op->samplers, samplers, count * sizeof(*samplers));
1757 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1760 static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
1762 const struct wined3d_cs_set_shader *op = data;
1764 /* CB binding may have been skipped earlier if the shader wasn't set, so make it happen. */
1765 if (!cs->state.shader[op->type] && op->shader)
1766 device_invalidate_state(cs->c.device, STATE_CONSTANT_BUFFER(op->type));
1767 cs->state.shader[op->type] = op->shader;
1768 device_invalidate_state(cs->c.device, STATE_SHADER(op->type));
1769 if (op->type != WINED3D_SHADER_TYPE_COMPUTE)
1770 device_invalidate_state(cs->c.device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
1771 else
1772 device_invalidate_state(cs->c.device, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
1775 void wined3d_device_context_emit_set_shader(struct wined3d_device_context *context,
1776 enum wined3d_shader_type type, struct wined3d_shader *shader)
1778 struct wined3d_cs_set_shader *op;
1780 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1781 op->opcode = WINED3D_CS_OP_SET_SHADER;
1782 op->type = type;
1783 op->shader = shader;
1785 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1788 static void wined3d_cs_exec_set_blend_state(struct wined3d_cs *cs, const void *data)
1790 const struct wined3d_cs_set_blend_state *op = data;
1791 struct wined3d_state *state = &cs->state;
1793 if (state->blend_state != op->state)
1795 state->blend_state = op->state;
1796 device_invalidate_state(cs->c.device, STATE_BLEND);
1798 state->blend_factor = op->factor;
1799 device_invalidate_state(cs->c.device, STATE_BLEND_FACTOR);
1800 state->sample_mask = op->sample_mask;
1801 device_invalidate_state(cs->c.device, STATE_SAMPLE_MASK);
1804 void wined3d_device_context_emit_set_blend_state(struct wined3d_device_context *context,
1805 struct wined3d_blend_state *state, const struct wined3d_color *blend_factor, unsigned int sample_mask)
1807 struct wined3d_cs_set_blend_state *op;
1809 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1810 op->opcode = WINED3D_CS_OP_SET_BLEND_STATE;
1811 op->state = state;
1812 op->factor = *blend_factor;
1813 op->sample_mask = sample_mask;
1815 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1818 static void wined3d_cs_exec_set_depth_stencil_state(struct wined3d_cs *cs, const void *data)
1820 const struct wined3d_cs_set_depth_stencil_state *op = data;
1821 struct wined3d_state *state = &cs->state;
1823 if (state->depth_stencil_state != op->state)
1825 state->depth_stencil_state = op->state;
1826 device_invalidate_state(cs->c.device, STATE_DEPTH_STENCIL);
1828 state->stencil_ref = op->stencil_ref;
1829 device_invalidate_state(cs->c.device, STATE_STENCIL_REF);
1832 void wined3d_device_context_emit_set_depth_stencil_state(struct wined3d_device_context *context,
1833 struct wined3d_depth_stencil_state *state, unsigned int stencil_ref)
1835 struct wined3d_cs_set_depth_stencil_state *op;
1837 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1838 op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE;
1839 op->state = state;
1840 op->stencil_ref = stencil_ref;
1842 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1845 static void wined3d_cs_exec_set_rasterizer_state(struct wined3d_cs *cs, const void *data)
1847 const struct wined3d_cs_set_rasterizer_state *op = data;
1849 cs->state.rasterizer_state = op->state;
1850 device_invalidate_state(cs->c.device, STATE_RASTERIZER);
1853 void wined3d_device_context_emit_set_rasterizer_state(struct wined3d_device_context *context,
1854 struct wined3d_rasterizer_state *rasterizer_state)
1856 struct wined3d_cs_set_rasterizer_state *op;
1858 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1859 op->opcode = WINED3D_CS_OP_SET_RASTERIZER_STATE;
1860 op->state = rasterizer_state;
1862 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1865 static void wined3d_cs_exec_set_render_state(struct wined3d_cs *cs, const void *data)
1867 const struct wined3d_cs_set_render_state *op = data;
1869 cs->state.render_states[op->state] = op->value;
1870 device_invalidate_state(cs->c.device, STATE_RENDER(op->state));
1873 void wined3d_device_context_emit_set_render_state(struct wined3d_device_context *context,
1874 enum wined3d_render_state state, unsigned int value)
1876 struct wined3d_cs_set_render_state *op;
1878 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1879 op->opcode = WINED3D_CS_OP_SET_RENDER_STATE;
1880 op->state = state;
1881 op->value = value;
1883 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1886 static void wined3d_cs_exec_set_texture_state(struct wined3d_cs *cs, const void *data)
1888 const struct wined3d_cs_set_texture_state *op = data;
1890 cs->state.texture_states[op->stage][op->state] = op->value;
1891 device_invalidate_state(cs->c.device, STATE_TEXTURESTAGE(op->stage, op->state));
1894 void wined3d_device_context_emit_set_texture_state(struct wined3d_device_context *context, unsigned int stage,
1895 enum wined3d_texture_stage_state state, unsigned int value)
1897 struct wined3d_cs_set_texture_state *op;
1899 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1900 op->opcode = WINED3D_CS_OP_SET_TEXTURE_STATE;
1901 op->stage = stage;
1902 op->state = state;
1903 op->value = value;
1905 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1908 static void wined3d_cs_exec_set_sampler_state(struct wined3d_cs *cs, const void *data)
1910 const struct wined3d_cs_set_sampler_state *op = data;
1912 cs->state.sampler_states[op->sampler_idx][op->state] = op->value;
1913 device_invalidate_state(cs->c.device, STATE_SAMPLER(op->sampler_idx));
1916 void wined3d_device_context_emit_set_sampler_state(struct wined3d_device_context *context, unsigned int sampler_idx,
1917 enum wined3d_sampler_state state, unsigned int value)
1919 struct wined3d_cs_set_sampler_state *op;
1921 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1922 op->opcode = WINED3D_CS_OP_SET_SAMPLER_STATE;
1923 op->sampler_idx = sampler_idx;
1924 op->state = state;
1925 op->value = value;
1927 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1930 static void wined3d_cs_exec_set_transform(struct wined3d_cs *cs, const void *data)
1932 const struct wined3d_cs_set_transform *op = data;
1934 cs->state.transforms[op->state] = op->matrix;
1935 if (op->state < WINED3D_TS_WORLD_MATRIX(cs->c.device->adapter->d3d_info.limits.ffp_vertex_blend_matrices))
1936 device_invalidate_state(cs->c.device, STATE_TRANSFORM(op->state));
1939 void wined3d_device_context_emit_set_transform(struct wined3d_device_context *context,
1940 enum wined3d_transform_state state, const struct wined3d_matrix *matrix)
1942 struct wined3d_cs_set_transform *op;
1944 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1945 op->opcode = WINED3D_CS_OP_SET_TRANSFORM;
1946 op->state = state;
1947 op->matrix = *matrix;
1949 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1952 static void wined3d_cs_exec_set_clip_plane(struct wined3d_cs *cs, const void *data)
1954 const struct wined3d_cs_set_clip_plane *op = data;
1956 cs->state.clip_planes[op->plane_idx] = op->plane;
1957 device_invalidate_state(cs->c.device, STATE_CLIPPLANE(op->plane_idx));
1960 void wined3d_device_context_emit_set_clip_plane(struct wined3d_device_context *context,
1961 unsigned int plane_idx, const struct wined3d_vec4 *plane)
1963 struct wined3d_cs_set_clip_plane *op;
1965 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
1966 op->opcode = WINED3D_CS_OP_SET_CLIP_PLANE;
1967 op->plane_idx = plane_idx;
1968 op->plane = *plane;
1970 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
1973 static void wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *data)
1975 const struct wined3d_cs_set_color_key *op = data;
1976 struct wined3d_texture *texture = op->texture;
1978 if (op->set)
1980 switch (op->flags)
1982 case WINED3D_CKEY_DST_BLT:
1983 texture->async.dst_blt_color_key = op->color_key;
1984 texture->async.color_key_flags |= WINED3D_CKEY_DST_BLT;
1985 break;
1987 case WINED3D_CKEY_DST_OVERLAY:
1988 texture->async.dst_overlay_color_key = op->color_key;
1989 texture->async.color_key_flags |= WINED3D_CKEY_DST_OVERLAY;
1990 break;
1992 case WINED3D_CKEY_SRC_BLT:
1993 if (texture == cs->state.textures[0])
1995 device_invalidate_state(cs->c.device, STATE_COLOR_KEY);
1996 if (!(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT))
1997 device_invalidate_state(cs->c.device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
2000 texture->async.src_blt_color_key = op->color_key;
2001 texture->async.color_key_flags |= WINED3D_CKEY_SRC_BLT;
2002 break;
2004 case WINED3D_CKEY_SRC_OVERLAY:
2005 texture->async.src_overlay_color_key = op->color_key;
2006 texture->async.color_key_flags |= WINED3D_CKEY_SRC_OVERLAY;
2007 break;
2010 else
2012 switch (op->flags)
2014 case WINED3D_CKEY_DST_BLT:
2015 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_BLT;
2016 break;
2018 case WINED3D_CKEY_DST_OVERLAY:
2019 texture->async.color_key_flags &= ~WINED3D_CKEY_DST_OVERLAY;
2020 break;
2022 case WINED3D_CKEY_SRC_BLT:
2023 if (texture == cs->state.textures[0] && texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
2024 device_invalidate_state(cs->c.device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
2026 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_BLT;
2027 break;
2029 case WINED3D_CKEY_SRC_OVERLAY:
2030 texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_OVERLAY;
2031 break;
2036 void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture *texture,
2037 WORD flags, const struct wined3d_color_key *color_key)
2039 struct wined3d_cs_set_color_key *op;
2041 op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2042 op->opcode = WINED3D_CS_OP_SET_COLOR_KEY;
2043 op->texture = texture;
2044 op->flags = flags;
2045 if (color_key)
2047 op->color_key = *color_key;
2048 op->set = 1;
2050 else
2051 op->set = 0;
2053 wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT);
2056 static void wined3d_cs_exec_set_material(struct wined3d_cs *cs, const void *data)
2058 const struct wined3d_cs_set_material *op = data;
2060 cs->state.material = op->material;
2061 device_invalidate_state(cs->c.device, STATE_MATERIAL);
2064 void wined3d_device_context_emit_set_material(struct wined3d_device_context *context,
2065 const struct wined3d_material *material)
2067 struct wined3d_cs_set_material *op;
2069 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2070 op->opcode = WINED3D_CS_OP_SET_MATERIAL;
2071 op->material = *material;
2073 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2076 static void wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data)
2078 const struct wined3d_cs_set_light *op = data;
2079 struct wined3d_light_info *light_info;
2080 unsigned int light_idx, hash_idx;
2082 light_idx = op->light.OriginalIndex;
2084 if (!(light_info = wined3d_light_state_get_light(&cs->state.light_state, light_idx)))
2086 TRACE("Adding new light.\n");
2087 if (!(light_info = heap_alloc_zero(sizeof(*light_info))))
2089 ERR("Failed to allocate light info.\n");
2090 return;
2093 hash_idx = LIGHTMAP_HASHFUNC(light_idx);
2094 list_add_head(&cs->state.light_state.light_map[hash_idx], &light_info->entry);
2095 light_info->glIndex = -1;
2096 light_info->OriginalIndex = light_idx;
2099 if (light_info->glIndex != -1)
2101 if (light_info->OriginalParms.type != op->light.OriginalParms.type)
2102 device_invalidate_state(cs->c.device, STATE_LIGHT_TYPE);
2103 device_invalidate_state(cs->c.device, STATE_ACTIVELIGHT(light_info->glIndex));
2106 light_info->OriginalParms = op->light.OriginalParms;
2107 light_info->position = op->light.position;
2108 light_info->direction = op->light.direction;
2109 light_info->exponent = op->light.exponent;
2110 light_info->cutoff = op->light.cutoff;
2113 void wined3d_device_context_emit_set_light(struct wined3d_device_context *context,
2114 const struct wined3d_light_info *light)
2116 struct wined3d_cs_set_light *op;
2118 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2119 op->opcode = WINED3D_CS_OP_SET_LIGHT;
2120 op->light = *light;
2122 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2125 static void wined3d_cs_exec_set_light_enable(struct wined3d_cs *cs, const void *data)
2127 const struct wined3d_cs_set_light_enable *op = data;
2128 struct wined3d_device *device = cs->c.device;
2129 struct wined3d_light_info *light_info;
2130 int prev_idx;
2132 if (!(light_info = wined3d_light_state_get_light(&cs->state.light_state, op->idx)))
2134 ERR("Light doesn't exist.\n");
2135 return;
2138 prev_idx = light_info->glIndex;
2139 wined3d_light_state_enable_light(&cs->state.light_state, &device->adapter->d3d_info, light_info, op->enable);
2140 if (light_info->glIndex != prev_idx)
2142 device_invalidate_state(device, STATE_LIGHT_TYPE);
2143 device_invalidate_state(device, STATE_ACTIVELIGHT(op->enable ? light_info->glIndex : prev_idx));
2147 void wined3d_device_context_emit_set_light_enable(struct wined3d_device_context *context, unsigned int idx, BOOL enable)
2149 struct wined3d_cs_set_light_enable *op;
2151 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2152 op->opcode = WINED3D_CS_OP_SET_LIGHT_ENABLE;
2153 op->idx = idx;
2154 op->enable = enable;
2156 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2159 static void wined3d_cs_exec_set_feature_level(struct wined3d_cs *cs, const void *data)
2161 const struct wined3d_cs_set_feature_level *op = data;
2163 cs->state.feature_level = op->level;
2166 void wined3d_device_context_emit_set_feature_level(struct wined3d_device_context *context,
2167 enum wined3d_feature_level level)
2169 struct wined3d_cs_set_feature_level *op;
2171 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2172 op->opcode = WINED3D_CS_OP_SET_FEATURE_LEVEL;
2173 op->level = level;
2175 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2178 static const struct
2180 size_t offset;
2181 size_t size;
2182 DWORD mask;
2184 wined3d_cs_push_constant_info[] =
2186 /* WINED3D_PUSH_CONSTANTS_VS_F */
2187 {FIELD_OFFSET(struct wined3d_state, vs_consts_f), sizeof(struct wined3d_vec4), WINED3D_SHADER_CONST_VS_F},
2188 /* WINED3D_PUSH_CONSTANTS_PS_F */
2189 {FIELD_OFFSET(struct wined3d_state, ps_consts_f), sizeof(struct wined3d_vec4), WINED3D_SHADER_CONST_PS_F},
2190 /* WINED3D_PUSH_CONSTANTS_VS_I */
2191 {FIELD_OFFSET(struct wined3d_state, vs_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_VS_I},
2192 /* WINED3D_PUSH_CONSTANTS_PS_I */
2193 {FIELD_OFFSET(struct wined3d_state, ps_consts_i), sizeof(struct wined3d_ivec4), WINED3D_SHADER_CONST_PS_I},
2194 /* WINED3D_PUSH_CONSTANTS_VS_B */
2195 {FIELD_OFFSET(struct wined3d_state, vs_consts_b), sizeof(BOOL), WINED3D_SHADER_CONST_VS_B},
2196 /* WINED3D_PUSH_CONSTANTS_PS_B */
2197 {FIELD_OFFSET(struct wined3d_state, ps_consts_b), sizeof(BOOL), WINED3D_SHADER_CONST_PS_B},
2200 static void wined3d_cs_st_push_constants(struct wined3d_device_context *context, enum wined3d_push_constants p,
2201 unsigned int start_idx, unsigned int count, const void *constants)
2203 struct wined3d_cs *cs = wined3d_cs_from_context(context);
2204 struct wined3d_device *device = cs->c.device;
2205 unsigned int context_count;
2206 unsigned int i;
2207 size_t offset;
2209 if (p == WINED3D_PUSH_CONSTANTS_VS_F)
2210 device->shader_backend->shader_update_float_vertex_constants(device, start_idx, count);
2211 else if (p == WINED3D_PUSH_CONSTANTS_PS_F)
2212 device->shader_backend->shader_update_float_pixel_constants(device, start_idx, count);
2214 offset = wined3d_cs_push_constant_info[p].offset + start_idx * wined3d_cs_push_constant_info[p].size;
2215 memcpy((BYTE *)&cs->state + offset, constants, count * wined3d_cs_push_constant_info[p].size);
2216 for (i = 0, context_count = device->context_count; i < context_count; ++i)
2218 device->contexts[i]->constant_update_mask |= wined3d_cs_push_constant_info[p].mask;
2222 static void wined3d_cs_exec_push_constants(struct wined3d_cs *cs, const void *data)
2224 const struct wined3d_cs_push_constants *op = data;
2226 wined3d_cs_st_push_constants(&cs->c, op->type, op->start_idx, op->count, op->constants);
2229 static void wined3d_cs_mt_push_constants(struct wined3d_device_context *context, enum wined3d_push_constants p,
2230 unsigned int start_idx, unsigned int count, const void *constants)
2232 struct wined3d_cs *cs = wined3d_cs_from_context(context);
2233 struct wined3d_cs_push_constants *op;
2234 size_t size;
2236 size = count * wined3d_cs_push_constant_info[p].size;
2237 op = wined3d_device_context_require_space(&cs->c, FIELD_OFFSET(struct wined3d_cs_push_constants, constants[size]),
2238 WINED3D_CS_QUEUE_DEFAULT);
2239 op->opcode = WINED3D_CS_OP_PUSH_CONSTANTS;
2240 op->type = p;
2241 op->start_idx = start_idx;
2242 op->count = count;
2243 memcpy(op->constants, constants, size);
2245 wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT);
2248 static void wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data)
2250 const struct wined3d_device *device = cs->c.device;
2251 const struct wined3d_cs_reset_state *op = data;
2252 const struct wined3d_state_entry *state_table;
2253 unsigned int state;
2255 state_cleanup(&cs->state);
2256 wined3d_state_reset(&cs->state, &device->adapter->d3d_info);
2257 if (op->invalidate)
2259 state_table = device->state_table;
2260 for (state = 0; state <= STATE_HIGHEST; ++state)
2262 if (state_table[state].representative)
2263 device_invalidate_state(device, state);
2268 void wined3d_device_context_emit_reset_state(struct wined3d_device_context *context, bool invalidate)
2270 struct wined3d_cs_reset_state *op;
2272 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2273 op->opcode = WINED3D_CS_OP_RESET_STATE;
2274 op->invalidate = invalidate;
2276 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2279 static void wined3d_cs_exec_callback(struct wined3d_cs *cs, const void *data)
2281 const struct wined3d_cs_callback *op = data;
2283 op->callback(op->object);
2286 static void wined3d_cs_emit_callback(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
2288 struct wined3d_cs_callback *op;
2290 op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2291 op->opcode = WINED3D_CS_OP_CALLBACK;
2292 op->callback = callback;
2293 op->object = object;
2295 wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT);
2298 void wined3d_cs_destroy_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
2300 wined3d_cs_emit_callback(cs, callback, object);
2303 void wined3d_cs_init_object(struct wined3d_cs *cs, void (*callback)(void *object), void *object)
2305 wined3d_cs_emit_callback(cs, callback, object);
2308 static void wined3d_cs_exec_query_issue(struct wined3d_cs *cs, const void *data)
2310 const struct wined3d_cs_query_issue *op = data;
2311 struct wined3d_query *query = op->query;
2312 BOOL poll;
2314 poll = query->query_ops->query_issue(query, op->flags);
2316 if (!cs->thread)
2317 return;
2319 if (poll && list_empty(&query->poll_list_entry))
2321 if (query->buffer_object)
2322 InterlockedIncrement(&query->counter_retrieved);
2323 else
2324 list_add_tail(&cs->query_poll_list, &query->poll_list_entry);
2325 return;
2328 /* This can happen if occlusion queries are restarted. This discards the
2329 * old result, since polling it could result in a GL error. */
2330 if ((op->flags & WINED3DISSUE_BEGIN) && !poll && !list_empty(&query->poll_list_entry))
2332 list_remove(&query->poll_list_entry);
2333 list_init(&query->poll_list_entry);
2334 InterlockedIncrement(&query->counter_retrieved);
2335 return;
2338 /* This can happen when an occlusion query is ended without being started,
2339 * in which case we don't want to poll, but still have to counter-balance
2340 * the increment of the main counter.
2342 * This can also happen if an event query is re-issued before the first
2343 * fence was reached. In this case the query is already in the list and
2344 * the poll function will check the new fence. We have to counter-balance
2345 * the discarded increment. */
2346 if (op->flags & WINED3DISSUE_END)
2347 InterlockedIncrement(&query->counter_retrieved);
2350 static void wined3d_cs_issue_query(struct wined3d_device_context *context,
2351 struct wined3d_query *query, unsigned int flags)
2353 struct wined3d_cs *cs = wined3d_cs_from_context(context);
2354 struct wined3d_cs_query_issue *op;
2356 if (flags & WINED3DISSUE_END)
2357 ++query->counter_main;
2359 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2360 op->opcode = WINED3D_CS_OP_QUERY_ISSUE;
2361 op->query = query;
2362 op->flags = flags;
2364 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2365 cs->queries_flushed = FALSE;
2367 if (flags & WINED3DISSUE_BEGIN)
2368 query->state = QUERY_BUILDING;
2369 else
2370 query->state = QUERY_SIGNALLED;
2373 static void wined3d_cs_acquire_command_list(struct wined3d_device_context *context, struct wined3d_command_list *list)
2375 struct wined3d_cs *cs = wined3d_cs_from_context(context);
2376 SIZE_T i;
2378 if (list->query_count)
2380 cs->queries_flushed = FALSE;
2382 for (i = 0; i < list->query_count; ++i)
2384 if (list->queries[i].flags & WINED3DISSUE_END)
2386 list->queries[i].query->counter_main++;
2387 list->queries[i].query->state = QUERY_SIGNALLED;
2389 else
2391 list->queries[i].query->state = QUERY_BUILDING;
2396 for (i = 0; i < list->resource_count; ++i)
2397 wined3d_resource_acquire(list->resources[i]);
2399 for (i = 0; i < list->command_list_count; ++i)
2400 wined3d_cs_acquire_command_list(context, list->command_lists[i]);
2402 for (i = 0; i < list->upload_count; ++i)
2403 invalidate_client_address(list->uploads[i].resource);
2406 static void wined3d_cs_exec_preload_resource(struct wined3d_cs *cs, const void *data)
2408 const struct wined3d_cs_preload_resource *op = data;
2409 struct wined3d_resource *resource = op->resource;
2411 resource->resource_ops->resource_preload(resource);
2412 wined3d_resource_release(resource);
2415 void wined3d_cs_emit_preload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
2417 struct wined3d_cs_preload_resource *op;
2419 op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2420 op->opcode = WINED3D_CS_OP_PRELOAD_RESOURCE;
2421 op->resource = resource;
2423 wined3d_resource_acquire(resource);
2425 wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT);
2428 static void wined3d_cs_exec_unload_resource(struct wined3d_cs *cs, const void *data)
2430 const struct wined3d_cs_unload_resource *op = data;
2431 struct wined3d_resource *resource = op->resource;
2433 resource->resource_ops->resource_unload(resource);
2434 wined3d_resource_release(resource);
2437 void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource)
2439 struct wined3d_cs_unload_resource *op;
2441 discard_client_address(resource);
2443 op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2444 op->opcode = WINED3D_CS_OP_UNLOAD_RESOURCE;
2445 op->resource = resource;
2447 wined3d_resource_acquire(resource);
2449 wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT);
2452 static void wined3d_device_context_upload_bo(struct wined3d_device_context *context,
2453 struct wined3d_resource *resource, unsigned int sub_resource_idx, const struct wined3d_box *box,
2454 const struct upload_bo *bo, unsigned int row_pitch, unsigned int slice_pitch)
2456 struct wined3d_cs_update_sub_resource *op;
2458 TRACE("context %p, resource %p, sub_resource_idx %u, box %s, bo %s, flags %#x, row_pitch %u, slice_pitch %u.\n",
2459 context, resource, sub_resource_idx, debug_box(box),
2460 debug_const_bo_address(&bo->addr), bo->flags, row_pitch, slice_pitch);
2462 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2463 op->opcode = WINED3D_CS_OP_UPDATE_SUB_RESOURCE;
2464 op->resource = resource;
2465 op->sub_resource_idx = sub_resource_idx;
2466 op->box = *box;
2467 op->bo = *bo;
2468 op->row_pitch = row_pitch;
2469 op->slice_pitch = slice_pitch;
2471 wined3d_device_context_acquire_resource(context, resource);
2473 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2476 static void wined3d_cs_exec_map(struct wined3d_cs *cs, const void *data)
2478 const struct wined3d_cs_map *op = data;
2479 struct wined3d_resource *resource = op->resource;
2481 *op->hr = resource->resource_ops->resource_sub_resource_map(resource,
2482 op->sub_resource_idx, op->map_ptr, op->box, op->flags);
2485 HRESULT wined3d_device_context_emit_map(struct wined3d_device_context *context,
2486 struct wined3d_resource *resource, unsigned int sub_resource_idx,
2487 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, unsigned int flags)
2489 struct wined3d_cs_map *op;
2490 HRESULT hr;
2492 /* Mapping resources from the worker thread isn't an issue by itself, but
2493 * increasing the map count would be visible to applications. */
2494 wined3d_not_from_cs(context->device->cs);
2496 if ((flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE))
2497 && context->ops->map_upload_bo(context, resource, sub_resource_idx, map_desc, box, flags))
2499 TRACE("Returning map pointer %p, row pitch %u, slice pitch %u.\n",
2500 map_desc->data, map_desc->row_pitch, map_desc->slice_pitch);
2501 return WINED3D_OK;
2504 wined3d_resource_wait_idle(resource);
2506 /* We might end up invalidating the resource on the CS thread. */
2507 invalidate_client_address(resource);
2509 if (!(op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_MAP)))
2510 return E_OUTOFMEMORY;
2511 op->opcode = WINED3D_CS_OP_MAP;
2512 op->resource = resource;
2513 op->sub_resource_idx = sub_resource_idx;
2514 op->map_ptr = &map_desc->data;
2515 op->box = box;
2516 op->flags = flags;
2517 op->hr = &hr;
2519 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_MAP);
2520 wined3d_device_context_finish(context, WINED3D_CS_QUEUE_MAP);
2522 if (SUCCEEDED(hr))
2523 wined3d_resource_get_sub_resource_map_pitch(resource, sub_resource_idx,
2524 &map_desc->row_pitch, &map_desc->slice_pitch);
2525 return hr;
2528 static void wined3d_cs_exec_unmap(struct wined3d_cs *cs, const void *data)
2530 const struct wined3d_cs_unmap *op = data;
2531 struct wined3d_resource *resource = op->resource;
2533 *op->hr = resource->resource_ops->resource_sub_resource_unmap(resource, op->sub_resource_idx);
2536 HRESULT wined3d_device_context_emit_unmap(struct wined3d_device_context *context,
2537 struct wined3d_resource *resource, unsigned int sub_resource_idx)
2539 struct wined3d_cs_unmap *op;
2540 struct wined3d_box box;
2541 struct upload_bo bo;
2542 HRESULT hr;
2544 if (context->ops->unmap_upload_bo(context, resource, sub_resource_idx, &box, &bo))
2546 unsigned int row_pitch, slice_pitch;
2548 wined3d_resource_get_sub_resource_map_pitch(resource, sub_resource_idx, &row_pitch, &slice_pitch);
2549 if (bo.flags & UPLOAD_BO_UPLOAD_ON_UNMAP)
2550 wined3d_device_context_upload_bo(context, resource, sub_resource_idx, &box, &bo, row_pitch, slice_pitch);
2551 return WINED3D_OK;
2554 wined3d_not_from_cs(context->device->cs);
2556 if (!(op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_MAP)))
2557 return E_OUTOFMEMORY;
2558 op->opcode = WINED3D_CS_OP_UNMAP;
2559 op->resource = resource;
2560 op->sub_resource_idx = sub_resource_idx;
2561 op->hr = &hr;
2563 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_MAP);
2564 wined3d_device_context_finish(context, WINED3D_CS_QUEUE_MAP);
2566 return hr;
2569 static void wined3d_cs_exec_map_bo_address(struct wined3d_cs *cs, const void *data)
2571 const struct wined3d_cs_map_bo_address *op = data;
2572 struct wined3d_context *context;
2574 context = context_acquire(cs->c.device, NULL, 0);
2575 wined3d_context_map_bo_address(context, &op->addr, op->size, op->flags);
2576 context_release(context);
2579 void wined3d_cs_map_bo_address(struct wined3d_cs *cs,
2580 struct wined3d_bo_address *addr, size_t size, unsigned int flags)
2582 struct wined3d_device_context *context = &cs->c;
2583 struct wined3d_cs_map_bo_address *op;
2585 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2586 op->opcode = WINED3D_CS_OP_MAP_BO_ADDRESS;
2587 op->addr = *addr;
2588 op->size = size;
2589 op->flags = flags;
2590 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_MAP);
2591 wined3d_device_context_finish(context, WINED3D_CS_QUEUE_MAP);
2594 static void wined3d_cs_exec_blt_sub_resource(struct wined3d_cs *cs, const void *data)
2596 const struct wined3d_cs_blt_sub_resource *op = data;
2598 if (op->dst_resource->type == WINED3D_RTYPE_BUFFER)
2600 wined3d_buffer_copy(buffer_from_resource(op->dst_resource), op->dst_box.left,
2601 buffer_from_resource(op->src_resource), op->src_box.left,
2602 op->src_box.right - op->src_box.left);
2604 else if (op->dst_resource->type == WINED3D_RTYPE_TEXTURE_3D)
2606 struct wined3d_texture *src_texture, *dst_texture;
2607 unsigned int level, update_w, update_h, update_d;
2608 unsigned int row_pitch, slice_pitch;
2609 struct wined3d_context *context;
2610 struct wined3d_bo_address addr;
2611 unsigned int location;
2613 if (op->flags & ~WINED3D_BLT_RAW)
2615 FIXME("Flags %#x not implemented for %s resources.\n",
2616 op->flags, debug_d3dresourcetype(op->dst_resource->type));
2617 goto error;
2620 if (!(op->flags & WINED3D_BLT_RAW) && op->src_resource->format != op->dst_resource->format)
2622 FIXME("Format conversion not implemented for %s resources.\n",
2623 debug_d3dresourcetype(op->dst_resource->type));
2624 goto error;
2627 update_w = op->dst_box.right - op->dst_box.left;
2628 update_h = op->dst_box.bottom - op->dst_box.top;
2629 update_d = op->dst_box.back - op->dst_box.front;
2630 if (op->src_box.right - op->src_box.left != update_w
2631 || op->src_box.bottom - op->src_box.top != update_h
2632 || op->src_box.back - op->src_box.front != update_d)
2634 FIXME("Stretching not implemented for %s resources.\n",
2635 debug_d3dresourcetype(op->dst_resource->type));
2636 goto error;
2639 dst_texture = texture_from_resource(op->dst_resource);
2640 src_texture = texture_from_resource(op->src_resource);
2642 context = context_acquire(cs->c.device, NULL, 0);
2644 location = src_texture->resource.map_binding;
2645 if (location == WINED3D_LOCATION_SYSMEM
2646 && wined3d_texture_can_use_pbo(src_texture, &context->device->adapter->d3d_info))
2647 location = WINED3D_LOCATION_BUFFER;
2649 if (!wined3d_texture_load_location(src_texture, op->src_sub_resource_idx,
2650 context, location))
2652 ERR("Failed to load source sub-resource into %s.\n",
2653 wined3d_debug_location(location));
2654 context_release(context);
2655 goto error;
2658 level = op->dst_sub_resource_idx % dst_texture->level_count;
2659 if (update_w == wined3d_texture_get_level_width(dst_texture, level)
2660 && update_h == wined3d_texture_get_level_height(dst_texture, level)
2661 && update_d == wined3d_texture_get_level_depth(dst_texture, level))
2663 wined3d_texture_prepare_location(dst_texture, op->dst_sub_resource_idx,
2664 context, WINED3D_LOCATION_TEXTURE_RGB);
2666 else if (!wined3d_texture_load_location(dst_texture, op->dst_sub_resource_idx,
2667 context, WINED3D_LOCATION_TEXTURE_RGB))
2669 ERR("Failed to load destination sub-resource.\n");
2670 context_release(context);
2671 goto error;
2674 wined3d_texture_get_memory(src_texture, op->src_sub_resource_idx, &addr, location);
2675 wined3d_texture_get_pitch(src_texture, op->src_sub_resource_idx % src_texture->level_count,
2676 &row_pitch, &slice_pitch);
2678 dst_texture->texture_ops->texture_upload_data(context, wined3d_const_bo_address(&addr),
2679 dst_texture->resource.format, &op->src_box, row_pitch, slice_pitch, dst_texture,
2680 op->dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB,
2681 op->dst_box.left, op->dst_box.top, op->dst_box.front);
2682 wined3d_texture_validate_location(dst_texture, op->dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2683 wined3d_texture_invalidate_location(dst_texture, op->dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2685 context_release(context);
2687 else
2689 if (FAILED(texture2d_blt(texture_from_resource(op->dst_resource), op->dst_sub_resource_idx,
2690 &op->dst_box, texture_from_resource(op->src_resource), op->src_sub_resource_idx,
2691 &op->src_box, op->flags, &op->fx, op->filter)))
2692 FIXME("Blit failed.\n");
2695 error:
2696 if (op->src_resource)
2697 wined3d_resource_release(op->src_resource);
2698 wined3d_resource_release(op->dst_resource);
2701 void wined3d_device_context_emit_blt_sub_resource(struct wined3d_device_context *context,
2702 struct wined3d_resource *dst_resource, unsigned int dst_sub_resource_idx, const struct wined3d_box *dst_box,
2703 struct wined3d_resource *src_resource, unsigned int src_sub_resource_idx, const struct wined3d_box *src_box,
2704 unsigned int flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2706 struct wined3d_cs_blt_sub_resource *op;
2708 /* If we are replacing the whole resource, the CS thread might discard and
2709 * rename the buffer object, in which case ours is no longer valid. */
2710 if (dst_resource->type == WINED3D_RTYPE_BUFFER && dst_box->right - dst_box->left == dst_resource->size)
2711 invalidate_client_address(dst_resource);
2713 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2714 op->opcode = WINED3D_CS_OP_BLT_SUB_RESOURCE;
2715 op->dst_resource = dst_resource;
2716 op->dst_sub_resource_idx = dst_sub_resource_idx;
2717 op->dst_box = *dst_box;
2718 op->src_resource = src_resource;
2719 op->src_sub_resource_idx = src_sub_resource_idx;
2720 op->src_box = *src_box;
2721 op->flags = flags;
2722 if (fx)
2723 op->fx = *fx;
2724 else
2725 memset(&op->fx, 0, sizeof(op->fx));
2726 op->filter = filter;
2728 wined3d_device_context_acquire_resource(context, dst_resource);
2729 if (src_resource)
2730 wined3d_device_context_acquire_resource(context, src_resource);
2732 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2733 if (flags & WINED3D_BLT_SYNCHRONOUS)
2734 wined3d_device_context_finish(context, WINED3D_CS_QUEUE_DEFAULT);
2737 static void wined3d_cs_exec_update_sub_resource(struct wined3d_cs *cs, const void *data)
2739 const struct wined3d_cs_update_sub_resource *op = data;
2740 struct wined3d_resource *resource = op->resource;
2741 const struct wined3d_box *box = &op->box;
2742 struct wined3d_context *context;
2744 context = context_acquire(cs->c.device, NULL, 0);
2746 if (resource->type == WINED3D_RTYPE_BUFFER)
2747 wined3d_buffer_update_sub_resource(buffer_from_resource(resource),
2748 context, &op->bo, box->left, box->right - box->left);
2749 else
2750 wined3d_texture_update_sub_resource(texture_from_resource(resource),
2751 op->sub_resource_idx, context, &op->bo, box, op->row_pitch, op->slice_pitch);
2753 context_release(context);
2755 wined3d_resource_release(resource);
2758 void wined3d_device_context_emit_update_sub_resource(struct wined3d_device_context *context,
2759 struct wined3d_resource *resource, unsigned int sub_resource_idx, const struct wined3d_box *box,
2760 const void *data, unsigned int row_pitch, unsigned int slice_pitch)
2762 struct wined3d_cs_update_sub_resource *op;
2763 struct wined3d_map_desc map_desc;
2764 struct wined3d_box dummy_box;
2765 struct upload_bo bo;
2767 /* If we are replacing the whole resource, the CS thread might discard and
2768 * rename the buffer object, in which case ours is no longer valid. */
2769 if (resource->type == WINED3D_RTYPE_BUFFER && box->right - box->left == resource->size)
2770 invalidate_client_address(resource);
2772 if (context->ops->map_upload_bo(context, resource, sub_resource_idx, &map_desc, box, WINED3D_MAP_WRITE))
2774 wined3d_format_copy_data(resource->format, data, row_pitch, slice_pitch, map_desc.data, map_desc.row_pitch,
2775 map_desc.slice_pitch, box->right - box->left, box->bottom - box->top, box->back - box->front);
2776 context->ops->unmap_upload_bo(context, resource, sub_resource_idx, &dummy_box, &bo);
2777 wined3d_device_context_upload_bo(context, resource, sub_resource_idx,
2778 box, &bo, map_desc.row_pitch, map_desc.slice_pitch);
2779 return;
2782 wined3d_resource_wait_idle(resource);
2784 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_MAP);
2785 op->opcode = WINED3D_CS_OP_UPDATE_SUB_RESOURCE;
2786 op->resource = resource;
2787 op->sub_resource_idx = sub_resource_idx;
2788 op->box = *box;
2789 op->bo.addr.buffer_object = 0;
2790 op->bo.addr.addr = data;
2791 op->bo.flags = 0;
2792 op->row_pitch = row_pitch;
2793 op->slice_pitch = slice_pitch;
2795 wined3d_device_context_acquire_resource(context, resource);
2797 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_MAP);
2798 /* The data pointer may go away, so we need to wait until it is read.
2799 * Copying the data may be faster if it's small. */
2800 wined3d_device_context_finish(context, WINED3D_CS_QUEUE_MAP);
2803 static void wined3d_cs_exec_add_dirty_texture_region(struct wined3d_cs *cs, const void *data)
2805 const struct wined3d_cs_add_dirty_texture_region *op = data;
2806 struct wined3d_texture *texture = op->texture;
2807 unsigned int sub_resource_idx, i;
2808 struct wined3d_context *context;
2810 context = context_acquire(cs->c.device, NULL, 0);
2811 sub_resource_idx = op->layer * texture->level_count;
2812 for (i = 0; i < texture->level_count; ++i, ++sub_resource_idx)
2814 if (wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding))
2815 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
2816 else
2817 ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
2819 context_release(context);
2821 wined3d_resource_release(&texture->resource);
2824 void wined3d_cs_emit_add_dirty_texture_region(struct wined3d_cs *cs,
2825 struct wined3d_texture *texture, unsigned int layer)
2827 struct wined3d_cs_add_dirty_texture_region *op;
2829 op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2830 op->opcode = WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION;
2831 op->texture = texture;
2832 op->layer = layer;
2834 wined3d_resource_acquire(&texture->resource);
2836 wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT);
2839 static void wined3d_cs_exec_clear_unordered_access_view(struct wined3d_cs *cs, const void *data)
2841 const struct wined3d_cs_clear_unordered_access_view *op = data;
2842 struct wined3d_unordered_access_view *view = op->view;
2843 struct wined3d_context *context;
2845 context = context_acquire(cs->c.device, NULL, 0);
2846 cs->c.device->adapter->adapter_ops->adapter_clear_uav(context, view, &op->clear_value, op->fp);
2847 context_release(context);
2849 wined3d_resource_release(view->resource);
2852 void wined3d_device_context_emit_clear_uav(struct wined3d_device_context *context,
2853 struct wined3d_unordered_access_view *view, const struct wined3d_uvec4 *clear_value, bool fp)
2855 struct wined3d_cs_clear_unordered_access_view *op;
2857 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2858 op->opcode = WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW;
2859 op->view = view;
2860 op->clear_value = *clear_value;
2861 op->fp = fp;
2863 wined3d_device_context_acquire_resource(context, view->resource);
2865 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2868 static void wined3d_cs_exec_copy_uav_counter(struct wined3d_cs *cs, const void *data)
2870 const struct wined3d_cs_copy_uav_counter *op = data;
2871 struct wined3d_unordered_access_view *view = op->view;
2872 struct wined3d_context *context;
2874 context = context_acquire(cs->c.device, NULL, 0);
2875 wined3d_unordered_access_view_copy_counter(view, op->buffer, op->offset, context);
2876 context_release(context);
2878 wined3d_resource_release(&op->buffer->resource);
2881 void wined3d_device_context_emit_copy_uav_counter(struct wined3d_device_context *context,
2882 struct wined3d_buffer *dst_buffer, unsigned int offset, struct wined3d_unordered_access_view *uav)
2884 struct wined3d_cs_copy_uav_counter *op;
2886 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2887 op->opcode = WINED3D_CS_OP_COPY_UAV_COUNTER;
2888 op->buffer = dst_buffer;
2889 op->offset = offset;
2890 op->view = uav;
2892 wined3d_device_context_acquire_resource(context, &dst_buffer->resource);
2894 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2897 static void wined3d_cs_exec_generate_mipmaps(struct wined3d_cs *cs, const void *data)
2899 const struct wined3d_cs_generate_mipmaps *op = data;
2900 struct wined3d_shader_resource_view *view = op->view;
2901 struct wined3d_context *context;
2903 context = context_acquire(cs->c.device, NULL, 0);
2904 cs->c.device->adapter->adapter_ops->adapter_generate_mipmap(context, view);
2905 context_release(context);
2907 wined3d_resource_release(view->resource);
2910 void wined3d_device_context_emit_generate_mipmaps(struct wined3d_device_context *context,
2911 struct wined3d_shader_resource_view *view)
2913 struct wined3d_cs_generate_mipmaps *op;
2915 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2916 op->opcode = WINED3D_CS_OP_GENERATE_MIPMAPS;
2917 op->view = view;
2919 wined3d_device_context_acquire_resource(context, view->resource);
2921 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
2924 static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
2926 struct wined3d_cs_stop *op;
2928 op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
2929 op->opcode = WINED3D_CS_OP_STOP;
2931 wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT);
2932 wined3d_cs_finish(cs, WINED3D_CS_QUEUE_DEFAULT);
2935 static void wined3d_cs_acquire_resource(struct wined3d_device_context *context, struct wined3d_resource *resource)
2937 wined3d_resource_acquire(resource);
2940 static void wined3d_cs_exec_execute_command_list(struct wined3d_cs *cs, const void *data);
2942 static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
2944 /* WINED3D_CS_OP_NOP */ wined3d_cs_exec_nop,
2945 /* WINED3D_CS_OP_PRESENT */ wined3d_cs_exec_present,
2946 /* WINED3D_CS_OP_CLEAR */ wined3d_cs_exec_clear,
2947 /* WINED3D_CS_OP_DISPATCH */ wined3d_cs_exec_dispatch,
2948 /* WINED3D_CS_OP_DRAW */ wined3d_cs_exec_draw,
2949 /* WINED3D_CS_OP_FLUSH */ wined3d_cs_exec_flush,
2950 /* WINED3D_CS_OP_SET_PREDICATION */ wined3d_cs_exec_set_predication,
2951 /* WINED3D_CS_OP_SET_VIEWPORTS */ wined3d_cs_exec_set_viewports,
2952 /* WINED3D_CS_OP_SET_SCISSOR_RECTS */ wined3d_cs_exec_set_scissor_rects,
2953 /* WINED3D_CS_OP_SET_RENDERTARGET_VIEWS */ wined3d_cs_exec_set_rendertarget_views,
2954 /* WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW */ wined3d_cs_exec_set_depth_stencil_view,
2955 /* WINED3D_CS_OP_SET_VERTEX_DECLARATION */ wined3d_cs_exec_set_vertex_declaration,
2956 /* WINED3D_CS_OP_SET_STREAM_SOURCES */ wined3d_cs_exec_set_stream_sources,
2957 /* WINED3D_CS_OP_SET_STREAM_OUTPUTS */ wined3d_cs_exec_set_stream_outputs,
2958 /* WINED3D_CS_OP_SET_INDEX_BUFFER */ wined3d_cs_exec_set_index_buffer,
2959 /* WINED3D_CS_OP_SET_CONSTANT_BUFFERS */ wined3d_cs_exec_set_constant_buffers,
2960 /* WINED3D_CS_OP_SET_TEXTURE */ wined3d_cs_exec_set_texture,
2961 /* WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEWS */ wined3d_cs_exec_set_shader_resource_views,
2962 /* WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEWS */ wined3d_cs_exec_set_unordered_access_views,
2963 /* WINED3D_CS_OP_SET_SAMPLERS */ wined3d_cs_exec_set_samplers,
2964 /* WINED3D_CS_OP_SET_SHADER */ wined3d_cs_exec_set_shader,
2965 /* WINED3D_CS_OP_SET_BLEND_STATE */ wined3d_cs_exec_set_blend_state,
2966 /* WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE */ wined3d_cs_exec_set_depth_stencil_state,
2967 /* WINED3D_CS_OP_SET_RASTERIZER_STATE */ wined3d_cs_exec_set_rasterizer_state,
2968 /* WINED3D_CS_OP_SET_RENDER_STATE */ wined3d_cs_exec_set_render_state,
2969 /* WINED3D_CS_OP_SET_TEXTURE_STATE */ wined3d_cs_exec_set_texture_state,
2970 /* WINED3D_CS_OP_SET_SAMPLER_STATE */ wined3d_cs_exec_set_sampler_state,
2971 /* WINED3D_CS_OP_SET_TRANSFORM */ wined3d_cs_exec_set_transform,
2972 /* WINED3D_CS_OP_SET_CLIP_PLANE */ wined3d_cs_exec_set_clip_plane,
2973 /* WINED3D_CS_OP_SET_COLOR_KEY */ wined3d_cs_exec_set_color_key,
2974 /* WINED3D_CS_OP_SET_MATERIAL */ wined3d_cs_exec_set_material,
2975 /* WINED3D_CS_OP_SET_LIGHT */ wined3d_cs_exec_set_light,
2976 /* WINED3D_CS_OP_SET_LIGHT_ENABLE */ wined3d_cs_exec_set_light_enable,
2977 /* WINED3D_CS_OP_SET_FEATURE_LEVEL */ wined3d_cs_exec_set_feature_level,
2978 /* WINED3D_CS_OP_PUSH_CONSTANTS */ wined3d_cs_exec_push_constants,
2979 /* WINED3D_CS_OP_RESET_STATE */ wined3d_cs_exec_reset_state,
2980 /* WINED3D_CS_OP_CALLBACK */ wined3d_cs_exec_callback,
2981 /* WINED3D_CS_OP_QUERY_ISSUE */ wined3d_cs_exec_query_issue,
2982 /* WINED3D_CS_OP_PRELOAD_RESOURCE */ wined3d_cs_exec_preload_resource,
2983 /* WINED3D_CS_OP_UNLOAD_RESOURCE */ wined3d_cs_exec_unload_resource,
2984 /* WINED3D_CS_OP_MAP */ wined3d_cs_exec_map,
2985 /* WINED3D_CS_OP_UNMAP */ wined3d_cs_exec_unmap,
2986 /* WINED3D_CS_OP_MAP_BO_ADDRESS */ wined3d_cs_exec_map_bo_address,
2987 /* WINED3D_CS_OP_BLT_SUB_RESOURCE */ wined3d_cs_exec_blt_sub_resource,
2988 /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE */ wined3d_cs_exec_update_sub_resource,
2989 /* WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION */ wined3d_cs_exec_add_dirty_texture_region,
2990 /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view,
2991 /* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter,
2992 /* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps,
2993 /* WINED3D_CS_OP_EXECUTE_COMMAND_LIST */ wined3d_cs_exec_execute_command_list,
2996 static void wined3d_cs_exec_execute_command_list(struct wined3d_cs *cs, const void *data)
2998 const struct wined3d_cs_execute_command_list *op = data;
2999 SIZE_T start = 0, end = op->list->data_size;
3000 const BYTE *cs_data = op->list->data;
3002 TRACE("Executing command list %p.\n", op->list);
3004 while (start < end)
3006 const struct wined3d_cs_packet *packet = wined3d_next_cs_packet(cs_data, &start);
3007 enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)packet->data;
3009 if (opcode >= WINED3D_CS_OP_STOP)
3010 ERR("Invalid opcode %#x.\n", opcode);
3011 else
3012 wined3d_cs_op_handlers[opcode](cs, packet->data);
3013 TRACE("%s executed.\n", debug_cs_op(opcode));
3017 void wined3d_device_context_emit_execute_command_list(struct wined3d_device_context *context,
3018 struct wined3d_command_list *list, bool restore_state)
3020 struct wined3d_cs_execute_command_list *op;
3022 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
3023 op->opcode = WINED3D_CS_OP_EXECUTE_COMMAND_LIST;
3024 op->list = list;
3026 context->ops->acquire_command_list(context, list);
3028 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
3030 if (restore_state)
3031 wined3d_device_context_set_state(context, context->state);
3032 else
3033 wined3d_device_context_reset_state(context);
3036 static void *wined3d_cs_st_require_space(struct wined3d_device_context *context,
3037 size_t size, enum wined3d_cs_queue_id queue_id)
3039 struct wined3d_cs *cs = wined3d_cs_from_context(context);
3041 if (size > (cs->data_size - cs->end))
3043 size_t new_size;
3044 void *new_data;
3046 new_size = max(size, cs->data_size * 2);
3047 if (!cs->end)
3048 new_data = heap_realloc(cs->data, new_size);
3049 else
3050 new_data = heap_alloc(new_size);
3051 if (!new_data)
3052 return NULL;
3054 cs->data_size = new_size;
3055 cs->start = cs->end = 0;
3056 cs->data = new_data;
3059 cs->end += size;
3061 return (BYTE *)cs->data + cs->start;
3064 static void wined3d_cs_st_submit(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id)
3066 struct wined3d_cs *cs = wined3d_cs_from_context(context);
3067 enum wined3d_cs_op opcode;
3068 size_t start;
3069 BYTE *data;
3071 data = cs->data;
3072 start = cs->start;
3073 cs->start = cs->end;
3075 opcode = *(const enum wined3d_cs_op *)&data[start];
3076 if (opcode >= WINED3D_CS_OP_STOP)
3077 ERR("Invalid opcode %#x.\n", opcode);
3078 else
3079 wined3d_cs_op_handlers[opcode](cs, &data[start]);
3081 if (cs->data == data)
3082 cs->start = cs->end = start;
3083 else if (!start)
3084 heap_free(data);
3087 static void wined3d_cs_st_finish(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id)
3091 static bool wined3d_cs_map_upload_bo(struct wined3d_device_context *context, struct wined3d_resource *resource,
3092 unsigned int sub_resource_idx, struct wined3d_map_desc *map_desc, const struct wined3d_box *box, uint32_t flags)
3094 /* Limit NOOVERWRITE maps to buffers for now; there are too many ways that
3095 * a texture can be invalidated to even count. */
3096 if (resource->type == WINED3D_RTYPE_BUFFER && (flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE)))
3098 const struct wined3d_d3d_info *d3d_info = &context->device->adapter->d3d_info;
3099 struct wined3d_client_resource *client = &resource->client;
3100 struct wined3d_device *device = context->device;
3101 struct wined3d_bo_address addr;
3102 struct wined3d_bo *bo;
3103 uint8_t *map_ptr;
3105 /* We can't use persistent maps if we might need to do vertex attribute
3106 * conversion; that will cause the CS thread to invalidate the BO. */
3107 if (!d3d_info->xyzrhw || !d3d_info->vertex_bgra || !d3d_info->ffp_generic_attributes)
3109 TRACE("Not returning a persistent buffer because we might need to do vertex attribute conversion.\n");
3110 return NULL;
3113 if (resource->pin_sysmem)
3115 TRACE("Not allocating an upload buffer because system memory is pinned for this resource.\n");
3116 return NULL;
3119 if ((flags & WINED3D_MAP_NOOVERWRITE) && client->addr.buffer_object == CLIENT_BO_DISCARDED)
3120 flags = (flags & ~WINED3D_MAP_NOOVERWRITE) | WINED3D_MAP_DISCARD;
3122 if (flags & WINED3D_MAP_DISCARD)
3124 if (!device->adapter->adapter_ops->adapter_alloc_bo(device, resource, sub_resource_idx, &addr))
3125 return false;
3127 client->addr = addr;
3129 else
3131 addr = client->addr;
3134 map_ptr = NULL;
3135 if ((bo = addr.buffer_object))
3137 wined3d_device_bo_map_lock(device);
3138 if ((map_ptr = bo->map_ptr))
3139 ++bo->client_map_count;
3140 wined3d_device_bo_map_unlock(device);
3142 if (!map_ptr)
3144 /* adapter_alloc_bo() should have given us a mapped BO if we are
3145 * discarding. */
3146 assert(flags & WINED3D_MAP_NOOVERWRITE);
3147 WARN_(d3d_perf)("Not accelerating a NOOVERWRITE map because the BO is not mapped.\n");
3148 return false;
3151 map_ptr += (uintptr_t)addr.addr;
3153 if (!map_ptr)
3155 assert(flags & WINED3D_MAP_NOOVERWRITE);
3156 WARN_(d3d_perf)("Not accelerating a NOOVERWRITE map because the sub-resource has no valid address.\n");
3157 return false;
3160 wined3d_resource_get_sub_resource_map_pitch(resource, sub_resource_idx,
3161 &map_desc->row_pitch, &map_desc->slice_pitch);
3163 client->mapped_upload.addr = *wined3d_const_bo_address(&addr);
3164 client->mapped_upload.flags = 0;
3165 if (bo)
3167 map_ptr += bo->memory_offset;
3168 /* If we are not mapping all buffers persistently, use
3169 * UPDATE_SUB_RESOURCE as a means of telling the CS thread to try
3170 * to unmap the resource, so that we can free VA space. */
3171 if (!bo->coherent || !wined3d_map_persistent())
3172 client->mapped_upload.flags |= UPLOAD_BO_UPLOAD_ON_UNMAP;
3174 map_desc->data = resource_offset_map_pointer(resource, sub_resource_idx, map_ptr, box);
3176 if (flags & WINED3D_MAP_DISCARD)
3177 client->mapped_upload.flags |= UPLOAD_BO_UPLOAD_ON_UNMAP | UPLOAD_BO_RENAME_ON_UNMAP;
3179 client->mapped_box = *box;
3181 TRACE("Returning bo %s, flags %#x.\n", debug_const_bo_address(&client->mapped_upload.addr),
3182 client->mapped_upload.flags);
3183 return true;
3186 return false;
3189 static bool wined3d_bo_address_is_null(struct wined3d_const_bo_address *addr)
3191 return !addr->buffer_object && !addr->addr;
3194 static bool wined3d_cs_unmap_upload_bo(struct wined3d_device_context *context, struct wined3d_resource *resource,
3195 unsigned int sub_resource_idx, struct wined3d_box *box, struct upload_bo *upload_bo)
3197 struct wined3d_client_resource *client = &resource->client;
3198 struct wined3d_device *device = context->device;
3199 struct wined3d_bo *bo;
3201 if (wined3d_bo_address_is_null(&client->mapped_upload.addr))
3202 return false;
3204 if ((bo = client->mapped_upload.addr.buffer_object))
3206 wined3d_device_bo_map_lock(device);
3207 --bo->client_map_count;
3208 wined3d_device_bo_map_unlock(device);
3211 *upload_bo = client->mapped_upload;
3212 *box = client->mapped_box;
3213 memset(&client->mapped_upload, 0, sizeof(client->mapped_upload));
3214 memset(&client->mapped_box, 0, sizeof(client->mapped_box));
3215 return true;
3218 static const struct wined3d_device_context_ops wined3d_cs_st_ops =
3220 wined3d_cs_st_require_space,
3221 wined3d_cs_st_submit,
3222 wined3d_cs_st_finish,
3223 wined3d_cs_st_push_constants,
3224 wined3d_cs_map_upload_bo,
3225 wined3d_cs_unmap_upload_bo,
3226 wined3d_cs_issue_query,
3227 wined3d_cs_flush,
3228 wined3d_cs_acquire_resource,
3229 wined3d_cs_acquire_command_list,
3232 static BOOL wined3d_cs_queue_is_empty(const struct wined3d_cs *cs, const struct wined3d_cs_queue *queue)
3234 wined3d_from_cs(cs);
3235 return *(volatile LONG *)&queue->head == queue->tail;
3238 static void wined3d_cs_queue_submit(struct wined3d_cs_queue *queue, struct wined3d_cs *cs)
3240 struct wined3d_cs_packet *packet;
3241 size_t packet_size;
3243 packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
3244 TRACE("Queuing op %s at %p.\n", debug_cs_op(*(const enum wined3d_cs_op *)packet->data), packet);
3245 packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[packet->size]);
3246 InterlockedExchange(&queue->head, (queue->head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1));
3248 if (InterlockedCompareExchange(&cs->waiting_for_event, FALSE, TRUE))
3249 SetEvent(cs->event);
3252 static void wined3d_cs_mt_submit(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id)
3254 struct wined3d_cs *cs = wined3d_cs_from_context(context);
3256 if (cs->thread_id == GetCurrentThreadId())
3257 return wined3d_cs_st_submit(context, queue_id);
3259 wined3d_cs_queue_submit(&cs->queue[queue_id], cs);
3262 static void *wined3d_cs_queue_require_space(struct wined3d_cs_queue *queue, size_t size, struct wined3d_cs *cs)
3264 size_t queue_size = ARRAY_SIZE(queue->data);
3265 size_t header_size, packet_size, remaining;
3266 struct wined3d_cs_packet *packet;
3268 header_size = FIELD_OFFSET(struct wined3d_cs_packet, data[0]);
3269 packet_size = FIELD_OFFSET(struct wined3d_cs_packet, data[size]);
3270 packet_size = (packet_size + header_size - 1) & ~(header_size - 1);
3271 size = packet_size - header_size;
3272 if (packet_size >= WINED3D_CS_QUEUE_SIZE)
3274 ERR("Packet size %lu >= queue size %u.\n",
3275 (unsigned long)packet_size, WINED3D_CS_QUEUE_SIZE);
3276 return NULL;
3279 remaining = queue_size - queue->head;
3280 if (remaining < packet_size)
3282 size_t nop_size = remaining - header_size;
3283 struct wined3d_cs_nop *nop;
3285 TRACE("Inserting a nop for %lu + %lu bytes.\n",
3286 (unsigned long)header_size, (unsigned long)nop_size);
3288 nop = wined3d_cs_queue_require_space(queue, nop_size, cs);
3289 if (nop_size)
3290 nop->opcode = WINED3D_CS_OP_NOP;
3292 wined3d_cs_queue_submit(queue, cs);
3293 assert(!queue->head);
3296 for (;;)
3298 LONG tail = *(volatile LONG *)&queue->tail;
3299 LONG head = queue->head;
3300 LONG new_pos;
3302 /* Empty. */
3303 if (head == tail)
3304 break;
3305 new_pos = (head + packet_size) & (WINED3D_CS_QUEUE_SIZE - 1);
3306 /* Head ahead of tail. We checked the remaining size above, so we only
3307 * need to make sure we don't make head equal to tail. */
3308 if (head > tail && (new_pos != tail))
3309 break;
3310 /* Tail ahead of head. Make sure the new head is before the tail as
3311 * well. Note that new_pos is 0 when it's at the end of the queue. */
3312 if (new_pos < tail && new_pos)
3313 break;
3315 TRACE("Waiting for free space. Head %u, tail %u, packet size %lu.\n",
3316 head, tail, (unsigned long)packet_size);
3319 packet = (struct wined3d_cs_packet *)&queue->data[queue->head];
3320 packet->size = size;
3321 return packet->data;
3324 static void *wined3d_cs_mt_require_space(struct wined3d_device_context *context,
3325 size_t size, enum wined3d_cs_queue_id queue_id)
3327 struct wined3d_cs *cs = wined3d_cs_from_context(context);
3329 if (cs->thread_id == GetCurrentThreadId())
3330 return wined3d_cs_st_require_space(context, size, queue_id);
3332 return wined3d_cs_queue_require_space(&cs->queue[queue_id], size, cs);
3335 static void wined3d_cs_mt_finish(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id)
3337 struct wined3d_cs *cs = wined3d_cs_from_context(context);
3339 if (cs->thread_id == GetCurrentThreadId())
3340 return wined3d_cs_st_finish(context, queue_id);
3342 while (cs->queue[queue_id].head != *(volatile LONG *)&cs->queue[queue_id].tail)
3343 YieldProcessor();
3346 static const struct wined3d_device_context_ops wined3d_cs_mt_ops =
3348 wined3d_cs_mt_require_space,
3349 wined3d_cs_mt_submit,
3350 wined3d_cs_mt_finish,
3351 wined3d_cs_mt_push_constants,
3352 wined3d_cs_map_upload_bo,
3353 wined3d_cs_unmap_upload_bo,
3354 wined3d_cs_issue_query,
3355 wined3d_cs_flush,
3356 wined3d_cs_acquire_resource,
3357 wined3d_cs_acquire_command_list,
3360 static void poll_queries(struct wined3d_cs *cs)
3362 struct wined3d_query *query, *cursor;
3364 LIST_FOR_EACH_ENTRY_SAFE(query, cursor, &cs->query_poll_list, struct wined3d_query, poll_list_entry)
3366 if (!query->query_ops->query_poll(query, 0))
3367 continue;
3369 list_remove(&query->poll_list_entry);
3370 list_init(&query->poll_list_entry);
3371 InterlockedIncrement(&query->counter_retrieved);
3375 static void wined3d_cs_wait_event(struct wined3d_cs *cs)
3377 InterlockedExchange(&cs->waiting_for_event, TRUE);
3379 /* The main thread might have enqueued a command and blocked on it after
3380 * the CS thread decided to enter wined3d_cs_wait_event(), but before
3381 * "waiting_for_event" was set.
3383 * Likewise, we can race with the main thread when resetting
3384 * "waiting_for_event", in which case we would need to call
3385 * WaitForSingleObject() because the main thread called SetEvent(). */
3386 if (!(wined3d_cs_queue_is_empty(cs, &cs->queue[WINED3D_CS_QUEUE_DEFAULT])
3387 && wined3d_cs_queue_is_empty(cs, &cs->queue[WINED3D_CS_QUEUE_MAP]))
3388 && InterlockedCompareExchange(&cs->waiting_for_event, FALSE, TRUE))
3389 return;
3391 WaitForSingleObject(cs->event, INFINITE);
3394 static void wined3d_cs_command_lock(const struct wined3d_cs *cs)
3396 if (cs->serialize_commands)
3397 EnterCriticalSection(&wined3d_command_cs);
3400 static void wined3d_cs_command_unlock(const struct wined3d_cs *cs)
3402 if (cs->serialize_commands)
3403 LeaveCriticalSection(&wined3d_command_cs);
3406 static DWORD WINAPI wined3d_cs_run(void *ctx)
3408 struct wined3d_cs_packet *packet;
3409 struct wined3d_cs_queue *queue;
3410 unsigned int spin_count = 0;
3411 struct wined3d_cs *cs = ctx;
3412 enum wined3d_cs_op opcode;
3413 HMODULE wined3d_module;
3414 unsigned int poll = 0;
3415 SIZE_T tail;
3417 TRACE("Started.\n");
3419 /* Copy the module handle to a local variable to avoid racing with the
3420 * thread freeing "cs" before the FreeLibraryAndExitThread() call. */
3421 wined3d_module = cs->wined3d_module;
3423 list_init(&cs->query_poll_list);
3424 cs->thread_id = GetCurrentThreadId();
3425 for (;;)
3427 if (++poll == WINED3D_CS_QUERY_POLL_INTERVAL)
3429 wined3d_cs_command_lock(cs);
3430 poll_queries(cs);
3431 wined3d_cs_command_unlock(cs);
3432 poll = 0;
3435 queue = &cs->queue[WINED3D_CS_QUEUE_MAP];
3436 if (wined3d_cs_queue_is_empty(cs, queue))
3438 queue = &cs->queue[WINED3D_CS_QUEUE_DEFAULT];
3439 if (wined3d_cs_queue_is_empty(cs, queue))
3441 if (++spin_count >= WINED3D_CS_SPIN_COUNT && list_empty(&cs->query_poll_list))
3442 wined3d_cs_wait_event(cs);
3443 continue;
3446 spin_count = 0;
3448 tail = queue->tail;
3449 packet = wined3d_next_cs_packet(queue->data, &tail);
3450 if (packet->size)
3452 opcode = *(const enum wined3d_cs_op *)packet->data;
3454 TRACE("Executing %s at %p.\n", debug_cs_op(opcode), packet);
3455 if (opcode >= WINED3D_CS_OP_STOP)
3457 if (opcode > WINED3D_CS_OP_STOP)
3458 ERR("Invalid opcode %#x.\n", opcode);
3459 break;
3462 wined3d_cs_command_lock(cs);
3463 wined3d_cs_op_handlers[opcode](cs, packet->data);
3464 wined3d_cs_command_unlock(cs);
3465 TRACE("%s at %p executed.\n", debug_cs_op(opcode), packet);
3468 tail &= (WINED3D_CS_QUEUE_SIZE - 1);
3469 InterlockedExchange(&queue->tail, tail);
3472 cs->queue[WINED3D_CS_QUEUE_MAP].tail = cs->queue[WINED3D_CS_QUEUE_MAP].head;
3473 cs->queue[WINED3D_CS_QUEUE_DEFAULT].tail = cs->queue[WINED3D_CS_QUEUE_DEFAULT].head;
3474 TRACE("Stopped.\n");
3475 FreeLibraryAndExitThread(wined3d_module, 0);
3478 struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device,
3479 const enum wined3d_feature_level *levels, unsigned int level_count)
3481 const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
3482 struct wined3d_cs *cs;
3484 if (!(cs = heap_alloc_zero(sizeof(*cs))))
3485 return NULL;
3487 if (FAILED(wined3d_state_create(device, levels, level_count, &cs->c.state)))
3489 heap_free(cs);
3490 return NULL;
3493 cs->c.ops = &wined3d_cs_st_ops;
3494 cs->c.device = device;
3495 cs->serialize_commands = TRACE_ON(d3d_sync) || wined3d_settings.cs_multithreaded & WINED3D_CSMT_SERIALIZE;
3497 if (cs->serialize_commands)
3498 ERR_(d3d_sync)("Forcing serialization of all command streams.\n");
3500 state_init(&cs->state, d3d_info, WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT, cs->c.state->feature_level);
3502 cs->data_size = WINED3D_INITIAL_CS_SIZE;
3503 if (!(cs->data = heap_alloc(cs->data_size)))
3504 goto fail;
3506 if (wined3d_settings.cs_multithreaded & WINED3D_CSMT_ENABLE
3507 && !RtlIsCriticalSectionLockedByThread(NtCurrentTeb()->Peb->LoaderLock))
3509 cs->c.ops = &wined3d_cs_mt_ops;
3511 if (!(cs->event = CreateEventW(NULL, FALSE, FALSE, NULL)))
3513 ERR("Failed to create command stream event.\n");
3514 heap_free(cs->data);
3515 goto fail;
3518 if (!(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
3519 (const WCHAR *)wined3d_cs_run, &cs->wined3d_module)))
3521 ERR("Failed to get wined3d module handle.\n");
3522 CloseHandle(cs->event);
3523 heap_free(cs->data);
3524 goto fail;
3527 if (!(cs->thread = CreateThread(NULL, 0, wined3d_cs_run, cs, 0, NULL)))
3529 ERR("Failed to create wined3d command stream thread.\n");
3530 FreeLibrary(cs->wined3d_module);
3531 CloseHandle(cs->event);
3532 heap_free(cs->data);
3533 goto fail;
3537 return cs;
3539 fail:
3540 wined3d_state_destroy(cs->c.state);
3541 state_cleanup(&cs->state);
3542 heap_free(cs);
3543 return NULL;
3546 void wined3d_cs_destroy(struct wined3d_cs *cs)
3548 if (cs->thread)
3550 wined3d_cs_emit_stop(cs);
3551 CloseHandle(cs->thread);
3552 if (!CloseHandle(cs->event))
3553 ERR("Closing event failed.\n");
3556 wined3d_state_destroy(cs->c.state);
3557 state_cleanup(&cs->state);
3558 heap_free(cs->data);
3559 heap_free(cs);
3562 static void wined3d_cs_packet_decref_objects(const struct wined3d_cs_packet *packet)
3564 enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)packet->data;
3565 unsigned int i;
3567 switch (opcode)
3569 case WINED3D_CS_OP_SET_SAMPLERS:
3571 struct wined3d_cs_set_samplers *op = (struct wined3d_cs_set_samplers *)packet->data;
3573 for (i = 0; i < op->count; ++i)
3575 if (op->samplers[i])
3576 wined3d_sampler_decref(op->samplers[i]);
3578 break;
3581 case WINED3D_CS_OP_SET_SHADER:
3583 struct wined3d_cs_set_shader *op = (struct wined3d_cs_set_shader *)packet->data;
3585 if (op->shader)
3586 wined3d_shader_decref(op->shader);
3587 break;
3590 case WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE:
3592 struct wined3d_cs_set_depth_stencil_state *op;
3594 op = (struct wined3d_cs_set_depth_stencil_state *)packet->data;
3595 if (op->state)
3596 wined3d_depth_stencil_state_decref(op->state);
3597 break;
3600 case WINED3D_CS_OP_SET_RASTERIZER_STATE:
3602 struct wined3d_cs_set_rasterizer_state *op;
3604 op = (struct wined3d_cs_set_rasterizer_state *)packet->data;
3605 if (op->state)
3606 wined3d_rasterizer_state_decref(op->state);
3607 break;
3610 case WINED3D_CS_OP_SET_BLEND_STATE:
3612 struct wined3d_cs_set_blend_state *op;
3614 op = (struct wined3d_cs_set_blend_state *)packet->data;
3615 if (op->state)
3616 wined3d_blend_state_decref(op->state);
3617 break;
3620 case WINED3D_CS_OP_SET_RENDERTARGET_VIEWS:
3622 struct wined3d_cs_set_rendertarget_views *op;
3624 op = (struct wined3d_cs_set_rendertarget_views *)packet->data;
3625 for (i = 0; i < op->count; ++i)
3627 if (op->views[i])
3628 wined3d_rendertarget_view_decref(op->views[i]);
3630 break;
3633 case WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEWS:
3635 struct wined3d_cs_set_shader_resource_views *op;
3637 op = (struct wined3d_cs_set_shader_resource_views *)packet->data;
3638 for (i = 0; i < op->count; ++i)
3640 if (op->views[i])
3641 wined3d_shader_resource_view_decref(op->views[i]);
3643 break;
3646 case WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEWS:
3648 struct wined3d_cs_set_unordered_access_views *op;
3650 op = (struct wined3d_cs_set_unordered_access_views *)packet->data;
3651 for (i = 0; i < op->count; ++i)
3653 if (op->uavs[i].view)
3654 wined3d_unordered_access_view_decref(op->uavs[i].view);
3656 break;
3659 case WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW:
3661 struct wined3d_cs_set_depth_stencil_view *op;
3663 op = (struct wined3d_cs_set_depth_stencil_view *)packet->data;
3664 if (op->view)
3665 wined3d_rendertarget_view_decref(op->view);
3666 break;
3669 case WINED3D_CS_OP_SET_CONSTANT_BUFFERS:
3671 struct wined3d_cs_set_constant_buffers *op;
3673 op = (struct wined3d_cs_set_constant_buffers *)packet->data;
3674 for (i = 0; i < op->count; ++i)
3676 if (op->buffers[i].buffer)
3677 wined3d_buffer_decref(op->buffers[i].buffer);
3679 break;
3682 case WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW:
3684 struct wined3d_cs_clear_unordered_access_view *op;
3686 op = (struct wined3d_cs_clear_unordered_access_view *)packet->data;
3687 wined3d_unordered_access_view_decref(op->view);
3688 break;
3691 case WINED3D_CS_OP_CLEAR:
3693 struct wined3d_cs_clear *op = (struct wined3d_cs_clear *)packet->data;
3695 for (i = 0; i < op->rt_count; ++i)
3697 if (op->fb.render_targets[i])
3698 wined3d_rendertarget_view_decref(op->fb.render_targets[i]);
3700 if (op->fb.depth_stencil)
3701 wined3d_rendertarget_view_decref(op->fb.depth_stencil);
3702 break;
3705 case WINED3D_CS_OP_DISPATCH:
3707 struct wined3d_cs_dispatch *op = (struct wined3d_cs_dispatch *)packet->data;
3709 if (op->parameters.indirect)
3710 wined3d_buffer_decref(op->parameters.u.indirect.buffer);
3711 break;
3714 case WINED3D_CS_OP_DRAW:
3716 struct wined3d_cs_draw *op = (struct wined3d_cs_draw *)packet->data;
3718 if (op->parameters.indirect)
3719 wined3d_buffer_decref(op->parameters.u.indirect.buffer);
3720 break;
3723 case WINED3D_CS_OP_SET_INDEX_BUFFER:
3725 struct wined3d_cs_set_index_buffer *op;
3727 op = (struct wined3d_cs_set_index_buffer *)packet->data;
3728 if (op->buffer)
3729 wined3d_buffer_decref(op->buffer);
3730 break;
3733 case WINED3D_CS_OP_SET_STREAM_OUTPUTS:
3735 struct wined3d_cs_set_stream_outputs *op;
3737 op = (struct wined3d_cs_set_stream_outputs *)packet->data;
3738 for (i = 0; i < ARRAY_SIZE(op->outputs); ++i)
3740 if (op->outputs[i].buffer)
3741 wined3d_buffer_decref(op->outputs[i].buffer);
3743 break;
3746 case WINED3D_CS_OP_SET_STREAM_SOURCES:
3748 struct wined3d_cs_set_stream_sources *op;
3750 op = (struct wined3d_cs_set_stream_sources *)packet->data;
3751 for (i = 0; i < op->count; ++i)
3753 if (op->streams[i].buffer)
3754 wined3d_buffer_decref(op->streams[i].buffer);
3756 break;
3759 case WINED3D_CS_OP_UPDATE_SUB_RESOURCE:
3761 struct wined3d_cs_update_sub_resource *op;
3763 op = (struct wined3d_cs_update_sub_resource *)packet->data;
3764 wined3d_resource_decref(op->resource);
3765 break;
3768 case WINED3D_CS_OP_BLT_SUB_RESOURCE:
3770 struct wined3d_cs_blt_sub_resource *op;
3772 op = (struct wined3d_cs_blt_sub_resource *)packet->data;
3773 if (op->src_resource)
3774 wined3d_resource_decref(op->src_resource);
3775 wined3d_resource_decref(op->dst_resource);
3776 break;
3779 case WINED3D_CS_OP_COPY_UAV_COUNTER:
3781 struct wined3d_cs_copy_uav_counter *op;
3783 op = (struct wined3d_cs_copy_uav_counter *)packet->data;
3784 wined3d_buffer_decref(op->buffer);
3785 wined3d_unordered_access_view_decref(op->view);
3786 break;
3789 case WINED3D_CS_OP_GENERATE_MIPMAPS:
3791 struct wined3d_cs_generate_mipmaps *op;
3793 op = (struct wined3d_cs_generate_mipmaps *)packet->data;
3794 wined3d_shader_resource_view_decref(op->view);
3795 break;
3798 default:
3799 break;
3803 static void wined3d_cs_packet_incref_objects(struct wined3d_cs_packet *packet)
3805 enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)packet->data;
3806 unsigned int i;
3808 switch (opcode)
3810 case WINED3D_CS_OP_SET_SAMPLERS:
3812 struct wined3d_cs_set_samplers *op = (struct wined3d_cs_set_samplers *)packet->data;
3814 for (i = 0; i < op->count; ++i)
3816 if (op->samplers[i])
3817 wined3d_sampler_incref(op->samplers[i]);
3819 break;
3822 case WINED3D_CS_OP_SET_SHADER:
3824 struct wined3d_cs_set_shader *op = (struct wined3d_cs_set_shader *)packet->data;
3826 if (op->shader)
3827 wined3d_shader_incref(op->shader);
3828 break;
3831 case WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE:
3833 struct wined3d_cs_set_depth_stencil_state *op;
3835 op = (struct wined3d_cs_set_depth_stencil_state *)packet->data;
3836 if (op->state)
3837 wined3d_depth_stencil_state_incref(op->state);
3838 break;
3841 case WINED3D_CS_OP_SET_RASTERIZER_STATE:
3843 struct wined3d_cs_set_rasterizer_state *op;
3845 op = (struct wined3d_cs_set_rasterizer_state *)packet->data;
3846 if (op->state)
3847 wined3d_rasterizer_state_incref(op->state);
3848 break;
3851 case WINED3D_CS_OP_SET_BLEND_STATE:
3853 struct wined3d_cs_set_blend_state *op;
3855 op = (struct wined3d_cs_set_blend_state *)packet->data;
3856 if (op->state)
3857 wined3d_blend_state_incref(op->state);
3858 break;
3861 case WINED3D_CS_OP_SET_RENDERTARGET_VIEWS:
3863 struct wined3d_cs_set_rendertarget_views *op;
3865 op = (struct wined3d_cs_set_rendertarget_views *)packet->data;
3866 for (i = 0; i < op->count; ++i)
3868 if (op->views[i])
3869 wined3d_rendertarget_view_incref(op->views[i]);
3871 break;
3874 case WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEWS:
3876 struct wined3d_cs_set_shader_resource_views *op;
3878 op = (struct wined3d_cs_set_shader_resource_views *)packet->data;
3879 for (i = 0; i < op->count; ++i)
3881 if (op->views[i])
3882 wined3d_shader_resource_view_incref(op->views[i]);
3884 break;
3887 case WINED3D_CS_OP_SET_UNORDERED_ACCESS_VIEWS:
3889 struct wined3d_cs_set_unordered_access_views *op;
3891 op = (struct wined3d_cs_set_unordered_access_views *)packet->data;
3892 for (i = 0; i < op->count; ++i)
3894 if (op->uavs[i].view)
3895 wined3d_unordered_access_view_incref(op->uavs[i].view);
3897 break;
3900 case WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW:
3902 struct wined3d_cs_set_depth_stencil_view *op;
3904 op = (struct wined3d_cs_set_depth_stencil_view *)packet->data;
3905 if (op->view)
3906 wined3d_rendertarget_view_incref(op->view);
3907 break;
3910 case WINED3D_CS_OP_SET_CONSTANT_BUFFERS:
3912 struct wined3d_cs_set_constant_buffers *op;
3914 op = (struct wined3d_cs_set_constant_buffers *)packet->data;
3915 for (i = 0; i < op->count; ++i)
3917 if (op->buffers[i].buffer)
3918 wined3d_buffer_incref(op->buffers[i].buffer);
3920 break;
3923 case WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW:
3925 struct wined3d_cs_clear_unordered_access_view *op;
3927 op = (struct wined3d_cs_clear_unordered_access_view *)packet->data;
3928 wined3d_unordered_access_view_incref(op->view);
3929 break;
3932 case WINED3D_CS_OP_CLEAR:
3934 struct wined3d_cs_clear *op = (struct wined3d_cs_clear *)packet->data;
3936 for (i = 0; i < op->rt_count; ++i)
3938 if (op->fb.render_targets[i])
3939 wined3d_rendertarget_view_incref(op->fb.render_targets[i]);
3941 if (op->fb.depth_stencil)
3942 wined3d_rendertarget_view_incref(op->fb.depth_stencil);
3943 break;
3946 case WINED3D_CS_OP_DISPATCH:
3948 struct wined3d_cs_dispatch *op = (struct wined3d_cs_dispatch *)packet->data;
3950 if (op->parameters.indirect)
3951 wined3d_buffer_incref(op->parameters.u.indirect.buffer);
3952 break;
3955 case WINED3D_CS_OP_DRAW:
3957 struct wined3d_cs_draw *op = (struct wined3d_cs_draw *)packet->data;
3959 if (op->parameters.indirect)
3960 wined3d_buffer_incref(op->parameters.u.indirect.buffer);
3961 break;
3964 case WINED3D_CS_OP_SET_INDEX_BUFFER:
3966 struct wined3d_cs_set_index_buffer *op;
3968 op = (struct wined3d_cs_set_index_buffer *)packet->data;
3969 if (op->buffer)
3970 wined3d_buffer_incref(op->buffer);
3971 break;
3974 case WINED3D_CS_OP_SET_STREAM_OUTPUTS:
3976 struct wined3d_cs_set_stream_outputs *op;
3978 op = (struct wined3d_cs_set_stream_outputs *)packet->data;
3979 for (i = 0; i < ARRAY_SIZE(op->outputs); ++i)
3981 if (op->outputs[i].buffer)
3982 wined3d_buffer_incref(op->outputs[i].buffer);
3984 break;
3987 case WINED3D_CS_OP_SET_STREAM_SOURCES:
3989 struct wined3d_cs_set_stream_sources *op;
3991 op = (struct wined3d_cs_set_stream_sources *)packet->data;
3992 for (i = 0; i < op->count; ++i)
3994 if (op->streams[i].buffer)
3995 wined3d_buffer_incref(op->streams[i].buffer);
3997 break;
4000 case WINED3D_CS_OP_UPDATE_SUB_RESOURCE:
4002 struct wined3d_cs_update_sub_resource *op;
4004 op = (struct wined3d_cs_update_sub_resource *)packet->data;
4005 wined3d_resource_incref(op->resource);
4006 break;
4009 case WINED3D_CS_OP_BLT_SUB_RESOURCE:
4011 struct wined3d_cs_blt_sub_resource *op;
4013 op = (struct wined3d_cs_blt_sub_resource *)packet->data;
4014 if (op->src_resource)
4015 wined3d_resource_incref(op->src_resource);
4016 wined3d_resource_incref(op->dst_resource);
4017 break;
4020 case WINED3D_CS_OP_COPY_UAV_COUNTER:
4022 struct wined3d_cs_copy_uav_counter *op;
4024 op = (struct wined3d_cs_copy_uav_counter *)packet->data;
4025 wined3d_buffer_incref(op->buffer);
4026 wined3d_unordered_access_view_incref(op->view);
4027 break;
4030 case WINED3D_CS_OP_GENERATE_MIPMAPS:
4032 struct wined3d_cs_generate_mipmaps *op;
4034 op = (struct wined3d_cs_generate_mipmaps *)packet->data;
4035 wined3d_shader_resource_view_incref(op->view);
4036 break;
4039 default:
4040 break;
4044 struct wined3d_deferred_context
4046 struct wined3d_device_context c;
4047 HANDLE upload_heap;
4049 SIZE_T data_size, data_capacity;
4050 void *data;
4052 SIZE_T resource_count, resources_capacity;
4053 struct wined3d_resource **resources;
4055 SIZE_T upload_count, uploads_capacity;
4056 struct wined3d_deferred_upload *uploads;
4058 /* List of command lists queued for execution on this context. A command
4059 * list can be the only thing holding a pointer to another command list, so
4060 * we need to hold a reference here and in wined3d_command_list as well. */
4061 SIZE_T command_list_count, command_lists_capacity;
4062 struct wined3d_command_list **command_lists;
4064 SIZE_T query_count, queries_capacity;
4065 struct wined3d_deferred_query_issue *queries;
4068 static struct wined3d_deferred_context *wined3d_deferred_context_from_context(struct wined3d_device_context *context)
4070 return CONTAINING_RECORD(context, struct wined3d_deferred_context, c);
4073 static void *wined3d_deferred_context_require_space(struct wined3d_device_context *context,
4074 size_t size, enum wined3d_cs_queue_id queue_id)
4076 struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
4077 struct wined3d_cs_packet *packet;
4078 size_t header_size, packet_size;
4080 if (queue_id != WINED3D_CS_QUEUE_DEFAULT)
4081 return NULL;
4083 header_size = offsetof(struct wined3d_cs_packet, data[0]);
4084 packet_size = offsetof(struct wined3d_cs_packet, data[size]);
4085 packet_size = (packet_size + header_size - 1) & ~(header_size - 1);
4087 if (!wined3d_array_reserve(&deferred->data, &deferred->data_capacity, deferred->data_size + packet_size, 1))
4088 return NULL;
4090 packet = (struct wined3d_cs_packet *)((BYTE *)deferred->data + deferred->data_size);
4091 TRACE("size was %zu, adding %zu\n", (size_t)deferred->data_size, packet_size);
4092 packet->size = packet_size - header_size;
4093 return &packet->data;
4096 static void wined3d_deferred_context_submit(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id)
4098 struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
4099 struct wined3d_cs_packet *packet;
4101 assert(queue_id == WINED3D_CS_QUEUE_DEFAULT);
4102 packet = wined3d_next_cs_packet(deferred->data, &deferred->data_size);
4103 wined3d_cs_packet_incref_objects(packet);
4106 static void wined3d_deferred_context_finish(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id)
4108 /* This should not happen; we cannot meaningfully finish a deferred context. */
4109 ERR("Ignoring finish() on a deferred context.\n");
4112 static void wined3d_deferred_context_push_constants(struct wined3d_device_context *context,
4113 enum wined3d_push_constants p, unsigned int start_idx, unsigned int count, const void *constants)
4115 FIXME("context %p, p %#x, start_idx %u, count %u, constants %p, stub!\n", context, p, start_idx, count, constants);
4118 static struct wined3d_deferred_upload *deferred_context_get_upload(struct wined3d_deferred_context *deferred,
4119 struct wined3d_resource *resource, unsigned int sub_resource_idx)
4121 SIZE_T i = deferred->upload_count;
4123 while (i--)
4125 struct wined3d_deferred_upload *upload = &deferred->uploads[i];
4127 if (upload->resource == resource && upload->sub_resource_idx == sub_resource_idx)
4128 return upload;
4131 return NULL;
4134 static bool wined3d_deferred_context_map_upload_bo(struct wined3d_device_context *context,
4135 struct wined3d_resource *resource, unsigned int sub_resource_idx,
4136 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, uint32_t flags)
4138 struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
4139 const struct wined3d_format *format = resource->format;
4140 struct wined3d_deferred_upload *upload;
4141 uint8_t *sysmem;
4142 size_t size;
4144 wined3d_format_calculate_pitch(format, 1, box->right - box->left,
4145 box->bottom - box->top, &map_desc->row_pitch, &map_desc->slice_pitch);
4147 size = (box->back - box->front - 1) * map_desc->slice_pitch
4148 + ((box->bottom - box->top - 1) / format->block_height) * map_desc->row_pitch
4149 + ((box->right - box->left + format->block_width - 1) / format->block_width) * format->block_byte_count;
4151 if (!(flags & WINED3D_MAP_WRITE))
4153 WARN("Flags %#x are not valid on a deferred context.\n", flags);
4154 return false;
4157 if (flags & ~(WINED3D_MAP_WRITE | WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE))
4159 FIXME("Unhandled flags %#x.\n", flags);
4160 return false;
4163 if (flags & WINED3D_MAP_NOOVERWRITE)
4165 if (!(upload = deferred_context_get_upload(deferred, resource, sub_resource_idx)))
4166 return false;
4168 upload->upload_flags = 0;
4169 map_desc->data = (void *)align((size_t)upload->sysmem, RESOURCE_ALIGNMENT);
4170 return true;
4173 if (!wined3d_array_reserve((void **)&deferred->uploads, &deferred->uploads_capacity,
4174 deferred->upload_count + 1, sizeof(*deferred->uploads)))
4175 return false;
4177 if (!deferred->upload_heap)
4178 deferred->upload_heap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
4179 if (!deferred->upload_heap)
4181 ERR("Failed to create upload heap.\n");
4182 return false;
4185 if (!(sysmem = HeapAlloc(deferred->upload_heap, 0, size + RESOURCE_ALIGNMENT - 1)))
4186 return false;
4188 upload = &deferred->uploads[deferred->upload_count++];
4189 upload->upload_flags = UPLOAD_BO_UPLOAD_ON_UNMAP;
4190 upload->resource = resource;
4191 wined3d_resource_incref(resource);
4192 upload->sub_resource_idx = sub_resource_idx;
4193 upload->sysmem = sysmem;
4194 upload->box = *box;
4196 map_desc->data = (void *)align((size_t)upload->sysmem, RESOURCE_ALIGNMENT);
4197 return true;
4200 static bool wined3d_deferred_context_unmap_upload_bo(struct wined3d_device_context *context,
4201 struct wined3d_resource *resource, unsigned int sub_resource_idx, struct wined3d_box *box, struct upload_bo *bo)
4203 struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
4204 const struct wined3d_deferred_upload *upload;
4206 if ((upload = deferred_context_get_upload(deferred, resource, sub_resource_idx)))
4208 *box = upload->box;
4209 bo->addr.buffer_object = 0;
4210 bo->addr.addr = (uint8_t *)align((size_t)upload->sysmem, RESOURCE_ALIGNMENT);
4211 bo->flags = upload->upload_flags;
4212 return true;
4215 return false;
4218 static void wined3d_deferred_context_issue_query(struct wined3d_device_context *context,
4219 struct wined3d_query *query, unsigned int flags)
4221 struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
4222 struct wined3d_cs_query_issue *op;
4224 op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
4225 op->opcode = WINED3D_CS_OP_QUERY_ISSUE;
4226 op->query = query;
4227 op->flags = flags;
4229 wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT);
4231 if (!wined3d_array_reserve((void **)&deferred->queries, &deferred->queries_capacity,
4232 deferred->query_count + 1, sizeof(*deferred->queries)))
4234 ERR("Failed to reserve memory.\n");
4235 return;
4238 deferred->queries[deferred->query_count].flags = flags;
4239 wined3d_query_incref(deferred->queries[deferred->query_count++].query = query);
4242 static void wined3d_deferred_context_flush(struct wined3d_device_context *context)
4244 FIXME("context %p, stub!\n", context);
4247 static void wined3d_deferred_context_acquire_resource(struct wined3d_device_context *context,
4248 struct wined3d_resource *resource)
4250 struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
4252 if (!wined3d_array_reserve((void **)&deferred->resources, &deferred->resources_capacity,
4253 deferred->resource_count + 1, sizeof(*deferred->resources)))
4254 return;
4256 deferred->resources[deferred->resource_count++] = resource;
4257 wined3d_resource_incref(resource);
4260 static void wined3d_deferred_context_acquire_command_list(struct wined3d_device_context *context,
4261 struct wined3d_command_list *list)
4263 struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
4265 /* Grab a reference to the command list. Note that this implicitly prevents
4266 * any dependent command lists or resources from being freed as well. */
4267 if (!wined3d_array_reserve((void **)&deferred->command_lists, &deferred->command_lists_capacity,
4268 deferred->command_list_count + 1, sizeof(*deferred->command_lists)))
4269 return;
4271 wined3d_command_list_incref(deferred->command_lists[deferred->command_list_count++] = list);
4274 static const struct wined3d_device_context_ops wined3d_deferred_context_ops =
4276 wined3d_deferred_context_require_space,
4277 wined3d_deferred_context_submit,
4278 wined3d_deferred_context_finish,
4279 wined3d_deferred_context_push_constants,
4280 wined3d_deferred_context_map_upload_bo,
4281 wined3d_deferred_context_unmap_upload_bo,
4282 wined3d_deferred_context_issue_query,
4283 wined3d_deferred_context_flush,
4284 wined3d_deferred_context_acquire_resource,
4285 wined3d_deferred_context_acquire_command_list,
4288 HRESULT CDECL wined3d_deferred_context_create(struct wined3d_device *device, struct wined3d_device_context **context)
4290 struct wined3d_deferred_context *object;
4291 HRESULT hr;
4293 TRACE("device %p, context %p.\n", device, context);
4295 if (!(object = heap_alloc_zero(sizeof(*object))))
4296 return E_OUTOFMEMORY;
4298 if (FAILED(hr = wined3d_state_create(device, &device->cs->c.state->feature_level, 1, &object->c.state)))
4300 heap_free(object);
4301 return hr;
4304 object->c.ops = &wined3d_deferred_context_ops;
4305 object->c.device = device;
4307 /* Make sure the first command list gets the state reset when executed.
4308 * Resets for subsequent command lists are encoded in wined3d_deferred_context_record_command_list(). */
4309 wined3d_device_context_emit_reset_state(&object->c, true);
4311 TRACE("Created deferred context %p.\n", object);
4312 *context = &object->c;
4314 return S_OK;
4317 void CDECL wined3d_deferred_context_destroy(struct wined3d_device_context *context)
4319 struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
4320 const struct wined3d_cs_packet *packet;
4321 SIZE_T i, offset = 0;
4323 TRACE("context %p.\n", context);
4325 for (i = 0; i < deferred->resource_count; ++i)
4326 wined3d_resource_decref(deferred->resources[i]);
4327 heap_free(deferred->resources);
4329 for (i = 0; i < deferred->upload_count; ++i)
4330 wined3d_resource_decref(deferred->uploads[i].resource);
4331 if (deferred->upload_heap)
4332 HeapDestroy(deferred->upload_heap);
4333 heap_free(deferred->uploads);
4335 for (i = 0; i < deferred->command_list_count; ++i)
4336 wined3d_command_list_decref(deferred->command_lists[i]);
4337 heap_free(deferred->command_lists);
4339 for (i = 0; i < deferred->query_count; ++i)
4340 wined3d_query_decref(deferred->queries[i].query);
4341 heap_free(deferred->queries);
4343 while (offset < deferred->data_size)
4345 packet = wined3d_next_cs_packet(deferred->data, &offset);
4346 wined3d_cs_packet_decref_objects(packet);
4349 wined3d_state_destroy(deferred->c.state);
4350 heap_free(deferred->data);
4351 heap_free(deferred);
4354 HRESULT CDECL wined3d_deferred_context_record_command_list(struct wined3d_device_context *context,
4355 bool restore, struct wined3d_command_list **list)
4357 struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
4358 struct wined3d_command_list *object;
4359 void *memory;
4361 TRACE("context %p, list %p.\n", context, list);
4363 wined3d_device_context_lock(context);
4364 memory = heap_alloc(sizeof(*object) + deferred->resource_count * sizeof(*object->resources)
4365 + deferred->upload_count * sizeof(*object->uploads)
4366 + deferred->command_list_count * sizeof(*object->command_lists)
4367 + deferred->query_count * sizeof(*object->queries)
4368 + deferred->data_size);
4370 if (!memory)
4372 wined3d_device_context_unlock(context);
4373 return E_OUTOFMEMORY;
4376 object = memory;
4377 memory = &object[1];
4378 memset(object, 0, sizeof(*object));
4379 object->refcount = 1;
4380 object->device = deferred->c.device;
4382 object->resources = memory;
4383 memory = &object->resources[deferred->resource_count];
4384 object->resource_count = deferred->resource_count;
4385 memcpy(object->resources, deferred->resources, deferred->resource_count * sizeof(*object->resources));
4386 /* Transfer our references to the resources to the command list. */
4388 object->uploads = memory;
4389 memory = &object->uploads[deferred->upload_count];
4390 object->upload_count = deferred->upload_count;
4391 memcpy(object->uploads, deferred->uploads, deferred->upload_count * sizeof(*object->uploads));
4392 /* Transfer our references to the resources to the command list. */
4394 object->command_lists = memory;
4395 memory = &object->command_lists[deferred->command_list_count];
4396 object->command_list_count = deferred->command_list_count;
4397 memcpy(object->command_lists, deferred->command_lists,
4398 deferred->command_list_count * sizeof(*object->command_lists));
4399 /* Transfer our references to the command lists to the command list. */
4401 object->queries = memory;
4402 memory = &object->queries[deferred->query_count];
4403 object->query_count = deferred->query_count;
4404 memcpy(object->queries, deferred->queries, deferred->query_count * sizeof(*object->queries));
4405 /* Transfer our references to the queries to the command list. */
4407 object->data = memory;
4408 object->data_size = deferred->data_size;
4409 memcpy(object->data, deferred->data, deferred->data_size);
4411 deferred->data_size = 0;
4412 deferred->resource_count = 0;
4413 deferred->upload_count = 0;
4414 deferred->command_list_count = 0;
4415 deferred->query_count = 0;
4417 object->upload_heap = deferred->upload_heap;
4418 deferred->upload_heap = 0;
4420 /* This is in fact recorded into a subsequent command list. */
4421 if (restore)
4422 wined3d_device_context_set_state(&deferred->c, deferred->c.state);
4423 else
4424 wined3d_device_context_reset_state(&deferred->c);
4426 TRACE("Created command list %p.\n", object);
4427 *list = object;
4428 wined3d_device_context_unlock(context);
4430 return S_OK;
4433 static void wined3d_command_list_destroy_object(void *object)
4435 struct wined3d_command_list *list = object;
4437 TRACE("list %p.\n", list);
4439 if (list->upload_heap)
4440 HeapDestroy(list->upload_heap);
4441 heap_free(list);
4444 ULONG CDECL wined3d_command_list_incref(struct wined3d_command_list *list)
4446 ULONG refcount = InterlockedIncrement(&list->refcount);
4448 TRACE("%p increasing refcount to %u.\n", list, refcount);
4450 return refcount;
4453 ULONG CDECL wined3d_command_list_decref(struct wined3d_command_list *list)
4455 ULONG refcount = InterlockedDecrement(&list->refcount);
4456 struct wined3d_device *device = list->device;
4457 const struct wined3d_cs_packet *packet;
4458 SIZE_T i, offset;
4460 TRACE("%p decreasing refcount to %u.\n", list, refcount);
4462 if (!refcount)
4464 for (i = 0; i < list->command_list_count; ++i)
4465 wined3d_command_list_decref(list->command_lists[i]);
4466 for (i = 0; i < list->resource_count; ++i)
4467 wined3d_resource_decref(list->resources[i]);
4468 for (i = 0; i < list->upload_count; ++i)
4469 wined3d_resource_decref(list->uploads[i].resource);
4470 for (i = 0; i < list->query_count; ++i)
4471 wined3d_query_decref(list->queries[i].query);
4473 offset = 0;
4474 while (offset < list->data_size)
4476 packet = wined3d_next_cs_packet(list->data, &offset);
4477 wined3d_cs_packet_decref_objects(packet);
4480 wined3d_mutex_lock();
4481 wined3d_cs_destroy_object(device->cs, wined3d_command_list_destroy_object, list);
4482 wined3d_mutex_unlock();
4485 return refcount;