blob: 3fc40c9734ef8de858e317737cc22fc89b9fb94d [file] [edit]
/*
* Copyright 2024 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 "vkd3d_shader.h"
#include <assert.h>
#include <stdio.h>
void vkd3d_shader_hash_range_parse(FILE *file, struct vkd3d_shader_hash_range **ranges,
size_t *range_size, size_t *range_count, enum vkd3d_shader_hash_range_kind kind)
{
vkd3d_shader_hash_t lo_hash;
vkd3d_shader_hash_t hi_hash;
size_t new_count = 0;
char *end_ptr;
char line[64];
while (fgets(line, sizeof(line), file))
{
if (!vkd3d_shader_hash_range_parse_line(line, &lo_hash, &hi_hash, &end_ptr))
continue;
if (lo_hash || hi_hash)
{
vkd3d_array_reserve((void **)ranges, range_size,
new_count + 1, sizeof(struct vkd3d_shader_hash_range));
(*ranges)[new_count].lo = lo_hash;
(*ranges)[new_count].hi = hi_hash;
if (kind == VKD3D_SHADER_HASH_RANGE_KIND_BARRIERS)
{
if (*end_ptr == '\0')
{
(*ranges)[new_count].flags = VKD3D_SHADER_META_FLAG_FORCE_COMPUTE_BARRIER_AFTER_DISPATCH;
end_ptr = "post-compute (default)";
}
else if (strcmp(end_ptr, "pre-compute") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_META_FLAG_FORCE_COMPUTE_BARRIER_BEFORE_DISPATCH;
else if (strcmp(end_ptr, "post-compute") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_META_FLAG_FORCE_COMPUTE_BARRIER_AFTER_DISPATCH;
else if (strcmp(end_ptr, "pre-raster") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_META_FLAG_FORCE_PRE_RASTERIZATION_BEFORE_DISPATCH;
else if (strcmp(end_ptr, "graphics") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_META_FLAG_FORCE_GRAPHICS_BEFORE_DISPATCH;
else
end_ptr = "N/A";
INFO("Inserting %s barrier for %016"PRIx64" - %016"PRIx64".\n",
end_ptr,
(*ranges)[new_count].lo,
(*ranges)[new_count].hi);
}
else if (kind == VKD3D_SHADER_HASH_RANGE_KIND_QA)
{
if (*end_ptr == '\0')
{
(*ranges)[new_count].flags = VKD3D_SHADER_HASH_RANGE_QA_FLAG_ALLOW;
end_ptr = "allow (default)";
}
else if (strcmp(end_ptr, "allow") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_HASH_RANGE_QA_FLAG_ALLOW;
else if (strcmp(end_ptr, "disallow") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_HASH_RANGE_QA_FLAG_DISALLOW;
else if (strcmp(end_ptr, "full") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_HASH_RANGE_QA_FLAG_FULL_QA;
else if (strcmp(end_ptr, "flush-nan") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_HASH_RANGE_QA_FLAG_FLUSH_NAN;
else if (strcmp(end_ptr, "expect-assume") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_HASH_RANGE_QA_FLAG_EXPECT_ASSUME;
else if (strcmp(end_ptr, "sync") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_HASH_RANGE_QA_FLAG_SYNC;
else if (strcmp(end_ptr, "sync-compute") == 0)
(*ranges)[new_count].flags = VKD3D_SHADER_HASH_RANGE_QA_FLAG_SYNC_COMPUTE;
else
end_ptr = "N/A";
INFO("Inserting %s QA check for %016"PRIx64" - %016"PRIx64".\n",
end_ptr,
(*ranges)[new_count].lo,
(*ranges)[new_count].hi);
}
new_count++;
}
}
*range_count = new_count;
}
VkMemoryPropertyFlags vkd3d_debug_buffer_memory_properties(struct d3d12_device *device,
VkMemoryPropertyFlags flags, bool high_throughput)
{
/* For high-throughput scenarios like sync-val, we absolutely cannot demote to host visible,
* or we risk 0.00001 fps. */
if ((vkd3d_config_flags & VKD3D_CONFIG_FLAG_BREADCRUMBS) && !high_throughput)
{
/* Expect crashes since we won't have time to flush caches.
* We use coherent in the debug_channel.h header, but not necessarily guaranteed to be coherent with
* host reads, so make extra sure. */
if (device->device_info.device_coherent_memory_features_amd.deviceCoherentMemory)
{
flags |= VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD | VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD;
INFO("Enabling uncached device memory for debug buffer.\n");
}
else if (device->device_info.vulkan_1_2_properties.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY)
{
/* Writes to sysmem seem to be coherent, but not ReBAR. Very slow, but hey,
* we're desperate when we're doing breadcrumb + debug ring! */
flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_CACHED_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
INFO("Forcing (implicitly-coherent) sysmem for debug buffer.\n");
}
}
return flags;
}