Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/servers/rendering/rendering_device_graph.cpp
20888 views
1
/**************************************************************************/
2
/* rendering_device_graph.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "rendering_device_graph.h"
32
33
#define PRINT_RENDER_GRAPH 0
34
#define FORCE_FULL_ACCESS_BITS 0
35
#define PRINT_RESOURCE_TRACKER_TOTAL 0
36
#define PRINT_COMMAND_RECORDING 0
37
38
// Prints the total number of bytes used for draw lists in a frame.
39
#define PRINT_DRAW_LIST_STATS 0
40
41
RenderingDeviceGraph::RenderingDeviceGraph() {
42
driver_honors_barriers = false;
43
driver_clears_with_copy_engine = false;
44
}
45
46
RenderingDeviceGraph::~RenderingDeviceGraph() {
47
}
48
49
String RenderingDeviceGraph::_usage_to_string(ResourceUsage p_usage) {
50
switch (p_usage) {
51
case RESOURCE_USAGE_NONE:
52
return "None";
53
case RESOURCE_USAGE_COPY_FROM:
54
return "Copy From";
55
case RESOURCE_USAGE_COPY_TO:
56
return "Copy To";
57
case RESOURCE_USAGE_RESOLVE_FROM:
58
return "Resolve From";
59
case RESOURCE_USAGE_RESOLVE_TO:
60
return "Resolve To";
61
case RESOURCE_USAGE_UNIFORM_BUFFER_READ:
62
return "Uniform Buffer Read";
63
case RESOURCE_USAGE_INDIRECT_BUFFER_READ:
64
return "Indirect Buffer Read";
65
case RESOURCE_USAGE_TEXTURE_BUFFER_READ:
66
return "Texture Buffer Read";
67
case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE:
68
return "Texture Buffer Read Write";
69
case RESOURCE_USAGE_STORAGE_BUFFER_READ:
70
return "Storage Buffer Read";
71
case RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE:
72
return "Storage Buffer Read Write";
73
case RESOURCE_USAGE_VERTEX_BUFFER_READ:
74
return "Vertex Buffer Read";
75
case RESOURCE_USAGE_INDEX_BUFFER_READ:
76
return "Index Buffer Read";
77
case RESOURCE_USAGE_TEXTURE_SAMPLE:
78
return "Texture Sample";
79
case RESOURCE_USAGE_STORAGE_IMAGE_READ:
80
return "Storage Image Read";
81
case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE:
82
return "Storage Image Read Write";
83
case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE:
84
return "Attachment Color Read Write";
85
case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE:
86
return "Attachment Depth Stencil Read Write";
87
case RESOURCE_USAGE_GENERAL:
88
return "General";
89
default:
90
ERR_FAIL_V_MSG("Invalid", vformat("Invalid resource usage %d.", p_usage));
91
}
92
}
93
94
bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) {
95
switch (p_usage) {
96
case RESOURCE_USAGE_COPY_FROM:
97
case RESOURCE_USAGE_RESOLVE_FROM:
98
case RESOURCE_USAGE_UNIFORM_BUFFER_READ:
99
case RESOURCE_USAGE_INDIRECT_BUFFER_READ:
100
case RESOURCE_USAGE_TEXTURE_BUFFER_READ:
101
case RESOURCE_USAGE_STORAGE_BUFFER_READ:
102
case RESOURCE_USAGE_VERTEX_BUFFER_READ:
103
case RESOURCE_USAGE_INDEX_BUFFER_READ:
104
case RESOURCE_USAGE_TEXTURE_SAMPLE:
105
case RESOURCE_USAGE_STORAGE_IMAGE_READ:
106
case RESOURCE_USAGE_ATTACHMENT_FRAGMENT_SHADING_RATE_READ:
107
case RESOURCE_USAGE_ATTACHMENT_FRAGMENT_DENSITY_MAP_READ:
108
case RESOURCE_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT:
109
case RESOURCE_USAGE_ACCELERATION_STRUCTURE_READ:
110
return false;
111
case RESOURCE_USAGE_COPY_TO:
112
case RESOURCE_USAGE_RESOLVE_TO:
113
case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE:
114
case RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE:
115
case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE:
116
case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE:
117
case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE:
118
case RESOURCE_USAGE_GENERAL:
119
case RESOURCE_USAGE_ACCELERATION_STRUCTURE_READ_WRITE:
120
return true;
121
default:
122
DEV_ASSERT(false && "Invalid resource tracker usage.");
123
return false;
124
}
125
}
126
127
RDD::TextureLayout RenderingDeviceGraph::_usage_to_image_layout(ResourceUsage p_usage) {
128
switch (p_usage) {
129
case RESOURCE_USAGE_COPY_FROM:
130
return RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL;
131
case RESOURCE_USAGE_COPY_TO:
132
return RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL;
133
case RESOURCE_USAGE_RESOLVE_FROM:
134
return RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL;
135
case RESOURCE_USAGE_RESOLVE_TO:
136
return RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL;
137
case RESOURCE_USAGE_TEXTURE_SAMPLE:
138
return RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
139
case RESOURCE_USAGE_STORAGE_IMAGE_READ:
140
case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE:
141
return RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL;
142
case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE:
143
return RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
144
case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE:
145
return RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
146
case RESOURCE_USAGE_ATTACHMENT_FRAGMENT_SHADING_RATE_READ:
147
return RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL;
148
case RESOURCE_USAGE_ATTACHMENT_FRAGMENT_DENSITY_MAP_READ:
149
return RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL;
150
case RESOURCE_USAGE_GENERAL:
151
return RDD::TEXTURE_LAYOUT_GENERAL;
152
case RESOURCE_USAGE_NONE:
153
return RDD::TEXTURE_LAYOUT_UNDEFINED;
154
default:
155
DEV_ASSERT(false && "Invalid resource tracker usage or not an image usage.");
156
return RDD::TEXTURE_LAYOUT_UNDEFINED;
157
}
158
}
159
160
RDD::BarrierAccessBits RenderingDeviceGraph::_usage_to_access_bits(ResourceUsage p_usage) {
161
#if FORCE_FULL_ACCESS_BITS
162
return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT);
163
#else
164
switch (p_usage) {
165
case RESOURCE_USAGE_NONE:
166
return RDD::BarrierAccessBits(0);
167
case RESOURCE_USAGE_COPY_FROM:
168
return RDD::BARRIER_ACCESS_COPY_READ_BIT;
169
case RESOURCE_USAGE_COPY_TO:
170
return RDD::BARRIER_ACCESS_COPY_WRITE_BIT;
171
case RESOURCE_USAGE_RESOLVE_FROM:
172
return RDD::BARRIER_ACCESS_RESOLVE_READ_BIT;
173
case RESOURCE_USAGE_RESOLVE_TO:
174
return RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT;
175
case RESOURCE_USAGE_UNIFORM_BUFFER_READ:
176
return RDD::BARRIER_ACCESS_UNIFORM_READ_BIT;
177
case RESOURCE_USAGE_INDIRECT_BUFFER_READ:
178
return RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT;
179
case RESOURCE_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT:
180
// Acceleration structure build inputs can be either storage buffers with vertices, indices, transforms, or
181
// other acceleration structures (BLAS)
182
return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_COPY_READ_BIT | RDD::BARRIER_ACCESS_ACCELERATION_STRUCTURE_READ_BIT);
183
case RESOURCE_USAGE_ACCELERATION_STRUCTURE_READ:
184
return RDD::BARRIER_ACCESS_ACCELERATION_STRUCTURE_READ_BIT;
185
case RESOURCE_USAGE_STORAGE_BUFFER_READ:
186
case RESOURCE_USAGE_STORAGE_IMAGE_READ:
187
case RESOURCE_USAGE_TEXTURE_BUFFER_READ:
188
case RESOURCE_USAGE_TEXTURE_SAMPLE:
189
return RDD::BARRIER_ACCESS_SHADER_READ_BIT;
190
case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE:
191
case RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE:
192
case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE:
193
return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_SHADER_READ_BIT | RDD::BARRIER_ACCESS_SHADER_WRITE_BIT);
194
case RESOURCE_USAGE_VERTEX_BUFFER_READ:
195
return RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
196
case RESOURCE_USAGE_INDEX_BUFFER_READ:
197
return RDD::BARRIER_ACCESS_INDEX_READ_BIT;
198
case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE:
199
return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
200
case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE:
201
return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
202
case RESOURCE_USAGE_ATTACHMENT_FRAGMENT_SHADING_RATE_READ:
203
return RDD::BARRIER_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT;
204
case RESOURCE_USAGE_ATTACHMENT_FRAGMENT_DENSITY_MAP_READ:
205
return RDD::BARRIER_ACCESS_FRAGMENT_DENSITY_MAP_ATTACHMENT_READ_BIT;
206
case RESOURCE_USAGE_GENERAL:
207
return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT);
208
case RESOURCE_USAGE_ACCELERATION_STRUCTURE_READ_WRITE:
209
return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_ACCELERATION_STRUCTURE_READ_BIT | RDD::BARRIER_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT);
210
default:
211
DEV_ASSERT(false && "Invalid usage.");
212
return RDD::BarrierAccessBits(0);
213
}
214
#endif
215
}
216
217
bool RenderingDeviceGraph::_check_command_intersection(ResourceTracker *p_resource_tracker, int32_t p_previous_command_index, int32_t p_command_index) const {
218
if (p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE && p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE) {
219
// We don't check possible intersections for usages that aren't consecutive color or depth writes.
220
return true;
221
}
222
223
const uint32_t previous_command_data_offset = command_data_offsets[p_previous_command_index];
224
const uint32_t current_command_data_offset = command_data_offsets[p_command_index];
225
const RecordedDrawListCommand &previous_draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[previous_command_data_offset]);
226
const RecordedDrawListCommand &current_draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[current_command_data_offset]);
227
if (previous_draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST || current_draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST) {
228
// We don't check possible intersections if both commands aren't draw lists.
229
return true;
230
}
231
232
// We check if the region used by both draw lists have an intersection.
233
return previous_draw_list_command.region.intersects(current_draw_list_command.region);
234
}
235
236
bool RenderingDeviceGraph::_check_command_partial_coverage(ResourceTracker *p_resource_tracker, int32_t p_command_index) const {
237
if (p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE && p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE) {
238
// We don't check for partial coverage in usages that aren't attachment writes.
239
return false;
240
}
241
242
const uint32_t command_data_offset = command_data_offsets[p_command_index];
243
const RecordedDrawListCommand &draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[command_data_offset]);
244
if (draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST) {
245
// We don't check for partial coverage on commands that aren't draw lists.
246
return false;
247
}
248
249
Rect2i texture_region(Point2i(0, 0), p_resource_tracker->texture_size);
250
return !draw_list_command.region.encloses(texture_region);
251
}
252
253
int32_t RenderingDeviceGraph::_add_to_command_list(int32_t p_command_index, int32_t p_list_index) {
254
DEV_ASSERT(p_command_index < int32_t(command_count));
255
DEV_ASSERT(p_list_index < int32_t(command_list_nodes.size()));
256
257
int32_t next_index = int32_t(command_list_nodes.size());
258
command_list_nodes.resize(next_index + 1);
259
260
RecordedCommandListNode &new_node = command_list_nodes[next_index];
261
new_node.command_index = p_command_index;
262
new_node.next_list_index = p_list_index;
263
return next_index;
264
}
265
266
void RenderingDeviceGraph::_add_adjacent_command(int32_t p_previous_command_index, int32_t p_command_index, RecordedCommand *r_command) {
267
const uint32_t previous_command_data_offset = command_data_offsets[p_previous_command_index];
268
RecordedCommand &previous_command = *reinterpret_cast<RecordedCommand *>(&command_data[previous_command_data_offset]);
269
previous_command.adjacent_command_list_index = _add_to_command_list(p_command_index, previous_command.adjacent_command_list_index);
270
previous_command.next_stages = previous_command.next_stages | r_command->self_stages;
271
r_command->previous_stages = r_command->previous_stages | previous_command.self_stages;
272
}
273
274
int32_t RenderingDeviceGraph::_add_to_slice_read_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index) {
275
DEV_ASSERT(p_command_index < int32_t(command_count));
276
DEV_ASSERT(p_list_index < int32_t(read_slice_list_nodes.size()));
277
278
int32_t next_index = int32_t(read_slice_list_nodes.size());
279
read_slice_list_nodes.resize(next_index + 1);
280
281
RecordedSliceListNode &new_node = read_slice_list_nodes[next_index];
282
new_node.command_index = p_command_index;
283
new_node.next_list_index = p_list_index;
284
new_node.subresources = p_subresources;
285
return next_index;
286
}
287
288
int32_t RenderingDeviceGraph::_add_to_write_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index, bool p_partial_coverage) {
289
DEV_ASSERT(p_command_index < int32_t(command_count));
290
DEV_ASSERT(p_list_index < int32_t(write_slice_list_nodes.size()));
291
292
int32_t next_index = int32_t(write_slice_list_nodes.size());
293
write_slice_list_nodes.resize(next_index + 1);
294
295
RecordedSliceListNode &new_node = write_slice_list_nodes[next_index];
296
new_node.command_index = p_command_index;
297
new_node.next_list_index = p_list_index;
298
new_node.subresources = p_subresources;
299
new_node.partial_coverage = p_partial_coverage;
300
return next_index;
301
}
302
303
// Ensures all commands are 8-byte aligned.
304
#define GRAPH_ALIGN(x) (((x) + 7u) & 0xFFFFFFF8u)
305
306
RenderingDeviceGraph::RecordedCommand *RenderingDeviceGraph::_allocate_command(uint32_t p_command_size, int32_t &r_command_index) {
307
uint32_t command_data_offset = command_data.size();
308
command_data_offset = GRAPH_ALIGN(command_data_offset);
309
command_data_offsets.push_back(command_data_offset);
310
command_data.resize(command_data_offset + p_command_size);
311
r_command_index = command_count++;
312
RecordedCommand *new_command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]);
313
*new_command = RecordedCommand();
314
return new_command;
315
}
316
317
RenderingDeviceGraph::DrawListInstruction *RenderingDeviceGraph::_allocate_draw_list_instruction(uint32_t p_instruction_size) {
318
uint32_t draw_list_data_offset = draw_instruction_list.data.size();
319
draw_list_data_offset = GRAPH_ALIGN(draw_list_data_offset);
320
draw_instruction_list.data.resize(draw_list_data_offset + p_instruction_size);
321
return reinterpret_cast<DrawListInstruction *>(&draw_instruction_list.data[draw_list_data_offset]);
322
}
323
324
RenderingDeviceGraph::ComputeListInstruction *RenderingDeviceGraph::_allocate_compute_list_instruction(uint32_t p_instruction_size) {
325
uint32_t compute_list_data_offset = compute_instruction_list.data.size();
326
compute_list_data_offset = GRAPH_ALIGN(compute_list_data_offset);
327
compute_instruction_list.data.resize(compute_list_data_offset + p_instruction_size);
328
return reinterpret_cast<ComputeListInstruction *>(&compute_instruction_list.data[compute_list_data_offset]);
329
}
330
331
void RenderingDeviceGraph::_check_discardable_attachment_dependency(ResourceTracker *p_resource_tracker, int32_t p_previous_command_index, int32_t p_command_index) {
332
if (!p_resource_tracker->is_discardable) {
333
return;
334
}
335
336
// Check if the command is a a draw list that clears the attachment completely. If it is, we don't need to modify the previous draw list.
337
uint32_t command_offset = command_data_offsets[p_command_index];
338
RecordedDrawListCommand *draw_list_command = reinterpret_cast<RecordedDrawListCommand *>(&command_data[command_offset]);
339
if (draw_list_command->type == RecordedCommand::TYPE_DRAW_LIST) {
340
ResourceTracker **trackers = draw_list_command->trackers();
341
for (uint32_t i = 0; i < draw_list_command->trackers_count; i++) {
342
if (trackers[i] == p_resource_tracker && draw_list_command->load_ops()[i] == RDD::ATTACHMENT_LOAD_OP_CLEAR) {
343
return;
344
}
345
}
346
}
347
348
// Check if the previous command is a draw list.
349
uint32_t previous_command_offset = command_data_offsets[p_previous_command_index];
350
RecordedDrawListCommand *previous_draw_list_command = reinterpret_cast<RecordedDrawListCommand *>(&command_data[previous_command_offset]);
351
if (previous_draw_list_command->type != RecordedCommand::TYPE_DRAW_LIST) {
352
return;
353
}
354
355
// Search for the tracker inside the draw list command and modify the store operation accordingly.
356
ResourceTracker **trackers = previous_draw_list_command->trackers();
357
for (uint32_t i = 0; i < previous_draw_list_command->trackers_count; i++) {
358
if (trackers[i] == p_resource_tracker) {
359
previous_draw_list_command->store_ops()[i] = RDD::ATTACHMENT_STORE_OP_STORE;
360
return;
361
}
362
}
363
}
364
365
RenderingDeviceGraph::RaytracingListInstruction *RenderingDeviceGraph::_allocate_raytracing_list_instruction(uint32_t p_instruction_size) {
366
uint32_t raytracing_list_data_offset = raytracing_instruction_list.data.size();
367
raytracing_instruction_list.data.resize(raytracing_list_data_offset + p_instruction_size);
368
return reinterpret_cast<RaytracingListInstruction *>(&raytracing_instruction_list.data[raytracing_list_data_offset]);
369
}
370
371
void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_trackers, ResourceUsage *p_resource_usages, uint32_t p_resource_count, int32_t p_command_index, RecordedCommand *r_command) {
372
// Assign the next stages derived from the stages the command requires first.
373
r_command->next_stages = r_command->self_stages;
374
375
if (command_label_index >= 0) {
376
// If a label is active, tag the command with the label.
377
r_command->label_index = command_label_index;
378
}
379
380
if (r_command->type == RecordedCommand::TYPE_CAPTURE_TIMESTAMP) {
381
// All previous commands starting from the previous timestamp should be adjacent to this command.
382
int32_t start_command_index = uint32_t(MAX(command_timestamp_index, 0));
383
for (int32_t i = start_command_index; i < p_command_index; i++) {
384
_add_adjacent_command(i, p_command_index, r_command);
385
}
386
387
// Make this command the new active timestamp command.
388
command_timestamp_index = p_command_index;
389
} else if (command_timestamp_index >= 0) {
390
// Timestamp command should be adjacent to this command.
391
_add_adjacent_command(command_timestamp_index, p_command_index, r_command);
392
}
393
394
if (command_synchronization_pending) {
395
// All previous commands should be adjacent to this command.
396
int32_t start_command_index = uint32_t(MAX(command_synchronization_index, 0));
397
for (int32_t i = start_command_index; i < p_command_index; i++) {
398
_add_adjacent_command(i, p_command_index, r_command);
399
}
400
401
command_synchronization_index = p_command_index;
402
command_synchronization_pending = false;
403
} else if (command_synchronization_index >= 0) {
404
// Synchronization command should be adjacent to this command.
405
_add_adjacent_command(command_synchronization_index, p_command_index, r_command);
406
}
407
408
for (uint32_t i = 0; i < p_resource_count; i++) {
409
ResourceTracker *resource_tracker = p_resource_trackers[i];
410
DEV_ASSERT(resource_tracker != nullptr);
411
412
resource_tracker->reset_if_outdated(tracking_frame);
413
414
const RDD::TextureSubresourceRange &subresources = resource_tracker->texture_subresources;
415
const Rect2i resource_tracker_rect(subresources.base_mipmap, subresources.base_layer, subresources.mipmap_count, subresources.layer_count);
416
Rect2i search_tracker_rect = resource_tracker_rect;
417
418
ResourceUsage new_resource_usage = p_resource_usages[i];
419
bool write_usage = _is_write_usage(new_resource_usage);
420
BitField<RDD::BarrierAccessBits> new_usage_access = _usage_to_access_bits(new_resource_usage);
421
bool is_resource_a_slice = resource_tracker->parent != nullptr;
422
if (is_resource_a_slice) {
423
// This resource depends on a parent resource.
424
resource_tracker->parent->reset_if_outdated(tracking_frame);
425
426
if (resource_tracker->texture_slice_command_index != p_command_index) {
427
// Indicate this slice has been used by this command.
428
resource_tracker->texture_slice_command_index = p_command_index;
429
}
430
431
if (resource_tracker->parent->usage == RESOURCE_USAGE_NONE) {
432
if (resource_tracker->parent->texture_driver_id.id != 0) {
433
// If the resource is a texture, we transition it entirely to the layout determined by the first slice that uses it.
434
_add_texture_barrier_to_command(resource_tracker->parent->texture_driver_id, RDD::BarrierAccessBits(0), new_usage_access, RDG::RESOURCE_USAGE_NONE, new_resource_usage, resource_tracker->parent->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
435
}
436
437
// If the parent hasn't been used yet, we assign the usage of the slice to the entire resource.
438
resource_tracker->parent->usage = new_resource_usage;
439
440
// Also assign the usage to the slice and consider it a write operation. Consider the parent's current usage access as its own.
441
resource_tracker->usage = new_resource_usage;
442
resource_tracker->usage_access = resource_tracker->parent->usage_access;
443
write_usage = true;
444
445
// Indicate the area that should be tracked is the entire resource.
446
const RDD::TextureSubresourceRange &parent_subresources = resource_tracker->parent->texture_subresources;
447
search_tracker_rect = Rect2i(parent_subresources.base_mipmap, parent_subresources.base_layer, parent_subresources.mipmap_count, parent_subresources.layer_count);
448
} else if (resource_tracker->in_parent_dirty_list) {
449
if (resource_tracker->parent->usage == new_resource_usage) {
450
// The slice will be transitioned to the resource of the parent and can be deleted from the dirty list.
451
ResourceTracker *previous_tracker = nullptr;
452
ResourceTracker *current_tracker = resource_tracker->parent->dirty_shared_list;
453
bool initialized_dirty_rect = false;
454
while (current_tracker != nullptr) {
455
current_tracker->reset_if_outdated(tracking_frame);
456
457
if (current_tracker == resource_tracker) {
458
current_tracker->in_parent_dirty_list = false;
459
460
if (previous_tracker != nullptr) {
461
previous_tracker->next_shared = current_tracker->next_shared;
462
} else {
463
resource_tracker->parent->dirty_shared_list = current_tracker->next_shared;
464
}
465
466
current_tracker = current_tracker->next_shared;
467
} else {
468
if (initialized_dirty_rect) {
469
resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->parent->texture_slice_or_dirty_rect.merge(current_tracker->texture_slice_or_dirty_rect);
470
} else {
471
resource_tracker->parent->texture_slice_or_dirty_rect = current_tracker->texture_slice_or_dirty_rect;
472
initialized_dirty_rect = true;
473
}
474
475
previous_tracker = current_tracker;
476
current_tracker = current_tracker->next_shared;
477
}
478
}
479
}
480
} else {
481
if (resource_tracker->parent->dirty_shared_list != nullptr && resource_tracker->parent->texture_slice_or_dirty_rect.intersects(resource_tracker->texture_slice_or_dirty_rect)) {
482
// There's an intersection with the current dirty area of the parent and the slice. We must verify if the intersection is against a slice
483
// that was used in this command or not. Any slice we can find that wasn't used by this command must be reverted to the layout of the parent.
484
ResourceTracker *previous_tracker = nullptr;
485
ResourceTracker *current_tracker = resource_tracker->parent->dirty_shared_list;
486
bool initialized_dirty_rect = false;
487
while (current_tracker != nullptr) {
488
current_tracker->reset_if_outdated(tracking_frame);
489
490
if (current_tracker->texture_slice_or_dirty_rect.intersects(resource_tracker->texture_slice_or_dirty_rect)) {
491
if (current_tracker->command_frame == tracking_frame && current_tracker->texture_slice_command_index == p_command_index) {
492
ERR_FAIL_MSG("Texture slices that overlap can't be used in the same command.");
493
} else {
494
// Delete the slice from the dirty list and revert it to the usage of the parent.
495
if (current_tracker->texture_driver_id.id != 0) {
496
_add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->parent->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
497
498
// Merge the area of the slice with the current tracking area of the command and indicate it's a write usage as well.
499
search_tracker_rect = search_tracker_rect.merge(current_tracker->texture_slice_or_dirty_rect);
500
write_usage = true;
501
}
502
503
current_tracker->in_parent_dirty_list = false;
504
505
if (previous_tracker != nullptr) {
506
previous_tracker->next_shared = current_tracker->next_shared;
507
} else {
508
resource_tracker->parent->dirty_shared_list = current_tracker->next_shared;
509
}
510
511
current_tracker = current_tracker->next_shared;
512
}
513
} else {
514
// Recalculate the dirty rect of the parent so the deleted slices are excluded.
515
if (initialized_dirty_rect) {
516
resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->parent->texture_slice_or_dirty_rect.merge(current_tracker->texture_slice_or_dirty_rect);
517
} else {
518
resource_tracker->parent->texture_slice_or_dirty_rect = current_tracker->texture_slice_or_dirty_rect;
519
initialized_dirty_rect = true;
520
}
521
522
previous_tracker = current_tracker;
523
current_tracker = current_tracker->next_shared;
524
}
525
}
526
}
527
528
// If it wasn't in the list, assume the usage is the same as the parent. Consider the parent's current usage access as its own.
529
resource_tracker->usage = resource_tracker->parent->usage;
530
resource_tracker->usage_access = resource_tracker->parent->usage_access;
531
532
if (resource_tracker->usage != new_resource_usage) {
533
// Insert to the dirty list if the requested usage is different.
534
resource_tracker->next_shared = resource_tracker->parent->dirty_shared_list;
535
resource_tracker->parent->dirty_shared_list = resource_tracker;
536
resource_tracker->in_parent_dirty_list = true;
537
if (resource_tracker->parent->dirty_shared_list != nullptr) {
538
resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->parent->texture_slice_or_dirty_rect.merge(resource_tracker->texture_slice_or_dirty_rect);
539
} else {
540
resource_tracker->parent->texture_slice_or_dirty_rect = resource_tracker->texture_slice_or_dirty_rect;
541
}
542
}
543
}
544
} else {
545
ResourceTracker *current_tracker = resource_tracker->dirty_shared_list;
546
if (current_tracker != nullptr) {
547
// Consider the usage as write if we must transition any of the slices.
548
write_usage = true;
549
}
550
551
while (current_tracker != nullptr) {
552
current_tracker->reset_if_outdated(tracking_frame);
553
554
if (current_tracker->texture_driver_id.id != 0) {
555
// Transition all slices to the layout of the parent resource.
556
_add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
557
}
558
559
current_tracker->in_parent_dirty_list = false;
560
current_tracker = current_tracker->next_shared;
561
}
562
563
resource_tracker->dirty_shared_list = nullptr;
564
}
565
566
// Use the resource's parent tracker directly for all search operations.
567
bool resource_has_parent = resource_tracker->parent != nullptr;
568
ResourceTracker *search_tracker = resource_has_parent ? resource_tracker->parent : resource_tracker;
569
bool different_usage = resource_tracker->usage != new_resource_usage;
570
bool write_usage_after_write = (write_usage && search_tracker->write_command_or_list_index >= 0);
571
if (different_usage || write_usage_after_write) {
572
// A barrier must be pushed if the usage is different of it's a write usage and there was already a command that wrote to this resource previously.
573
if (resource_tracker->texture_driver_id.id != 0) {
574
if (resource_tracker->usage_access.is_empty()) {
575
// FIXME: If the tracker does not know the previous type of usage, assume the generic memory write one.
576
// Tracking access bits across texture slices can be tricky, so this failsafe can be removed once that's improved.
577
resource_tracker->usage_access = RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT;
578
}
579
580
_add_texture_barrier_to_command(resource_tracker->texture_driver_id, resource_tracker->usage_access, new_usage_access, resource_tracker->usage, new_resource_usage, resource_tracker->texture_subresources, command_transition_barriers, r_command->transition_barrier_index, r_command->transition_barrier_count);
581
} else if (resource_tracker->buffer_driver_id.id != 0) {
582
#if USE_BUFFER_BARRIERS
583
_add_buffer_barrier_to_command(resource_tracker->buffer_driver_id, resource_tracker->usage_access, new_usage_access, r_command->buffer_barrier_index, r_command->buffer_barrier_count);
584
#endif
585
// Memory barriers are pushed regardless of buffer barriers being used or not.
586
r_command->memory_barrier.src_access = r_command->memory_barrier.src_access | resource_tracker->usage_access;
587
r_command->memory_barrier.dst_access = r_command->memory_barrier.dst_access | new_usage_access;
588
} else if (resource_tracker->acceleration_structure_driver_id.id != 0) {
589
// Make sure the acceleration structure has been built before accessing it from raytracing shaders.
590
_add_acceleration_structure_barrier_to_command(resource_tracker->acceleration_structure_driver_id, resource_tracker->usage_access, new_usage_access, command_acceleration_structure_barriers, r_command->acceleration_structure_barrier_index, r_command->acceleration_structure_barrier_count);
591
r_command->memory_barrier.src_access = r_command->memory_barrier.src_access | resource_tracker->usage_access;
592
r_command->memory_barrier.dst_access = r_command->memory_barrier.dst_access | new_usage_access;
593
} else {
594
DEV_ASSERT(false && "Resource tracker does not contain a valid buffer or texture ID.");
595
}
596
}
597
598
// Always update the access of the tracker according to the latest usage.
599
resource_tracker->usage_access = new_usage_access;
600
601
// Always accumulate the stages of the tracker with the commands that use it.
602
search_tracker->current_frame_stages = search_tracker->current_frame_stages | r_command->self_stages;
603
604
if (!search_tracker->previous_frame_stages.is_empty()) {
605
// Add to the command the stages the tracker was used on in the previous frame.
606
r_command->previous_stages = r_command->previous_stages | search_tracker->previous_frame_stages;
607
search_tracker->previous_frame_stages.clear();
608
}
609
610
if (different_usage) {
611
// Even if the usage of the resource isn't a write usage explicitly, a different usage implies a transition and it should therefore be considered a write.
612
// In the case of buffers however, this is not exactly necessary if the driver does not consider different buffer usages as different states.
613
write_usage = write_usage || bool(resource_tracker->texture_driver_id) || driver_buffers_require_transitions;
614
resource_tracker->usage = new_resource_usage;
615
}
616
617
bool write_usage_has_partial_coverage = !different_usage && _check_command_partial_coverage(resource_tracker, p_command_index);
618
if (search_tracker->write_command_or_list_index >= 0) {
619
if (search_tracker->write_command_list_enabled) {
620
// Make this command adjacent to any commands that wrote to this resource and intersect with the slice if it applies.
621
// For buffers or textures that never use slices, this list will only be one element long at most.
622
int32_t previous_write_list_index = -1;
623
int32_t write_list_index = search_tracker->write_command_or_list_index;
624
while (write_list_index >= 0) {
625
const RecordedSliceListNode &write_list_node = write_slice_list_nodes[write_list_index];
626
if (!resource_has_parent || search_tracker_rect.intersects(write_list_node.subresources)) {
627
if (write_list_node.command_index == p_command_index) {
628
ERR_FAIL_COND_MSG(!resource_has_parent, "Command can't have itself as a dependency.");
629
} else if (!write_list_node.partial_coverage || _check_command_intersection(resource_tracker, write_list_node.command_index, p_command_index)) {
630
_check_discardable_attachment_dependency(search_tracker, write_list_node.command_index, p_command_index);
631
632
// Command is dependent on this command. Add this command to the adjacency list of the write command.
633
_add_adjacent_command(write_list_node.command_index, p_command_index, r_command);
634
635
if (resource_has_parent && write_usage && search_tracker_rect.encloses(write_list_node.subresources) && !write_usage_has_partial_coverage) {
636
// Eliminate redundant writes from the list.
637
if (previous_write_list_index >= 0) {
638
RecordedSliceListNode &previous_list_node = write_slice_list_nodes[previous_write_list_index];
639
previous_list_node.next_list_index = write_list_node.next_list_index;
640
} else {
641
search_tracker->write_command_or_list_index = write_list_node.next_list_index;
642
}
643
644
write_list_index = write_list_node.next_list_index;
645
continue;
646
}
647
}
648
}
649
650
previous_write_list_index = write_list_index;
651
write_list_index = write_list_node.next_list_index;
652
}
653
} else {
654
// The index is just the latest command index that wrote to the resource.
655
if (search_tracker->write_command_or_list_index == p_command_index) {
656
ERR_FAIL_MSG("Command can't have itself as a dependency.");
657
} else {
658
_check_discardable_attachment_dependency(search_tracker, search_tracker->write_command_or_list_index, p_command_index);
659
_add_adjacent_command(search_tracker->write_command_or_list_index, p_command_index, r_command);
660
}
661
}
662
}
663
664
if (write_usage) {
665
bool use_write_list = resource_has_parent || write_usage_has_partial_coverage;
666
if (use_write_list) {
667
if (!search_tracker->write_command_list_enabled && search_tracker->write_command_or_list_index >= 0) {
668
// Write command list was not being used but there was a write command recorded. Add a new node with the entire parent resource's subresources and the recorded command index to the list.
669
const RDD::TextureSubresourceRange &tracker_subresources = search_tracker->texture_subresources;
670
Rect2i tracker_rect(tracker_subresources.base_mipmap, tracker_subresources.base_layer, tracker_subresources.mipmap_count, tracker_subresources.layer_count);
671
search_tracker->write_command_or_list_index = _add_to_write_list(search_tracker->write_command_or_list_index, tracker_rect, -1, false);
672
}
673
674
search_tracker->write_command_or_list_index = _add_to_write_list(p_command_index, search_tracker_rect, search_tracker->write_command_or_list_index, write_usage_has_partial_coverage);
675
search_tracker->write_command_list_enabled = true;
676
} else {
677
search_tracker->write_command_or_list_index = p_command_index;
678
search_tracker->write_command_list_enabled = false;
679
}
680
681
// We add this command to the adjacency list of all commands that were reading from the entire resource.
682
int32_t read_full_command_list_index = search_tracker->read_full_command_list_index;
683
while (read_full_command_list_index >= 0) {
684
int32_t read_full_command_index = command_list_nodes[read_full_command_list_index].command_index;
685
int32_t read_full_next_index = command_list_nodes[read_full_command_list_index].next_list_index;
686
if (read_full_command_index == p_command_index) {
687
if (!resource_has_parent) {
688
// Only slices are allowed to be in different usages in the same command as they are guaranteed to have no overlap in the same command.
689
ERR_FAIL_MSG("Command can't have itself as a dependency.");
690
}
691
} else {
692
// Add this command to the adjacency list of each command that was reading this resource.
693
_add_adjacent_command(read_full_command_index, p_command_index, r_command);
694
}
695
696
read_full_command_list_index = read_full_next_index;
697
}
698
699
if (!use_write_list) {
700
// Clear the full list if this resource is not a slice.
701
search_tracker->read_full_command_list_index = -1;
702
}
703
704
// We add this command to the adjacency list of all commands that were reading from resource slices.
705
int32_t previous_slice_command_list_index = -1;
706
int32_t read_slice_command_list_index = search_tracker->read_slice_command_list_index;
707
while (read_slice_command_list_index >= 0) {
708
const RecordedSliceListNode &read_list_node = read_slice_list_nodes[read_slice_command_list_index];
709
if (!use_write_list || search_tracker_rect.encloses(read_list_node.subresources)) {
710
if (previous_slice_command_list_index >= 0) {
711
// Erase this element and connect the previous one to the next element.
712
read_slice_list_nodes[previous_slice_command_list_index].next_list_index = read_list_node.next_list_index;
713
} else {
714
// Erase this element from the head of the list.
715
DEV_ASSERT(search_tracker->read_slice_command_list_index == read_slice_command_list_index);
716
search_tracker->read_slice_command_list_index = read_list_node.next_list_index;
717
}
718
719
// Advance to the next element.
720
read_slice_command_list_index = read_list_node.next_list_index;
721
} else {
722
previous_slice_command_list_index = read_slice_command_list_index;
723
read_slice_command_list_index = read_list_node.next_list_index;
724
}
725
726
if (!resource_has_parent || search_tracker_rect.intersects(read_list_node.subresources)) {
727
// Add this command to the adjacency list of each command that was reading this resource.
728
// We only add the dependency if there's an intersection between slices or this resource isn't a slice.
729
_add_adjacent_command(read_list_node.command_index, p_command_index, r_command);
730
}
731
}
732
} else if (resource_has_parent) {
733
// We add a read dependency to the tracker to indicate this command reads from the resource slice.
734
search_tracker->read_slice_command_list_index = _add_to_slice_read_list(p_command_index, resource_tracker_rect, search_tracker->read_slice_command_list_index);
735
} else {
736
// We add a read dependency to the tracker to indicate this command reads from the entire resource.
737
search_tracker->read_full_command_list_index = _add_to_command_list(p_command_index, search_tracker->read_full_command_list_index);
738
}
739
}
740
}
741
742
void RenderingDeviceGraph::_add_texture_barrier_to_command(RDD::TextureID p_texture_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, ResourceUsage p_prev_usage, ResourceUsage p_next_usage, RDD::TextureSubresourceRange p_subresources, LocalVector<RDD::TextureBarrier> &r_barrier_vector, int32_t &r_barrier_index, int32_t &r_barrier_count) {
743
if (!driver_honors_barriers) {
744
return;
745
}
746
747
if (r_barrier_index < 0) {
748
r_barrier_index = r_barrier_vector.size();
749
}
750
751
RDD::TextureBarrier texture_barrier;
752
texture_barrier.texture = p_texture_id;
753
texture_barrier.src_access = p_src_access;
754
texture_barrier.dst_access = p_dst_access;
755
texture_barrier.prev_layout = _usage_to_image_layout(p_prev_usage);
756
texture_barrier.next_layout = _usage_to_image_layout(p_next_usage);
757
texture_barrier.subresources = p_subresources;
758
r_barrier_vector.push_back(texture_barrier);
759
r_barrier_count++;
760
}
761
762
#if USE_BUFFER_BARRIERS
763
void RenderingDeviceGraph::_add_buffer_barrier_to_command(RDD::BufferID p_buffer_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, int32_t &r_barrier_index, int32_t &r_barrier_count) {
764
if (!driver_honors_barriers) {
765
return;
766
}
767
768
if (r_barrier_index < 0) {
769
r_barrier_index = command_buffer_barriers.size();
770
}
771
772
RDD::BufferBarrier buffer_barrier;
773
buffer_barrier.buffer = p_buffer_id;
774
buffer_barrier.src_access = p_src_access;
775
buffer_barrier.dst_access = p_dst_access;
776
buffer_barrier.offset = 0;
777
buffer_barrier.size = RDD::BUFFER_WHOLE_SIZE;
778
command_buffer_barriers.push_back(buffer_barrier);
779
r_barrier_count++;
780
}
781
#endif
782
783
void RenderingDeviceGraph::_add_acceleration_structure_barrier_to_command(RDD::AccelerationStructureID p_acceleration_structure_id, BitField<RDD::BarrierAccessBits> p_src_access, BitField<RDD::BarrierAccessBits> p_dst_access, LocalVector<RDD::AccelerationStructureBarrier> &r_barrier_vector, int32_t &r_barrier_index, int32_t &r_barrier_count) {
784
if (!driver_honors_barriers) {
785
return;
786
}
787
788
if (r_barrier_index < 0) {
789
r_barrier_index = r_barrier_vector.size();
790
}
791
792
RDD::AccelerationStructureBarrier accel_barrier;
793
accel_barrier.acceleration_structure = p_acceleration_structure_id;
794
accel_barrier.src_access = p_src_access;
795
accel_barrier.dst_access = p_dst_access;
796
accel_barrier.offset = 0;
797
accel_barrier.size = RDD::BUFFER_WHOLE_SIZE;
798
r_barrier_vector.push_back(accel_barrier);
799
r_barrier_count++;
800
}
801
802
void RenderingDeviceGraph::_run_raytracing_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
803
uint32_t instruction_data_cursor = 0;
804
while (instruction_data_cursor < p_instruction_data_size) {
805
DEV_ASSERT((instruction_data_cursor + sizeof(RaytracingListInstruction)) <= p_instruction_data_size);
806
807
const RaytracingListInstruction *instruction = reinterpret_cast<const RaytracingListInstruction *>(&p_instruction_data[instruction_data_cursor]);
808
switch (instruction->type) {
809
case RaytracingListInstruction::TYPE_BIND_PIPELINE: {
810
const RaytracingListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const RaytracingListBindPipelineInstruction *>(instruction);
811
driver->command_bind_raytracing_pipeline(p_command_buffer, bind_pipeline_instruction->pipeline);
812
instruction_data_cursor += sizeof(RaytracingListBindPipelineInstruction);
813
} break;
814
case RaytracingListInstruction::TYPE_BIND_UNIFORM_SET: {
815
const RaytracingListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const RaytracingListBindUniformSetInstruction *>(instruction);
816
driver->command_bind_raytracing_uniform_set(p_command_buffer, bind_uniform_set_instruction->uniform_set, bind_uniform_set_instruction->shader, bind_uniform_set_instruction->set_index);
817
instruction_data_cursor += sizeof(RaytracingListBindUniformSetInstruction);
818
} break;
819
case RaytracingListInstruction::TYPE_TRACE_RAYS: {
820
const RaytracingListTraceRaysInstruction *trace_rays_instruction = reinterpret_cast<const RaytracingListTraceRaysInstruction *>(instruction);
821
driver->command_trace_rays(p_command_buffer, trace_rays_instruction->width, trace_rays_instruction->height);
822
instruction_data_cursor += sizeof(RaytracingListTraceRaysInstruction);
823
} break;
824
case RaytracingListInstruction::TYPE_SET_PUSH_CONSTANT: {
825
const RaytracingListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const RaytracingListSetPushConstantInstruction *>(instruction);
826
const VectorView push_constant_data_view(reinterpret_cast<const uint32_t *>(set_push_constant_instruction->data()), set_push_constant_instruction->size / sizeof(uint32_t));
827
driver->command_bind_push_constants(p_command_buffer, set_push_constant_instruction->shader, 0, push_constant_data_view);
828
instruction_data_cursor += sizeof(RaytracingListSetPushConstantInstruction);
829
instruction_data_cursor += set_push_constant_instruction->size;
830
} break;
831
case RaytracingListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
832
const RaytracingListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const RaytracingListUniformSetPrepareForUseInstruction *>(instruction);
833
driver->command_uniform_set_prepare_for_use(p_command_buffer, uniform_set_prepare_for_use_instruction->uniform_set, uniform_set_prepare_for_use_instruction->shader, uniform_set_prepare_for_use_instruction->set_index);
834
instruction_data_cursor += sizeof(RaytracingListUniformSetPrepareForUseInstruction);
835
} break;
836
default:
837
DEV_ASSERT(false && "Unknown raytracing list instruction type.");
838
return;
839
}
840
}
841
}
842
843
void RenderingDeviceGraph::_run_compute_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
844
uint32_t instruction_data_cursor = 0;
845
while (instruction_data_cursor < p_instruction_data_size) {
846
DEV_ASSERT((instruction_data_cursor + sizeof(ComputeListInstruction)) <= p_instruction_data_size);
847
848
const ComputeListInstruction *instruction = reinterpret_cast<const ComputeListInstruction *>(&p_instruction_data[instruction_data_cursor]);
849
switch (instruction->type) {
850
case ComputeListInstruction::TYPE_BIND_PIPELINE: {
851
const ComputeListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const ComputeListBindPipelineInstruction *>(instruction);
852
driver->command_bind_compute_pipeline(p_command_buffer, bind_pipeline_instruction->pipeline);
853
instruction_data_cursor += sizeof(ComputeListBindPipelineInstruction);
854
} break;
855
case ComputeListInstruction::TYPE_BIND_UNIFORM_SETS: {
856
const ComputeListBindUniformSetsInstruction *bind_uniform_sets_instruction = reinterpret_cast<const ComputeListBindUniformSetsInstruction *>(instruction);
857
driver->command_bind_compute_uniform_sets(p_command_buffer, VectorView<RDD::UniformSetID>(bind_uniform_sets_instruction->uniform_set_ids(), bind_uniform_sets_instruction->set_count), bind_uniform_sets_instruction->shader, bind_uniform_sets_instruction->first_set_index, bind_uniform_sets_instruction->set_count, bind_uniform_sets_instruction->dynamic_offsets_mask);
858
instruction_data_cursor += sizeof(ComputeListBindUniformSetsInstruction) + sizeof(RDD::UniformSetID) * bind_uniform_sets_instruction->set_count;
859
} break;
860
case ComputeListInstruction::TYPE_DISPATCH: {
861
const ComputeListDispatchInstruction *dispatch_instruction = reinterpret_cast<const ComputeListDispatchInstruction *>(instruction);
862
driver->command_compute_dispatch(p_command_buffer, dispatch_instruction->x_groups, dispatch_instruction->y_groups, dispatch_instruction->z_groups);
863
instruction_data_cursor += sizeof(ComputeListDispatchInstruction);
864
} break;
865
case ComputeListInstruction::TYPE_DISPATCH_INDIRECT: {
866
const ComputeListDispatchIndirectInstruction *dispatch_indirect_instruction = reinterpret_cast<const ComputeListDispatchIndirectInstruction *>(instruction);
867
driver->command_compute_dispatch_indirect(p_command_buffer, dispatch_indirect_instruction->buffer, dispatch_indirect_instruction->offset);
868
instruction_data_cursor += sizeof(ComputeListDispatchIndirectInstruction);
869
} break;
870
case ComputeListInstruction::TYPE_SET_PUSH_CONSTANT: {
871
const ComputeListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const ComputeListSetPushConstantInstruction *>(instruction);
872
const VectorView push_constant_data_view(reinterpret_cast<const uint32_t *>(set_push_constant_instruction->data()), set_push_constant_instruction->size / sizeof(uint32_t));
873
driver->command_bind_push_constants(p_command_buffer, set_push_constant_instruction->shader, 0, push_constant_data_view);
874
instruction_data_cursor += sizeof(ComputeListSetPushConstantInstruction);
875
instruction_data_cursor += set_push_constant_instruction->size;
876
} break;
877
case ComputeListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
878
const ComputeListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const ComputeListUniformSetPrepareForUseInstruction *>(instruction);
879
driver->command_uniform_set_prepare_for_use(p_command_buffer, uniform_set_prepare_for_use_instruction->uniform_set, uniform_set_prepare_for_use_instruction->shader, uniform_set_prepare_for_use_instruction->set_index);
880
instruction_data_cursor += sizeof(ComputeListUniformSetPrepareForUseInstruction);
881
} break;
882
default:
883
DEV_ASSERT(false && "Unknown compute list instruction type.");
884
return;
885
}
886
887
instruction_data_cursor = GRAPH_ALIGN(instruction_data_cursor);
888
}
889
}
890
891
void RenderingDeviceGraph::_get_draw_list_render_pass_and_framebuffer(const RecordedDrawListCommand *p_draw_list_command, RDD::RenderPassID &r_render_pass, RDD::FramebufferID &r_framebuffer) {
892
DEV_ASSERT(p_draw_list_command->trackers_count <= 21 && "Max number of attachments that can be encoded into the key.");
893
894
// Build a unique key from the load and store ops for each attachment.
895
const RDD::AttachmentLoadOp *load_ops = p_draw_list_command->load_ops();
896
const RDD::AttachmentStoreOp *store_ops = p_draw_list_command->store_ops();
897
uint64_t key = 0;
898
for (uint32_t i = 0; i < p_draw_list_command->trackers_count; i++) {
899
key |= uint64_t(load_ops[i]) << (i * 3);
900
key |= uint64_t(store_ops[i]) << (i * 3 + 2);
901
}
902
903
// Check the storage map if the render pass and the framebuffer needs to be created.
904
FramebufferCache *framebuffer_cache = p_draw_list_command->framebuffer_cache;
905
HashMap<uint64_t, FramebufferStorage>::Iterator it = framebuffer_cache->storage_map.find(key);
906
if (it == framebuffer_cache->storage_map.end()) {
907
FramebufferStorage storage;
908
VectorView<RDD::AttachmentLoadOp> load_ops_view(load_ops, p_draw_list_command->trackers_count);
909
VectorView<RDD::AttachmentStoreOp> store_ops_view(store_ops, p_draw_list_command->trackers_count);
910
storage.render_pass = render_pass_creation_function(driver, load_ops_view, store_ops_view, framebuffer_cache->render_pass_creation_user_data);
911
ERR_FAIL_COND(!storage.render_pass);
912
913
storage.framebuffer = driver->framebuffer_create(storage.render_pass, framebuffer_cache->textures, framebuffer_cache->width, framebuffer_cache->height);
914
ERR_FAIL_COND(!storage.framebuffer);
915
916
it = framebuffer_cache->storage_map.insert(key, storage);
917
}
918
919
r_render_pass = it->value.render_pass;
920
r_framebuffer = it->value.framebuffer;
921
}
922
923
#if PRINT_DRAW_LIST_STATS
924
static uint32_t draw_list_total_size = 0;
925
#endif
926
927
void RenderingDeviceGraph::_run_draw_list_command(RDD::CommandBufferID p_command_buffer, const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
928
#if PRINT_DRAW_LIST_STATS
929
draw_list_total_size += p_instruction_data_size;
930
#endif
931
932
uint32_t instruction_data_cursor = 0;
933
while (instruction_data_cursor < p_instruction_data_size) {
934
DEV_ASSERT((instruction_data_cursor + sizeof(DrawListInstruction)) <= p_instruction_data_size);
935
936
const DrawListInstruction *instruction = reinterpret_cast<const DrawListInstruction *>(&p_instruction_data[instruction_data_cursor]);
937
switch (instruction->type) {
938
case DrawListInstruction::TYPE_BIND_INDEX_BUFFER: {
939
const DrawListBindIndexBufferInstruction *bind_index_buffer_instruction = reinterpret_cast<const DrawListBindIndexBufferInstruction *>(instruction);
940
driver->command_render_bind_index_buffer(p_command_buffer, bind_index_buffer_instruction->buffer, bind_index_buffer_instruction->format, bind_index_buffer_instruction->offset);
941
instruction_data_cursor += sizeof(DrawListBindIndexBufferInstruction);
942
} break;
943
case DrawListInstruction::TYPE_BIND_PIPELINE: {
944
const DrawListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const DrawListBindPipelineInstruction *>(instruction);
945
driver->command_bind_render_pipeline(p_command_buffer, bind_pipeline_instruction->pipeline);
946
instruction_data_cursor += sizeof(DrawListBindPipelineInstruction);
947
} break;
948
case DrawListInstruction::TYPE_BIND_UNIFORM_SETS: {
949
const DrawListBindUniformSetsInstruction *bind_uniform_sets_instruction = reinterpret_cast<const DrawListBindUniformSetsInstruction *>(instruction);
950
driver->command_bind_render_uniform_sets(p_command_buffer, VectorView<RDD::UniformSetID>(bind_uniform_sets_instruction->uniform_set_ids(), bind_uniform_sets_instruction->set_count), bind_uniform_sets_instruction->shader, bind_uniform_sets_instruction->first_set_index, bind_uniform_sets_instruction->set_count, bind_uniform_sets_instruction->dynamic_offsets_mask);
951
instruction_data_cursor += sizeof(DrawListBindUniformSetsInstruction) + sizeof(RDD::UniformSetID) * bind_uniform_sets_instruction->set_count;
952
} break;
953
case DrawListInstruction::TYPE_BIND_VERTEX_BUFFERS: {
954
const DrawListBindVertexBuffersInstruction *bind_vertex_buffers_instruction = reinterpret_cast<const DrawListBindVertexBuffersInstruction *>(instruction);
955
driver->command_render_bind_vertex_buffers(p_command_buffer, bind_vertex_buffers_instruction->vertex_buffers_count, bind_vertex_buffers_instruction->vertex_buffers(), bind_vertex_buffers_instruction->vertex_buffer_offsets(), bind_vertex_buffers_instruction->dynamic_offsets_mask);
956
instruction_data_cursor += sizeof(DrawListBindVertexBuffersInstruction);
957
instruction_data_cursor += sizeof(RDD::BufferID) * bind_vertex_buffers_instruction->vertex_buffers_count;
958
instruction_data_cursor += sizeof(uint64_t) * bind_vertex_buffers_instruction->vertex_buffers_count;
959
} break;
960
case DrawListInstruction::TYPE_CLEAR_ATTACHMENTS: {
961
const DrawListClearAttachmentsInstruction *clear_attachments_instruction = reinterpret_cast<const DrawListClearAttachmentsInstruction *>(instruction);
962
const VectorView attachments_clear_view(clear_attachments_instruction->attachments_clear(), clear_attachments_instruction->attachments_clear_count);
963
const VectorView attachments_clear_rect_view(clear_attachments_instruction->attachments_clear_rect(), clear_attachments_instruction->attachments_clear_rect_count);
964
driver->command_render_clear_attachments(p_command_buffer, attachments_clear_view, attachments_clear_rect_view);
965
instruction_data_cursor += sizeof(DrawListClearAttachmentsInstruction);
966
instruction_data_cursor += sizeof(RDD::AttachmentClear) * clear_attachments_instruction->attachments_clear_count;
967
instruction_data_cursor += sizeof(Rect2i) * clear_attachments_instruction->attachments_clear_rect_count;
968
} break;
969
case DrawListInstruction::TYPE_DRAW: {
970
const DrawListDrawInstruction *draw_instruction = reinterpret_cast<const DrawListDrawInstruction *>(instruction);
971
driver->command_render_draw(p_command_buffer, draw_instruction->vertex_count, draw_instruction->instance_count, 0, 0);
972
instruction_data_cursor += sizeof(DrawListDrawInstruction);
973
} break;
974
case DrawListInstruction::TYPE_DRAW_INDEXED: {
975
const DrawListDrawIndexedInstruction *draw_indexed_instruction = reinterpret_cast<const DrawListDrawIndexedInstruction *>(instruction);
976
driver->command_render_draw_indexed(p_command_buffer, draw_indexed_instruction->index_count, draw_indexed_instruction->instance_count, draw_indexed_instruction->first_index, 0, 0);
977
instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
978
} break;
979
case DrawListInstruction::TYPE_DRAW_INDIRECT: {
980
const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction);
981
driver->command_render_draw_indirect(p_command_buffer, draw_indirect_instruction->buffer, draw_indirect_instruction->offset, draw_indirect_instruction->draw_count, draw_indirect_instruction->stride);
982
instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction);
983
} break;
984
case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: {
985
const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction);
986
driver->command_render_draw_indexed_indirect(p_command_buffer, draw_indexed_indirect_instruction->buffer, draw_indexed_indirect_instruction->offset, draw_indexed_indirect_instruction->draw_count, draw_indexed_indirect_instruction->stride);
987
instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction);
988
} break;
989
case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
990
const DrawListExecuteCommandsInstruction *execute_commands_instruction = reinterpret_cast<const DrawListExecuteCommandsInstruction *>(instruction);
991
driver->command_buffer_execute_secondary(p_command_buffer, execute_commands_instruction->command_buffer);
992
instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction);
993
} break;
994
case DrawListInstruction::TYPE_NEXT_SUBPASS: {
995
const DrawListNextSubpassInstruction *next_subpass_instruction = reinterpret_cast<const DrawListNextSubpassInstruction *>(instruction);
996
driver->command_next_render_subpass(p_command_buffer, next_subpass_instruction->command_buffer_type);
997
instruction_data_cursor += sizeof(DrawListNextSubpassInstruction);
998
} break;
999
case DrawListInstruction::TYPE_SET_BLEND_CONSTANTS: {
1000
const DrawListSetBlendConstantsInstruction *set_blend_constants_instruction = reinterpret_cast<const DrawListSetBlendConstantsInstruction *>(instruction);
1001
driver->command_render_set_blend_constants(p_command_buffer, set_blend_constants_instruction->color);
1002
instruction_data_cursor += sizeof(DrawListSetBlendConstantsInstruction);
1003
} break;
1004
case DrawListInstruction::TYPE_SET_LINE_WIDTH: {
1005
const DrawListSetLineWidthInstruction *set_line_width_instruction = reinterpret_cast<const DrawListSetLineWidthInstruction *>(instruction);
1006
driver->command_render_set_line_width(p_command_buffer, set_line_width_instruction->width);
1007
instruction_data_cursor += sizeof(DrawListSetLineWidthInstruction);
1008
} break;
1009
case DrawListInstruction::TYPE_SET_PUSH_CONSTANT: {
1010
const DrawListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const DrawListSetPushConstantInstruction *>(instruction);
1011
const VectorView push_constant_data_view(reinterpret_cast<const uint32_t *>(set_push_constant_instruction->data()), set_push_constant_instruction->size / sizeof(uint32_t));
1012
driver->command_bind_push_constants(p_command_buffer, set_push_constant_instruction->shader, 0, push_constant_data_view);
1013
instruction_data_cursor += sizeof(DrawListSetPushConstantInstruction);
1014
instruction_data_cursor += set_push_constant_instruction->size;
1015
} break;
1016
case DrawListInstruction::TYPE_SET_SCISSOR: {
1017
const DrawListSetScissorInstruction *set_scissor_instruction = reinterpret_cast<const DrawListSetScissorInstruction *>(instruction);
1018
driver->command_render_set_scissor(p_command_buffer, set_scissor_instruction->rect);
1019
instruction_data_cursor += sizeof(DrawListSetScissorInstruction);
1020
} break;
1021
case DrawListInstruction::TYPE_SET_VIEWPORT: {
1022
const DrawListSetViewportInstruction *set_viewport_instruction = reinterpret_cast<const DrawListSetViewportInstruction *>(instruction);
1023
driver->command_render_set_viewport(p_command_buffer, set_viewport_instruction->rect);
1024
instruction_data_cursor += sizeof(DrawListSetViewportInstruction);
1025
} break;
1026
case DrawListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
1027
const DrawListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const DrawListUniformSetPrepareForUseInstruction *>(instruction);
1028
driver->command_uniform_set_prepare_for_use(p_command_buffer, uniform_set_prepare_for_use_instruction->uniform_set, uniform_set_prepare_for_use_instruction->shader, uniform_set_prepare_for_use_instruction->set_index);
1029
instruction_data_cursor += sizeof(DrawListUniformSetPrepareForUseInstruction);
1030
} break;
1031
default:
1032
DEV_ASSERT(false && "Unknown draw list instruction type.");
1033
return;
1034
}
1035
1036
instruction_data_cursor = GRAPH_ALIGN(instruction_data_cursor);
1037
}
1038
}
1039
1040
void RenderingDeviceGraph::_add_draw_list_begin(FramebufferCache *p_framebuffer_cache, RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<AttachmentOperation> p_attachment_operations, VectorView<RDD::RenderPassClearValue> p_attachment_clear_values, BitField<RDD::PipelineStageBits> p_stages, uint32_t p_breadcrumb, bool p_split_cmd_buffer) {
1041
DEV_ASSERT(p_attachment_operations.size() == p_attachment_clear_values.size());
1042
1043
draw_instruction_list.clear();
1044
draw_instruction_list.index++;
1045
draw_instruction_list.framebuffer_cache = p_framebuffer_cache;
1046
draw_instruction_list.render_pass = p_render_pass;
1047
draw_instruction_list.framebuffer = p_framebuffer;
1048
draw_instruction_list.region = p_region;
1049
draw_instruction_list.stages = p_stages;
1050
draw_instruction_list.attachment_operations.resize(p_attachment_operations.size());
1051
draw_instruction_list.attachment_clear_values.resize(p_attachment_clear_values.size());
1052
1053
for (uint32_t i = 0; i < p_attachment_operations.size(); i++) {
1054
draw_instruction_list.attachment_operations[i] = p_attachment_operations[i];
1055
draw_instruction_list.attachment_clear_values[i] = p_attachment_clear_values[i];
1056
}
1057
1058
draw_instruction_list.split_cmd_buffer = p_split_cmd_buffer;
1059
1060
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
1061
draw_instruction_list.breadcrumb = p_breadcrumb;
1062
#endif
1063
}
1064
1065
void RenderingDeviceGraph::_run_secondary_command_buffer_task(const SecondaryCommandBuffer *p_secondary) {
1066
driver->command_buffer_begin_secondary(p_secondary->command_buffer, p_secondary->render_pass, 0, p_secondary->framebuffer);
1067
_run_draw_list_command(p_secondary->command_buffer, p_secondary->instruction_data.ptr(), p_secondary->instruction_data.size());
1068
driver->command_buffer_end(p_secondary->command_buffer);
1069
}
1070
1071
void RenderingDeviceGraph::_wait_for_secondary_command_buffer_tasks() {
1072
for (uint32_t i = 0; i < frames[frame].secondary_command_buffers_used; i++) {
1073
WorkerThreadPool::TaskID &task = frames[frame].secondary_command_buffers[i].task;
1074
if (task != WorkerThreadPool::INVALID_TASK_ID) {
1075
WorkerThreadPool::get_singleton()->wait_for_task_completion(task);
1076
task = WorkerThreadPool::INVALID_TASK_ID;
1077
}
1078
}
1079
}
1080
1081
void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, RDD::CommandBufferID &r_command_buffer, CommandBufferPool &r_command_buffer_pool, int32_t &r_current_label_index, int32_t &r_current_label_level) {
1082
for (uint32_t i = 0; i < p_sorted_commands_count; i++) {
1083
const uint32_t command_index = p_sorted_commands[i].index;
1084
const uint32_t command_data_offset = command_data_offsets[command_index];
1085
const RecordedCommand *command = reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offset]);
1086
_run_label_command_change(r_command_buffer, command->label_index, p_level, false, true, &p_sorted_commands[i], p_sorted_commands_count - i, r_current_label_index, r_current_label_level);
1087
1088
switch (command->type) {
1089
case RecordedCommand::TYPE_ACCELERATION_STRUCTURE_BUILD: {
1090
const RecordedAccelerationStructureBuildCommand *as_build_command = reinterpret_cast<const RecordedAccelerationStructureBuildCommand *>(command);
1091
driver->command_build_acceleration_structure(r_command_buffer, as_build_command->acceleration_structure, as_build_command->scratch_buffer);
1092
} break;
1093
case RecordedCommand::TYPE_BUFFER_CLEAR: {
1094
const RecordedBufferClearCommand *buffer_clear_command = reinterpret_cast<const RecordedBufferClearCommand *>(command);
1095
driver->command_clear_buffer(r_command_buffer, buffer_clear_command->buffer, buffer_clear_command->offset, buffer_clear_command->size);
1096
} break;
1097
case RecordedCommand::TYPE_BUFFER_COPY: {
1098
const RecordedBufferCopyCommand *buffer_copy_command = reinterpret_cast<const RecordedBufferCopyCommand *>(command);
1099
driver->command_copy_buffer(r_command_buffer, buffer_copy_command->source, buffer_copy_command->destination, buffer_copy_command->region);
1100
} break;
1101
case RecordedCommand::TYPE_BUFFER_GET_DATA: {
1102
const RecordedBufferGetDataCommand *buffer_get_data_command = reinterpret_cast<const RecordedBufferGetDataCommand *>(command);
1103
driver->command_copy_buffer(r_command_buffer, buffer_get_data_command->source, buffer_get_data_command->destination, buffer_get_data_command->region);
1104
} break;
1105
case RecordedCommand::TYPE_BUFFER_UPDATE: {
1106
const RecordedBufferUpdateCommand *buffer_update_command = reinterpret_cast<const RecordedBufferUpdateCommand *>(command);
1107
const RecordedBufferCopy *command_buffer_copies = buffer_update_command->buffer_copies();
1108
for (uint32_t j = 0; j < buffer_update_command->buffer_copies_count; j++) {
1109
driver->command_copy_buffer(r_command_buffer, command_buffer_copies[j].source, buffer_update_command->destination, command_buffer_copies[j].region);
1110
}
1111
} break;
1112
case RecordedCommand::TYPE_DRIVER_CALLBACK: {
1113
const RecordedDriverCallbackCommand *driver_callback_command = reinterpret_cast<const RecordedDriverCallbackCommand *>(command);
1114
driver_callback_command->callback(driver, r_command_buffer, driver_callback_command->userdata);
1115
} break;
1116
case RecordedCommand::TYPE_RAYTRACING_LIST: {
1117
const RecordedRaytracingListCommand *raytracing_list_command = reinterpret_cast<const RecordedRaytracingListCommand *>(command);
1118
_run_raytracing_list_command(r_command_buffer, raytracing_list_command->instruction_data(), raytracing_list_command->instruction_data_size);
1119
} break;
1120
case RecordedCommand::TYPE_COMPUTE_LIST: {
1121
if (device.workarounds.avoid_compute_after_draw && workarounds_state.draw_list_found) {
1122
// Avoid compute after draw workaround. Refer to the comment that enables this in the Vulkan driver for more information.
1123
workarounds_state.draw_list_found = false;
1124
1125
// Create or reuse a command buffer and finish recording the current one.
1126
driver->command_buffer_end(r_command_buffer);
1127
1128
while (r_command_buffer_pool.buffers_used >= r_command_buffer_pool.buffers.size()) {
1129
RDD::CommandBufferID command_buffer = driver->command_buffer_create(r_command_buffer_pool.pool);
1130
RDD::SemaphoreID command_semaphore = driver->semaphore_create();
1131
r_command_buffer_pool.buffers.push_back(command_buffer);
1132
r_command_buffer_pool.semaphores.push_back(command_semaphore);
1133
}
1134
1135
// Start recording on the next usable command buffer from the pool.
1136
uint32_t command_buffer_index = r_command_buffer_pool.buffers_used++;
1137
r_command_buffer = r_command_buffer_pool.buffers[command_buffer_index];
1138
driver->command_buffer_begin(r_command_buffer);
1139
}
1140
1141
const RecordedComputeListCommand *compute_list_command = reinterpret_cast<const RecordedComputeListCommand *>(command);
1142
_run_compute_list_command(r_command_buffer, compute_list_command->instruction_data(), compute_list_command->instruction_data_size);
1143
} break;
1144
case RecordedCommand::TYPE_DRAW_LIST: {
1145
if (device.workarounds.avoid_compute_after_draw) {
1146
// Indicate that a draw list was encountered for the workaround.
1147
workarounds_state.draw_list_found = true;
1148
}
1149
1150
const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command);
1151
1152
if (draw_list_command->split_cmd_buffer) {
1153
// Create or reuse a command buffer and finish recording the current one.
1154
driver->command_buffer_end(r_command_buffer);
1155
1156
while (r_command_buffer_pool.buffers_used >= r_command_buffer_pool.buffers.size()) {
1157
RDD::CommandBufferID command_buffer = driver->command_buffer_create(r_command_buffer_pool.pool);
1158
RDD::SemaphoreID command_semaphore = driver->semaphore_create();
1159
r_command_buffer_pool.buffers.push_back(command_buffer);
1160
r_command_buffer_pool.semaphores.push_back(command_semaphore);
1161
}
1162
1163
// Start recording on the next usable command buffer from the pool.
1164
uint32_t command_buffer_index = r_command_buffer_pool.buffers_used++;
1165
r_command_buffer = r_command_buffer_pool.buffers[command_buffer_index];
1166
driver->command_buffer_begin(r_command_buffer);
1167
}
1168
1169
const VectorView clear_values(draw_list_command->clear_values(), draw_list_command->clear_values_count);
1170
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
1171
driver->command_insert_breadcrumb(r_command_buffer, draw_list_command->breadcrumb);
1172
#endif
1173
RDD::RenderPassID render_pass;
1174
RDD::FramebufferID framebuffer;
1175
if (draw_list_command->framebuffer_cache != nullptr) {
1176
_get_draw_list_render_pass_and_framebuffer(draw_list_command, render_pass, framebuffer);
1177
} else {
1178
render_pass = draw_list_command->render_pass;
1179
framebuffer = draw_list_command->framebuffer;
1180
}
1181
1182
if (framebuffer && render_pass) {
1183
driver->command_begin_render_pass(r_command_buffer, render_pass, framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values);
1184
_run_draw_list_command(r_command_buffer, draw_list_command->instruction_data(), draw_list_command->instruction_data_size);
1185
driver->command_end_render_pass(r_command_buffer);
1186
}
1187
} break;
1188
case RecordedCommand::TYPE_TEXTURE_CLEAR_COLOR: {
1189
const RecordedTextureClearColorCommand *texture_clear_color_command = reinterpret_cast<const RecordedTextureClearColorCommand *>(command);
1190
driver->command_clear_color_texture(r_command_buffer, texture_clear_color_command->texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, texture_clear_color_command->color, texture_clear_color_command->range);
1191
} break;
1192
case RecordedCommand::TYPE_TEXTURE_CLEAR_DEPTH_STENCIL: {
1193
const RecordedTextureClearDepthStencilCommand *texture_clear_depth_stencil_command = reinterpret_cast<const RecordedTextureClearDepthStencilCommand *>(command);
1194
driver->command_clear_depth_stencil_texture(r_command_buffer, texture_clear_depth_stencil_command->texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, texture_clear_depth_stencil_command->depth, texture_clear_depth_stencil_command->stencil, texture_clear_depth_stencil_command->range);
1195
} break;
1196
case RecordedCommand::TYPE_TEXTURE_COPY: {
1197
const RecordedTextureCopyCommand *texture_copy_command = reinterpret_cast<const RecordedTextureCopyCommand *>(command);
1198
const VectorView<RDD::TextureCopyRegion> command_texture_copy_regions_view(texture_copy_command->texture_copy_regions(), texture_copy_command->texture_copy_regions_count);
1199
driver->command_copy_texture(r_command_buffer, texture_copy_command->from_texture, RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL, texture_copy_command->to_texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, command_texture_copy_regions_view);
1200
} break;
1201
case RecordedCommand::TYPE_TEXTURE_GET_DATA: {
1202
const RecordedTextureGetDataCommand *texture_get_data_command = reinterpret_cast<const RecordedTextureGetDataCommand *>(command);
1203
const VectorView<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_view(texture_get_data_command->buffer_texture_copy_regions(), texture_get_data_command->buffer_texture_copy_regions_count);
1204
driver->command_copy_texture_to_buffer(r_command_buffer, texture_get_data_command->from_texture, RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL, texture_get_data_command->to_buffer, command_buffer_texture_copy_regions_view);
1205
} break;
1206
case RecordedCommand::TYPE_TEXTURE_RESOLVE: {
1207
const RecordedTextureResolveCommand *texture_resolve_command = reinterpret_cast<const RecordedTextureResolveCommand *>(command);
1208
driver->command_resolve_texture(r_command_buffer, texture_resolve_command->from_texture, RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL, texture_resolve_command->src_layer, texture_resolve_command->src_mipmap, texture_resolve_command->to_texture, RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL, texture_resolve_command->dst_layer, texture_resolve_command->dst_mipmap);
1209
} break;
1210
case RecordedCommand::TYPE_TEXTURE_UPDATE: {
1211
const RecordedTextureUpdateCommand *texture_update_command = reinterpret_cast<const RecordedTextureUpdateCommand *>(command);
1212
const RecordedBufferToTextureCopy *command_buffer_to_texture_copies = texture_update_command->buffer_to_texture_copies();
1213
for (uint32_t j = 0; j < texture_update_command->buffer_to_texture_copies_count; j++) {
1214
driver->command_copy_buffer_to_texture(r_command_buffer, command_buffer_to_texture_copies[j].from_buffer, texture_update_command->to_texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, command_buffer_to_texture_copies[j].region);
1215
}
1216
} break;
1217
case RecordedCommand::TYPE_CAPTURE_TIMESTAMP: {
1218
const RecordedCaptureTimestampCommand *texture_capture_timestamp_command = reinterpret_cast<const RecordedCaptureTimestampCommand *>(command);
1219
driver->command_timestamp_write(r_command_buffer, texture_capture_timestamp_command->pool, texture_capture_timestamp_command->index);
1220
} break;
1221
default: {
1222
DEV_ASSERT(false && "Unknown recorded command type.");
1223
return;
1224
}
1225
}
1226
}
1227
}
1228
1229
void RenderingDeviceGraph::_run_label_command_change(RDD::CommandBufferID p_command_buffer, int32_t p_new_label_index, int32_t p_new_level, bool p_ignore_previous_value, bool p_use_label_for_empty, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, int32_t &r_current_label_index, int32_t &r_current_label_level) {
1230
if (command_label_count == 0) {
1231
// Ignore any label operations if no labels were pushed.
1232
return;
1233
}
1234
1235
if (p_ignore_previous_value || p_new_label_index != r_current_label_index || p_new_level != r_current_label_level) {
1236
if (!p_ignore_previous_value && (p_use_label_for_empty || r_current_label_index >= 0 || r_current_label_level >= 0)) {
1237
// End the current label.
1238
driver->command_end_label(p_command_buffer);
1239
}
1240
1241
String label_name;
1242
Color label_color;
1243
if (p_new_label_index >= 0) {
1244
const char *label_chars = &command_label_chars[command_label_offsets[p_new_label_index]];
1245
label_name.append_utf8(label_chars);
1246
label_color = command_label_colors[p_new_label_index];
1247
} else if (p_use_label_for_empty) {
1248
label_name = "Command Graph";
1249
label_color = Color(1, 1, 1, 1);
1250
} else {
1251
return;
1252
}
1253
1254
// Add the level to the name.
1255
label_name += " (L" + itos(p_new_level) + ")";
1256
1257
if (p_sorted_commands != nullptr && p_sorted_commands_count > 0) {
1258
// Analyze the commands in the level that have the same label to detect what type of operations are performed.
1259
bool copy_commands = false;
1260
bool compute_commands = false;
1261
bool draw_commands = false;
1262
bool custom_commands = false;
1263
for (uint32_t i = 0; i < p_sorted_commands_count; i++) {
1264
const uint32_t command_index = p_sorted_commands[i].index;
1265
const uint32_t command_data_offset = command_data_offsets[command_index];
1266
const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]);
1267
if (command->label_index != p_new_label_index) {
1268
break;
1269
}
1270
1271
switch (command->type) {
1272
case RecordedCommand::TYPE_BUFFER_CLEAR:
1273
case RecordedCommand::TYPE_BUFFER_COPY:
1274
case RecordedCommand::TYPE_BUFFER_GET_DATA:
1275
case RecordedCommand::TYPE_BUFFER_UPDATE:
1276
case RecordedCommand::TYPE_TEXTURE_CLEAR_COLOR:
1277
case RecordedCommand::TYPE_TEXTURE_CLEAR_DEPTH_STENCIL:
1278
case RecordedCommand::TYPE_TEXTURE_COPY:
1279
case RecordedCommand::TYPE_TEXTURE_GET_DATA:
1280
case RecordedCommand::TYPE_TEXTURE_RESOLVE:
1281
case RecordedCommand::TYPE_TEXTURE_UPDATE: {
1282
copy_commands = true;
1283
} break;
1284
case RecordedCommand::TYPE_COMPUTE_LIST: {
1285
compute_commands = true;
1286
} break;
1287
case RecordedCommand::TYPE_DRAW_LIST: {
1288
draw_commands = true;
1289
} break;
1290
case RecordedCommand::TYPE_DRIVER_CALLBACK: {
1291
custom_commands = true;
1292
} break;
1293
default: {
1294
// Ignore command.
1295
} break;
1296
}
1297
1298
if (copy_commands && compute_commands && draw_commands && custom_commands) {
1299
// There's no more command types to find.
1300
break;
1301
}
1302
}
1303
1304
if (copy_commands || compute_commands || draw_commands || custom_commands) {
1305
// Add the operations to the name.
1306
bool plus_after_copy = copy_commands && (compute_commands || draw_commands || custom_commands);
1307
bool plus_after_compute = compute_commands && (draw_commands || custom_commands);
1308
bool plus_after_draw = draw_commands && custom_commands;
1309
label_name += " (";
1310
label_name += copy_commands ? "Copy" : "";
1311
label_name += plus_after_copy ? "+" : "";
1312
label_name += compute_commands ? "Compute" : "";
1313
label_name += plus_after_compute ? "+" : "";
1314
label_name += draw_commands ? "Draw" : "";
1315
label_name += plus_after_draw ? "+" : "";
1316
label_name += custom_commands ? "Custom" : "";
1317
label_name += ")";
1318
}
1319
}
1320
1321
// Start the new label.
1322
CharString label_name_utf8 = label_name.utf8();
1323
driver->command_begin_label(p_command_buffer, label_name_utf8.get_data(), label_color);
1324
1325
r_current_label_index = p_new_label_index;
1326
r_current_label_level = p_new_level;
1327
}
1328
}
1329
1330
void RenderingDeviceGraph::_boost_priority_for_render_commands(RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, uint32_t &r_boosted_priority) {
1331
if (p_sorted_commands_count == 0) {
1332
return;
1333
}
1334
1335
const uint32_t boosted_priority_value = 0;
1336
if (r_boosted_priority > 0) {
1337
bool perform_sort = false;
1338
for (uint32_t j = 0; j < p_sorted_commands_count; j++) {
1339
if (p_sorted_commands[j].priority == r_boosted_priority) {
1340
p_sorted_commands[j].priority = boosted_priority_value;
1341
perform_sort = true;
1342
}
1343
}
1344
1345
if (perform_sort) {
1346
SortArray<RecordedCommandSort> command_sorter;
1347
command_sorter.sort(p_sorted_commands, p_sorted_commands_count);
1348
}
1349
}
1350
1351
if (p_sorted_commands[p_sorted_commands_count - 1].priority != boosted_priority_value) {
1352
r_boosted_priority = p_sorted_commands[p_sorted_commands_count - 1].priority;
1353
}
1354
}
1355
1356
void RenderingDeviceGraph::_group_barriers_for_render_commands(RDD::CommandBufferID p_command_buffer, const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count, bool p_full_memory_barrier) {
1357
if (!driver_honors_barriers) {
1358
return;
1359
}
1360
1361
barrier_group.clear();
1362
barrier_group.src_stages = RDD::PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1363
barrier_group.dst_stages = RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
1364
1365
for (uint32_t i = 0; i < p_sorted_commands_count; i++) {
1366
const uint32_t command_index = p_sorted_commands[i].index;
1367
const uint32_t command_data_offset = command_data_offsets[command_index];
1368
const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]);
1369
1370
#if PRINT_COMMAND_RECORDING
1371
print_line(vformat("Grouping barriers for #%d", command_index));
1372
#endif
1373
1374
// Merge command's stage bits with the barrier group.
1375
barrier_group.src_stages = barrier_group.src_stages | command->previous_stages;
1376
barrier_group.dst_stages = barrier_group.dst_stages | command->next_stages;
1377
1378
// Merge command's memory barrier bits with the barrier group.
1379
barrier_group.memory_barrier.src_access = barrier_group.memory_barrier.src_access | command->memory_barrier.src_access;
1380
barrier_group.memory_barrier.dst_access = barrier_group.memory_barrier.dst_access | command->memory_barrier.dst_access;
1381
1382
// Gather texture barriers.
1383
for (int32_t j = 0; j < command->normalization_barrier_count; j++) {
1384
const RDD::TextureBarrier &recorded_barrier = command_normalization_barriers[command->normalization_barrier_index + j];
1385
barrier_group.normalization_barriers.push_back(recorded_barrier);
1386
#if PRINT_COMMAND_RECORDING
1387
print_line(vformat("Normalization Barrier #%d", barrier_group.normalization_barriers.size() - 1));
1388
#endif
1389
}
1390
1391
for (int32_t j = 0; j < command->transition_barrier_count; j++) {
1392
const RDD::TextureBarrier &recorded_barrier = command_transition_barriers[command->transition_barrier_index + j];
1393
barrier_group.transition_barriers.push_back(recorded_barrier);
1394
#if PRINT_COMMAND_RECORDING
1395
print_line(vformat("Transition Barrier #%d", barrier_group.transition_barriers.size() - 1));
1396
#endif
1397
}
1398
1399
#if USE_BUFFER_BARRIERS
1400
// Gather buffer barriers.
1401
for (int32_t j = 0; j < command->buffer_barrier_count; j++) {
1402
const RDD::BufferBarrier &recorded_barrier = command_buffer_barriers[command->buffer_barrier_index + j];
1403
barrier_group.buffer_barriers.push_back(recorded_barrier);
1404
}
1405
#endif
1406
1407
// Gather acceleration structure barriers.
1408
for (int32_t j = 0; j < command->acceleration_structure_barrier_count; j++) {
1409
const RDD::AccelerationStructureBarrier &recorded_barrier = command_acceleration_structure_barriers[command->acceleration_structure_barrier_index + j];
1410
barrier_group.acceleration_structure_barriers.push_back(recorded_barrier);
1411
}
1412
}
1413
1414
if (p_full_memory_barrier) {
1415
barrier_group.src_stages = RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT;
1416
barrier_group.dst_stages = RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT;
1417
barrier_group.memory_barrier.src_access = RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT;
1418
barrier_group.memory_barrier.dst_access = RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT;
1419
}
1420
1421
const bool is_memory_barrier_empty = barrier_group.memory_barrier.src_access.is_empty() && barrier_group.memory_barrier.dst_access.is_empty();
1422
const bool are_texture_barriers_empty = barrier_group.normalization_barriers.is_empty() && barrier_group.transition_barriers.is_empty();
1423
#if USE_BUFFER_BARRIERS
1424
const bool are_buffer_barriers_empty = barrier_group.buffer_barriers.is_empty();
1425
#else
1426
const bool are_buffer_barriers_empty = true;
1427
#endif
1428
const bool are_acceleration_structure_barriers_empty = barrier_group.acceleration_structure_barriers.is_empty();
1429
if (is_memory_barrier_empty && are_texture_barriers_empty && are_buffer_barriers_empty && are_acceleration_structure_barriers_empty) {
1430
// Commands don't require synchronization.
1431
return;
1432
}
1433
1434
const VectorView<RDD::MemoryAccessBarrier> memory_barriers = !is_memory_barrier_empty ? barrier_group.memory_barrier : VectorView<RDD::MemoryAccessBarrier>();
1435
const VectorView<RDD::TextureBarrier> texture_barriers = barrier_group.normalization_barriers.is_empty() ? barrier_group.transition_barriers : barrier_group.normalization_barriers;
1436
#if USE_BUFFER_BARRIERS
1437
const VectorView<RDD::BufferBarrier> buffer_barriers = !are_buffer_barriers_empty ? barrier_group.buffer_barriers : VectorView<RDD::BufferBarrier>();
1438
#else
1439
const VectorView<RDD::BufferBarrier> buffer_barriers = VectorView<RDD::BufferBarrier>();
1440
#endif
1441
const VectorView<RDD::AccelerationStructureBarrier> acceleration_structure_barriers = !are_acceleration_structure_barriers_empty ? barrier_group.acceleration_structure_barriers : VectorView<RDD::AccelerationStructureBarrier>();
1442
1443
driver->command_pipeline_barrier(p_command_buffer, barrier_group.src_stages, barrier_group.dst_stages, memory_barriers, buffer_barriers, texture_barriers, acceleration_structure_barriers);
1444
1445
bool separate_texture_barriers = !barrier_group.normalization_barriers.is_empty() && !barrier_group.transition_barriers.is_empty();
1446
if (separate_texture_barriers) {
1447
driver->command_pipeline_barrier(p_command_buffer, barrier_group.src_stages, barrier_group.dst_stages, VectorView<RDD::MemoryAccessBarrier>(), VectorView<RDD::BufferBarrier>(), barrier_group.transition_barriers, VectorView<RDD::AccelerationStructureBarrier>());
1448
}
1449
}
1450
1451
void RenderingDeviceGraph::_print_render_commands(const RecordedCommandSort *p_sorted_commands, uint32_t p_sorted_commands_count) {
1452
for (uint32_t i = 0; i < p_sorted_commands_count; i++) {
1453
const uint32_t command_index = p_sorted_commands[i].index;
1454
const uint32_t command_level = p_sorted_commands[i].level;
1455
const uint32_t command_data_offset = command_data_offsets[command_index];
1456
const RecordedCommand *command = reinterpret_cast<RecordedCommand *>(&command_data[command_data_offset]);
1457
switch (command->type) {
1458
case RecordedCommand::TYPE_BUFFER_CLEAR: {
1459
const RecordedBufferClearCommand *buffer_clear_command = reinterpret_cast<const RecordedBufferClearCommand *>(command);
1460
print_line(command_index, "LEVEL", command_level, "BUFFER CLEAR DESTINATION", itos(buffer_clear_command->buffer.id));
1461
} break;
1462
case RecordedCommand::TYPE_BUFFER_COPY: {
1463
const RecordedBufferCopyCommand *buffer_copy_command = reinterpret_cast<const RecordedBufferCopyCommand *>(command);
1464
print_line(command_index, "LEVEL", command_level, "BUFFER COPY SOURCE", itos(buffer_copy_command->source.id), "DESTINATION", itos(buffer_copy_command->destination.id));
1465
} break;
1466
case RecordedCommand::TYPE_BUFFER_GET_DATA: {
1467
const RecordedBufferGetDataCommand *buffer_get_data_command = reinterpret_cast<const RecordedBufferGetDataCommand *>(command);
1468
print_line(command_index, "LEVEL", command_level, "BUFFER GET DATA DESTINATION", itos(buffer_get_data_command->destination.id));
1469
} break;
1470
case RecordedCommand::TYPE_BUFFER_UPDATE: {
1471
const RecordedBufferUpdateCommand *buffer_update_command = reinterpret_cast<const RecordedBufferUpdateCommand *>(command);
1472
print_line(command_index, "LEVEL", command_level, "BUFFER UPDATE DESTINATION", itos(buffer_update_command->destination.id), "COPIES", buffer_update_command->buffer_copies_count);
1473
} break;
1474
case RecordedCommand::TYPE_DRIVER_CALLBACK: {
1475
print_line(command_index, "LEVEL", command_level, "DRIVER CALLBACK");
1476
} break;
1477
case RecordedCommand::TYPE_COMPUTE_LIST: {
1478
const RecordedComputeListCommand *compute_list_command = reinterpret_cast<const RecordedComputeListCommand *>(command);
1479
print_line(command_index, "LEVEL", command_level, "COMPUTE LIST SIZE", compute_list_command->instruction_data_size);
1480
} break;
1481
case RecordedCommand::TYPE_DRAW_LIST: {
1482
const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command);
1483
print_line(command_index, "LEVEL", command_level, "DRAW LIST SIZE", draw_list_command->instruction_data_size);
1484
} break;
1485
case RecordedCommand::TYPE_TEXTURE_CLEAR_COLOR: {
1486
const RecordedTextureClearColorCommand *texture_clear_color_command = reinterpret_cast<const RecordedTextureClearColorCommand *>(command);
1487
print_line(command_index, "LEVEL", command_level, "TEXTURE CLEAR COLOR", itos(texture_clear_color_command->texture.id), "COLOR", texture_clear_color_command->color);
1488
} break;
1489
case RecordedCommand::TYPE_TEXTURE_CLEAR_DEPTH_STENCIL: {
1490
const RecordedTextureClearDepthStencilCommand *texture_clear_depth_stencil_command = reinterpret_cast<const RecordedTextureClearDepthStencilCommand *>(command);
1491
print_line(command_index, "LEVEL", command_level, "TEXTURE CLEAR DEPTH STENCIL", itos(texture_clear_depth_stencil_command->texture.id), "DEPTH", rtos(texture_clear_depth_stencil_command->depth), "STENCIL", itos(texture_clear_depth_stencil_command->stencil));
1492
} break;
1493
case RecordedCommand::TYPE_TEXTURE_COPY: {
1494
const RecordedTextureCopyCommand *texture_copy_command = reinterpret_cast<const RecordedTextureCopyCommand *>(command);
1495
print_line(command_index, "LEVEL", command_level, "TEXTURE COPY FROM", itos(texture_copy_command->from_texture.id), "TO", itos(texture_copy_command->to_texture.id));
1496
} break;
1497
case RecordedCommand::TYPE_TEXTURE_GET_DATA: {
1498
print_line(command_index, "LEVEL", command_level, "TEXTURE GET DATA");
1499
} break;
1500
case RecordedCommand::TYPE_TEXTURE_RESOLVE: {
1501
const RecordedTextureResolveCommand *texture_resolve_command = reinterpret_cast<const RecordedTextureResolveCommand *>(command);
1502
print_line(command_index, "LEVEL", command_level, "TEXTURE RESOLVE FROM", itos(texture_resolve_command->from_texture.id), "TO", itos(texture_resolve_command->to_texture.id));
1503
} break;
1504
case RecordedCommand::TYPE_TEXTURE_UPDATE: {
1505
const RecordedTextureUpdateCommand *texture_update_command = reinterpret_cast<const RecordedTextureUpdateCommand *>(command);
1506
print_line(command_index, "LEVEL", command_level, "TEXTURE UPDATE TO", itos(texture_update_command->to_texture.id));
1507
} break;
1508
case RecordedCommand::TYPE_CAPTURE_TIMESTAMP: {
1509
const RecordedCaptureTimestampCommand *texture_capture_timestamp_command = reinterpret_cast<const RecordedCaptureTimestampCommand *>(command);
1510
print_line(command_index, "LEVEL", command_level, "CAPTURE TIMESTAMP POOL", itos(texture_capture_timestamp_command->pool.id), "INDEX", texture_capture_timestamp_command->index);
1511
} break;
1512
default:
1513
DEV_ASSERT(false && "Unknown recorded command type.");
1514
return;
1515
}
1516
}
1517
}
1518
1519
void RenderingDeviceGraph::_print_draw_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
1520
uint32_t instruction_data_cursor = 0;
1521
while (instruction_data_cursor < p_instruction_data_size) {
1522
DEV_ASSERT((instruction_data_cursor + sizeof(DrawListInstruction)) <= p_instruction_data_size);
1523
1524
const DrawListInstruction *instruction = reinterpret_cast<const DrawListInstruction *>(&p_instruction_data[instruction_data_cursor]);
1525
switch (instruction->type) {
1526
case DrawListInstruction::TYPE_BIND_INDEX_BUFFER: {
1527
const DrawListBindIndexBufferInstruction *bind_index_buffer_instruction = reinterpret_cast<const DrawListBindIndexBufferInstruction *>(instruction);
1528
print_line("\tBIND INDEX BUFFER ID", itos(bind_index_buffer_instruction->buffer.id), "FORMAT", bind_index_buffer_instruction->format, "OFFSET", bind_index_buffer_instruction->offset);
1529
instruction_data_cursor += sizeof(DrawListBindIndexBufferInstruction);
1530
} break;
1531
case DrawListInstruction::TYPE_BIND_PIPELINE: {
1532
const DrawListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const DrawListBindPipelineInstruction *>(instruction);
1533
print_line("\tBIND PIPELINE ID", itos(bind_pipeline_instruction->pipeline.id));
1534
instruction_data_cursor += sizeof(DrawListBindPipelineInstruction);
1535
} break;
1536
case DrawListInstruction::TYPE_BIND_UNIFORM_SETS: {
1537
const DrawListBindUniformSetsInstruction *bind_uniform_sets_instruction = reinterpret_cast<const DrawListBindUniformSetsInstruction *>(instruction);
1538
print_line("\tBIND UNIFORM SETS COUNT", bind_uniform_sets_instruction->set_count);
1539
for (uint32_t i = 0; i < bind_uniform_sets_instruction->set_count; i++) {
1540
print_line("\tBIND UNIFORM SET ID", itos(bind_uniform_sets_instruction->uniform_set_ids()[i].id), "START INDEX", bind_uniform_sets_instruction->first_set_index, "DYNAMIC_OFFSETS", bind_uniform_sets_instruction->dynamic_offsets_mask);
1541
}
1542
instruction_data_cursor += sizeof(DrawListBindUniformSetsInstruction) + sizeof(RDD::UniformSetID) * bind_uniform_sets_instruction->set_count;
1543
} break;
1544
case DrawListInstruction::TYPE_BIND_VERTEX_BUFFERS: {
1545
const DrawListBindVertexBuffersInstruction *bind_vertex_buffers_instruction = reinterpret_cast<const DrawListBindVertexBuffersInstruction *>(instruction);
1546
print_line("\tBIND VERTEX BUFFERS COUNT", bind_vertex_buffers_instruction->vertex_buffers_count);
1547
instruction_data_cursor += sizeof(DrawListBindVertexBuffersInstruction);
1548
instruction_data_cursor += sizeof(RDD::BufferID) * bind_vertex_buffers_instruction->vertex_buffers_count;
1549
instruction_data_cursor += sizeof(uint64_t) * bind_vertex_buffers_instruction->vertex_buffers_count;
1550
} break;
1551
case DrawListInstruction::TYPE_CLEAR_ATTACHMENTS: {
1552
const DrawListClearAttachmentsInstruction *clear_attachments_instruction = reinterpret_cast<const DrawListClearAttachmentsInstruction *>(instruction);
1553
print_line("\tATTACHMENTS CLEAR COUNT", clear_attachments_instruction->attachments_clear_count, "RECT COUNT", clear_attachments_instruction->attachments_clear_rect_count);
1554
instruction_data_cursor += sizeof(DrawListClearAttachmentsInstruction);
1555
instruction_data_cursor += sizeof(RDD::AttachmentClear) * clear_attachments_instruction->attachments_clear_count;
1556
instruction_data_cursor += sizeof(Rect2i) * clear_attachments_instruction->attachments_clear_rect_count;
1557
} break;
1558
case DrawListInstruction::TYPE_DRAW: {
1559
const DrawListDrawInstruction *draw_instruction = reinterpret_cast<const DrawListDrawInstruction *>(instruction);
1560
print_line("\tDRAW VERTICES", draw_instruction->vertex_count, "INSTANCES", draw_instruction->instance_count);
1561
instruction_data_cursor += sizeof(DrawListDrawInstruction);
1562
} break;
1563
case DrawListInstruction::TYPE_DRAW_INDEXED: {
1564
const DrawListDrawIndexedInstruction *draw_indexed_instruction = reinterpret_cast<const DrawListDrawIndexedInstruction *>(instruction);
1565
print_line("\tDRAW INDICES", draw_indexed_instruction->index_count, "INSTANCES", draw_indexed_instruction->instance_count, "FIRST INDEX", draw_indexed_instruction->first_index);
1566
instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
1567
} break;
1568
case DrawListInstruction::TYPE_DRAW_INDIRECT: {
1569
const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction);
1570
print_line("\tDRAW INDIRECT BUFFER ID", itos(draw_indirect_instruction->buffer.id), "OFFSET", draw_indirect_instruction->offset, "DRAW COUNT", draw_indirect_instruction->draw_count, "STRIDE", draw_indirect_instruction->stride);
1571
instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction);
1572
} break;
1573
case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: {
1574
const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction);
1575
print_line("\tDRAW INDEXED INDIRECT BUFFER ID", itos(draw_indexed_indirect_instruction->buffer.id), "OFFSET", draw_indexed_indirect_instruction->offset, "DRAW COUNT", draw_indexed_indirect_instruction->draw_count, "STRIDE", draw_indexed_indirect_instruction->stride);
1576
instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction);
1577
} break;
1578
case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
1579
print_line("\tEXECUTE COMMANDS");
1580
instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction);
1581
} break;
1582
case DrawListInstruction::TYPE_NEXT_SUBPASS: {
1583
print_line("\tNEXT SUBPASS");
1584
instruction_data_cursor += sizeof(DrawListNextSubpassInstruction);
1585
} break;
1586
case DrawListInstruction::TYPE_SET_BLEND_CONSTANTS: {
1587
const DrawListSetBlendConstantsInstruction *set_blend_constants_instruction = reinterpret_cast<const DrawListSetBlendConstantsInstruction *>(instruction);
1588
print_line("\tSET BLEND CONSTANTS COLOR", set_blend_constants_instruction->color);
1589
instruction_data_cursor += sizeof(DrawListSetBlendConstantsInstruction);
1590
} break;
1591
case DrawListInstruction::TYPE_SET_LINE_WIDTH: {
1592
const DrawListSetLineWidthInstruction *set_line_width_instruction = reinterpret_cast<const DrawListSetLineWidthInstruction *>(instruction);
1593
print_line("\tSET LINE WIDTH", set_line_width_instruction->width);
1594
instruction_data_cursor += sizeof(DrawListSetLineWidthInstruction);
1595
} break;
1596
case DrawListInstruction::TYPE_SET_PUSH_CONSTANT: {
1597
const DrawListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const DrawListSetPushConstantInstruction *>(instruction);
1598
print_line("\tSET PUSH CONSTANT SIZE", set_push_constant_instruction->size);
1599
instruction_data_cursor += sizeof(DrawListSetPushConstantInstruction);
1600
instruction_data_cursor += set_push_constant_instruction->size;
1601
} break;
1602
case DrawListInstruction::TYPE_SET_SCISSOR: {
1603
const DrawListSetScissorInstruction *set_scissor_instruction = reinterpret_cast<const DrawListSetScissorInstruction *>(instruction);
1604
print_line("\tSET SCISSOR", set_scissor_instruction->rect);
1605
instruction_data_cursor += sizeof(DrawListSetScissorInstruction);
1606
} break;
1607
case DrawListInstruction::TYPE_SET_VIEWPORT: {
1608
const DrawListSetViewportInstruction *set_viewport_instruction = reinterpret_cast<const DrawListSetViewportInstruction *>(instruction);
1609
print_line("\tSET VIEWPORT", set_viewport_instruction->rect);
1610
instruction_data_cursor += sizeof(DrawListSetViewportInstruction);
1611
} break;
1612
case DrawListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
1613
const DrawListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const DrawListUniformSetPrepareForUseInstruction *>(instruction);
1614
print_line("\tUNIFORM SET PREPARE FOR USE ID", itos(uniform_set_prepare_for_use_instruction->uniform_set.id), "SHADER ID", itos(uniform_set_prepare_for_use_instruction->shader.id), "INDEX", uniform_set_prepare_for_use_instruction->set_index);
1615
instruction_data_cursor += sizeof(DrawListUniformSetPrepareForUseInstruction);
1616
} break;
1617
default:
1618
DEV_ASSERT(false && "Unknown draw list instruction type.");
1619
return;
1620
}
1621
1622
instruction_data_cursor = GRAPH_ALIGN(instruction_data_cursor);
1623
}
1624
}
1625
1626
void RenderingDeviceGraph::_print_raytracing_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
1627
uint32_t instruction_data_cursor = 0;
1628
while (instruction_data_cursor < p_instruction_data_size) {
1629
DEV_ASSERT((instruction_data_cursor + sizeof(RaytracingListInstruction)) <= p_instruction_data_size);
1630
1631
const RaytracingListInstruction *instruction = reinterpret_cast<const RaytracingListInstruction *>(&p_instruction_data[instruction_data_cursor]);
1632
switch (instruction->type) {
1633
case RaytracingListInstruction::TYPE_BIND_PIPELINE: {
1634
const RaytracingListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const RaytracingListBindPipelineInstruction *>(instruction);
1635
print_line("\tBIND PIPELINE ID", itos(bind_pipeline_instruction->pipeline.id));
1636
instruction_data_cursor += sizeof(RaytracingListBindPipelineInstruction);
1637
} break;
1638
case RaytracingListInstruction::TYPE_BIND_UNIFORM_SET: {
1639
const RaytracingListBindUniformSetInstruction *bind_uniform_set_instruction = reinterpret_cast<const RaytracingListBindUniformSetInstruction *>(instruction);
1640
print_line("\tBIND UNIFORM SET ID", itos(bind_uniform_set_instruction->uniform_set.id), "SHADER ID", itos(bind_uniform_set_instruction->shader.id));
1641
instruction_data_cursor += sizeof(RaytracingListBindUniformSetInstruction);
1642
} break;
1643
case RaytracingListInstruction::TYPE_SET_PUSH_CONSTANT: {
1644
const RaytracingListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const RaytracingListSetPushConstantInstruction *>(instruction);
1645
print_line("\tSET PUSH CONSTANT SIZE", set_push_constant_instruction->size);
1646
instruction_data_cursor += sizeof(RaytracingListSetPushConstantInstruction);
1647
instruction_data_cursor += set_push_constant_instruction->size;
1648
} break;
1649
case RaytracingListInstruction::TYPE_TRACE_RAYS: {
1650
const RaytracingListTraceRaysInstruction *trace_rays_instruction = reinterpret_cast<const RaytracingListTraceRaysInstruction *>(instruction);
1651
print_line("\tTRACE RAYS WIDTH", itos(trace_rays_instruction->width), "HEIGHT", itos(trace_rays_instruction->height));
1652
instruction_data_cursor += sizeof(RaytracingListTraceRaysInstruction);
1653
} break;
1654
case RaytracingListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
1655
const RaytracingListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const RaytracingListUniformSetPrepareForUseInstruction *>(instruction);
1656
print_line("\tUNIFORM SET PREPARE FOR USE ID", itos(uniform_set_prepare_for_use_instruction->uniform_set.id), "SHADER ID", itos(uniform_set_prepare_for_use_instruction->shader.id), "INDEX", itos(uniform_set_prepare_for_use_instruction->set_index));
1657
instruction_data_cursor += sizeof(RaytracingListUniformSetPrepareForUseInstruction);
1658
} break;
1659
default:
1660
DEV_ASSERT(false && "Unknown raytracing list instruction type.");
1661
return;
1662
}
1663
}
1664
}
1665
1666
void RenderingDeviceGraph::_print_compute_list(const uint8_t *p_instruction_data, uint32_t p_instruction_data_size) {
1667
uint32_t instruction_data_cursor = 0;
1668
while (instruction_data_cursor < p_instruction_data_size) {
1669
DEV_ASSERT((instruction_data_cursor + sizeof(ComputeListInstruction)) <= p_instruction_data_size);
1670
1671
const ComputeListInstruction *instruction = reinterpret_cast<const ComputeListInstruction *>(&p_instruction_data[instruction_data_cursor]);
1672
switch (instruction->type) {
1673
case ComputeListInstruction::TYPE_BIND_PIPELINE: {
1674
const ComputeListBindPipelineInstruction *bind_pipeline_instruction = reinterpret_cast<const ComputeListBindPipelineInstruction *>(instruction);
1675
print_line("\tBIND PIPELINE ID", itos(bind_pipeline_instruction->pipeline.id));
1676
instruction_data_cursor += sizeof(ComputeListBindPipelineInstruction);
1677
} break;
1678
case ComputeListInstruction::TYPE_BIND_UNIFORM_SETS: {
1679
const ComputeListBindUniformSetsInstruction *bind_uniform_sets_instruction = reinterpret_cast<const ComputeListBindUniformSetsInstruction *>(instruction);
1680
print_line("\tBIND UNIFORM SETS COUNT", bind_uniform_sets_instruction->set_count);
1681
for (uint32_t i = 0; i < bind_uniform_sets_instruction->set_count; i++) {
1682
print_line("\tBIND UNIFORM SET ID", itos(bind_uniform_sets_instruction->uniform_set_ids()[i].id), "START INDEX", bind_uniform_sets_instruction->first_set_index, "DYNAMIC_OFFSETS", bind_uniform_sets_instruction->dynamic_offsets_mask);
1683
}
1684
instruction_data_cursor += sizeof(ComputeListBindUniformSetsInstruction) + sizeof(RDD::UniformSetID) * bind_uniform_sets_instruction->set_count;
1685
} break;
1686
case ComputeListInstruction::TYPE_DISPATCH: {
1687
const ComputeListDispatchInstruction *dispatch_instruction = reinterpret_cast<const ComputeListDispatchInstruction *>(instruction);
1688
print_line("\tDISPATCH", dispatch_instruction->x_groups, dispatch_instruction->y_groups, dispatch_instruction->z_groups);
1689
instruction_data_cursor += sizeof(ComputeListDispatchInstruction);
1690
} break;
1691
case ComputeListInstruction::TYPE_DISPATCH_INDIRECT: {
1692
const ComputeListDispatchIndirectInstruction *dispatch_indirect_instruction = reinterpret_cast<const ComputeListDispatchIndirectInstruction *>(instruction);
1693
print_line("\tDISPATCH INDIRECT BUFFER ID", itos(dispatch_indirect_instruction->buffer.id), "OFFSET", dispatch_indirect_instruction->offset);
1694
instruction_data_cursor += sizeof(ComputeListDispatchIndirectInstruction);
1695
} break;
1696
case ComputeListInstruction::TYPE_SET_PUSH_CONSTANT: {
1697
const ComputeListSetPushConstantInstruction *set_push_constant_instruction = reinterpret_cast<const ComputeListSetPushConstantInstruction *>(instruction);
1698
print_line("\tSET PUSH CONSTANT SIZE", set_push_constant_instruction->size);
1699
instruction_data_cursor += sizeof(ComputeListSetPushConstantInstruction);
1700
instruction_data_cursor += set_push_constant_instruction->size;
1701
} break;
1702
case ComputeListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE: {
1703
const ComputeListUniformSetPrepareForUseInstruction *uniform_set_prepare_for_use_instruction = reinterpret_cast<const ComputeListUniformSetPrepareForUseInstruction *>(instruction);
1704
print_line("\tUNIFORM SET PREPARE FOR USE ID", itos(uniform_set_prepare_for_use_instruction->uniform_set.id), "SHADER ID", itos(uniform_set_prepare_for_use_instruction->shader.id), "INDEX", itos(uniform_set_prepare_for_use_instruction->set_index));
1705
instruction_data_cursor += sizeof(ComputeListUniformSetPrepareForUseInstruction);
1706
} break;
1707
default:
1708
DEV_ASSERT(false && "Unknown compute list instruction type.");
1709
return;
1710
}
1711
1712
instruction_data_cursor = GRAPH_ALIGN(instruction_data_cursor);
1713
}
1714
}
1715
1716
void RenderingDeviceGraph::initialize(RDD *p_driver, RenderingContextDriver::Device p_device, RenderPassCreationFunction p_render_pass_creation_function, uint32_t p_frame_count, RDD::CommandQueueFamilyID p_secondary_command_queue_family, uint32_t p_secondary_command_buffers_per_frame) {
1717
DEV_ASSERT(p_driver != nullptr);
1718
DEV_ASSERT(p_render_pass_creation_function != nullptr);
1719
DEV_ASSERT(p_frame_count > 0);
1720
1721
driver = p_driver;
1722
device = p_device;
1723
render_pass_creation_function = p_render_pass_creation_function;
1724
frames.resize(p_frame_count);
1725
1726
for (uint32_t i = 0; i < p_frame_count; i++) {
1727
frames[i].secondary_command_buffers.resize(p_secondary_command_buffers_per_frame);
1728
1729
for (uint32_t j = 0; j < p_secondary_command_buffers_per_frame; j++) {
1730
SecondaryCommandBuffer &secondary = frames[i].secondary_command_buffers[j];
1731
secondary.command_pool = driver->command_pool_create(p_secondary_command_queue_family, RDD::COMMAND_BUFFER_TYPE_SECONDARY);
1732
secondary.command_buffer = driver->command_buffer_create(secondary.command_pool);
1733
secondary.task = WorkerThreadPool::INVALID_TASK_ID;
1734
}
1735
}
1736
1737
driver_honors_barriers = driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS);
1738
driver_clears_with_copy_engine = driver->api_trait_get(RDD::API_TRAIT_CLEARS_WITH_COPY_ENGINE);
1739
driver_buffers_require_transitions = driver->api_trait_get(RDD::API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS);
1740
}
1741
1742
void RenderingDeviceGraph::finalize() {
1743
if (!frames.is_empty()) {
1744
_wait_for_secondary_command_buffer_tasks();
1745
}
1746
1747
for (Frame &f : frames) {
1748
for (SecondaryCommandBuffer &secondary : f.secondary_command_buffers) {
1749
if (secondary.command_pool.id != 0) {
1750
driver->command_pool_free(secondary.command_pool);
1751
}
1752
}
1753
}
1754
1755
frames.clear();
1756
}
1757
1758
void RenderingDeviceGraph::begin() {
1759
command_data.clear();
1760
command_data_offsets.clear();
1761
command_normalization_barriers.clear();
1762
command_transition_barriers.clear();
1763
command_buffer_barriers.clear();
1764
command_acceleration_structure_barriers.clear();
1765
command_label_chars.clear();
1766
command_label_colors.clear();
1767
command_label_offsets.clear();
1768
command_list_nodes.clear();
1769
read_slice_list_nodes.clear();
1770
write_slice_list_nodes.clear();
1771
command_count = 0;
1772
command_label_count = 0;
1773
command_timestamp_index = -1;
1774
command_synchronization_index = -1;
1775
command_synchronization_pending = false;
1776
command_label_index = -1;
1777
frames[frame].secondary_command_buffers_used = 0;
1778
draw_instruction_list.index = 0;
1779
compute_instruction_list.index = 0;
1780
tracking_frame++;
1781
1782
#ifdef DEV_ENABLED
1783
write_dependency_counters.clear();
1784
#endif
1785
}
1786
1787
void RenderingDeviceGraph::add_acceleration_structure_build(RDD::AccelerationStructureID p_acceleration_structure, RDD::BufferID p_scratch_buffer, ResourceTracker *p_dst_tracker, VectorView<ResourceTracker *> p_src_trackers) {
1788
int32_t command_index;
1789
RecordedAccelerationStructureBuildCommand *command = static_cast<RecordedAccelerationStructureBuildCommand *>(_allocate_command(sizeof(RecordedAccelerationStructureBuildCommand), command_index));
1790
command->type = RecordedCommand::TYPE_ACCELERATION_STRUCTURE_BUILD;
1791
command->self_stages = RDD::PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT;
1792
command->acceleration_structure = p_acceleration_structure;
1793
command->scratch_buffer = p_scratch_buffer;
1794
1795
thread_local LocalVector<ResourceTracker *> trackers;
1796
thread_local LocalVector<ResourceUsage> usages;
1797
1798
// Sources and destination.
1799
uint32_t resource_count = p_src_trackers.size() + 1;
1800
trackers.resize(resource_count);
1801
usages.resize(resource_count);
1802
1803
for (uint32_t i = 0; i < p_src_trackers.size(); ++i) {
1804
trackers[i] = p_src_trackers[i];
1805
usages[i] = RESOURCE_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT;
1806
}
1807
1808
trackers[resource_count - 1] = p_dst_tracker;
1809
usages[resource_count - 1] = RESOURCE_USAGE_ACCELERATION_STRUCTURE_READ_WRITE;
1810
1811
_add_command_to_graph(trackers.ptr(), usages.ptr(), usages.size(), command_index, command);
1812
}
1813
1814
void RenderingDeviceGraph::add_buffer_clear(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_offset, uint32_t p_size) {
1815
DEV_ASSERT(p_dst_tracker != nullptr);
1816
1817
int32_t command_index;
1818
RecordedBufferClearCommand *command = static_cast<RecordedBufferClearCommand *>(_allocate_command(sizeof(RecordedBufferClearCommand), command_index));
1819
command->type = RecordedCommand::TYPE_BUFFER_CLEAR;
1820
command->buffer = p_dst;
1821
command->offset = p_offset;
1822
command->size = p_size;
1823
1824
ResourceUsage usage;
1825
if (driver_clears_with_copy_engine) {
1826
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
1827
usage = RESOURCE_USAGE_COPY_TO;
1828
} else {
1829
// If the driver is uncapable of using the copy engine for clearing the buffer (e.g. D3D12), we must transition it to storage buffer read/write usage.
1830
command->self_stages = RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT;
1831
usage = RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE;
1832
}
1833
1834
_add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
1835
}
1836
1837
void RenderingDeviceGraph::add_buffer_copy(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, RDD::BufferCopyRegion p_region) {
1838
// Source tracker is allowed to be null as it could be a read-only buffer.
1839
DEV_ASSERT(p_dst_tracker != nullptr);
1840
1841
int32_t command_index;
1842
RecordedBufferCopyCommand *command = static_cast<RecordedBufferCopyCommand *>(_allocate_command(sizeof(RecordedBufferCopyCommand), command_index));
1843
command->type = RecordedCommand::TYPE_BUFFER_COPY;
1844
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
1845
command->source = p_src;
1846
command->destination = p_dst;
1847
command->region = p_region;
1848
1849
ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
1850
ResourceUsage usages[2] = { RESOURCE_USAGE_COPY_TO, RESOURCE_USAGE_COPY_FROM };
1851
_add_command_to_graph(trackers, usages, p_src_tracker != nullptr ? 2 : 1, command_index, command);
1852
}
1853
1854
void RenderingDeviceGraph::add_buffer_get_data(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, RDD::BufferCopyRegion p_region) {
1855
// Source tracker is allowed to be null as it could be a read-only buffer.
1856
int32_t command_index;
1857
RecordedBufferGetDataCommand *command = static_cast<RecordedBufferGetDataCommand *>(_allocate_command(sizeof(RecordedBufferGetDataCommand), command_index));
1858
command->type = RecordedCommand::TYPE_BUFFER_GET_DATA;
1859
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
1860
command->source = p_src;
1861
command->destination = p_dst;
1862
command->region = p_region;
1863
1864
if (p_src_tracker != nullptr) {
1865
ResourceUsage usage = RESOURCE_USAGE_COPY_FROM;
1866
_add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command);
1867
} else {
1868
_add_command_to_graph(nullptr, nullptr, 0, command_index, command);
1869
}
1870
}
1871
1872
void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferCopy> p_buffer_copies) {
1873
DEV_ASSERT(p_dst_tracker != nullptr);
1874
1875
size_t buffer_copies_size = p_buffer_copies.size() * sizeof(RecordedBufferCopy);
1876
uint64_t command_size = sizeof(RecordedBufferUpdateCommand) + buffer_copies_size;
1877
int32_t command_index;
1878
RecordedBufferUpdateCommand *command = static_cast<RecordedBufferUpdateCommand *>(_allocate_command(command_size, command_index));
1879
command->type = RecordedCommand::TYPE_BUFFER_UPDATE;
1880
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
1881
command->destination = p_dst;
1882
command->buffer_copies_count = p_buffer_copies.size();
1883
1884
RecordedBufferCopy *buffer_copies = command->buffer_copies();
1885
for (uint32_t i = 0; i < command->buffer_copies_count; i++) {
1886
buffer_copies[i] = p_buffer_copies[i];
1887
}
1888
1889
ResourceUsage buffer_usage = RESOURCE_USAGE_COPY_TO;
1890
_add_command_to_graph(&p_dst_tracker, &buffer_usage, 1, command_index, command);
1891
}
1892
1893
void RenderingDeviceGraph::add_driver_callback(RDD::DriverCallback p_callback, void *p_userdata, VectorView<ResourceTracker *> p_trackers, VectorView<RenderingDeviceGraph::ResourceUsage> p_usages) {
1894
DEV_ASSERT(p_trackers.size() == p_usages.size());
1895
1896
int32_t command_index;
1897
RecordedDriverCallbackCommand *command = static_cast<RecordedDriverCallbackCommand *>(_allocate_command(sizeof(RecordedDriverCallbackCommand), command_index));
1898
command->type = RecordedCommand::TYPE_DRIVER_CALLBACK;
1899
command->callback = p_callback;
1900
command->userdata = p_userdata;
1901
_add_command_to_graph((ResourceTracker **)p_trackers.ptr(), (ResourceUsage *)p_usages.ptr(), p_trackers.size(), command_index, command);
1902
}
1903
1904
void RenderingDeviceGraph::add_raytracing_list_begin() {
1905
raytracing_instruction_list.clear();
1906
raytracing_instruction_list.index++;
1907
}
1908
1909
void RenderingDeviceGraph::add_raytracing_list_bind_pipeline(RDD::RaytracingPipelineID p_pipeline) {
1910
RaytracingListBindPipelineInstruction *instruction = reinterpret_cast<RaytracingListBindPipelineInstruction *>(_allocate_raytracing_list_instruction(sizeof(RaytracingListBindPipelineInstruction)));
1911
instruction->type = RaytracingListInstruction::TYPE_BIND_PIPELINE;
1912
instruction->pipeline = p_pipeline;
1913
raytracing_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_RAY_TRACING_SHADER_BIT);
1914
}
1915
1916
void RenderingDeviceGraph::add_raytracing_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
1917
RaytracingListBindUniformSetInstruction *instruction = reinterpret_cast<RaytracingListBindUniformSetInstruction *>(_allocate_raytracing_list_instruction(sizeof(RaytracingListBindUniformSetInstruction)));
1918
instruction->type = RaytracingListInstruction::TYPE_BIND_UNIFORM_SET;
1919
instruction->shader = p_shader;
1920
instruction->uniform_set = p_uniform_set;
1921
instruction->set_index = set_index;
1922
}
1923
1924
void RenderingDeviceGraph::add_raytracing_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size) {
1925
uint32_t instruction_size = sizeof(RaytracingListSetPushConstantInstruction) + p_data_size;
1926
RaytracingListSetPushConstantInstruction *instruction = reinterpret_cast<RaytracingListSetPushConstantInstruction *>(_allocate_raytracing_list_instruction(instruction_size));
1927
instruction->type = RaytracingListInstruction::TYPE_SET_PUSH_CONSTANT;
1928
instruction->size = p_data_size;
1929
instruction->shader = p_shader;
1930
memcpy(instruction->data(), p_data, p_data_size);
1931
}
1932
1933
void RenderingDeviceGraph::add_raytracing_list_trace_rays(uint32_t p_width, uint32_t p_height) {
1934
RaytracingListTraceRaysInstruction *instruction = reinterpret_cast<RaytracingListTraceRaysInstruction *>(_allocate_raytracing_list_instruction(sizeof(RaytracingListTraceRaysInstruction)));
1935
instruction->type = RaytracingListInstruction::TYPE_TRACE_RAYS;
1936
instruction->width = p_width;
1937
instruction->height = p_height;
1938
}
1939
1940
void RenderingDeviceGraph::add_raytracing_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
1941
RaytracingListUniformSetPrepareForUseInstruction *instruction = reinterpret_cast<RaytracingListUniformSetPrepareForUseInstruction *>(_allocate_raytracing_list_instruction(sizeof(RaytracingListUniformSetPrepareForUseInstruction)));
1942
instruction->type = RaytracingListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE;
1943
instruction->shader = p_shader;
1944
instruction->uniform_set = p_uniform_set;
1945
instruction->set_index = set_index;
1946
}
1947
1948
void RenderingDeviceGraph::add_raytracing_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage) {
1949
DEV_ASSERT(p_tracker != nullptr);
1950
1951
p_tracker->reset_if_outdated(tracking_frame);
1952
1953
if (p_tracker->raytracing_list_index != raytracing_instruction_list.index) {
1954
raytracing_instruction_list.command_trackers.push_back(p_tracker);
1955
raytracing_instruction_list.command_tracker_usages.push_back(p_usage);
1956
p_tracker->raytracing_list_index = raytracing_instruction_list.index;
1957
p_tracker->raytracing_list_usage = p_usage;
1958
}
1959
#ifdef DEV_ENABLED
1960
else if (p_tracker->raytracing_list_usage != p_usage) {
1961
ERR_FAIL_MSG(vformat("Tracker can't have more than one type of usage in the same raytracing list. Raytracing list usage is %d and the requested usage is %d.", p_tracker->raytracing_list_usage, p_usage));
1962
}
1963
#endif
1964
}
1965
1966
void RenderingDeviceGraph::add_raytracing_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages) {
1967
DEV_ASSERT(p_trackers.size() == p_usages.size());
1968
1969
for (uint32_t i = 0; i < p_trackers.size(); i++) {
1970
add_raytracing_list_usage(p_trackers[i], p_usages[i]);
1971
}
1972
}
1973
1974
void RenderingDeviceGraph::add_raytracing_list_end() {
1975
int32_t command_index;
1976
uint32_t instruction_data_size = raytracing_instruction_list.data.size();
1977
uint32_t command_size = sizeof(RecordedRaytracingListCommand) + instruction_data_size;
1978
RecordedRaytracingListCommand *command = static_cast<RecordedRaytracingListCommand *>(_allocate_command(command_size, command_index));
1979
command->type = RecordedCommand::TYPE_RAYTRACING_LIST;
1980
command->self_stages = raytracing_instruction_list.stages;
1981
command->instruction_data_size = instruction_data_size;
1982
memcpy(command->instruction_data(), raytracing_instruction_list.data.ptr(), instruction_data_size);
1983
_add_command_to_graph(raytracing_instruction_list.command_trackers.ptr(), raytracing_instruction_list.command_tracker_usages.ptr(), raytracing_instruction_list.command_trackers.size(), command_index, command);
1984
}
1985
1986
void RenderingDeviceGraph::add_compute_list_begin(RDD::BreadcrumbMarker p_phase, uint32_t p_breadcrumb_data) {
1987
compute_instruction_list.clear();
1988
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
1989
compute_instruction_list.breadcrumb = p_breadcrumb_data | (p_phase & ((1 << 16) - 1));
1990
#endif
1991
compute_instruction_list.index++;
1992
}
1993
1994
void RenderingDeviceGraph::add_compute_list_bind_pipeline(RDD::PipelineID p_pipeline) {
1995
ComputeListBindPipelineInstruction *instruction = reinterpret_cast<ComputeListBindPipelineInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListBindPipelineInstruction)));
1996
instruction->type = ComputeListInstruction::TYPE_BIND_PIPELINE;
1997
instruction->pipeline = p_pipeline;
1998
compute_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
1999
}
2000
2001
void RenderingDeviceGraph::add_compute_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
2002
add_compute_list_bind_uniform_sets(p_shader, VectorView(&p_uniform_set, 1), set_index, 1);
2003
}
2004
2005
void RenderingDeviceGraph::add_compute_list_bind_uniform_sets(RDD::ShaderID p_shader, VectorView<RDD::UniformSetID> p_uniform_sets, uint32_t p_first_set_index, uint32_t p_set_count) {
2006
DEV_ASSERT(p_uniform_sets.size() >= p_set_count);
2007
2008
uint32_t instruction_size = sizeof(ComputeListBindUniformSetsInstruction) + sizeof(RDD::UniformSetID) * p_set_count;
2009
ComputeListBindUniformSetsInstruction *instruction = reinterpret_cast<ComputeListBindUniformSetsInstruction *>(_allocate_compute_list_instruction(instruction_size));
2010
instruction->type = ComputeListInstruction::TYPE_BIND_UNIFORM_SETS;
2011
instruction->shader = p_shader;
2012
instruction->first_set_index = p_first_set_index;
2013
instruction->set_count = p_set_count;
2014
instruction->dynamic_offsets_mask = driver->uniform_sets_get_dynamic_offsets(p_uniform_sets, p_shader, p_first_set_index, p_set_count);
2015
2016
RDD::UniformSetID *ids = instruction->uniform_set_ids();
2017
for (uint32_t i = 0; i < p_set_count; i++) {
2018
ids[i] = p_uniform_sets[i];
2019
}
2020
}
2021
2022
void RenderingDeviceGraph::add_compute_list_dispatch(uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {
2023
ComputeListDispatchInstruction *instruction = reinterpret_cast<ComputeListDispatchInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListDispatchInstruction)));
2024
instruction->type = ComputeListInstruction::TYPE_DISPATCH;
2025
instruction->x_groups = p_x_groups;
2026
instruction->y_groups = p_y_groups;
2027
instruction->z_groups = p_z_groups;
2028
}
2029
2030
void RenderingDeviceGraph::add_compute_list_dispatch_indirect(RDD::BufferID p_buffer, uint32_t p_offset) {
2031
ComputeListDispatchIndirectInstruction *instruction = reinterpret_cast<ComputeListDispatchIndirectInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListDispatchIndirectInstruction)));
2032
instruction->type = ComputeListInstruction::TYPE_DISPATCH_INDIRECT;
2033
instruction->buffer = p_buffer;
2034
instruction->offset = p_offset;
2035
compute_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
2036
}
2037
2038
void RenderingDeviceGraph::add_compute_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size) {
2039
uint32_t instruction_size = sizeof(ComputeListSetPushConstantInstruction) + p_data_size;
2040
ComputeListSetPushConstantInstruction *instruction = reinterpret_cast<ComputeListSetPushConstantInstruction *>(_allocate_compute_list_instruction(instruction_size));
2041
instruction->type = ComputeListInstruction::TYPE_SET_PUSH_CONSTANT;
2042
instruction->size = p_data_size;
2043
instruction->shader = p_shader;
2044
memcpy(instruction->data(), p_data, p_data_size);
2045
}
2046
2047
void RenderingDeviceGraph::add_compute_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
2048
ComputeListUniformSetPrepareForUseInstruction *instruction = reinterpret_cast<ComputeListUniformSetPrepareForUseInstruction *>(_allocate_compute_list_instruction(sizeof(ComputeListUniformSetPrepareForUseInstruction)));
2049
instruction->type = ComputeListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE;
2050
instruction->shader = p_shader;
2051
instruction->uniform_set = p_uniform_set;
2052
instruction->set_index = set_index;
2053
}
2054
2055
void RenderingDeviceGraph::add_compute_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage) {
2056
DEV_ASSERT(p_tracker != nullptr);
2057
2058
p_tracker->reset_if_outdated(tracking_frame);
2059
2060
if (p_tracker->compute_list_index != compute_instruction_list.index) {
2061
compute_instruction_list.command_trackers.push_back(p_tracker);
2062
compute_instruction_list.command_tracker_usages.push_back(p_usage);
2063
p_tracker->compute_list_index = compute_instruction_list.index;
2064
p_tracker->compute_list_usage = p_usage;
2065
}
2066
#ifdef DEV_ENABLED
2067
else if (p_tracker->compute_list_usage != p_usage) {
2068
ERR_FAIL_MSG(vformat("Tracker can't have more than one type of usage in the same compute list. Compute list usage is %s and the requested usage is %s.", _usage_to_string(p_tracker->compute_list_usage), _usage_to_string(p_usage)));
2069
}
2070
#endif
2071
}
2072
2073
void RenderingDeviceGraph::add_compute_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages) {
2074
DEV_ASSERT(p_trackers.size() == p_usages.size());
2075
2076
for (uint32_t i = 0; i < p_trackers.size(); i++) {
2077
add_compute_list_usage(p_trackers[i], p_usages[i]);
2078
}
2079
}
2080
2081
void RenderingDeviceGraph::add_compute_list_end() {
2082
int32_t command_index;
2083
uint32_t instruction_data_size = compute_instruction_list.data.size();
2084
uint32_t command_size = sizeof(RecordedComputeListCommand) + instruction_data_size;
2085
RecordedComputeListCommand *command = static_cast<RecordedComputeListCommand *>(_allocate_command(command_size, command_index));
2086
command->type = RecordedCommand::TYPE_COMPUTE_LIST;
2087
command->self_stages = compute_instruction_list.stages;
2088
command->instruction_data_size = instruction_data_size;
2089
memcpy(command->instruction_data(), compute_instruction_list.data.ptr(), instruction_data_size);
2090
_add_command_to_graph(compute_instruction_list.command_trackers.ptr(), compute_instruction_list.command_tracker_usages.ptr(), compute_instruction_list.command_trackers.size(), command_index, command);
2091
}
2092
2093
void RenderingDeviceGraph::add_draw_list_begin(FramebufferCache *p_framebuffer_cache, Rect2i p_region, VectorView<AttachmentOperation> p_attachment_operations, VectorView<RDD::RenderPassClearValue> p_attachment_clear_values, BitField<RDD::PipelineStageBits> p_stages, uint32_t p_breadcrumb, bool p_split_cmd_buffer) {
2094
_add_draw_list_begin(p_framebuffer_cache, RDD::RenderPassID(), RDD::FramebufferID(), p_region, p_attachment_operations, p_attachment_clear_values, p_stages, p_breadcrumb, p_split_cmd_buffer);
2095
}
2096
2097
void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass, RDD::FramebufferID p_framebuffer, Rect2i p_region, VectorView<AttachmentOperation> p_attachment_operations, VectorView<RDD::RenderPassClearValue> p_attachment_clear_values, BitField<RDD::PipelineStageBits> p_stages, uint32_t p_breadcrumb, bool p_split_cmd_buffer) {
2098
_add_draw_list_begin(nullptr, p_render_pass, p_framebuffer, p_region, p_attachment_operations, p_attachment_clear_values, p_stages, p_breadcrumb, p_split_cmd_buffer);
2099
}
2100
2101
void RenderingDeviceGraph::add_draw_list_bind_index_buffer(RDD::BufferID p_buffer, RDD::IndexBufferFormat p_format, uint32_t p_offset) {
2102
DrawListBindIndexBufferInstruction *instruction = reinterpret_cast<DrawListBindIndexBufferInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListBindIndexBufferInstruction)));
2103
instruction->type = DrawListInstruction::TYPE_BIND_INDEX_BUFFER;
2104
instruction->buffer = p_buffer;
2105
instruction->format = p_format;
2106
instruction->offset = p_offset;
2107
2108
if (instruction->buffer.id != 0) {
2109
draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT);
2110
}
2111
}
2112
2113
void RenderingDeviceGraph::add_draw_list_bind_pipeline(RDD::PipelineID p_pipeline, BitField<RDD::PipelineStageBits> p_pipeline_stage_bits) {
2114
DrawListBindPipelineInstruction *instruction = reinterpret_cast<DrawListBindPipelineInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListBindPipelineInstruction)));
2115
instruction->type = DrawListInstruction::TYPE_BIND_PIPELINE;
2116
instruction->pipeline = p_pipeline;
2117
draw_instruction_list.stages = draw_instruction_list.stages | p_pipeline_stage_bits;
2118
}
2119
2120
void RenderingDeviceGraph::add_draw_list_bind_uniform_set(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
2121
add_draw_list_bind_uniform_sets(p_shader, VectorView(&p_uniform_set, 1), set_index, 1);
2122
}
2123
2124
void RenderingDeviceGraph::add_draw_list_bind_uniform_sets(RDD::ShaderID p_shader, VectorView<RDD::UniformSetID> p_uniform_sets, uint32_t p_first_index, uint32_t p_set_count) {
2125
DEV_ASSERT(p_uniform_sets.size() >= p_set_count);
2126
2127
uint32_t instruction_size = sizeof(DrawListBindUniformSetsInstruction) + sizeof(RDD::UniformSetID) * p_set_count;
2128
DrawListBindUniformSetsInstruction *instruction = reinterpret_cast<DrawListBindUniformSetsInstruction *>(_allocate_draw_list_instruction(instruction_size));
2129
instruction->type = DrawListInstruction::TYPE_BIND_UNIFORM_SETS;
2130
instruction->shader = p_shader;
2131
instruction->first_set_index = p_first_index;
2132
instruction->set_count = p_set_count;
2133
instruction->dynamic_offsets_mask = driver->uniform_sets_get_dynamic_offsets(p_uniform_sets, p_shader, p_first_index, p_set_count);
2134
2135
for (uint32_t i = 0; i < p_set_count; i++) {
2136
instruction->uniform_set_ids()[i] = p_uniform_sets[i];
2137
}
2138
}
2139
2140
void RenderingDeviceGraph::add_draw_list_bind_vertex_buffers(Span<RDD::BufferID> p_vertex_buffers, Span<uint64_t> p_vertex_buffer_offsets) {
2141
DEV_ASSERT(p_vertex_buffers.size() == p_vertex_buffer_offsets.size());
2142
2143
uint32_t instruction_size = sizeof(DrawListBindVertexBuffersInstruction) + sizeof(RDD::BufferID) * p_vertex_buffers.size() + sizeof(uint64_t) * p_vertex_buffer_offsets.size();
2144
DrawListBindVertexBuffersInstruction *instruction = reinterpret_cast<DrawListBindVertexBuffersInstruction *>(_allocate_draw_list_instruction(instruction_size));
2145
instruction->type = DrawListInstruction::TYPE_BIND_VERTEX_BUFFERS;
2146
instruction->vertex_buffers_count = p_vertex_buffers.size();
2147
instruction->dynamic_offsets_mask = driver->buffer_get_dynamic_offsets(p_vertex_buffers);
2148
2149
RDD::BufferID *vertex_buffers = instruction->vertex_buffers();
2150
uint64_t *vertex_buffer_offsets = instruction->vertex_buffer_offsets();
2151
for (uint32_t i = 0; i < instruction->vertex_buffers_count; i++) {
2152
vertex_buffers[i] = p_vertex_buffers[i];
2153
vertex_buffer_offsets[i] = p_vertex_buffer_offsets[i];
2154
}
2155
2156
if (instruction->vertex_buffers_count > 0) {
2157
draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT);
2158
}
2159
}
2160
2161
void RenderingDeviceGraph::add_draw_list_clear_attachments(VectorView<RDD::AttachmentClear> p_attachments_clear, VectorView<Rect2i> p_attachments_clear_rect) {
2162
uint32_t instruction_size = sizeof(DrawListClearAttachmentsInstruction) + sizeof(RDD::AttachmentClear) * p_attachments_clear.size() + sizeof(Rect2i) * p_attachments_clear_rect.size();
2163
DrawListClearAttachmentsInstruction *instruction = reinterpret_cast<DrawListClearAttachmentsInstruction *>(_allocate_draw_list_instruction(instruction_size));
2164
instruction->type = DrawListInstruction::TYPE_CLEAR_ATTACHMENTS;
2165
instruction->attachments_clear_count = p_attachments_clear.size();
2166
instruction->attachments_clear_rect_count = p_attachments_clear_rect.size();
2167
2168
RDD::AttachmentClear *attachments_clear = instruction->attachments_clear();
2169
Rect2i *attachments_clear_rect = instruction->attachments_clear_rect();
2170
for (uint32_t i = 0; i < instruction->attachments_clear_count; i++) {
2171
attachments_clear[i] = p_attachments_clear[i];
2172
}
2173
2174
for (uint32_t i = 0; i < instruction->attachments_clear_rect_count; i++) {
2175
attachments_clear_rect[i] = p_attachments_clear_rect[i];
2176
}
2177
}
2178
2179
void RenderingDeviceGraph::add_draw_list_draw(uint32_t p_vertex_count, uint32_t p_instance_count) {
2180
DrawListDrawInstruction *instruction = reinterpret_cast<DrawListDrawInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawInstruction)));
2181
instruction->type = DrawListInstruction::TYPE_DRAW;
2182
instruction->vertex_count = p_vertex_count;
2183
instruction->instance_count = p_instance_count;
2184
}
2185
2186
void RenderingDeviceGraph::add_draw_list_draw_indexed(uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index) {
2187
DrawListDrawIndexedInstruction *instruction = reinterpret_cast<DrawListDrawIndexedInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndexedInstruction)));
2188
instruction->type = DrawListInstruction::TYPE_DRAW_INDEXED;
2189
instruction->index_count = p_index_count;
2190
instruction->instance_count = p_instance_count;
2191
instruction->first_index = p_first_index;
2192
}
2193
2194
void RenderingDeviceGraph::add_draw_list_draw_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
2195
DrawListDrawIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndirectInstruction)));
2196
instruction->type = DrawListInstruction::TYPE_DRAW_INDIRECT;
2197
instruction->buffer = p_buffer;
2198
instruction->offset = p_offset;
2199
instruction->draw_count = p_draw_count;
2200
instruction->stride = p_stride;
2201
draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
2202
}
2203
2204
void RenderingDeviceGraph::add_draw_list_draw_indexed_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
2205
DrawListDrawIndexedIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndexedIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndexedIndirectInstruction)));
2206
instruction->type = DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT;
2207
instruction->buffer = p_buffer;
2208
instruction->offset = p_offset;
2209
instruction->draw_count = p_draw_count;
2210
instruction->stride = p_stride;
2211
draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
2212
}
2213
2214
void RenderingDeviceGraph::add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer) {
2215
DrawListExecuteCommandsInstruction *instruction = reinterpret_cast<DrawListExecuteCommandsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListExecuteCommandsInstruction)));
2216
instruction->type = DrawListInstruction::TYPE_EXECUTE_COMMANDS;
2217
instruction->command_buffer = p_command_buffer;
2218
}
2219
2220
void RenderingDeviceGraph::add_draw_list_next_subpass(RDD::CommandBufferType p_command_buffer_type) {
2221
DrawListNextSubpassInstruction *instruction = reinterpret_cast<DrawListNextSubpassInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListNextSubpassInstruction)));
2222
instruction->type = DrawListInstruction::TYPE_NEXT_SUBPASS;
2223
instruction->command_buffer_type = p_command_buffer_type;
2224
}
2225
2226
void RenderingDeviceGraph::add_draw_list_set_blend_constants(const Color &p_color) {
2227
DrawListSetBlendConstantsInstruction *instruction = reinterpret_cast<DrawListSetBlendConstantsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetBlendConstantsInstruction)));
2228
instruction->type = DrawListInstruction::TYPE_SET_BLEND_CONSTANTS;
2229
instruction->color = p_color;
2230
}
2231
2232
void RenderingDeviceGraph::add_draw_list_set_line_width(float p_width) {
2233
DrawListSetLineWidthInstruction *instruction = reinterpret_cast<DrawListSetLineWidthInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetLineWidthInstruction)));
2234
instruction->type = DrawListInstruction::TYPE_SET_LINE_WIDTH;
2235
instruction->width = p_width;
2236
}
2237
2238
void RenderingDeviceGraph::add_draw_list_set_push_constant(RDD::ShaderID p_shader, const void *p_data, uint32_t p_data_size) {
2239
uint32_t instruction_size = sizeof(DrawListSetPushConstantInstruction) + p_data_size;
2240
DrawListSetPushConstantInstruction *instruction = reinterpret_cast<DrawListSetPushConstantInstruction *>(_allocate_draw_list_instruction(instruction_size));
2241
instruction->type = DrawListInstruction::TYPE_SET_PUSH_CONSTANT;
2242
instruction->size = p_data_size;
2243
instruction->shader = p_shader;
2244
memcpy(instruction->data(), p_data, p_data_size);
2245
}
2246
2247
void RenderingDeviceGraph::add_draw_list_set_scissor(Rect2i p_rect) {
2248
DrawListSetScissorInstruction *instruction = reinterpret_cast<DrawListSetScissorInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetScissorInstruction)));
2249
instruction->type = DrawListInstruction::TYPE_SET_SCISSOR;
2250
instruction->rect = p_rect;
2251
}
2252
2253
void RenderingDeviceGraph::add_draw_list_set_viewport(Rect2i p_rect) {
2254
DrawListSetViewportInstruction *instruction = reinterpret_cast<DrawListSetViewportInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListSetViewportInstruction)));
2255
instruction->type = DrawListInstruction::TYPE_SET_VIEWPORT;
2256
instruction->rect = p_rect;
2257
}
2258
2259
void RenderingDeviceGraph::add_draw_list_uniform_set_prepare_for_use(RDD::ShaderID p_shader, RDD::UniformSetID p_uniform_set, uint32_t set_index) {
2260
DrawListUniformSetPrepareForUseInstruction *instruction = reinterpret_cast<DrawListUniformSetPrepareForUseInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListUniformSetPrepareForUseInstruction)));
2261
instruction->type = DrawListInstruction::TYPE_UNIFORM_SET_PREPARE_FOR_USE;
2262
instruction->shader = p_shader;
2263
instruction->uniform_set = p_uniform_set;
2264
instruction->set_index = set_index;
2265
}
2266
2267
void RenderingDeviceGraph::add_draw_list_usage(ResourceTracker *p_tracker, ResourceUsage p_usage) {
2268
p_tracker->reset_if_outdated(tracking_frame);
2269
2270
if (p_tracker->draw_list_index != draw_instruction_list.index) {
2271
draw_instruction_list.command_trackers.push_back(p_tracker);
2272
draw_instruction_list.command_tracker_usages.push_back(p_usage);
2273
p_tracker->draw_list_index = draw_instruction_list.index;
2274
p_tracker->draw_list_usage = p_usage;
2275
}
2276
#ifdef DEV_ENABLED
2277
else if (p_tracker->draw_list_usage != p_usage) {
2278
ERR_FAIL_MSG(vformat("Tracker can't have more than one type of usage in the same draw list. Draw list usage is %s and the requested usage is %s.", _usage_to_string(p_tracker->draw_list_usage), _usage_to_string(p_usage)));
2279
}
2280
#endif
2281
}
2282
2283
void RenderingDeviceGraph::add_draw_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages) {
2284
DEV_ASSERT(p_trackers.size() == p_usages.size());
2285
2286
for (uint32_t i = 0; i < p_trackers.size(); i++) {
2287
add_draw_list_usage(p_trackers[i], p_usages[i]);
2288
}
2289
}
2290
2291
void RenderingDeviceGraph::add_draw_list_end() {
2292
FramebufferCache *framebuffer_cache = draw_instruction_list.framebuffer_cache;
2293
int32_t command_index;
2294
uint32_t clear_values_size = sizeof(RDD::RenderPassClearValue) * draw_instruction_list.attachment_clear_values.size();
2295
uint32_t trackers_count = framebuffer_cache != nullptr ? framebuffer_cache->trackers.size() : 0;
2296
uint32_t trackers_and_ops_size = (sizeof(ResourceTracker *) + sizeof(RDD::AttachmentLoadOp) + sizeof(RDD::AttachmentStoreOp)) * trackers_count;
2297
uint32_t instruction_data_size = draw_instruction_list.data.size();
2298
uint32_t command_size = sizeof(RecordedDrawListCommand) + clear_values_size + trackers_and_ops_size + instruction_data_size;
2299
RecordedDrawListCommand *command = static_cast<RecordedDrawListCommand *>(_allocate_command(command_size, command_index));
2300
command->type = RecordedCommand::TYPE_DRAW_LIST;
2301
command->self_stages = draw_instruction_list.stages;
2302
command->framebuffer_cache = framebuffer_cache;
2303
command->render_pass = draw_instruction_list.render_pass;
2304
command->framebuffer = draw_instruction_list.framebuffer;
2305
command->instruction_data_size = instruction_data_size;
2306
command->command_buffer_type = RDD::COMMAND_BUFFER_TYPE_PRIMARY;
2307
command->region = draw_instruction_list.region;
2308
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
2309
command->breadcrumb = draw_instruction_list.breadcrumb;
2310
#endif
2311
command->split_cmd_buffer = draw_instruction_list.split_cmd_buffer;
2312
command->clear_values_count = draw_instruction_list.attachment_clear_values.size();
2313
command->trackers_count = trackers_count;
2314
2315
// Initialize the load and store operations to their default behaviors. The store behavior will be modified if a command depends on the result of this render pass.
2316
uint32_t attachment_op_count = draw_instruction_list.attachment_operations.size();
2317
ResourceTracker **trackers = command->trackers();
2318
RDD::AttachmentLoadOp *load_ops = command->load_ops();
2319
RDD::AttachmentStoreOp *store_ops = command->store_ops();
2320
for (uint32_t i = 0; i < command->trackers_count; i++) {
2321
ResourceTracker *resource_tracker = framebuffer_cache->trackers[i];
2322
if (resource_tracker != nullptr) {
2323
if (i < command->clear_values_count && i < attachment_op_count && draw_instruction_list.attachment_operations[i] == ATTACHMENT_OPERATION_CLEAR) {
2324
load_ops[i] = RDD::ATTACHMENT_LOAD_OP_CLEAR;
2325
} else if (i < attachment_op_count && draw_instruction_list.attachment_operations[i] == ATTACHMENT_OPERATION_IGNORE) {
2326
load_ops[i] = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
2327
} else if (resource_tracker->is_discardable) {
2328
bool resource_has_parent = resource_tracker->parent != nullptr;
2329
ResourceTracker *search_tracker = resource_has_parent ? resource_tracker->parent : resource_tracker;
2330
search_tracker->reset_if_outdated(tracking_frame);
2331
bool resource_was_modified_this_frame = search_tracker->write_command_or_list_index >= 0;
2332
load_ops[i] = resource_was_modified_this_frame ? RDD::ATTACHMENT_LOAD_OP_LOAD : RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
2333
} else {
2334
load_ops[i] = RDD::ATTACHMENT_LOAD_OP_LOAD;
2335
}
2336
2337
store_ops[i] = resource_tracker->is_discardable ? RDD::ATTACHMENT_STORE_OP_DONT_CARE : RDD::ATTACHMENT_STORE_OP_STORE;
2338
} else {
2339
load_ops[i] = RDD::ATTACHMENT_LOAD_OP_DONT_CARE;
2340
store_ops[i] = RDD::ATTACHMENT_STORE_OP_DONT_CARE;
2341
}
2342
2343
trackers[i] = resource_tracker;
2344
}
2345
2346
RDD::RenderPassClearValue *clear_values = command->clear_values();
2347
for (uint32_t i = 0; i < command->clear_values_count; i++) {
2348
clear_values[i] = draw_instruction_list.attachment_clear_values[i];
2349
}
2350
2351
memcpy(command->instruction_data(), draw_instruction_list.data.ptr(), instruction_data_size);
2352
_add_command_to_graph(draw_instruction_list.command_trackers.ptr(), draw_instruction_list.command_tracker_usages.ptr(), draw_instruction_list.command_trackers.size(), command_index, command);
2353
}
2354
2355
void RenderingDeviceGraph::add_texture_clear_color(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, const Color &p_color, const RDD::TextureSubresourceRange &p_range) {
2356
DEV_ASSERT(p_dst_tracker != nullptr);
2357
2358
int32_t command_index;
2359
RecordedTextureClearColorCommand *command = static_cast<RecordedTextureClearColorCommand *>(_allocate_command(sizeof(RecordedTextureClearColorCommand), command_index));
2360
command->type = RecordedCommand::TYPE_TEXTURE_CLEAR_COLOR;
2361
command->texture = p_dst;
2362
command->color = p_color;
2363
command->range = p_range;
2364
2365
ResourceUsage usage;
2366
if (driver_clears_with_copy_engine) {
2367
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
2368
usage = RESOURCE_USAGE_COPY_TO;
2369
} else {
2370
// If the driver is uncapable of using the copy engine for clearing the image (e.g. D3D12), we must either transition the
2371
// resource to a render target or a storage image as that's the only two ways it can perform the operation.
2372
if (p_dst_tracker->texture_usage & RDD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
2373
command->self_stages = RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2374
usage = RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE;
2375
} else {
2376
command->self_stages = RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT;
2377
usage = RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE;
2378
}
2379
}
2380
2381
_add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
2382
}
2383
2384
void RenderingDeviceGraph::add_texture_clear_depth_stencil(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, float p_depth, uint8_t p_stencil, const RDD::TextureSubresourceRange &p_range) {
2385
DEV_ASSERT(p_dst_tracker != nullptr);
2386
2387
int32_t command_index;
2388
RecordedTextureClearDepthStencilCommand *command = static_cast<RecordedTextureClearDepthStencilCommand *>(_allocate_command(sizeof(RecordedTextureClearDepthStencilCommand), command_index));
2389
command->type = RecordedCommand::TYPE_TEXTURE_CLEAR_DEPTH_STENCIL;
2390
command->texture = p_dst;
2391
command->depth = p_depth;
2392
command->stencil = p_stencil;
2393
command->range = p_range;
2394
2395
ResourceUsage usage;
2396
if (driver_clears_with_copy_engine) {
2397
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
2398
usage = RESOURCE_USAGE_COPY_TO;
2399
} else {
2400
// If the driver is uncapable of using the copy engine for clearing the image (e.g. D3D12), we must transition the
2401
// resource to a depth stencil as that's the only way it can perform the operation.
2402
command->self_stages = RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
2403
usage = RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE;
2404
}
2405
2406
_add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
2407
}
2408
2409
void RenderingDeviceGraph::add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RDD::TextureCopyRegion> p_texture_copy_regions) {
2410
DEV_ASSERT(p_src_tracker != nullptr);
2411
DEV_ASSERT(p_dst_tracker != nullptr);
2412
2413
int32_t command_index;
2414
uint64_t command_size = sizeof(RecordedTextureCopyCommand) + p_texture_copy_regions.size() * sizeof(RDD::TextureCopyRegion);
2415
RecordedTextureCopyCommand *command = static_cast<RecordedTextureCopyCommand *>(_allocate_command(command_size, command_index));
2416
command->type = RecordedCommand::TYPE_TEXTURE_COPY;
2417
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
2418
command->from_texture = p_src;
2419
command->to_texture = p_dst;
2420
command->texture_copy_regions_count = p_texture_copy_regions.size();
2421
2422
RDD::TextureCopyRegion *texture_copy_regions = command->texture_copy_regions();
2423
for (uint32_t i = 0; i < command->texture_copy_regions_count; i++) {
2424
texture_copy_regions[i] = p_texture_copy_regions[i];
2425
}
2426
2427
ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
2428
ResourceUsage usages[2] = { RESOURCE_USAGE_COPY_TO, RESOURCE_USAGE_COPY_FROM };
2429
_add_command_to_graph(trackers, usages, 2, command_index, command);
2430
}
2431
2432
void RenderingDeviceGraph::add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions, ResourceTracker *p_dst_tracker) {
2433
DEV_ASSERT(p_src_tracker != nullptr);
2434
2435
int32_t command_index;
2436
uint64_t command_size = sizeof(RecordedTextureGetDataCommand) + p_buffer_texture_copy_regions.size() * sizeof(RDD::BufferTextureCopyRegion);
2437
RecordedTextureGetDataCommand *command = static_cast<RecordedTextureGetDataCommand *>(_allocate_command(command_size, command_index));
2438
command->type = RecordedCommand::TYPE_TEXTURE_GET_DATA;
2439
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
2440
command->from_texture = p_src;
2441
command->to_buffer = p_dst;
2442
command->buffer_texture_copy_regions_count = p_buffer_texture_copy_regions.size();
2443
2444
RDD::BufferTextureCopyRegion *buffer_texture_copy_regions = command->buffer_texture_copy_regions();
2445
for (uint32_t i = 0; i < command->buffer_texture_copy_regions_count; i++) {
2446
buffer_texture_copy_regions[i] = p_buffer_texture_copy_regions[i];
2447
}
2448
2449
if (p_dst_tracker != nullptr) {
2450
// Add the optional destination tracker if it was provided.
2451
ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
2452
ResourceUsage usages[2] = { RESOURCE_USAGE_COPY_TO, RESOURCE_USAGE_COPY_FROM };
2453
_add_command_to_graph(trackers, usages, 2, command_index, command);
2454
} else {
2455
ResourceUsage usage = RESOURCE_USAGE_COPY_FROM;
2456
_add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command);
2457
}
2458
}
2459
2460
void RenderingDeviceGraph::add_texture_resolve(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_src_layer, uint32_t p_src_mipmap, uint32_t p_dst_layer, uint32_t p_dst_mipmap) {
2461
DEV_ASSERT(p_src_tracker != nullptr);
2462
DEV_ASSERT(p_dst_tracker != nullptr);
2463
2464
int32_t command_index;
2465
RecordedTextureResolveCommand *command = static_cast<RecordedTextureResolveCommand *>(_allocate_command(sizeof(RecordedTextureResolveCommand), command_index));
2466
command->type = RecordedCommand::TYPE_TEXTURE_RESOLVE;
2467
command->self_stages = RDD::PIPELINE_STAGE_RESOLVE_BIT;
2468
command->from_texture = p_src;
2469
command->to_texture = p_dst;
2470
command->src_layer = p_src_layer;
2471
command->src_mipmap = p_src_mipmap;
2472
command->dst_layer = p_dst_layer;
2473
command->dst_mipmap = p_dst_mipmap;
2474
2475
ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
2476
ResourceUsage usages[2] = { RESOURCE_USAGE_RESOLVE_TO, RESOURCE_USAGE_RESOLVE_FROM };
2477
_add_command_to_graph(trackers, usages, 2, command_index, command);
2478
}
2479
2480
void RenderingDeviceGraph::add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies, VectorView<ResourceTracker *> p_buffer_trackers) {
2481
DEV_ASSERT(p_dst_tracker != nullptr);
2482
2483
int32_t command_index;
2484
uint64_t command_size = sizeof(RecordedTextureUpdateCommand) + p_buffer_copies.size() * sizeof(RecordedBufferToTextureCopy);
2485
RecordedTextureUpdateCommand *command = static_cast<RecordedTextureUpdateCommand *>(_allocate_command(command_size, command_index));
2486
command->type = RecordedCommand::TYPE_TEXTURE_UPDATE;
2487
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
2488
command->to_texture = p_dst;
2489
command->buffer_to_texture_copies_count = p_buffer_copies.size();
2490
2491
RecordedBufferToTextureCopy *buffer_to_texture_copies = command->buffer_to_texture_copies();
2492
for (uint32_t i = 0; i < command->buffer_to_texture_copies_count; i++) {
2493
buffer_to_texture_copies[i] = p_buffer_copies[i];
2494
}
2495
2496
if (p_buffer_trackers.size() > 0) {
2497
// Add the optional buffer trackers if they were provided.
2498
thread_local LocalVector<ResourceTracker *> trackers;
2499
thread_local LocalVector<ResourceUsage> usages;
2500
trackers.clear();
2501
usages.clear();
2502
for (uint32_t i = 0; i < p_buffer_trackers.size(); i++) {
2503
trackers.push_back(p_buffer_trackers[i]);
2504
usages.push_back(RESOURCE_USAGE_COPY_FROM);
2505
}
2506
2507
trackers.push_back(p_dst_tracker);
2508
usages.push_back(RESOURCE_USAGE_COPY_TO);
2509
2510
_add_command_to_graph(trackers.ptr(), usages.ptr(), trackers.size(), command_index, command);
2511
} else {
2512
ResourceUsage usage = RESOURCE_USAGE_COPY_TO;
2513
_add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
2514
}
2515
}
2516
2517
void RenderingDeviceGraph::add_capture_timestamp(RDD::QueryPoolID p_query_pool, uint32_t p_index) {
2518
int32_t command_index;
2519
RecordedCaptureTimestampCommand *command = static_cast<RecordedCaptureTimestampCommand *>(_allocate_command(sizeof(RecordedCaptureTimestampCommand), command_index));
2520
command->type = RecordedCommand::TYPE_CAPTURE_TIMESTAMP;
2521
command->self_stages = 0;
2522
command->pool = p_query_pool;
2523
command->index = p_index;
2524
_add_command_to_graph(nullptr, nullptr, 0, command_index, command);
2525
}
2526
2527
void RenderingDeviceGraph::add_synchronization() {
2528
// Synchronization is only acknowledged if commands have been recorded on the graph already.
2529
if (command_count > 0) {
2530
command_synchronization_pending = true;
2531
}
2532
}
2533
2534
void RenderingDeviceGraph::begin_label(const Span<char> &p_label_name, const Color &p_color) {
2535
uint32_t command_label_offset = command_label_chars.size();
2536
int command_label_size = p_label_name.size();
2537
command_label_chars.resize(command_label_offset + command_label_size + 1);
2538
memcpy(&command_label_chars[command_label_offset], p_label_name.ptr(), command_label_size);
2539
command_label_chars[command_label_offset + command_label_size] = '\0';
2540
command_label_colors.push_back(p_color);
2541
command_label_offsets.push_back(command_label_offset);
2542
command_label_index = command_label_count;
2543
command_label_count++;
2544
}
2545
2546
void RenderingDeviceGraph::end_label() {
2547
command_label_index = -1;
2548
}
2549
2550
void RenderingDeviceGraph::end(bool p_reorder_commands, bool p_full_barriers, RDD::CommandBufferID &r_command_buffer, CommandBufferPool &r_command_buffer_pool) {
2551
if (command_count == 0) {
2552
// No commands have been logged, do nothing.
2553
return;
2554
}
2555
2556
thread_local LocalVector<RecordedCommandSort> commands_sorted;
2557
if (p_reorder_commands) {
2558
thread_local LocalVector<int64_t> command_stack;
2559
thread_local LocalVector<int32_t> sorted_command_indices;
2560
thread_local LocalVector<uint32_t> command_degrees;
2561
int32_t adjacency_list_index = 0;
2562
int32_t command_index;
2563
2564
// Count all the incoming connections to every node by traversing their adjacency list.
2565
command_degrees.resize(command_count);
2566
memset(command_degrees.ptr(), 0, sizeof(uint32_t) * command_degrees.size());
2567
for (uint32_t i = 0; i < command_count; i++) {
2568
const RecordedCommand &recorded_command = *reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offsets[i]]);
2569
adjacency_list_index = recorded_command.adjacent_command_list_index;
2570
while (adjacency_list_index >= 0) {
2571
const RecordedCommandListNode &command_list_node = command_list_nodes[adjacency_list_index];
2572
DEV_ASSERT((command_list_node.command_index != int32_t(i)) && "Command can't have itself as a dependency.");
2573
command_degrees[command_list_node.command_index] += 1;
2574
adjacency_list_index = command_list_node.next_list_index;
2575
}
2576
}
2577
2578
// Push to the stack all nodes that have no incoming connections.
2579
command_stack.clear();
2580
for (uint32_t i = 0; i < command_count; i++) {
2581
if (command_degrees[i] == 0) {
2582
command_stack.push_back(i);
2583
}
2584
}
2585
2586
sorted_command_indices.clear();
2587
while (!command_stack.is_empty()) {
2588
// Pop command from the stack.
2589
command_index = command_stack[command_stack.size() - 1];
2590
command_stack.resize(command_stack.size() - 1);
2591
2592
// Add it to the sorted commands.
2593
sorted_command_indices.push_back(command_index);
2594
2595
// Search for its adjacents and lower their degree for every visit. If the degree reaches zero, we push the command to the stack.
2596
const uint32_t command_data_offset = command_data_offsets[command_index];
2597
const RecordedCommand &recorded_command = *reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offset]);
2598
adjacency_list_index = recorded_command.adjacent_command_list_index;
2599
while (adjacency_list_index >= 0) {
2600
const RecordedCommandListNode &command_list_node = command_list_nodes[adjacency_list_index];
2601
uint32_t &command_degree = command_degrees[command_list_node.command_index];
2602
DEV_ASSERT(command_degree > 0);
2603
command_degree--;
2604
if (command_degree == 0) {
2605
command_stack.push_back(command_list_node.command_index);
2606
}
2607
2608
adjacency_list_index = command_list_node.next_list_index;
2609
}
2610
}
2611
2612
// Batch buffer, texture, draw lists and compute operations together.
2613
const uint32_t PriorityTable[RecordedCommand::TYPE_MAX] = {
2614
0, // TYPE_NONE
2615
1, // TYPE_BUFFER_CLEAR
2616
1, // TYPE_BUFFER_COPY
2617
1, // TYPE_BUFFER_GET_DATA
2618
1, // TYPE_BUFFER_UPDATE
2619
4, // TYPE_COMPUTE_LIST
2620
3, // TYPE_DRAW_LIST
2621
2, // TYPE_TEXTURE_CLEAR_COLOR
2622
2, // TYPE_TEXTURE_CLEAR_DEPTH_STENCIL
2623
2, // TYPE_TEXTURE_COPY
2624
2, // TYPE_TEXTURE_GET_DATA
2625
2, // TYPE_TEXTURE_RESOLVE
2626
2, // TYPE_TEXTURE_UPDATE
2627
2, // TYPE_CAPTURE_TIMESTAMP
2628
5, // TYPE_DRIVER_CALLBACK
2629
};
2630
2631
commands_sorted.clear();
2632
commands_sorted.resize(command_count);
2633
2634
for (uint32_t i = 0; i < command_count; i++) {
2635
const int32_t sorted_command_index = sorted_command_indices[i];
2636
const uint32_t command_data_offset = command_data_offsets[sorted_command_index];
2637
const RecordedCommand recorded_command = *reinterpret_cast<const RecordedCommand *>(&command_data[command_data_offset]);
2638
const uint32_t next_command_level = commands_sorted[sorted_command_index].level + 1;
2639
adjacency_list_index = recorded_command.adjacent_command_list_index;
2640
while (adjacency_list_index >= 0) {
2641
const RecordedCommandListNode &command_list_node = command_list_nodes[adjacency_list_index];
2642
uint32_t &adjacent_command_level = commands_sorted[command_list_node.command_index].level;
2643
if (adjacent_command_level < next_command_level) {
2644
adjacent_command_level = next_command_level;
2645
}
2646
2647
adjacency_list_index = command_list_node.next_list_index;
2648
}
2649
2650
commands_sorted[sorted_command_index].index = sorted_command_index;
2651
commands_sorted[sorted_command_index].priority = PriorityTable[recorded_command.type];
2652
}
2653
} else {
2654
commands_sorted.clear();
2655
commands_sorted.resize(command_count);
2656
2657
for (uint32_t i = 0; i < command_count; i++) {
2658
commands_sorted[i].index = i;
2659
}
2660
}
2661
2662
_wait_for_secondary_command_buffer_tasks();
2663
2664
if (command_count > 0) {
2665
int32_t current_label_index = -1;
2666
int32_t current_label_level = -1;
2667
_run_label_command_change(r_command_buffer, -1, -1, true, true, nullptr, 0, current_label_index, current_label_level);
2668
2669
if (device.workarounds.avoid_compute_after_draw) {
2670
// Reset the state of the workaround.
2671
workarounds_state.draw_list_found = false;
2672
}
2673
2674
#if PRINT_DRAW_LIST_STATS
2675
draw_list_total_size = 0;
2676
#endif
2677
2678
if (p_reorder_commands) {
2679
#if PRINT_RENDER_GRAPH
2680
print_line("BEFORE SORT");
2681
_print_render_commands(commands_sorted.ptr(), command_count);
2682
#endif
2683
2684
commands_sorted.sort();
2685
2686
#if PRINT_RENDER_GRAPH
2687
print_line("AFTER SORT");
2688
_print_render_commands(commands_sorted.ptr(), command_count);
2689
#endif
2690
2691
#if PRINT_COMMAND_RECORDING
2692
print_line(vformat("Recording %d commands", command_count));
2693
#endif
2694
2695
uint32_t boosted_priority = 0;
2696
uint32_t current_level = commands_sorted[0].level;
2697
uint32_t current_level_start = 0;
2698
for (uint32_t i = 0; i < command_count; i++) {
2699
if (current_level != commands_sorted[i].level) {
2700
RecordedCommandSort *level_command_ptr = &commands_sorted[current_level_start];
2701
uint32_t level_command_count = i - current_level_start;
2702
_boost_priority_for_render_commands(level_command_ptr, level_command_count, boosted_priority);
2703
_group_barriers_for_render_commands(r_command_buffer, level_command_ptr, level_command_count, p_full_barriers);
2704
_run_render_commands(current_level, level_command_ptr, level_command_count, r_command_buffer, r_command_buffer_pool, current_label_index, current_label_level);
2705
current_level = commands_sorted[i].level;
2706
current_level_start = i;
2707
}
2708
}
2709
2710
RecordedCommandSort *level_command_ptr = &commands_sorted[current_level_start];
2711
uint32_t level_command_count = command_count - current_level_start;
2712
_boost_priority_for_render_commands(level_command_ptr, level_command_count, boosted_priority);
2713
_group_barriers_for_render_commands(r_command_buffer, level_command_ptr, level_command_count, p_full_barriers);
2714
_run_render_commands(current_level, level_command_ptr, level_command_count, r_command_buffer, r_command_buffer_pool, current_label_index, current_label_level);
2715
2716
#if PRINT_RENDER_GRAPH
2717
print_line("COMMANDS", command_count, "LEVELS", current_level + 1);
2718
#endif
2719
} else {
2720
for (uint32_t i = 0; i < command_count; i++) {
2721
_group_barriers_for_render_commands(r_command_buffer, &commands_sorted[i], 1, p_full_barriers);
2722
_run_render_commands(i, &commands_sorted[i], 1, r_command_buffer, r_command_buffer_pool, current_label_index, current_label_level);
2723
}
2724
}
2725
2726
_run_label_command_change(r_command_buffer, -1, -1, false, false, nullptr, 0, current_label_index, current_label_level);
2727
2728
#if PRINT_DRAW_LIST_STATS
2729
print_line(vformat("Draw list %d bytes", draw_list_total_size));
2730
#endif
2731
#if PRINT_COMMAND_RECORDING
2732
print_line(vformat("Recorded %d commands", command_count));
2733
#endif
2734
}
2735
2736
// Advance the frame counter. It's not necessary to do this if no commands are recorded because that means no secondary command buffers were used.
2737
frame = (frame + 1) % frames.size();
2738
}
2739
2740
#if PRINT_RESOURCE_TRACKER_TOTAL
2741
static uint32_t resource_tracker_total = 0;
2742
#endif
2743
2744
RenderingDeviceGraph::ResourceTracker *RenderingDeviceGraph::resource_tracker_create() {
2745
#if PRINT_RESOURCE_TRACKER_TOTAL
2746
print_line("Resource trackers:", ++resource_tracker_total);
2747
#endif
2748
return memnew(ResourceTracker);
2749
}
2750
2751
void RenderingDeviceGraph::resource_tracker_free(ResourceTracker *p_tracker) {
2752
if (p_tracker == nullptr) {
2753
return;
2754
}
2755
2756
if (p_tracker->in_parent_dirty_list) {
2757
// Delete the tracker from the parent's dirty linked list.
2758
if (p_tracker->parent->dirty_shared_list == p_tracker) {
2759
p_tracker->parent->dirty_shared_list = p_tracker->next_shared;
2760
} else {
2761
ResourceTracker *node = p_tracker->parent->dirty_shared_list;
2762
while (node != nullptr) {
2763
if (node->next_shared == p_tracker) {
2764
node->next_shared = p_tracker->next_shared;
2765
node = nullptr;
2766
} else {
2767
node = node->next_shared;
2768
}
2769
}
2770
}
2771
}
2772
2773
memdelete(p_tracker);
2774
2775
#if PRINT_RESOURCE_TRACKER_TOTAL
2776
print_line("Resource trackers:", --resource_tracker_total);
2777
#endif
2778
}
2779
2780
RenderingDeviceGraph::FramebufferCache *RenderingDeviceGraph::framebuffer_cache_create() {
2781
return memnew(FramebufferCache);
2782
}
2783
2784
void RenderingDeviceGraph::framebuffer_cache_free(RDD *p_driver, FramebufferCache *p_cache) {
2785
DEV_ASSERT(p_driver != nullptr);
2786
2787
if (p_cache == nullptr) {
2788
return;
2789
}
2790
2791
for (KeyValue<uint64_t, FramebufferStorage> &E : p_cache->storage_map) {
2792
p_driver->framebuffer_free(E.value.framebuffer);
2793
p_driver->render_pass_free(E.value.render_pass);
2794
}
2795
2796
memdelete(p_cache);
2797
}
2798
2799