Skip to content

Commit 568589c

Browse files
authored
Merge pull request godotengine#90993 from darksylinc/matias-TheForge
Add debug utilities for Vulkan
2 parents 37ae2a2 + 364f916 commit 568589c

32 files changed

+1321
-108
lines changed

core/os/memory.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include <stdio.h>
3737
#include <stdlib.h>
38+
#include <string.h>
3839

3940
void *operator new(size_t p_size, const char *p_description) {
4041
return Memory::alloc_static(p_size, false);
@@ -65,6 +66,38 @@ SafeNumeric<uint64_t> Memory::max_usage;
6566

6667
SafeNumeric<uint64_t> Memory::alloc_count;
6768

69+
inline bool is_power_of_2(size_t x) { return x && ((x & (x - 1U)) == 0U); }
70+
71+
void *Memory::alloc_aligned_static(size_t p_bytes, size_t p_alignment) {
72+
DEV_ASSERT(is_power_of_2(p_alignment));
73+
74+
void *p1, *p2;
75+
if ((p1 = (void *)malloc(p_bytes + p_alignment - 1 + sizeof(uint32_t))) == nullptr) {
76+
return nullptr;
77+
}
78+
79+
p2 = (void *)(((uintptr_t)p1 + sizeof(uint32_t) + p_alignment - 1) & ~((p_alignment)-1));
80+
*((uint32_t *)p2 - 1) = (uint32_t)((uintptr_t)p2 - (uintptr_t)p1);
81+
return p2;
82+
}
83+
84+
void *Memory::realloc_aligned_static(void *p_memory, size_t p_bytes, size_t p_prev_bytes, size_t p_alignment) {
85+
if (p_memory == nullptr) {
86+
return alloc_aligned_static(p_bytes, p_alignment);
87+
}
88+
89+
void *ret = alloc_aligned_static(p_bytes, p_alignment);
90+
memcpy(ret, p_memory, p_prev_bytes);
91+
free_aligned_static(p_memory);
92+
return ret;
93+
}
94+
95+
void Memory::free_aligned_static(void *p_memory) {
96+
uint32_t offset = *((uint32_t *)p_memory - 1);
97+
void *p = (void *)((uint8_t *)p_memory - offset);
98+
free(p);
99+
}
100+
68101
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
69102
#ifdef DEBUG_ENABLED
70103
bool prepad = true;

core/os/memory.h

+24
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,30 @@ class Memory {
6262
static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false);
6363
static void free_static(void *p_ptr, bool p_pad_align = false);
6464

65+
// ↓ return value of alloc_aligned_static
66+
// ┌─────────────────┬─────────┬─────────┬──────────────────┐
67+
// │ padding (up to │ uint32_t│ void* │ padding (up to │
68+
// │ p_alignment - 1)│ offset │ p_bytes │ p_alignment - 1) │
69+
// └─────────────────┴─────────┴─────────┴──────────────────┘
70+
//
71+
// alloc_aligned_static will allocate p_bytes + p_alignment - 1 + sizeof(uint32_t) and
72+
// then offset the pointer until alignment is satisfied.
73+
//
74+
// This offset is stored before the start of the returned ptr so we can retrieve the original/real
75+
// start of the ptr in order to free it.
76+
//
77+
// The rest is wasted as padding in the beginning and end of the ptr. The sum of padding at
78+
// both start and end of the block must add exactly to p_alignment - 1.
79+
//
80+
// p_alignment MUST be a power of 2.
81+
static void *alloc_aligned_static(size_t p_bytes, size_t p_alignment);
82+
static void *realloc_aligned_static(void *p_memory, size_t p_bytes, size_t p_prev_bytes, size_t p_alignment);
83+
// Pass the ptr returned by alloc_aligned_static to free it.
84+
// e.g.
85+
// void *data = realloc_aligned_static( bytes, 16 );
86+
// free_aligned_static( data );
87+
static void free_aligned_static(void *p_memory);
88+
6589
static uint64_t get_mem_available();
6690
static uint64_t get_mem_usage();
6791
static uint64_t get_mem_max_usage();

doc/classes/RenderingDevice.xml

+124-1
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,15 @@
218218
<param index="6" name="clear_depth" type="float" default="1.0" />
219219
<param index="7" name="clear_stencil" type="int" default="0" />
220220
<param index="8" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
221+
<param index="9" name="breadcrumb" type="int" default="0" />
221222
<description>
222223
Starts a list of raster drawing commands created with the [code]draw_*[/code] methods. The returned value should be passed to other [code]draw_list_*[/code] functions.
223224
Multiple draw lists cannot be created at the same time; you must finish the previous draw list first using [method draw_list_end].
224225
A simple drawing operation might look like this (code is not a complete example):
225226
[codeblock]
226227
var rd = RenderingDevice.new()
227228
var clear_colors = PackedColorArray([Color(0, 0, 0, 0), Color(0, 0, 0, 0), Color(0, 0, 0, 0)])
228-
var draw_list = rd.draw_list_begin(framebuffers[i], RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_DISCARD, clear_colors)
229+
var draw_list = rd.draw_list_begin(framebuffers[i], RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_DISCARD, clear_colors, RenderingDevice.OPAQUE_PASS)
229230

230231
# Draw opaque.
231232
rd.draw_list_bind_render_pipeline(draw_list, raster_pipeline)
@@ -240,6 +241,11 @@
240241

241242
rd.draw_list_end()
242243
[/codeblock]
244+
The [param breadcrumb] parameter can be an arbitrary 32-bit integer that is useful to diagnose GPU crashes. If Godot is built in dev or debug mode; when the GPU crashes Godot will dump all shaders that were being executed at the time of the crash and the breadcrumb is useful to diagnose what passes did those shaders belong to.
245+
It does not affect rendering behavior and can be set to 0. It is recommended to use [enum BreadcrumbMarker] enumerations for consistency but it's not required. It is also possible to use bitwise operations to add extra data. e.g.
246+
[codeblock]
247+
rd.draw_list_begin(fb[i], RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_DISCARD, clear_colors, RenderingDevice.OPAQUE_PASS | 5)
248+
[/codeblock]
243249
</description>
244250
</method>
245251
<method name="draw_list_begin_for_screen">
@@ -487,6 +493,31 @@
487493
Returns the index of the last frame rendered that has rendering timestamps available for querying.
488494
</description>
489495
</method>
496+
<method name="get_device_allocation_count" qualifiers="const">
497+
<return type="int" />
498+
<description>
499+
Returns how many allocations the GPU has performed for internal driver structures.
500+
This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown.
501+
</description>
502+
</method>
503+
<method name="get_device_allocs_by_object_type" qualifiers="const">
504+
<return type="int" />
505+
<param index="0" name="type" type="int" />
506+
<description>
507+
Same as [method get_device_allocation_count] but filtered for a given object type.
508+
The type argument must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns 0.
509+
This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown.
510+
</description>
511+
</method>
512+
<method name="get_device_memory_by_object_type" qualifiers="const">
513+
<return type="int" />
514+
<param index="0" name="type" type="int" />
515+
<description>
516+
Same as [method get_device_total_memory] but filtered for a given object type.
517+
The type argument must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns 0.
518+
This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown.
519+
</description>
520+
</method>
490521
<method name="get_device_name" qualifiers="const">
491522
<return type="String" />
492523
<description>
@@ -499,12 +530,44 @@
499530
Returns the universally unique identifier for the pipeline cache. This is used to cache shader files on disk, which avoids shader recompilations on subsequent engine runs. This UUID varies depending on the graphics card model, but also the driver version. Therefore, updating graphics drivers will invalidate the shader cache.
500531
</description>
501532
</method>
533+
<method name="get_device_total_memory" qualifiers="const">
534+
<return type="int" />
535+
<description>
536+
Returns how much bytes the GPU is using.
537+
This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown.
538+
</description>
539+
</method>
502540
<method name="get_device_vendor_name" qualifiers="const">
503541
<return type="String" />
504542
<description>
505543
Returns the vendor of the video adapter (e.g. "NVIDIA Corporation"). Equivalent to [method RenderingServer.get_video_adapter_vendor]. See also [method get_device_name].
506544
</description>
507545
</method>
546+
<method name="get_driver_allocation_count" qualifiers="const">
547+
<return type="int" />
548+
<description>
549+
Returns how many allocations the GPU driver has performed for internal driver structures.
550+
This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown.
551+
</description>
552+
</method>
553+
<method name="get_driver_allocs_by_object_type" qualifiers="const">
554+
<return type="int" />
555+
<param index="0" name="type" type="int" />
556+
<description>
557+
Same as [method get_driver_allocation_count] but filtered for a given object type.
558+
The type argument must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns 0.
559+
This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown.
560+
</description>
561+
</method>
562+
<method name="get_driver_memory_by_object_type" qualifiers="const">
563+
<return type="int" />
564+
<param index="0" name="type" type="int" />
565+
<description>
566+
Same as [method get_driver_total_memory] but filtered for a given object type.
567+
The type argument must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns 0.
568+
This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown.
569+
</description>
570+
</method>
508571
<method name="get_driver_resource">
509572
<return type="int" />
510573
<param index="0" name="resource" type="int" enum="RenderingDevice.DriverResource" />
@@ -514,6 +577,13 @@
514577
Returns the unique identifier of the driver [param resource] for the specified [param rid]. Some driver resource types ignore the specified [param rid] (see [enum DriverResource] descriptions). [param index] is always ignored but must be specified anyway.
515578
</description>
516579
</method>
580+
<method name="get_driver_total_memory" qualifiers="const">
581+
<return type="int" />
582+
<description>
583+
Returns how much bytes the GPU driver is using for internal driver structures.
584+
This is only used by Vulkan in Debug builds and can return 0 when this information is not tracked or unknown.
585+
</description>
586+
</method>
517587
<method name="get_frame_delay" qualifiers="const">
518588
<return type="int" />
519589
<description>
@@ -527,6 +597,33 @@
527597
Returns the memory usage in bytes corresponding to the given [param type]. When using Vulkan, these statistics are calculated by [url=https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator]Vulkan Memory Allocator[/url].
528598
</description>
529599
</method>
600+
<method name="get_perf_report" qualifiers="const">
601+
<return type="String" />
602+
<description>
603+
Returns a string with a performance report from the past frame. Updates every frame.
604+
</description>
605+
</method>
606+
<method name="get_tracked_object_name" qualifiers="const">
607+
<return type="String" />
608+
<param index="0" name="type_index" type="int" />
609+
<description>
610+
Returns the name of the type of object for the given [param type_index]. This value must be in range [code][0; get_tracked_object_type_count - 1][/code]. If [method get_tracked_object_type_count] is 0, then type argument is ignored and always returns the same string.
611+
The return value is important because it gives meaning to the types passed to [method get_driver_memory_by_object_type], [method get_driver_allocs_by_object_type], [method get_device_memory_by_object_type], and [method get_device_allocs_by_object_type]. Examples of strings it can return (not exhaustive):
612+
- DEVICE_MEMORY
613+
- PIPELINE_CACHE
614+
- SWAPCHAIN_KHR
615+
- COMMAND_POOL
616+
Thus if e.g. [code]get_tracked_object_name(5)[/code] returns "COMMAND_POOL", then [code]get_device_memory_by_object_type(5)[/code] returns the bytes used by the GPU for command pools.
617+
This is only used by Vulkan in Debug builds.
618+
</description>
619+
</method>
620+
<method name="get_tracked_object_type_count" qualifiers="const">
621+
<return type="int" />
622+
<description>
623+
Returns how many types of trackable objects are.
624+
This is only used by Vulkan in Debug builds.
625+
</description>
626+
</method>
530627
<method name="index_array_create">
531628
<return type="RID" />
532629
<param index="0" name="index_buffer" type="RID" />
@@ -2362,5 +2459,31 @@
23622459
<constant name="INVALID_FORMAT_ID" value="-1">
23632460
Returned by functions that return a format ID if a value is invalid.
23642461
</constant>
2462+
<constant name="NONE" value="0" enum="BreadcrumbMarker">
2463+
</constant>
2464+
<constant name="REFLECTION_PROBES" value="65536" enum="BreadcrumbMarker">
2465+
</constant>
2466+
<constant name="SKY_PASS" value="131072" enum="BreadcrumbMarker">
2467+
</constant>
2468+
<constant name="LIGHTMAPPER_PASS" value="196608" enum="BreadcrumbMarker">
2469+
</constant>
2470+
<constant name="SHADOW_PASS_DIRECTIONAL" value="262144" enum="BreadcrumbMarker">
2471+
</constant>
2472+
<constant name="SHADOW_PASS_CUBE" value="327680" enum="BreadcrumbMarker">
2473+
</constant>
2474+
<constant name="OPAQUE_PASS" value="393216" enum="BreadcrumbMarker">
2475+
</constant>
2476+
<constant name="ALPHA_PASS" value="458752" enum="BreadcrumbMarker">
2477+
</constant>
2478+
<constant name="TRANSPARENT_PASS" value="524288" enum="BreadcrumbMarker">
2479+
</constant>
2480+
<constant name="POST_PROCESSING_PASS" value="589824" enum="BreadcrumbMarker">
2481+
</constant>
2482+
<constant name="BLIT_PASS" value="655360" enum="BreadcrumbMarker">
2483+
</constant>
2484+
<constant name="UI_PASS" value="720896" enum="BreadcrumbMarker">
2485+
</constant>
2486+
<constant name="DEBUG_PASS" value="786432" enum="BreadcrumbMarker">
2487+
</constant>
23652488
</constants>
23662489
</class>

drivers/d3d12/rendering_device_driver_d3d12.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -3815,6 +3815,11 @@ void RenderingDeviceDriverD3D12::shader_free(ShaderID p_shader) {
38153815
VersatileResource::free(resources_allocator, shader_info_in);
38163816
}
38173817

3818+
void RenderingDeviceDriverD3D12::shader_destroy_modules(ShaderID p_shader) {
3819+
ShaderInfo *shader_info_in = (ShaderInfo *)p_shader.id;
3820+
shader_info_in->stages_bytecode.clear();
3821+
}
3822+
38183823
/*********************/
38193824
/**** UNIFORM SET ****/
38203825
/*********************/
@@ -6036,6 +6041,10 @@ void RenderingDeviceDriverD3D12::command_end_label(CommandBufferID p_cmd_buffer)
60366041
#endif
60376042
}
60386043

6044+
void RenderingDeviceDriverD3D12::command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) {
6045+
// TODO: Implement via DRED.
6046+
}
6047+
60396048
/********************/
60406049
/**** SUBMISSION ****/
60416050
/********************/

drivers/d3d12/rendering_device_driver_d3d12.h

+6
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
714714
virtual ShaderID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) override final;
715715
virtual uint32_t shader_get_layout_hash(ShaderID p_shader) override final;
716716
virtual void shader_free(ShaderID p_shader) override final;
717+
virtual void shader_destroy_modules(ShaderID p_shader) override final;
717718

718719
/*********************/
719720
/**** UNIFORM SET ****/
@@ -945,6 +946,11 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
945946
virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final;
946947
virtual void command_end_label(CommandBufferID p_cmd_buffer) override final;
947948

949+
/****************/
950+
/**** DEBUG *****/
951+
/****************/
952+
virtual void command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) override final;
953+
948954
/********************/
949955
/**** SUBMISSION ****/
950956
/********************/

drivers/metal/rendering_device_driver_metal.h

+5
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) RenderingDeviceDriverMetal : public
231231
virtual Vector<uint8_t> shader_compile_binary_from_spirv(VectorView<ShaderStageSPIRVData> p_spirv, const String &p_shader_name) override final;
232232
virtual ShaderID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, ShaderDescription &r_shader_desc, String &r_name) override final;
233233
virtual void shader_free(ShaderID p_shader) override final;
234+
virtual void shader_destroy_modules(ShaderID p_shader) override final;
234235

235236
#pragma mark - Uniform Set
236237

@@ -376,6 +377,10 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) RenderingDeviceDriverMetal : public
376377
virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final;
377378
virtual void command_end_label(CommandBufferID p_cmd_buffer) override final;
378379

380+
#pragma mark - Debug
381+
382+
virtual void command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) override final;
383+
379384
#pragma mark - Submission
380385

381386
virtual void begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) override final;

drivers/metal/rendering_device_driver_metal.mm

+10
Original file line numberDiff line numberDiff line change
@@ -2447,6 +2447,10 @@ void deserialize(BufReader &p_reader) {
24472447
delete obj;
24482448
}
24492449

2450+
void RenderingDeviceDriverMetal::shader_destroy_modules(ShaderID p_shader) {
2451+
// TODO.
2452+
}
2453+
24502454
/*********************/
24512455
/**** UNIFORM SET ****/
24522456
/*********************/
@@ -3541,6 +3545,12 @@ bool isArrayTexture(MTLTextureType p_type) {
35413545
[cb->get_command_buffer() popDebugGroup];
35423546
}
35433547

3548+
#pragma mark - Debug
3549+
3550+
void RenderingDeviceDriverMetal::command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) {
3551+
// TODO: Implement.
3552+
}
3553+
35443554
#pragma mark - Submission
35453555

35463556
void RenderingDeviceDriverMetal::begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) {

0 commit comments

Comments
 (0)