mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-30 09:35:40 +00:00
Merge pull request #2438 from Wunkolo/vk-debug
GPU/Vulkan: Add debug utility functions
This commit is contained in:
commit
c6c9abcb1c
|
@ -44,9 +44,20 @@
|
|||
#define vkCreateAndroidSurfaceKHR ds_vkCreateAndroidSurfaceKHR
|
||||
#define vkCreateMacOSSurfaceMVK ds_vkCreateMacOSSurfaceMVK
|
||||
#define vkCreateMetalSurfaceEXT ds_vkCreateMetalSurfaceEXT
|
||||
|
||||
// VK_EXT_debug_utils
|
||||
#define vkCmdBeginDebugUtilsLabelEXT ds_vkCmdBeginDebugUtilsLabelEXT
|
||||
#define vkCmdEndDebugUtilsLabelEXT ds_vkCmdEndDebugUtilsLabelEXT
|
||||
#define vkCmdInsertDebugUtilsLabelEXT ds_vkCmdInsertDebugUtilsLabelEXT
|
||||
#define vkCreateDebugUtilsMessengerEXT ds_vkCreateDebugUtilsMessengerEXT
|
||||
#define vkDestroyDebugUtilsMessengerEXT ds_vkDestroyDebugUtilsMessengerEXT
|
||||
#define vkQueueBeginDebugUtilsLabelEXT ds_vkQueueBeginDebugUtilsLabelEXT
|
||||
#define vkQueueEndDebugUtilsLabelEXT ds_vkQueueEndDebugUtilsLabelEXT
|
||||
#define vkQueueInsertDebugUtilsLabelEXT ds_vkQueueInsertDebugUtilsLabelEXT
|
||||
#define vkSetDebugUtilsObjectNameEXT ds_vkSetDebugUtilsObjectNameEXT
|
||||
#define vkSetDebugUtilsObjectTagEXT ds_vkSetDebugUtilsObjectTagEXT
|
||||
#define vkSubmitDebugUtilsMessageEXT ds_vkSubmitDebugUtilsMessageEXT
|
||||
|
||||
#define vkGetPhysicalDeviceProperties2 ds_vkGetPhysicalDeviceProperties2
|
||||
#define vkGetPhysicalDeviceSurfaceCapabilities2KHR ds_vkGetPhysicalDeviceSurfaceCapabilities2KHR
|
||||
#define vkGetPhysicalDeviceDisplayPropertiesKHR ds_vkGetPhysicalDeviceDisplayPropertiesKHR
|
||||
|
|
|
@ -66,8 +66,17 @@ VULKAN_INSTANCE_ENTRY_POINT(vkCreateMacOSSurfaceMVK, false)
|
|||
VULKAN_INSTANCE_ENTRY_POINT(vkCreateMetalSurfaceEXT, false)
|
||||
#endif
|
||||
|
||||
// VK_EXT_debug_utils
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkCmdBeginDebugUtilsLabelEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkCmdEndDebugUtilsLabelEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkCmdInsertDebugUtilsLabelEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkCreateDebugUtilsMessengerEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkDestroyDebugUtilsMessengerEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkQueueBeginDebugUtilsLabelEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkQueueEndDebugUtilsLabelEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkQueueInsertDebugUtilsLabelEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkSetDebugUtilsObjectNameEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkSetDebugUtilsObjectTagEXT, false)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkSubmitDebugUtilsMessageEXT, false)
|
||||
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceProperties2, false)
|
||||
|
|
|
@ -632,6 +632,7 @@ bool Context::CreateCommandBuffers()
|
|||
{
|
||||
VkResult res;
|
||||
|
||||
uint32_t frame_index = 0;
|
||||
for (FrameResources& resources : m_frame_resources)
|
||||
{
|
||||
resources.needs_fence_wait = false;
|
||||
|
@ -644,6 +645,8 @@ bool Context::CreateCommandBuffers()
|
|||
LOG_VULKAN_ERROR(res, "vkCreateCommandPool failed: ");
|
||||
return false;
|
||||
}
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), resources.command_pool, "Frame Command Pool %u",
|
||||
frame_index);
|
||||
|
||||
VkCommandBufferAllocateInfo buffer_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr,
|
||||
resources.command_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
|
||||
|
@ -654,6 +657,8 @@ bool Context::CreateCommandBuffers()
|
|||
LOG_VULKAN_ERROR(res, "vkAllocateCommandBuffers failed: ");
|
||||
return false;
|
||||
}
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), resources.command_buffer, "Frame Command Buffer %u",
|
||||
frame_index);
|
||||
|
||||
VkFenceCreateInfo fence_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT};
|
||||
|
||||
|
@ -663,7 +668,7 @@ bool Context::CreateCommandBuffers()
|
|||
LOG_VULKAN_ERROR(res, "vkCreateFence failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), resources.fence, "Frame Fence %u", frame_index);
|
||||
// TODO: A better way to choose the number of descriptors.
|
||||
VkDescriptorPoolSize pool_sizes[] = {{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1024},
|
||||
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1024},
|
||||
|
@ -683,6 +688,10 @@ bool Context::CreateCommandBuffers()
|
|||
LOG_VULKAN_ERROR(res, "vkCreateDescriptorPool failed: ");
|
||||
return false;
|
||||
}
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), resources.descriptor_pool, "Frame Descriptor Pool %u",
|
||||
frame_index);
|
||||
|
||||
++frame_index;
|
||||
}
|
||||
|
||||
ActivateCommandBuffer(0);
|
||||
|
@ -741,7 +750,7 @@ bool Context::CreateGlobalDescriptorPool()
|
|||
LOG_VULKAN_ERROR(res, "vkCreateDescriptorPool failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_global_descriptor_pool, "Global Descriptor Pool");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -909,6 +918,7 @@ void Context::DoSubmitCommandBuffer(u32 index, VkSemaphore wait_semaphore, VkSem
|
|||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = &signal_semaphore;
|
||||
}
|
||||
const Vulkan::Util::DebugScope debugScope(m_graphics_queue, "Context::DoSubmitCommandBuffer: %u", index);
|
||||
|
||||
VkResult res = vkQueueSubmit(m_graphics_queue, 1, &submit_info, resources.fence);
|
||||
if (res != VK_SUCCESS)
|
||||
|
@ -930,7 +940,7 @@ void Context::DoPresent(VkSemaphore wait_semaphore, VkSwapchainKHR present_swap_
|
|||
&present_swap_chain,
|
||||
&present_image_index,
|
||||
nullptr};
|
||||
|
||||
const Vulkan::Util::DebugScope debugScope(m_present_queue, "Context::DoPresent: %u", present_image_index);
|
||||
VkResult res = vkQueuePresentKHR(m_present_queue, &present_info);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
|
@ -1103,7 +1113,6 @@ void Context::DeferPipelineDestruction(VkPipeline pipeline)
|
|||
resources.cleanup_resources.push_back([this, pipeline]() { vkDestroyPipeline(m_device, pipeline, nullptr); });
|
||||
}
|
||||
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
|
@ -1137,10 +1146,15 @@ bool Context::EnableDebugUtils()
|
|||
}
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT messenger_info = {
|
||||
VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, nullptr, 0,
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT,
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
|
||||
DebugMessengerCallback, nullptr};
|
||||
VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
||||
nullptr,
|
||||
0,
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT,
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
|
||||
DebugMessengerCallback,
|
||||
nullptr};
|
||||
|
||||
VkResult res = vkCreateDebugUtilsMessengerEXT(m_instance, &messenger_info, nullptr, &m_debug_messenger_callback);
|
||||
if (res != VK_SUCCESS)
|
||||
|
|
|
@ -100,6 +100,10 @@ void StagingTexture::CopyFromTexture(VkCommandBuffer command_buffer, Texture& sr
|
|||
Assert((src_x + width) <= src_texture.GetWidth() && (src_y + height) <= src_texture.GetHeight());
|
||||
Assert((dst_x + width) <= m_width && (dst_y + height) <= m_height);
|
||||
|
||||
const Vulkan::Util::DebugScope debugScope(command_buffer,
|
||||
"StagingTexture::CopyFromTexture: {%u,%u} Lyr:%u Lvl:%u {%u,%u} %ux%u",
|
||||
src_x, src_y, src_layer, src_level, dst_x, dst_y, width, height);
|
||||
|
||||
VkImageLayout old_layout = src_texture.GetLayout();
|
||||
src_texture.TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
|
@ -123,6 +127,9 @@ void StagingTexture::CopyFromTexture(VkCommandBuffer command_buffer, Texture& sr
|
|||
void StagingTexture::CopyFromTexture(Texture& src_texture, u32 src_x, u32 src_y, u32 src_layer, u32 src_level,
|
||||
u32 dst_x, u32 dst_y, u32 width, u32 height)
|
||||
{
|
||||
const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
"StagingTexture::CopyFromTexture: {%u,%u} Lyr:%u Lvl:%u {%u,%u} %ux%u",
|
||||
src_x, src_y, src_layer, src_level, dst_x, dst_y, width, height);
|
||||
CopyFromTexture(g_vulkan_context->GetCurrentCommandBuffer(), src_texture, src_x, src_y, src_layer, src_level, dst_x,
|
||||
dst_y, width, height);
|
||||
|
||||
|
@ -162,6 +169,9 @@ void StagingTexture::CopyToTexture(VkCommandBuffer command_buffer, u32 src_x, u3
|
|||
void StagingTexture::CopyToTexture(u32 src_x, u32 src_y, Texture& dst_texture, u32 dst_x, u32 dst_y, u32 dst_layer,
|
||||
u32 dst_level, u32 width, u32 height)
|
||||
{
|
||||
const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
"StagingTexture::CopyToTexture: {%u,%u} | {%u,%u} Lyr:%u Lvl:%u %ux%u",
|
||||
src_x, src_y, dst_x, dst_y, dst_layer, dst_level, width, height);
|
||||
CopyToTexture(g_vulkan_context->GetCurrentCommandBuffer(), src_x, src_y, dst_texture, dst_x, dst_y, dst_layer,
|
||||
dst_level, width, height);
|
||||
|
||||
|
|
|
@ -239,6 +239,8 @@ void Texture::TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout n
|
|||
{
|
||||
if (m_layout == new_layout)
|
||||
return;
|
||||
const Vulkan::Util::DebugScope debugScope(command_buffer, "Texture::TransitionToLayout: %s",
|
||||
Vulkan::Util::VkImageLayoutToString(new_layout));
|
||||
|
||||
TransitionSubresourcesToLayout(command_buffer, 0, m_levels, 0, m_layers, m_layout, new_layout);
|
||||
|
||||
|
@ -249,6 +251,11 @@ void Texture::TransitionSubresourcesToLayout(VkCommandBuffer command_buffer, u32
|
|||
u32 start_layer, u32 num_layers, VkImageLayout old_layout,
|
||||
VkImageLayout new_layout)
|
||||
{
|
||||
const Vulkan::Util::DebugScope debugScope(
|
||||
command_buffer, "Texture::TransitionSubresourcesToLayout: Lvl:[%u,%u) Lyr:[%u,%u) %s -> %s", start_level,
|
||||
start_level + num_levels, start_layer, start_layer + num_layers, Vulkan::Util::VkImageLayoutToString(old_layout),
|
||||
Vulkan::Util::VkImageLayoutToString(new_layout));
|
||||
|
||||
VkImageMemoryBarrier barrier = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
|
@ -359,7 +366,6 @@ void Texture::TransitionSubresourcesToLayout(VkCommandBuffer command_buffer, u32
|
|||
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(command_buffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
|
@ -382,6 +388,8 @@ void Texture::UpdateFromBuffer(VkCommandBuffer cmdbuf, u32 level, u32 layer, u32
|
|||
VkBuffer buffer, u32 buffer_offset)
|
||||
{
|
||||
const VkImageLayout old_layout = m_layout;
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "Texture::UpdateFromBuffer: Lvl:%u Lyr:%u {%u,%u} %ux%u", level,
|
||||
layer, x, y, width, height);
|
||||
TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
const VkBufferImageCopy bic = {static_cast<VkDeviceSize>(buffer_offset),
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "context.h"
|
||||
#include "shader_compiler.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace Vulkan {
|
||||
namespace Util {
|
||||
bool IsDepthFormat(VkFormat format)
|
||||
|
@ -417,6 +419,71 @@ const char* VkResultToString(VkResult res)
|
|||
return "UNKNOWN_VK_RESULT";
|
||||
}
|
||||
}
|
||||
const char* VkImageLayoutToString(VkImageLayout layout)
|
||||
{
|
||||
switch (layout)
|
||||
{
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
return "VK_IMAGE_LAYOUT_UNDEFINED";
|
||||
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
return "VK_IMAGE_LAYOUT_GENERAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_PREINITIALIZED:
|
||||
return "VK_IMAGE_LAYOUT_PREINITIALIZED";
|
||||
|
||||
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL:
|
||||
return "VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL";
|
||||
|
||||
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
|
||||
return "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR";
|
||||
|
||||
case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR:
|
||||
return "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR";
|
||||
|
||||
case VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV:
|
||||
return "VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV";
|
||||
|
||||
case VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT:
|
||||
return "VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT";
|
||||
|
||||
default:
|
||||
return "UNKNOWN_VK_RESULT";
|
||||
}
|
||||
}
|
||||
|
||||
void LogVulkanResult(int level, const char* func_name, VkResult res, const char* msg, ...)
|
||||
{
|
||||
|
@ -429,6 +496,78 @@ void LogVulkanResult(int level, const char* func_name, VkResult res, const char*
|
|||
static_cast<int>(res), VkResultToString(res));
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
u8 DebugScope<VkCommandBuffer>::depth = 0;
|
||||
u8 DebugScope<VkQueue>::depth = 0;
|
||||
|
||||
static std::array<float, 4> Palette(float phase, const std::array<float, 3>& a, const std::array<float, 3>& b,
|
||||
const std::array<float, 3>& c, const std::array<float, 3>& d)
|
||||
{
|
||||
std::array<float, 4> result;
|
||||
result[0] = a[0] + b[0] * std::cos(6.28318f * (c[0] * phase + d[0]));
|
||||
result[1] = a[1] + b[1] * std::cos(6.28318f * (c[1] * phase + d[1]));
|
||||
result[2] = a[2] + b[2] * std::cos(6.28318f * (c[2] * phase + d[2]));
|
||||
result[3] = 1.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
DebugScope<VkCommandBuffer>::DebugScope(VkCommandBuffer context, const char* format, ...) : command_buffer(context)
|
||||
{
|
||||
if (command_buffer)
|
||||
{
|
||||
std::va_list ap;
|
||||
|
||||
SmallString str;
|
||||
va_start(ap, format);
|
||||
str.FormatVA(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
++depth;
|
||||
const float depth_phase = depth / static_cast<float>(max_depth);
|
||||
BeginDebugScope(command_buffer, str,
|
||||
Palette(depth_phase, {0.5, 0.5, 0.5}, {0.5, 0.5, 0.5}, {1.0, 1.0, 0.5}, {0.8, 0.90, 0.30}));
|
||||
}
|
||||
}
|
||||
|
||||
DebugScope<VkCommandBuffer>::~DebugScope()
|
||||
{
|
||||
if (command_buffer)
|
||||
{
|
||||
--depth;
|
||||
EndDebugScope(command_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
DebugScope<VkQueue>::DebugScope(VkQueue context, const char* format, ...) : queue(context)
|
||||
{
|
||||
if (queue)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
SmallString str;
|
||||
str.FormatVA(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
const float depth_phase = depth / static_cast<float>(max_depth);
|
||||
BeginDebugScope(queue, str,
|
||||
Palette(depth_phase, {0.5, 0.5, 0.5}, {0.5, 0.5, 0.5}, {2.0, 1.0, 0.0}, {0.5, 0.20, 0.25}));
|
||||
++depth;
|
||||
}
|
||||
}
|
||||
|
||||
DebugScope<VkQueue>::~DebugScope()
|
||||
{
|
||||
if (queue)
|
||||
{
|
||||
--depth;
|
||||
EndDebugScope(queue);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Util
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../string.h"
|
||||
#include "../types.h"
|
||||
#include "vulkan_loader.h"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdarg>
|
||||
#include <string_view>
|
||||
|
||||
namespace Vulkan {
|
||||
namespace Util {
|
||||
|
||||
|
@ -74,10 +76,202 @@ VkShaderModule CompileAndCreateFragmentShader(std::string_view source_code);
|
|||
VkShaderModule CompileAndCreateComputeShader(std::string_view source_code);
|
||||
|
||||
const char* VkResultToString(VkResult res);
|
||||
const char* VkImageLayoutToString(VkImageLayout layout);
|
||||
void LogVulkanResult(int level, const char* func_name, VkResult res, const char* msg, ...) printflike(4, 5);
|
||||
|
||||
#define LOG_VULKAN_ERROR(res, ...) ::Vulkan::Util::LogVulkanResult(1, __func__, res, __VA_ARGS__)
|
||||
|
||||
// Provides a compile-time mapping between a Vulkan-type into its matching VkObjectType
|
||||
template<typename T>
|
||||
struct VkObjectTypeMap;
|
||||
|
||||
// clang-format off
|
||||
template<> struct VkObjectTypeMap<VkInstance > { using type = VkInstance ; static constexpr VkObjectType value = VK_OBJECT_TYPE_INSTANCE; };
|
||||
template<> struct VkObjectTypeMap<VkPhysicalDevice > { using type = VkPhysicalDevice ; static constexpr VkObjectType value = VK_OBJECT_TYPE_PHYSICAL_DEVICE; };
|
||||
template<> struct VkObjectTypeMap<VkDevice > { using type = VkDevice ; static constexpr VkObjectType value = VK_OBJECT_TYPE_DEVICE; };
|
||||
template<> struct VkObjectTypeMap<VkQueue > { using type = VkQueue ; static constexpr VkObjectType value = VK_OBJECT_TYPE_QUEUE; };
|
||||
template<> struct VkObjectTypeMap<VkSemaphore > { using type = VkSemaphore ; static constexpr VkObjectType value = VK_OBJECT_TYPE_SEMAPHORE; };
|
||||
template<> struct VkObjectTypeMap<VkCommandBuffer > { using type = VkCommandBuffer ; static constexpr VkObjectType value = VK_OBJECT_TYPE_COMMAND_BUFFER; };
|
||||
template<> struct VkObjectTypeMap<VkFence > { using type = VkFence ; static constexpr VkObjectType value = VK_OBJECT_TYPE_FENCE; };
|
||||
template<> struct VkObjectTypeMap<VkDeviceMemory > { using type = VkDeviceMemory ; static constexpr VkObjectType value = VK_OBJECT_TYPE_DEVICE_MEMORY; };
|
||||
template<> struct VkObjectTypeMap<VkBuffer > { using type = VkBuffer ; static constexpr VkObjectType value = VK_OBJECT_TYPE_BUFFER; };
|
||||
template<> struct VkObjectTypeMap<VkImage > { using type = VkImage ; static constexpr VkObjectType value = VK_OBJECT_TYPE_IMAGE; };
|
||||
template<> struct VkObjectTypeMap<VkEvent > { using type = VkEvent ; static constexpr VkObjectType value = VK_OBJECT_TYPE_EVENT; };
|
||||
template<> struct VkObjectTypeMap<VkQueryPool > { using type = VkQueryPool ; static constexpr VkObjectType value = VK_OBJECT_TYPE_QUERY_POOL; };
|
||||
template<> struct VkObjectTypeMap<VkBufferView > { using type = VkBufferView ; static constexpr VkObjectType value = VK_OBJECT_TYPE_BUFFER_VIEW; };
|
||||
template<> struct VkObjectTypeMap<VkImageView > { using type = VkImageView ; static constexpr VkObjectType value = VK_OBJECT_TYPE_IMAGE_VIEW; };
|
||||
template<> struct VkObjectTypeMap<VkShaderModule > { using type = VkShaderModule ; static constexpr VkObjectType value = VK_OBJECT_TYPE_SHADER_MODULE; };
|
||||
template<> struct VkObjectTypeMap<VkPipelineCache > { using type = VkPipelineCache ; static constexpr VkObjectType value = VK_OBJECT_TYPE_PIPELINE_CACHE; };
|
||||
template<> struct VkObjectTypeMap<VkPipelineLayout > { using type = VkPipelineLayout ; static constexpr VkObjectType value = VK_OBJECT_TYPE_PIPELINE_LAYOUT; };
|
||||
template<> struct VkObjectTypeMap<VkRenderPass > { using type = VkRenderPass ; static constexpr VkObjectType value = VK_OBJECT_TYPE_RENDER_PASS; };
|
||||
template<> struct VkObjectTypeMap<VkPipeline > { using type = VkPipeline ; static constexpr VkObjectType value = VK_OBJECT_TYPE_PIPELINE; };
|
||||
template<> struct VkObjectTypeMap<VkDescriptorSetLayout > { using type = VkDescriptorSetLayout ; static constexpr VkObjectType value = VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT; };
|
||||
template<> struct VkObjectTypeMap<VkSampler > { using type = VkSampler ; static constexpr VkObjectType value = VK_OBJECT_TYPE_SAMPLER; };
|
||||
template<> struct VkObjectTypeMap<VkDescriptorPool > { using type = VkDescriptorPool ; static constexpr VkObjectType value = VK_OBJECT_TYPE_DESCRIPTOR_POOL; };
|
||||
template<> struct VkObjectTypeMap<VkDescriptorSet > { using type = VkDescriptorSet ; static constexpr VkObjectType value = VK_OBJECT_TYPE_DESCRIPTOR_SET; };
|
||||
template<> struct VkObjectTypeMap<VkFramebuffer > { using type = VkFramebuffer ; static constexpr VkObjectType value = VK_OBJECT_TYPE_FRAMEBUFFER; };
|
||||
template<> struct VkObjectTypeMap<VkCommandPool > { using type = VkCommandPool ; static constexpr VkObjectType value = VK_OBJECT_TYPE_COMMAND_POOL; };
|
||||
template<> struct VkObjectTypeMap<VkDescriptorUpdateTemplate> { using type = VkDescriptorUpdateTemplate; static constexpr VkObjectType value = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE; };
|
||||
template<> struct VkObjectTypeMap<VkSurfaceKHR > { using type = VkSurfaceKHR ; static constexpr VkObjectType value = VK_OBJECT_TYPE_SURFACE_KHR; };
|
||||
template<> struct VkObjectTypeMap<VkSwapchainKHR > { using type = VkSwapchainKHR ; static constexpr VkObjectType value = VK_OBJECT_TYPE_SWAPCHAIN_KHR; };
|
||||
template<> struct VkObjectTypeMap<VkDebugUtilsMessengerEXT > { using type = VkDebugUtilsMessengerEXT ; static constexpr VkObjectType value = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT; };
|
||||
// clang-format on
|
||||
|
||||
inline void SetObjectName(VkDevice device, void* object_handle, VkObjectType object_type, const char* format, ...)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (!vkSetDebugUtilsObjectNameEXT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::va_list ap;
|
||||
|
||||
SmallString str;
|
||||
va_start(ap, format);
|
||||
str.FormatVA(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
const VkDebugUtilsObjectNameInfoEXT nameInfo{VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, nullptr, object_type,
|
||||
reinterpret_cast<uint64_t>(object_handle), str};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void SetObjectName(VkDevice device, T object_handle, const char* format, ...)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
SetObjectName(device, reinterpret_cast<void*>((typename VkObjectTypeMap<T>::type)object_handle),
|
||||
VkObjectTypeMap<T>::value, format, ap);
|
||||
va_end(ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Command buffer debug utils
|
||||
inline void BeginDebugScope(VkCommandBuffer command_buffer, const char* scope_name,
|
||||
const std::array<float, 4>& scope_color = {0.5, 0.5, 0.5, 1.0})
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (!vkCmdBeginDebugUtilsLabelEXT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const VkDebugUtilsLabelEXT label{VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
||||
nullptr,
|
||||
scope_name,
|
||||
{scope_color[0], scope_color[1], scope_color[2], scope_color[3]}};
|
||||
vkCmdBeginDebugUtilsLabelEXT(command_buffer, &label);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void EndDebugScope(VkCommandBuffer command_buffer)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (!vkCmdEndDebugUtilsLabelEXT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
vkCmdEndDebugUtilsLabelEXT(command_buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void InsertDebugLabel(VkCommandBuffer command_buffer, const char* label_name,
|
||||
const std::array<float, 4>& label_color = {0.5, 0.5, 0.5, 1.0})
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (!vkCmdInsertDebugUtilsLabelEXT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const VkDebugUtilsLabelEXT label{VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
||||
nullptr,
|
||||
label_name,
|
||||
{label_color[0], label_color[1], label_color[2], label_color[3]}};
|
||||
vkCmdInsertDebugUtilsLabelEXT(command_buffer, &label);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Queue debug utils
|
||||
inline void BeginDebugScope(VkQueue queue, const char* scope_name,
|
||||
const std::array<float, 4>& scope_color = {0.75, 0.75, 0.75, 1.0})
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (!vkQueueBeginDebugUtilsLabelEXT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const VkDebugUtilsLabelEXT label{VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
||||
nullptr,
|
||||
scope_name,
|
||||
{scope_color[0], scope_color[1], scope_color[2], scope_color[3]}};
|
||||
vkQueueBeginDebugUtilsLabelEXT(queue, &label);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void EndDebugScope(VkQueue queue)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (!vkQueueEndDebugUtilsLabelEXT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
vkQueueEndDebugUtilsLabelEXT(queue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void InsertDebugLabel(VkQueue queue, const char* label_name,
|
||||
const std::array<float, 4>& label_color = {0.75, 0.75, 0.75, 1.0})
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (!vkQueueInsertDebugUtilsLabelEXT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const VkDebugUtilsLabelEXT label{VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
||||
nullptr,
|
||||
label_name,
|
||||
{label_color[0], label_color[1], label_color[2], label_color[3]}};
|
||||
vkQueueInsertDebugUtilsLabelEXT(queue, &label);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class DebugScope
|
||||
{
|
||||
public:
|
||||
DebugScope(T context, const char* format, ...) {}
|
||||
};
|
||||
|
||||
#ifdef _DEBUG
|
||||
template<>
|
||||
class DebugScope<VkCommandBuffer>
|
||||
{
|
||||
public:
|
||||
DebugScope(VkCommandBuffer context, const char* format, ...);
|
||||
~DebugScope();
|
||||
|
||||
private:
|
||||
static constexpr u8 max_depth = 8u;
|
||||
static u8 depth;
|
||||
VkCommandBuffer command_buffer;
|
||||
};
|
||||
|
||||
template<>
|
||||
class DebugScope<VkQueue>
|
||||
{
|
||||
public:
|
||||
DebugScope(VkQueue context, const char* format, ...);
|
||||
~DebugScope();
|
||||
|
||||
private:
|
||||
static constexpr u8 max_depth = 8u;
|
||||
static u8 depth;
|
||||
VkQueue queue;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace Util
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -115,6 +115,9 @@ bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
|
|||
{0, 0, 0},
|
||||
{m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1u}};
|
||||
|
||||
VkCommandBuffer buf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(buf, "GPU_HW_Vulkan::DoState");
|
||||
|
||||
if (sw.IsReading())
|
||||
{
|
||||
Vulkan::Texture* tex = static_cast<Vulkan::Texture*>((*host_texture)->GetHandle());
|
||||
|
@ -124,7 +127,6 @@ bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
|
|||
return false;
|
||||
}
|
||||
|
||||
VkCommandBuffer buf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const VkImageLayout old_tex_layout = tex->GetLayout();
|
||||
const VkImageLayout old_vram_layout = m_vram_texture.GetLayout();
|
||||
tex->TransitionToLayout(buf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
@ -158,7 +160,6 @@ bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
|
|||
return false;
|
||||
}
|
||||
|
||||
VkCommandBuffer buf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const VkImageLayout old_vram_layout = m_vram_texture.GetLayout();
|
||||
tex->TransitionToLayout(buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
m_vram_texture.TransitionToLayout(buf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
@ -191,6 +192,7 @@ void GPU_HW_Vulkan::ResetGraphicsAPIState()
|
|||
void GPU_HW_Vulkan::RestoreGraphicsAPIState()
|
||||
{
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::RestoreGraphicsAPIState");
|
||||
m_vram_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
VkDeviceSize vertex_buffer_offset = 0;
|
||||
|
@ -389,6 +391,7 @@ void GPU_HW_Vulkan::BeginRenderPass(VkRenderPass render_pass, VkFramebuffer fram
|
|||
{{static_cast<s32>(x), static_cast<s32>(y)}, {width, height}},
|
||||
(clear_value ? 1u : 0u),
|
||||
clear_value};
|
||||
Vulkan::Util::BeginDebugScope(g_vulkan_context->GetCurrentCommandBuffer(), "GPU_HW_Vulkan::BeginRenderPass");
|
||||
vkCmdBeginRenderPass(g_vulkan_context->GetCurrentCommandBuffer(), &bi, VK_SUBPASS_CONTENTS_INLINE);
|
||||
m_current_render_pass = render_pass;
|
||||
}
|
||||
|
@ -408,6 +411,7 @@ void GPU_HW_Vulkan::EndRenderPass()
|
|||
return;
|
||||
|
||||
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
m_current_render_pass = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
|
@ -432,11 +436,16 @@ bool GPU_HW_Vulkan::CreatePipelineLayouts()
|
|||
if (m_batch_descriptor_set_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_batch_descriptor_set_layout,
|
||||
"Batch Descriptor Set Layout");
|
||||
|
||||
// textures start at 1
|
||||
dslbuilder.AddBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
m_single_sampler_descriptor_set_layout = dslbuilder.Create(device);
|
||||
if (m_single_sampler_descriptor_set_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_single_sampler_descriptor_set_layout,
|
||||
"Single Sampler Descriptor Set Layout");
|
||||
|
||||
if (m_use_ssbos_for_vram_writes)
|
||||
dslbuilder.AddBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
|
@ -445,47 +454,64 @@ bool GPU_HW_Vulkan::CreatePipelineLayouts()
|
|||
m_vram_write_descriptor_set_layout = dslbuilder.Create(device);
|
||||
if (m_vram_write_descriptor_set_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_write_descriptor_set_layout,
|
||||
"VRAM Write Descriptor Set Layout");
|
||||
|
||||
Vulkan::PipelineLayoutBuilder plbuilder;
|
||||
plbuilder.AddDescriptorSet(m_batch_descriptor_set_layout);
|
||||
m_batch_pipeline_layout = plbuilder.Create(device);
|
||||
if (m_batch_pipeline_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_batch_pipeline_layout, "Batch Pipeline Layout");
|
||||
|
||||
plbuilder.AddDescriptorSet(m_single_sampler_descriptor_set_layout);
|
||||
plbuilder.AddPushConstants(VK_SHADER_STAGE_FRAGMENT_BIT, 0, MAX_PUSH_CONSTANTS_SIZE);
|
||||
m_single_sampler_pipeline_layout = plbuilder.Create(device);
|
||||
if (m_single_sampler_pipeline_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_single_sampler_pipeline_layout,
|
||||
"Single Sampler Pipeline Layout");
|
||||
|
||||
plbuilder.AddPushConstants(VK_SHADER_STAGE_FRAGMENT_BIT, 0, MAX_PUSH_CONSTANTS_SIZE);
|
||||
m_no_samplers_pipeline_layout = plbuilder.Create(device);
|
||||
if (m_no_samplers_pipeline_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_no_samplers_pipeline_layout,
|
||||
"No Samplers Pipeline Layout");
|
||||
|
||||
plbuilder.AddDescriptorSet(m_vram_write_descriptor_set_layout);
|
||||
plbuilder.AddPushConstants(VK_SHADER_STAGE_FRAGMENT_BIT, 0, MAX_PUSH_CONSTANTS_SIZE);
|
||||
m_vram_write_pipeline_layout = plbuilder.Create(device);
|
||||
if (m_vram_write_pipeline_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_write_pipeline_layout,
|
||||
"VRAM Write Pipeline Layout");
|
||||
|
||||
plbuilder.AddDescriptorSet(m_single_sampler_descriptor_set_layout);
|
||||
plbuilder.AddPushConstants(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, MAX_PUSH_CONSTANTS_SIZE);
|
||||
m_downsample_pipeline_layout = plbuilder.Create(device);
|
||||
if (m_downsample_pipeline_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_downsample_pipeline_layout,
|
||||
"Downsample Pipeline Layout");
|
||||
|
||||
dslbuilder.AddBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
dslbuilder.AddBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
m_downsample_composite_descriptor_set_layout = dslbuilder.Create(device);
|
||||
if (m_downsample_composite_descriptor_set_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(),
|
||||
|
||||
m_downsample_composite_descriptor_set_layout,
|
||||
"Downsample Composite Descriptor Set Layout");
|
||||
|
||||
plbuilder.AddDescriptorSet(m_downsample_composite_descriptor_set_layout);
|
||||
plbuilder.AddPushConstants(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, MAX_PUSH_CONSTANTS_SIZE);
|
||||
m_downsample_composite_pipeline_layout = plbuilder.Create(device);
|
||||
if (m_downsample_composite_pipeline_layout == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_downsample_composite_pipeline_layout,
|
||||
"Downsample Composite Pipeline Layout");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -501,6 +527,7 @@ bool GPU_HW_Vulkan::CreateSamplers()
|
|||
m_point_sampler = sbuilder.Create(device);
|
||||
if (m_point_sampler == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_point_sampler, "Point Sampler");
|
||||
|
||||
sbuilder.SetLinearSampler(false, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER);
|
||||
sbuilder.SetAddressMode(VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
|
@ -508,11 +535,13 @@ bool GPU_HW_Vulkan::CreateSamplers()
|
|||
m_linear_sampler = sbuilder.Create(device);
|
||||
if (m_linear_sampler == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_linear_sampler, "Linear Sampler");
|
||||
|
||||
sbuilder.SetLinearSampler(true, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER);
|
||||
m_trilinear_sampler = sbuilder.Create(device);
|
||||
if (m_trilinear_sampler == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_trilinear_sampler, "Trilinear Sampler");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -553,6 +582,32 @@ bool GPU_HW_Vulkan::CreateFramebuffer()
|
|||
return false;
|
||||
}
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_texture.GetImage(), "VRAM Texture");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_texture.GetView(), "VRAM Texture View");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_texture.GetDeviceMemory(), "VRAM Texture Memory");
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_depth_texture.GetImage(), "VRAM Depth Texture");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_depth_texture.GetView(), "VRAM Depth Texture View");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_depth_texture.GetDeviceMemory(),
|
||||
"VRAM Depth Texture Memory");
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_read_texture.GetImage(), "VRAM Read Texture");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_read_texture.GetView(), "VRAM Read Texture View");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_read_texture.GetDeviceMemory(),
|
||||
"VRAM Read Texture Memory");
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_display_texture.GetImage(), "Display Texture");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_display_texture.GetView(), "Display Texture View");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_display_texture.GetDeviceMemory(),
|
||||
"Display Texture Memory");
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_readback_texture.GetImage(),
|
||||
"VRAM Readback Texture");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_readback_texture.GetView(),
|
||||
"VRAM Readback Texture View");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_readback_texture.GetDeviceMemory(),
|
||||
"VRAM Readback Texture Memory");
|
||||
|
||||
m_vram_render_pass =
|
||||
g_vulkan_context->GetRenderPass(texture_format, depth_format, samples, VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||
m_vram_update_depth_render_pass =
|
||||
|
@ -572,6 +627,12 @@ bool GPU_HW_Vulkan::CreateFramebuffer()
|
|||
return false;
|
||||
}
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_render_pass, "VRAM Render Pass");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_update_depth_render_pass,
|
||||
"VRAM Update Depth Render Pass");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_display_load_render_pass, "Display Load Render Pass");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_readback_render_pass, "VRAM Readback Render Pass");
|
||||
|
||||
// vram framebuffer has both colour and depth
|
||||
Vulkan::FramebufferBuilder fbb;
|
||||
fbb.AddAttachment(m_vram_texture.GetView());
|
||||
|
@ -581,6 +642,7 @@ bool GPU_HW_Vulkan::CreateFramebuffer()
|
|||
m_vram_framebuffer = fbb.Create(g_vulkan_context->GetDevice());
|
||||
if (m_vram_framebuffer == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_framebuffer, "VRAM Framebuffer");
|
||||
|
||||
m_vram_update_depth_framebuffer = m_vram_depth_texture.CreateFramebuffer(m_vram_update_depth_render_pass);
|
||||
m_vram_readback_framebuffer = m_vram_readback_texture.CreateFramebuffer(m_vram_readback_render_pass);
|
||||
|
@ -590,8 +652,14 @@ bool GPU_HW_Vulkan::CreateFramebuffer()
|
|||
{
|
||||
return false;
|
||||
}
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_update_depth_framebuffer,
|
||||
"VRAM Update Depth Framebuffer");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_readback_framebuffer, "VRAM Readback Framebuffer");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_display_framebuffer, "Display Framebuffer");
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::CreateFramebuffer");
|
||||
|
||||
m_vram_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
m_vram_depth_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
m_vram_read_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
@ -780,12 +848,26 @@ void GPU_HW_Vulkan::DestroyFramebuffer()
|
|||
|
||||
bool GPU_HW_Vulkan::CreateVertexBuffer()
|
||||
{
|
||||
return m_vertex_stream_buffer.Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VERTEX_BUFFER_SIZE);
|
||||
if (!m_vertex_stream_buffer.Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VERTEX_BUFFER_SIZE))
|
||||
return false;
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vertex_stream_buffer.GetBuffer(),
|
||||
"Vertex Stream Buffer");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vertex_stream_buffer.GetDeviceMemory(),
|
||||
"Vertex Stream Buffer Memory");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPU_HW_Vulkan::CreateUniformBuffer()
|
||||
{
|
||||
return m_uniform_stream_buffer.Create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, UNIFORM_BUFFER_SIZE);
|
||||
if (!m_uniform_stream_buffer.Create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, UNIFORM_BUFFER_SIZE))
|
||||
return false;
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_uniform_stream_buffer.GetBuffer(),
|
||||
"Uniform Stream Buffer");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_uniform_stream_buffer.GetDeviceMemory(),
|
||||
"Uniform Stream Buffer Memory");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPU_HW_Vulkan::CreateTextureBuffer()
|
||||
|
@ -810,7 +892,6 @@ bool GPU_HW_Vulkan::CreateTextureBuffer()
|
|||
{
|
||||
if (!m_texture_stream_buffer.Create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VRAM_UPDATE_TEXTURE_BUFFER_SIZE))
|
||||
return false;
|
||||
|
||||
Vulkan::BufferViewBuilder bvbuilder;
|
||||
bvbuilder.Set(m_texture_stream_buffer.GetBuffer(), VK_FORMAT_R16_UINT, 0, m_texture_stream_buffer.GetCurrentSize());
|
||||
m_texture_stream_buffer_view = bvbuilder.Create(g_vulkan_context->GetDevice());
|
||||
|
@ -827,6 +908,13 @@ bool GPU_HW_Vulkan::CreateTextureBuffer()
|
|||
dsubuilder.Update(g_vulkan_context->GetDevice());
|
||||
}
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_texture_stream_buffer.GetBuffer(),
|
||||
"Texture Stream Buffer");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_texture_stream_buffer.GetDeviceMemory(),
|
||||
"Texture Stream Buffer Memory");
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_write_descriptor_set, "VRAM Write Descriptor Set");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1100,6 +1188,8 @@ bool GPU_HW_Vulkan::CompilePipelines()
|
|||
vkDestroyShaderModule(device, fs, nullptr);
|
||||
if (m_vram_update_depth_pipeline == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_update_depth_pipeline,
|
||||
"VRAM Update Depth Pipeline");
|
||||
|
||||
progress.Increment();
|
||||
}
|
||||
|
@ -1125,6 +1215,7 @@ bool GPU_HW_Vulkan::CompilePipelines()
|
|||
vkDestroyShaderModule(device, fs, nullptr);
|
||||
if (m_vram_readback_pipeline == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_vram_readback_pipeline, "VRAM Read Pipeline");
|
||||
|
||||
progress.Increment();
|
||||
}
|
||||
|
@ -1183,6 +1274,8 @@ bool GPU_HW_Vulkan::CompilePipelines()
|
|||
vkDestroyShaderModule(g_vulkan_context->GetDevice(), fs, nullptr);
|
||||
if (m_downsample_first_pass_pipeline == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_downsample_first_pass_pipeline,
|
||||
"Downsample First Pass Pipeline");
|
||||
|
||||
fs = g_vulkan_shader_cache->GetFragmentShader(shadergen.GenerateAdaptiveDownsampleMipFragmentShader(false));
|
||||
if (fs == VK_NULL_HANDLE)
|
||||
|
@ -1193,6 +1286,8 @@ bool GPU_HW_Vulkan::CompilePipelines()
|
|||
vkDestroyShaderModule(g_vulkan_context->GetDevice(), fs, nullptr);
|
||||
if (m_downsample_mid_pass_pipeline == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_downsample_mid_pass_pipeline,
|
||||
"Downsample Mid Pass Pipeline");
|
||||
|
||||
fs = g_vulkan_shader_cache->GetFragmentShader(shadergen.GenerateAdaptiveDownsampleBlurFragmentShader());
|
||||
if (fs == VK_NULL_HANDLE)
|
||||
|
@ -1204,6 +1299,8 @@ bool GPU_HW_Vulkan::CompilePipelines()
|
|||
vkDestroyShaderModule(g_vulkan_context->GetDevice(), fs, nullptr);
|
||||
if (m_downsample_blur_pass_pipeline == VK_NULL_HANDLE)
|
||||
return false;
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_downsample_blur_pass_pipeline,
|
||||
"Downsample Blur Pass Pipeline");
|
||||
|
||||
fs = g_vulkan_shader_cache->GetFragmentShader(shadergen.GenerateAdaptiveDownsampleCompositeFragmentShader());
|
||||
if (fs == VK_NULL_HANDLE)
|
||||
|
@ -1216,6 +1313,9 @@ bool GPU_HW_Vulkan::CompilePipelines()
|
|||
vkDestroyShaderModule(g_vulkan_context->GetDevice(), fs, nullptr);
|
||||
if (m_downsample_composite_pass_pipeline == VK_NULL_HANDLE)
|
||||
return false;
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_downsample_composite_pass_pipeline,
|
||||
"Downsample Composite Pass Pipeline");
|
||||
}
|
||||
else if (m_downsample_mode == GPUDownsampleMode::Box)
|
||||
{
|
||||
|
@ -1237,6 +1337,9 @@ bool GPU_HW_Vulkan::CompilePipelines()
|
|||
vkDestroyShaderModule(g_vulkan_context->GetDevice(), fs, nullptr);
|
||||
if (m_downsample_first_pass_pipeline == VK_NULL_HANDLE)
|
||||
return false;
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_downsample_first_pass_pipeline,
|
||||
"Downsample First Pass Pipeline");
|
||||
}
|
||||
|
||||
progress.Increment();
|
||||
|
@ -1274,6 +1377,8 @@ void GPU_HW_Vulkan::DrawBatchVertices(BatchRenderMode render_mode, u32 base_vert
|
|||
BeginVRAMRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::DrawBatchVertices: [%u,%u)", base_vertex,
|
||||
base_vertex + num_vertices);
|
||||
|
||||
// [depth_test][render_mode][texture_mode][transparency_mode][dithering][interlacing]
|
||||
const u8 depth_test = m_batch.use_depth_buffer ? static_cast<u8>(2) : BoolToUInt8(m_batch.check_mask_before_draw);
|
||||
|
@ -1289,7 +1394,9 @@ void GPU_HW_Vulkan::SetScissorFromDrawingArea()
|
|||
{
|
||||
int left, top, right, bottom;
|
||||
CalcScissorRect(&left, &top, &right, &bottom);
|
||||
|
||||
const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
"GPU_HW_Vulkan::SetScissorFromDrawingArea: {%u,%u} {%u,%u}", left, top,
|
||||
right, bottom);
|
||||
Vulkan::Util::SetScissor(g_vulkan_context->GetCurrentCommandBuffer(), left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
|
@ -1301,6 +1408,7 @@ void GPU_HW_Vulkan::ClearDisplay()
|
|||
m_host_display->ClearDisplayTexture();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::ClearDisplay");
|
||||
m_display_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
static const VkClearColorValue cc = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||
|
@ -1313,6 +1421,9 @@ void GPU_HW_Vulkan::UpdateDisplay()
|
|||
GPU_HW::UpdateDisplay();
|
||||
EndRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::UpdateDisplay");
|
||||
|
||||
if (g_settings.debugging.show_vram)
|
||||
{
|
||||
if (IsUsingMultisampling())
|
||||
|
@ -1380,7 +1491,6 @@ void GPU_HW_Vulkan::UpdateDisplay()
|
|||
const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y + reinterpret_field_offset,
|
||||
reinterpret_crop_left, reinterpret_field_offset};
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
m_display_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
m_vram_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
|
@ -1399,6 +1509,7 @@ void GPU_HW_Vulkan::UpdateDisplay()
|
|||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_single_sampler_pipeline_layout, 0, 1,
|
||||
&m_vram_read_descriptor_set, 0, nullptr);
|
||||
Vulkan::Util::SetViewportAndScissor(cmdbuf, 0, 0, scaled_display_width, scaled_display_height);
|
||||
|
||||
vkCmdDraw(cmdbuf, 3, 1, 0, 0);
|
||||
|
||||
EndRenderPass();
|
||||
|
@ -1442,6 +1553,8 @@ void GPU_HW_Vulkan::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
|
|||
EndRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::ReadVRAM: %u %u %ux%u", x, y, width, height);
|
||||
|
||||
m_vram_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
m_vram_readback_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
|
@ -1460,7 +1573,6 @@ void GPU_HW_Vulkan::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
|
|||
&m_vram_read_descriptor_set, 0, nullptr);
|
||||
Vulkan::Util::SetViewportAndScissor(cmdbuf, 0, 0, encoded_width, encoded_height);
|
||||
vkCmdDraw(cmdbuf, 3, 1, 0, 0);
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
m_vram_readback_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
@ -1487,6 +1599,9 @@ void GPU_HW_Vulkan::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
|||
BeginVRAMRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::FillVRAM: {%u,%u} %ux%u %08x", x, y, width, height,
|
||||
color);
|
||||
|
||||
const VRAMFillUBOData uniforms = GetVRAMFillUBOData(x, y, width, height, color);
|
||||
vkCmdPushConstants(cmdbuf, m_no_samplers_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(uniforms),
|
||||
&uniforms);
|
||||
|
@ -1539,9 +1654,11 @@ void GPU_HW_Vulkan::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void*
|
|||
std::memcpy(m_texture_stream_buffer.GetCurrentHostPointer(), data, data_size);
|
||||
m_texture_stream_buffer.CommitMemory(data_size);
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::UpdateVRAM: {%u,%u} %ux%u", x, y, width, height);
|
||||
|
||||
BeginVRAMRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const VRAMWriteUBOData uniforms = GetVRAMWriteUBOData(x, y, width, height, start_index, set_mask, check_mask);
|
||||
vkCmdPushConstants(cmdbuf, m_vram_write_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(uniforms),
|
||||
&uniforms);
|
||||
|
@ -1561,6 +1678,9 @@ void GPU_HW_Vulkan::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void*
|
|||
|
||||
void GPU_HW_Vulkan::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height)
|
||||
{
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::CopyVRAM: {%u, %u} {%u, %u} %ux%u", src_x, src_y,
|
||||
dst_x, dst_y, width, height);
|
||||
if (IsUsingSoftwareRendererForReadbacks())
|
||||
CopySoftwareRendererVRAM(src_x, src_y, dst_x, dst_y, width, height);
|
||||
|
||||
|
@ -1577,7 +1697,6 @@ void GPU_HW_Vulkan::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 wid
|
|||
|
||||
BeginVRAMRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
m_vram_copy_pipelines[BoolToUInt8(m_GPUSTAT.check_mask_before_draw && !m_pgxp_depth_buffer)]);
|
||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_single_sampler_pipeline_layout, 0, 1,
|
||||
|
@ -1606,8 +1725,6 @@ void GPU_HW_Vulkan::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 wid
|
|||
|
||||
EndRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
|
||||
m_vram_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_GENERAL);
|
||||
|
||||
const VkImageCopy ic{{VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u},
|
||||
|
@ -1626,6 +1743,7 @@ void GPU_HW_Vulkan::UpdateVRAMReadTexture()
|
|||
EndRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::UpdateVRAMReadTexture");
|
||||
m_vram_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
m_vram_read_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
|
@ -1655,7 +1773,6 @@ void GPU_HW_Vulkan::UpdateVRAMReadTexture()
|
|||
|
||||
m_vram_read_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
m_vram_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
GPU_HW::UpdateVRAMReadTexture();
|
||||
}
|
||||
|
||||
|
@ -1665,8 +1782,8 @@ void GPU_HW_Vulkan::UpdateDepthBufferFromMaskBit()
|
|||
return;
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::UpdateDepthBufferFromMaskBit");
|
||||
m_vram_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
BeginRenderPass(m_vram_update_depth_render_pass, m_vram_update_depth_framebuffer, 0, 0, m_vram_texture.GetWidth(),
|
||||
|
@ -1690,6 +1807,7 @@ void GPU_HW_Vulkan::ClearDepthBuffer()
|
|||
EndRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::ClearDepthBuffer");
|
||||
m_vram_depth_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
static const VkClearDepthStencilValue cds = {1.0f};
|
||||
|
@ -1712,12 +1830,20 @@ bool GPU_HW_Vulkan::CreateTextureReplacementStreamBuffer()
|
|||
return false;
|
||||
}
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_texture_replacment_stream_buffer.GetBuffer(),
|
||||
"Texture Replacement Stream Buffer");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_texture_replacment_stream_buffer.GetDeviceMemory(),
|
||||
"Texture Replacement Stream Buffer Memory");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPU_HW_Vulkan::BlitVRAMReplacementTexture(const TextureReplacementTexture* tex, u32 dst_x, u32 dst_y, u32 width,
|
||||
u32 height)
|
||||
{
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::BlitVRAMReplacementTexture: {%u,%u} %ux%u", dst_x,
|
||||
dst_y, width, height);
|
||||
if (!CreateTextureReplacementStreamBuffer())
|
||||
return false;
|
||||
|
||||
|
@ -1752,7 +1878,6 @@ bool GPU_HW_Vulkan::BlitVRAMReplacementTexture(const TextureReplacementTexture*
|
|||
m_texture_replacment_stream_buffer.CommitMemory(required_size);
|
||||
|
||||
// buffer -> texture
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
m_vram_write_replacement_texture.UpdateFromBuffer(cmdbuf, 0, 0, 0, 0, tex->GetWidth(), tex->GetHeight(),
|
||||
m_texture_replacment_stream_buffer.GetBuffer(), buffer_offset);
|
||||
|
||||
|
@ -1786,6 +1911,8 @@ void GPU_HW_Vulkan::DownsampleFramebuffer(Vulkan::Texture& source, u32 left, u32
|
|||
void GPU_HW_Vulkan::DownsampleFramebufferBoxFilter(Vulkan::Texture& source, u32 left, u32 top, u32 width, u32 height)
|
||||
{
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::DownsampleFramebufferBoxFilter: {%u,%u} %ux%u",
|
||||
left, top, width, height);
|
||||
source.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
m_downsample_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
|
@ -1825,6 +1952,8 @@ void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 l
|
|||
{width, height, 1u}};
|
||||
|
||||
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "Downsample Framebuffer Adaptive:");
|
||||
|
||||
source.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
m_downsample_texture.TransitionSubresourcesToLayout(cmdbuf, 0, 1, 0, 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
@ -1838,6 +1967,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 l
|
|||
const u32 levels = m_downsample_texture.GetLevels();
|
||||
for (u32 level = 1; level < levels; level++)
|
||||
{
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "Generate Mip: %u", level);
|
||||
m_downsample_texture.TransitionSubresourcesToLayout(
|
||||
cmdbuf, level, 1, 0, 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
|
@ -1865,6 +1995,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 l
|
|||
|
||||
// blur pass at lowest resolution
|
||||
{
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "Blur Pass at lowest resolution");
|
||||
const u32 last_level = levels - 1;
|
||||
|
||||
m_downsample_weight_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
@ -1892,6 +2023,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 l
|
|||
|
||||
// resolve pass
|
||||
{
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuf, "Resolve pass");
|
||||
m_display_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
BeginRenderPass(m_display_load_render_pass, m_display_framebuffer, left, top, width, height);
|
||||
|
@ -1901,10 +2033,8 @@ void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 l
|
|||
&m_downsample_composite_descriptor_set, 0, nullptr);
|
||||
vkCmdDraw(cmdbuf, 3, 1, 0, 0);
|
||||
EndRenderPass();
|
||||
|
||||
m_display_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
|
||||
RestoreGraphicsAPIState();
|
||||
|
||||
m_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(),
|
||||
|
|
|
@ -185,7 +185,8 @@ std::unique_ptr<HostDisplayTexture> VulkanHostDisplay::CreateTexture(u32 width,
|
|||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
"VulkanHostDisplay::CreateTexture");
|
||||
texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
if (data)
|
||||
|
@ -632,6 +633,8 @@ bool VulkanHostDisplay::Render()
|
|||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
Vulkan::Texture& swap_chain_texture = m_swap_chain->GetCurrentTexture();
|
||||
|
||||
{
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuffer, "VulkanHostDisplay::Render");
|
||||
// Swap chain images start in undefined
|
||||
swap_chain_texture.OverrideImageLayout(VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
swap_chain_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
@ -644,8 +647,10 @@ bool VulkanHostDisplay::Render()
|
|||
RenderSoftwareCursor();
|
||||
|
||||
vkCmdEndRenderPass(cmdbuffer);
|
||||
Vulkan::Util::EndDebugScope(cmdbuffer);
|
||||
|
||||
swap_chain_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
}
|
||||
|
||||
g_vulkan_context->SubmitCommandBuffer(m_swap_chain->GetImageAvailableSemaphore(),
|
||||
m_swap_chain->GetRenderingFinishedSemaphore(), m_swap_chain->GetSwapChain(),
|
||||
|
@ -722,7 +727,8 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
|||
const VkFramebuffer fb = tex.CreateFramebuffer(rp);
|
||||
if (!fb)
|
||||
return false;
|
||||
|
||||
const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
"VulkanHostDisplay::RenderScreenshot: %ux%u", width, height);
|
||||
tex.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height, 0);
|
||||
|
@ -742,6 +748,7 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
|||
}
|
||||
|
||||
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
tex.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
staging_tex.CopyFromTexture(tex, 0, 0, 0, 0, 0, 0, width, height);
|
||||
staging_tex.ReadTexels(0, 0, width, height, out_pixels->data(), *out_stride);
|
||||
|
@ -764,11 +771,15 @@ void VulkanHostDisplay::BeginSwapChainRenderPass(VkFramebuffer framebuffer, u32
|
|||
{{0, 0}, {width, height}},
|
||||
1u,
|
||||
&clear_value};
|
||||
Vulkan::Util::BeginDebugScope(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
"VulkanHostDisplay::BeginSwapChainRenderPass");
|
||||
vkCmdBeginRenderPass(g_vulkan_context->GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderDisplay()
|
||||
{
|
||||
const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(),
|
||||
"VulkanHostDisplay::RenderDisplay");
|
||||
if (!HasDisplayTexture())
|
||||
{
|
||||
BeginSwapChainRenderPass(m_swap_chain->GetCurrentFramebuffer(), m_swap_chain->GetWidth(),
|
||||
|
@ -798,6 +809,9 @@ void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height,
|
|||
s32 texture_view_width, s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(
|
||||
cmdbuffer, "VulkanHostDisplay::RenderDisplay: {%u,%u} %ux%u | %ux%u | {%u,%u} %ux%u", left, top, width, height,
|
||||
texture_height, texture_width, texture_view_x, texture_view_y, texture_view_width, texture_view_height);
|
||||
|
||||
VkDescriptorSet ds = g_vulkan_context->AllocateDescriptorSet(m_descriptor_set_layout);
|
||||
if (ds == VK_NULL_HANDLE)
|
||||
|
@ -830,6 +844,7 @@ void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height,
|
|||
|
||||
void VulkanHostDisplay::RenderImGui()
|
||||
{
|
||||
const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(), "Imgui");
|
||||
ImGui::Render();
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), g_vulkan_context->GetCurrentCommandBuffer());
|
||||
}
|
||||
|
@ -846,6 +861,8 @@ void VulkanHostDisplay::RenderSoftwareCursor()
|
|||
void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuffer, "VulkanHostDisplay::RenderSoftwareCursor: {%u,%u} %ux%u", left,
|
||||
top, width, height);
|
||||
|
||||
VkDescriptorSet ds = g_vulkan_context->AllocateDescriptorSet(m_descriptor_set_layout);
|
||||
if (ds == VK_NULL_HANDLE)
|
||||
|
@ -997,6 +1014,7 @@ bool VulkanHostDisplay::SetPostProcessingChain(const std::string_view& config)
|
|||
m_post_processing_chain.ClearStages();
|
||||
return false;
|
||||
}
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), stage.pipeline, (shader.GetName() + "Pipeline").c_str());
|
||||
|
||||
m_post_processing_stages.push_back(std::move(stage));
|
||||
}
|
||||
|
@ -1010,7 +1028,10 @@ bool VulkanHostDisplay::SetPostProcessingChain(const std::string_view& config)
|
|||
m_post_processing_chain.ClearStages();
|
||||
return false;
|
||||
}
|
||||
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_post_processing_ubo.GetBuffer(),
|
||||
"Post Processing Uniform Buffer");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_post_processing_ubo.GetDeviceMemory(),
|
||||
"Post Processing Uniform Buffer Memory");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1035,6 +1056,12 @@ bool VulkanHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t
|
|||
{
|
||||
return false;
|
||||
}
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_post_processing_input_texture.GetImage(),
|
||||
"Post Processing Input Texture");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_post_processing_input_texture.GetView(),
|
||||
"Post Processing Input Texture View");
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_post_processing_input_texture.GetDeviceMemory(),
|
||||
"Post Processing Input Texture Memory");
|
||||
}
|
||||
|
||||
const u32 target_count = (static_cast<u32>(m_post_processing_stages.size()) - 1);
|
||||
|
@ -1056,6 +1083,12 @@ bool VulkanHostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 t
|
|||
{
|
||||
return false;
|
||||
}
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), pps.output_texture.GetImage(),
|
||||
"Post Processing Output Texture %u", i);
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), pps.output_texture.GetDeviceMemory(),
|
||||
"Post Processing Output Texture Memory %u", i);
|
||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), pps.output_texture.GetView(),
|
||||
"Post Processing Output Texture View %u", i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1068,6 +1101,9 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
|||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
|
||||
u32 target_width, u32 target_height)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
const Vulkan::Util::DebugScope debugScope(cmdbuffer, "VulkanHostDisplay::ApplyPostProcessingChain");
|
||||
|
||||
if (!CheckPostProcessingRenderTargets(target_width, target_height))
|
||||
{
|
||||
BeginSwapChainRenderPass(target_fb, target_width, target_height);
|
||||
|
@ -1077,12 +1113,12 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
|||
}
|
||||
|
||||
// downsample/upsample - use same viewport for remainder
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
BeginSwapChainRenderPass(m_post_processing_input_framebuffer, target_width, target_height);
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, m_display_linear_filtering);
|
||||
vkCmdEndRenderPass(cmdbuffer);
|
||||
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
texture_handle = &m_post_processing_input_texture;
|
||||
|
@ -1097,6 +1133,9 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
|||
for (u32 i = 0; i < static_cast<u32>(m_post_processing_stages.size()); i++)
|
||||
{
|
||||
PostProcessingStage& pps = m_post_processing_stages[i];
|
||||
const Vulkan::Util::DebugScope debugScope(g_vulkan_context->GetCurrentCommandBuffer(), "Post Processing Stage: %s",
|
||||
m_post_processing_chain.GetShaderStage(i).GetName().c_str());
|
||||
|
||||
if (i != final_stage)
|
||||
{
|
||||
pps.output_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
@ -1163,6 +1202,7 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
|||
if (i != final_stage)
|
||||
{
|
||||
vkCmdEndRenderPass(cmdbuffer);
|
||||
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
pps.output_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
texture_handle = &pps.output_texture;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue