vkd3d: Add support for a shader debug ring.

Will allow replaced shaders to emit debug messages to a buffer.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
This commit is contained in:
Hans-Kristian Arntzen 2020-09-21 13:42:53 +02:00
parent 29fe4da015
commit 9d36ab59d6
9 changed files with 613 additions and 2 deletions

View File

@ -118,6 +118,7 @@ libvkd3d_la_SOURCES = \
libs/vkd3d/resource.c \
libs/vkd3d/state.c \
libs/vkd3d/utils.c \
libs/vkd3d/debug_ring.c \
libs/vkd3d/vkd3d.map \
libs/vkd3d/vkd3d_main.c \
libs/vkd3d/vkd3d_private.h \

View File

@ -0,0 +1,208 @@
/*
* Copyright 2020 Hans-Kristian Arntzen for Valve Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef DEBUG_CHANNEL_H_
#define DEBUG_CHANNEL_H_
#extension GL_EXT_buffer_reference : require
#extension GL_ARB_gpu_shader_int64 : require
#extension GL_KHR_shader_subgroup_basic : require
#extension GL_KHR_shader_subgroup_ballot : require
layout(buffer_reference, std430, buffer_reference_align = 4) buffer ControlBlock
{
uint message_counter;
uint instance_counter;
};
layout(buffer_reference, std430, buffer_reference_align = 4) buffer RingBuffer
{
uint data[];
};
layout(constant_id = 0) const uint64_t DEBUG_SHADER_HASH = 0;
layout(constant_id = 1) const uint64_t DEBUG_SHADER_ATOMIC_BDA = 0;
layout(constant_id = 2) const uint64_t DEBUG_SHADER_RING_BDA = 0;
layout(constant_id = 3) const uint DEBUG_SHADER_RING_SIZE = 0;
const uint DEBUG_SHADER_RING_MASK = DEBUG_SHADER_RING_SIZE - 1;
const bool DEBUG_SHADER_RING_ACTIVE = DEBUG_SHADER_ATOMIC_BDA != 0;
const uint DEBUG_CHANNEL_FMT_HEX = 0;
const uint DEBUG_CHANNEL_FMT_I32 = 1;
const uint DEBUG_CHANNEL_FMT_F32 = 2;
const uint DEBUG_CHANNEL_FMT_HEX_ALL = DEBUG_CHANNEL_FMT_HEX * 0x55555555u;
const uint DEBUG_CHANNEL_FMT_I32_ALL = DEBUG_CHANNEL_FMT_I32 * 0x55555555u;
const uint DEBUG_CHANNEL_FMT_F32_ALL = DEBUG_CHANNEL_FMT_F32 * 0x55555555u;
uint DEBUG_CHANNEL_INSTANCE_COUNTER;
uvec3 DEBUG_CHANNEL_ID;
void DEBUG_CHANNEL_INIT(uvec3 id)
{
if (!DEBUG_SHADER_RING_ACTIVE)
return;
DEBUG_CHANNEL_ID = id;
uint inst;
if (subgroupElect())
inst = atomicAdd(ControlBlock(DEBUG_SHADER_ATOMIC_BDA).instance_counter, 1u);
DEBUG_CHANNEL_INSTANCE_COUNTER = subgroupBroadcastFirst(inst);
}
void DEBUG_CHANNEL_WRITE_HEADER(RingBuffer buf, uint offset, uint num_words, uint fmt)
{
buf.data[(offset + 0) & DEBUG_SHADER_RING_MASK] = num_words;
buf.data[(offset + 1) & DEBUG_SHADER_RING_MASK] = uint(DEBUG_SHADER_HASH);
buf.data[(offset + 2) & DEBUG_SHADER_RING_MASK] = uint(DEBUG_SHADER_HASH >> 32);
buf.data[(offset + 3) & DEBUG_SHADER_RING_MASK] = DEBUG_CHANNEL_INSTANCE_COUNTER;
buf.data[(offset + 4) & DEBUG_SHADER_RING_MASK] = DEBUG_CHANNEL_ID.x;
buf.data[(offset + 5) & DEBUG_SHADER_RING_MASK] = DEBUG_CHANNEL_ID.y;
buf.data[(offset + 6) & DEBUG_SHADER_RING_MASK] = DEBUG_CHANNEL_ID.z;
buf.data[(offset + 7) & DEBUG_SHADER_RING_MASK] = fmt;
}
uint DEBUG_CHANNEL_ALLOCATE(uint words)
{
uint offset = atomicAdd(ControlBlock(DEBUG_SHADER_ATOMIC_BDA).message_counter, words);
return offset;
}
void DEBUG_CHANNEL_MSG_()
{
if (!DEBUG_SHADER_RING_ACTIVE)
return;
uint words = 8;
uint offset = DEBUG_CHANNEL_ALLOCATE(words);
DEBUG_CHANNEL_WRITE_HEADER(RingBuffer(DEBUG_SHADER_RING_BDA), offset, words, 0);
}
void DEBUG_CHANNEL_MSG_(uint fmt, uint v0)
{
if (!DEBUG_SHADER_RING_ACTIVE)
return;
RingBuffer buf = RingBuffer(DEBUG_SHADER_RING_BDA);
uint words = 9;
uint offset = DEBUG_CHANNEL_ALLOCATE(words);
DEBUG_CHANNEL_WRITE_HEADER(buf, offset, words, fmt);
buf.data[(offset + 8) & DEBUG_SHADER_RING_MASK] = v0;
}
void DEBUG_CHANNEL_MSG_(uint fmt, uint v0, uint v1)
{
if (!DEBUG_SHADER_RING_ACTIVE)
return;
RingBuffer buf = RingBuffer(DEBUG_SHADER_RING_BDA);
uint words = 10;
uint offset = DEBUG_CHANNEL_ALLOCATE(words);
DEBUG_CHANNEL_WRITE_HEADER(buf, offset, words, fmt);
buf.data[(offset + 8) & DEBUG_SHADER_RING_MASK] = v0;
buf.data[(offset + 9) & DEBUG_SHADER_RING_MASK] = v1;
}
void DEBUG_CHANNEL_MSG_(uint fmt, uint v0, uint v1, uint v2)
{
if (!DEBUG_SHADER_RING_ACTIVE)
return;
RingBuffer buf = RingBuffer(DEBUG_SHADER_RING_BDA);
uint words = 11;
uint offset = DEBUG_CHANNEL_ALLOCATE(words);
DEBUG_CHANNEL_WRITE_HEADER(buf, offset, words, fmt);
buf.data[(offset + 8) & DEBUG_SHADER_RING_MASK] = v0;
buf.data[(offset + 9) & DEBUG_SHADER_RING_MASK] = v1;
buf.data[(offset + 10) & DEBUG_SHADER_RING_MASK] = v2;
}
void DEBUG_CHANNEL_MSG_(uint fmt, uint v0, uint v1, uint v2, uint v3)
{
if (!DEBUG_SHADER_RING_ACTIVE)
return;
RingBuffer buf = RingBuffer(DEBUG_SHADER_RING_BDA);
uint words = 12;
uint offset = DEBUG_CHANNEL_ALLOCATE(words);
DEBUG_CHANNEL_WRITE_HEADER(buf, offset, words, fmt);
buf.data[(offset + 8) & DEBUG_SHADER_RING_MASK] = v0;
buf.data[(offset + 9) & DEBUG_SHADER_RING_MASK] = v1;
buf.data[(offset + 10) & DEBUG_SHADER_RING_MASK] = v2;
buf.data[(offset + 11) & DEBUG_SHADER_RING_MASK] = v3;
}
void DEBUG_CHANNEL_MSG()
{
DEBUG_CHANNEL_MSG_();
}
void DEBUG_CHANNEL_MSG(uint v0)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_HEX_ALL, v0);
}
void DEBUG_CHANNEL_MSG(uint v0, uint v1)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_HEX_ALL, v0, v1);
}
void DEBUG_CHANNEL_MSG(uint v0, uint v1, uint v2)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_HEX_ALL, v0, v1, v2);
}
void DEBUG_CHANNEL_MSG(uint v0, uint v1, uint v2, uint v3)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_HEX_ALL, v0, v1, v2, v3);
}
void DEBUG_CHANNEL_MSG(int v0)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_I32_ALL, v0);
}
void DEBUG_CHANNEL_MSG(int v0, int v1)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_I32_ALL, v0, v1);
}
void DEBUG_CHANNEL_MSG(int v0, int v1, int v2)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_I32_ALL, v0, v1, v2);
}
void DEBUG_CHANNEL_MSG(int v0, int v1, int v2, int v3)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_I32_ALL, v0, v1, v2, v3);
}
void DEBUG_CHANNEL_MSG(float v0)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_F32_ALL, floatBitsToUint(v0));
}
void DEBUG_CHANNEL_MSG(float v0, float v1)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_F32_ALL, floatBitsToUint(v0), floatBitsToUint(v1));
}
void DEBUG_CHANNEL_MSG(float v0, float v1, float v2)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_F32_ALL, floatBitsToUint(v0), floatBitsToUint(v1), floatBitsToUint(v2));
}
void DEBUG_CHANNEL_MSG(float v0, float v1, float v2, float v3)
{
DEBUG_CHANNEL_MSG_(DEBUG_CHANNEL_FMT_F32_ALL, floatBitsToUint(v0), floatBitsToUint(v1), floatBitsToUint(v2), floatBitsToUint(v3));
}
#endif

View File

@ -278,6 +278,10 @@ static void vkd3d_wait_for_gpu_timeline_semaphores(struct vkd3d_fence_worker *wo
return;
}
/* This is a good time to kick the debug ring thread into action. */
if (device->debug_ring.active)
pthread_cond_signal(&device->debug_ring.ring_cond);
for (i = 0, j = 0; i < worker->fence_count; ++i)
{
struct vkd3d_waiting_fence *current = &worker->fences[i];
@ -2759,6 +2763,8 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_Close(d3d12_command_list_ifa
1, &barrier, 0, NULL, 0, NULL));
}
vkd3d_shader_debug_ring_end_command_buffer(list);
if ((vr = VK_CALL(vkEndCommandBuffer(list->vk_command_buffer))) < 0)
{
WARN("Failed to end command buffer, vr %d.\n", vr);
@ -2807,6 +2813,7 @@ static void d3d12_command_list_reset_state(struct d3d12_command_list *list,
#else
list->debug_capture = false;
#endif
list->has_replaced_shaders = false;
list->current_framebuffer = VK_NULL_HANDLE;
list->current_pipeline = VK_NULL_HANDLE;
@ -4753,10 +4760,13 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetPipelineState(d3d12_command_
TRACE("iface %p, pipeline_state %p.\n", iface, pipeline_state);
if (TRACE_ON() && state)
if ((TRACE_ON() || list->device->debug_ring.active) && state)
{
if (d3d12_pipeline_state_has_replaced_shaders(state))
{
TRACE("Binding pipeline state %p which has replaced shader(s)!\n", pipeline_state);
list->has_replaced_shaders = true;
}
if (state->vk_bind_point == VK_PIPELINE_BIND_POINT_COMPUTE)
{

321
libs/vkd3d/debug_ring.c Normal file
View File

@ -0,0 +1,321 @@
/*
* Copyright 2020 Hans-Kristian Arntzen for Valve Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API
#include "vkd3d_private.h"
#include "vkd3d_debug.h"
#include "vkd3d_common.h"
#include <stdio.h>
void vkd3d_shader_debug_ring_init_spec_constant(struct d3d12_device *device,
struct vkd3d_shader_debug_ring_spec_info *info, vkd3d_shader_hash_t hash)
{
info->spec_info.pData = &info->constants;
info->spec_info.dataSize = sizeof(info->constants);
info->spec_info.pMapEntries = info->map_entries;
info->spec_info.mapEntryCount = 4;
info->constants.hash = hash;
info->constants.host_bda = device->debug_ring.ring_device_address;
info->constants.atomic_bda = device->debug_ring.atomic_device_address;
info->constants.ring_words = device->debug_ring.ring_size / sizeof(uint32_t);
info->map_entries[0].constantID = 0;
info->map_entries[0].offset = offsetof(struct vkd3d_shader_debug_ring_spec_constants, hash);
info->map_entries[0].size = sizeof(uint64_t);
info->map_entries[1].constantID = 1;
info->map_entries[1].offset = offsetof(struct vkd3d_shader_debug_ring_spec_constants, atomic_bda);
info->map_entries[1].size = sizeof(uint64_t);
info->map_entries[2].constantID = 2;
info->map_entries[2].offset = offsetof(struct vkd3d_shader_debug_ring_spec_constants, host_bda);
info->map_entries[2].size = sizeof(uint64_t);
info->map_entries[3].constantID = 3;
info->map_entries[3].offset = offsetof(struct vkd3d_shader_debug_ring_spec_constants, ring_words);
info->map_entries[3].size = sizeof(uint32_t);
}
void *vkd3d_shader_debug_ring_thread_main(void *arg)
{
uint32_t last_counter, new_counter, count, i, j, message_word_count, debug_instance, debug_thread_id[3], fmt;
struct vkd3d_shader_debug_ring *ring;
struct d3d12_device *device = arg;
const uint32_t *ring_counter;
const uint32_t *ring_base;
char message_buffer[4096];
bool is_active = true;
uint64_t shader_hash;
size_t ring_mask;
ring = &device->debug_ring;
ring_mask = ring->ring_size - 1;
ring_counter = ring->mapped;
ring_base = ring_counter + (ring->ring_offset / sizeof(uint32_t));
last_counter = 0;
vkd3d_set_thread_name("debug-ring");
while (is_active)
{
pthread_mutex_lock(&ring->ring_lock);
pthread_cond_wait(&ring->ring_cond, &ring->ring_lock);
is_active = ring->active;
pthread_mutex_unlock(&ring->ring_lock);
new_counter = *ring_counter;
if (last_counter != new_counter)
{
count = (new_counter - last_counter) & ring_mask;
/* Assume that each iteration can safely use 1/4th of the buffer to avoid WAR hazards. */
if ((new_counter - last_counter) > (ring->ring_size / 16))
{
ERR("Debug ring is probably too small (%u new words this iteration), increase size to avoid risk of dropping messages.\n",
new_counter - last_counter);
}
for (i = 0; i < count; )
{
#define READ_RING_WORD(off) ring_base[((off) + i + last_counter) & ring_mask]
message_word_count = READ_RING_WORD(0);
if (i + message_word_count > count)
break;
if (message_word_count < 8 || message_word_count > 16 + 8)
break;
shader_hash = (uint64_t)READ_RING_WORD(1) | ((uint64_t)READ_RING_WORD(2) << 32);
debug_instance = READ_RING_WORD(3);
for (j = 0; j < 3; j++)
debug_thread_id[j] = READ_RING_WORD(4 + j);
fmt = READ_RING_WORD(7);
snprintf(message_buffer, sizeof(message_buffer), "Shader: %"PRIx64": Instance %u, ID (%u, %u, %u):",
shader_hash, debug_instance,
debug_thread_id[0], debug_thread_id[1], debug_thread_id[2]);
i += 8;
message_word_count -= 8;
for (j = 0; j < message_word_count; j++)
{
union
{
float f32;
uint32_t u32;
int32_t i32;
} u;
const char *delim;
size_t len, avail;
u.u32 = READ_RING_WORD(j);
len = strlen(message_buffer);
if (len + 1 >= sizeof(message_buffer))
break;
avail = sizeof(message_buffer) - len;
delim = j == 0 ? " " : ", ";
#define VKD3D_DEBUG_CHANNEL_FMT_HEX 0u
#define VKD3D_DEBUG_CHANNEL_FMT_I32 1u
#define VKD3D_DEBUG_CHANNEL_FMT_F32 2u
switch ((fmt >> (2u * j)) & 3u)
{
case VKD3D_DEBUG_CHANNEL_FMT_HEX:
snprintf(message_buffer + len, avail, "%s#%x", delim, u.u32);
break;
case VKD3D_DEBUG_CHANNEL_FMT_I32:
snprintf(message_buffer + len, avail, "%s%d", delim, u.i32);
break;
case VKD3D_DEBUG_CHANNEL_FMT_F32:
snprintf(message_buffer + len, avail, "%s%f", delim, u.f32);
break;
default:
snprintf(message_buffer + len, avail, "%s????", delim);
break;
}
}
ERR("%s\n", message_buffer);
#undef READ_RING_WORD
i += message_word_count;
}
}
last_counter = new_counter;
}
return NULL;
}
HRESULT vkd3d_shader_debug_ring_init(struct vkd3d_shader_debug_ring *ring,
struct d3d12_device *device)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
D3D12_HEAP_PROPERTIES heap_properties;
D3D12_RESOURCE_DESC resource_desc;
const char *env;
memset(ring, 0, sizeof(*ring));
if (!(env = getenv("VKD3D_SHADER_DEBUG_RING_SIZE_LOG2")))
return S_OK;
ring->active = true;
ring->ring_size = (size_t)1 << strtoul(env, NULL, 0);
// Reserve 4k to be used as a control block of some sort.
ring->ring_offset = 4096;
WARN("Enabling shader debug ring of size: %zu.\n", ring->ring_size);
if (!device->device_info.buffer_device_address_features.bufferDeviceAddress)
{
ERR("Buffer device address must be supported to use VKD3D_SHADER_DEBUG_RING feature.\n");
return E_INVALIDARG;
}
memset(&heap_properties, 0, sizeof(heap_properties));
heap_properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
heap_properties.Type = D3D12_HEAP_TYPE_CUSTOM;
heap_properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
memset(&resource_desc, 0, sizeof(resource_desc));
resource_desc.Width = ring->ring_offset + ring->ring_size;
resource_desc.Height = 1;
resource_desc.DepthOrArraySize = 1;
resource_desc.MipLevels = 1;
resource_desc.Format = DXGI_FORMAT_UNKNOWN;
resource_desc.SampleDesc.Count = 1;
resource_desc.SampleDesc.Quality = 0;
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
if (FAILED(vkd3d_create_buffer(device, &heap_properties, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS,
&resource_desc, &ring->host_buffer)))
goto err_free_buffers;
if (FAILED(vkd3d_allocate_buffer_memory(device, ring->host_buffer, NULL,
&heap_properties, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS, &ring->host_buffer_memory, NULL, NULL)))
goto err_free_buffers;
ring->ring_device_address = vkd3d_get_buffer_device_address(device, ring->host_buffer) + ring->ring_offset;
resource_desc.Width = ring->ring_offset;
memset(&heap_properties, 0, sizeof(heap_properties));
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
if (FAILED(vkd3d_create_buffer(device, &heap_properties, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS,
&resource_desc, &ring->device_atomic_buffer)))
goto err_free_buffers;
if (FAILED(vkd3d_allocate_buffer_memory(device, ring->device_atomic_buffer, NULL,
&heap_properties, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS, &ring->device_atomic_buffer_memory, NULL, NULL)))
goto err_free_buffers;
if (VK_CALL(vkMapMemory(device->vk_device, ring->host_buffer_memory, 0, VK_WHOLE_SIZE, 0, &ring->mapped)) != VK_SUCCESS)
goto err_free_buffers;
ring->atomic_device_address = vkd3d_get_buffer_device_address(device, ring->device_atomic_buffer);
if (pthread_mutex_init(&ring->ring_lock, NULL) != 0)
goto err_free_buffers;
if (pthread_cond_init(&ring->ring_cond, NULL) != 0)
goto err_destroy_mutex;
if (pthread_create(&ring->ring_thread, NULL, vkd3d_shader_debug_ring_thread_main, device) != 0)
{
ERR("Failed to create ring thread.\n");
goto err_destroy_cond;
}
return S_OK;
err_destroy_mutex:
pthread_mutex_destroy(&ring->ring_lock);
err_destroy_cond:
pthread_cond_destroy(&ring->ring_cond);
err_free_buffers:
VK_CALL(vkDestroyBuffer(device->vk_device, ring->host_buffer, NULL));
VK_CALL(vkDestroyBuffer(device->vk_device, ring->device_atomic_buffer, NULL));
VK_CALL(vkFreeMemory(device->vk_device, ring->host_buffer_memory, NULL));
VK_CALL(vkFreeMemory(device->vk_device, ring->device_atomic_buffer_memory, NULL));
memset(ring, 0, sizeof(*ring));
return E_OUTOFMEMORY;
}
void vkd3d_shader_debug_ring_cleanup(struct vkd3d_shader_debug_ring *ring,
struct d3d12_device *device)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
if (!ring->active)
return;
pthread_mutex_lock(&ring->ring_lock);
ring->active = false;
pthread_cond_signal(&ring->ring_cond);
pthread_mutex_unlock(&ring->ring_lock);
pthread_join(ring->ring_thread, NULL);
pthread_mutex_destroy(&ring->ring_lock);
pthread_cond_destroy(&ring->ring_cond);
VK_CALL(vkDestroyBuffer(device->vk_device, ring->host_buffer, NULL));
VK_CALL(vkDestroyBuffer(device->vk_device, ring->device_atomic_buffer, NULL));
VK_CALL(vkFreeMemory(device->vk_device, ring->host_buffer_memory, NULL));
VK_CALL(vkFreeMemory(device->vk_device, ring->device_atomic_buffer_memory, NULL));
}
void vkd3d_shader_debug_ring_end_command_buffer(struct d3d12_command_list *list)
{
const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
VkBufferCopy buffer_copy;
VkMemoryBarrier barrier;
if (list->device->debug_ring.active &&
list->has_replaced_shaders &&
(list->type == D3D12_COMMAND_LIST_TYPE_DIRECT || list->type == D3D12_COMMAND_LIST_TYPE_COMPUTE))
{
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
barrier.pNext = NULL;
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
1, &barrier, 0, NULL, 0, NULL));
buffer_copy.size = list->device->debug_ring.ring_offset;
buffer_copy.dstOffset = 0;
buffer_copy.srcOffset = 0;
VK_CALL(vkCmdCopyBuffer(list->vk_command_buffer,
list->device->debug_ring.device_atomic_buffer,
list->device->debug_ring.host_buffer,
1, &buffer_copy));
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0,
1, &barrier, 0, NULL, 0, NULL));
}
}

View File

@ -2204,6 +2204,7 @@ static void d3d12_device_destroy(struct d3d12_device *device)
vkd3d_private_store_destroy(&device->private_store);
vkd3d_cleanup_format_info(device);
vkd3d_shader_debug_ring_cleanup(&device->debug_ring, device);
vkd3d_sampler_state_cleanup(&device->sampler_state, device);
vkd3d_view_map_destroy(&device->sampler_map, device);
vkd3d_meta_ops_cleanup(&device->meta_ops, device);
@ -4582,6 +4583,9 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
if (FAILED(hr = vkd3d_sampler_state_init(&device->sampler_state, device)))
goto out_cleanup_view_map;
if (FAILED(hr = vkd3d_shader_debug_ring_init(&device->debug_ring, device)))
goto out_cleanup_sampler_state;
vkd3d_render_pass_cache_init(&device->render_pass_cache);
vkd3d_gpu_va_allocator_init(&device->gpu_va_allocator);
@ -4591,6 +4595,8 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
d3d12_device_caps_init(device);
return S_OK;
out_cleanup_sampler_state:
vkd3d_sampler_state_cleanup(&device->sampler_state, device);
out_cleanup_view_map:
vkd3d_view_map_destroy(&device->sampler_map, device);
out_cleanup_meta_ops:

View File

@ -28,6 +28,7 @@ vkd3d_src = [
'resource.c',
'state.c',
'utils.c',
'debug_ring.c',
'vkd3d_main.c',
]

View File

@ -4204,7 +4204,7 @@ static unsigned int vkd3d_view_flags_from_d3d12_buffer_uav_flags(D3D12_BUFFER_UA
return 0;
}
static VkDeviceAddress vkd3d_get_buffer_device_address(struct d3d12_device *device, VkBuffer vk_buffer)
VkDeviceAddress vkd3d_get_buffer_device_address(struct d3d12_device *device, VkBuffer vk_buffer)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;

View File

@ -1601,6 +1601,7 @@ static HRESULT vkd3d_create_compute_pipeline(struct d3d12_device *device,
struct vkd3d_shader_meta *meta)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
struct vkd3d_shader_debug_ring_spec_info spec_info;
VkComputePipelineCreateInfo pipeline_info;
VkResult vr;
HRESULT hr;
@ -1615,6 +1616,12 @@ static HRESULT vkd3d_create_compute_pipeline(struct d3d12_device *device,
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
pipeline_info.basePipelineIndex = -1;
if (meta->replaced && device->debug_ring.active)
{
vkd3d_shader_debug_ring_init_spec_constant(device, &spec_info, meta->hash);
pipeline_info.stage.pSpecializationInfo = &spec_info.spec_info;
}
vr = VK_CALL(vkCreateComputePipelines(device->vk_device,
vk_cache, 1, &pipeline_info, NULL, vk_pipeline));
VK_CALL(vkDestroyShaderModule(device->vk_device, pipeline_info.stage.module, NULL));
@ -2540,6 +2547,14 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
shader_stages[i].stage, b, &shader_interface, compile_args, &graphics->stage_meta[graphics->stage_count])))
goto fail;
if (graphics->stage_meta[graphics->stage_count].replaced && device->debug_ring.active)
{
vkd3d_shader_debug_ring_init_spec_constant(device,
&graphics->spec_info[graphics->stage_count],
graphics->stage_meta[graphics->stage_count].hash);
graphics->stages[graphics->stage_count].pSpecializationInfo = &graphics->spec_info[graphics->stage_count].spec_info;
}
++graphics->stage_count;
}

View File

@ -924,8 +924,24 @@ enum vkd3d_dynamic_state_flag
VKD3D_DYNAMIC_STATE_VERTEX_BUFFER_STRIDE = (1 << 9),
};
struct vkd3d_shader_debug_ring_spec_constants
{
uint64_t hash;
uint64_t atomic_bda;
uint64_t host_bda;
uint32_t ring_words;
};
struct vkd3d_shader_debug_ring_spec_info
{
struct vkd3d_shader_debug_ring_spec_constants constants;
VkSpecializationMapEntry map_entries[4];
VkSpecializationInfo spec_info;
};
struct d3d12_graphics_pipeline_state
{
struct vkd3d_shader_debug_ring_spec_info spec_info[VKD3D_MAX_SHADER_STAGES];
VkPipelineShaderStageCreateInfo stages[VKD3D_MAX_SHADER_STAGES];
struct vkd3d_shader_meta stage_meta[VKD3D_MAX_SHADER_STAGES];
size_t stage_count;
@ -1261,6 +1277,7 @@ struct d3d12_command_list
bool is_valid;
bool need_host_barrier;
bool debug_capture;
bool has_replaced_shaders;
VkCommandBuffer vk_command_buffer;
DXGI_FORMAT index_buffer_format;
@ -1479,6 +1496,26 @@ struct vkd3d_sampler_state
size_t vk_descriptor_pool_count;
};
struct vkd3d_shader_debug_ring
{
VkBuffer host_buffer;
VkBuffer device_atomic_buffer;
VkDeviceMemory host_buffer_memory;
VkDeviceMemory device_atomic_buffer_memory;
void *mapped;
VkDeviceAddress ring_device_address;
VkDeviceAddress atomic_device_address;
size_t ring_size;
size_t ring_offset;
pthread_t ring_thread;
pthread_mutex_t ring_lock;
pthread_cond_t ring_cond;
bool active;
};
HRESULT vkd3d_sampler_state_init(struct vkd3d_sampler_state *state,
struct d3d12_device *device) DECLSPEC_HIDDEN;
void vkd3d_sampler_state_cleanup(struct vkd3d_sampler_state *state,
@ -1491,6 +1528,15 @@ HRESULT vkd3d_sampler_state_allocate_descriptor_set(struct vkd3d_sampler_state *
void vkd3d_sampler_state_free_descriptor_set(struct vkd3d_sampler_state *state,
struct d3d12_device *device, VkDescriptorSet vk_set, VkDescriptorPool vk_pool) DECLSPEC_HIDDEN;
HRESULT vkd3d_shader_debug_ring_init(struct vkd3d_shader_debug_ring *state,
struct d3d12_device *device) DECLSPEC_HIDDEN;
void vkd3d_shader_debug_ring_cleanup(struct vkd3d_shader_debug_ring *state,
struct d3d12_device *device) DECLSPEC_HIDDEN;
void *vkd3d_shader_debug_ring_thread_main(void *arg) DECLSPEC_HIDDEN;
void vkd3d_shader_debug_ring_init_spec_constant(struct d3d12_device *device,
struct vkd3d_shader_debug_ring_spec_info *info, vkd3d_shader_hash_t hash) DECLSPEC_HIDDEN;
void vkd3d_shader_debug_ring_end_command_buffer(struct d3d12_command_list *list) DECLSPEC_HIDDEN;
/* NULL resources */
struct vkd3d_null_resources
{
@ -1827,6 +1873,7 @@ struct d3d12_device
struct vkd3d_meta_ops meta_ops;
struct vkd3d_view_map sampler_map;
struct vkd3d_sampler_state sampler_state;
struct vkd3d_shader_debug_ring debug_ring;
};
HRESULT d3d12_device_create(struct vkd3d_instance *instance,
@ -2055,6 +2102,8 @@ static inline void vk_prepend_struct(void *header, void *structure)
vk_header->pNext = vk_structure;
}
VkDeviceAddress vkd3d_get_buffer_device_address(struct d3d12_device *device, VkBuffer vk_buffer) DECLSPEC_HIDDEN;
#define VKD3D_NULL_BUFFER_SIZE 16
#endif /* __VKD3D_PRIVATE_H */