renderer_vulkan: Properly format structs

This commit is contained in:
GPUCode
2022-12-29 20:11:57 +02:00
parent 98e0ecf6a7
commit d3392ae0b1
19 changed files with 1492 additions and 1139 deletions

View File

@@ -118,7 +118,8 @@ void Config::ReadValues() {
static_cast<Settings::GraphicsAPI>(sdl2_config->GetInteger("Renderer", "graphics_api", 2)); static_cast<Settings::GraphicsAPI>(sdl2_config->GetInteger("Renderer", "graphics_api", 2));
Settings::values.async_command_recording = Settings::values.async_command_recording =
sdl2_config->GetBoolean("Renderer", "async_command_recording", true); sdl2_config->GetBoolean("Renderer", "async_command_recording", true);
Settings::values.spirv_shader_gen = sdl2_config->GetBoolean("Renderer", "spirv_shader_gen", true); Settings::values.spirv_shader_gen =
sdl2_config->GetBoolean("Renderer", "spirv_shader_gen", true);
Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "renderer_debug", false); Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "renderer_debug", false);
Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true); Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true);
Settings::values.use_hw_shader = sdl2_config->GetBoolean("Renderer", "use_hw_shader", true); Settings::values.use_hw_shader = sdl2_config->GetBoolean("Renderer", "use_hw_shader", true);

View File

@@ -167,7 +167,8 @@ void RendererVulkan::PrepareRendertarget() {
LCD::Read(color_fill.raw, lcd_color_addr); LCD::Read(color_fill.raw, lcd_color_addr);
if (color_fill.is_enabled) { if (color_fill.is_enabled) {
LoadColorToActiveVkTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, screen_infos[i].texture); LoadColorToActiveVkTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b,
screen_infos[i].texture);
} else { } else {
TextureInfo& texture = screen_infos[i].texture; TextureInfo& texture = screen_infos[i].texture;
if (texture.width != framebuffer.width || texture.height != framebuffer.height || if (texture.width != framebuffer.width || texture.height != framebuffer.height ||
@@ -197,7 +198,8 @@ void RendererVulkan::BeginRendering() {
present_textures[i] = vk::DescriptorImageInfo{ present_textures[i] = vk::DescriptorImageInfo{
.imageView = info.display_texture ? info.display_texture->image_view .imageView = info.display_texture ? info.display_texture->image_view
: info.texture.alloc.image_view, : info.texture.alloc.image_view,
.imageLayout = vk::ImageLayout::eGeneral}; .imageLayout = vk::ImageLayout::eGeneral,
};
} }
present_textures[3] = vk::DescriptorImageInfo{.sampler = present_samplers[current_sampler]}; present_textures[3] = vk::DescriptorImageInfo{.sampler = present_samplers[current_sampler]};
@@ -295,41 +297,53 @@ void RendererVulkan::CompileShaders() {
void RendererVulkan::BuildLayouts() { void RendererVulkan::BuildLayouts() {
const std::array present_layout_bindings = { const std::array present_layout_bindings = {
vk::DescriptorSetLayoutBinding{.binding = 0, vk::DescriptorSetLayoutBinding{
.binding = 0,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.descriptorCount = 3, .descriptorCount = 3,
.stageFlags = vk::ShaderStageFlagBits::eFragment}, .stageFlags = vk::ShaderStageFlagBits::eFragment,
vk::DescriptorSetLayoutBinding{.binding = 1, },
vk::DescriptorSetLayoutBinding{
.binding = 1,
.descriptorType = vk::DescriptorType::eSampler, .descriptorType = vk::DescriptorType::eSampler,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eFragment}}; .stageFlags = vk::ShaderStageFlagBits::eFragment,
},
};
const vk::DescriptorSetLayoutCreateInfo present_layout_info = { const vk::DescriptorSetLayoutCreateInfo present_layout_info = {
.bindingCount = static_cast<u32>(present_layout_bindings.size()), .bindingCount = static_cast<u32>(present_layout_bindings.size()),
.pBindings = present_layout_bindings.data()}; .pBindings = present_layout_bindings.data(),
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
present_descriptor_layout = device.createDescriptorSetLayout(present_layout_info); present_descriptor_layout = device.createDescriptorSetLayout(present_layout_info);
const std::array update_template_entries = { const std::array update_template_entries = {
vk::DescriptorUpdateTemplateEntry{.dstBinding = 0, vk::DescriptorUpdateTemplateEntry{
.dstBinding = 0,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 3, .descriptorCount = 3,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.offset = 0, .offset = 0,
.stride = sizeof(vk::DescriptorImageInfo)}, .stride = sizeof(vk::DescriptorImageInfo),
vk::DescriptorUpdateTemplateEntry{.dstBinding = 1, },
vk::DescriptorUpdateTemplateEntry{
.dstBinding = 1,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampler, .descriptorType = vk::DescriptorType::eSampler,
.offset = 3 * sizeof(vk::DescriptorImageInfo), .offset = 3 * sizeof(vk::DescriptorImageInfo),
.stride = 0}}; .stride = 0,
},
};
const vk::DescriptorUpdateTemplateCreateInfo template_info = { const vk::DescriptorUpdateTemplateCreateInfo template_info = {
.descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()), .descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()),
.pDescriptorUpdateEntries = update_template_entries.data(), .pDescriptorUpdateEntries = update_template_entries.data(),
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet, .templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
.descriptorSetLayout = present_descriptor_layout}; .descriptorSetLayout = present_descriptor_layout,
};
present_update_template = device.createDescriptorUpdateTemplate(template_info); present_update_template = device.createDescriptorUpdateTemplate(template_info);
@@ -339,37 +353,49 @@ void RendererVulkan::BuildLayouts() {
.size = sizeof(PresentUniformData), .size = sizeof(PresentUniformData),
}; };
const vk::PipelineLayoutCreateInfo layout_info = {.setLayoutCount = 1, const vk::PipelineLayoutCreateInfo layout_info = {
.setLayoutCount = 1,
.pSetLayouts = &present_descriptor_layout, .pSetLayouts = &present_descriptor_layout,
.pushConstantRangeCount = 1, .pushConstantRangeCount = 1,
.pPushConstantRanges = &push_range}; .pPushConstantRanges = &push_range,
};
present_pipeline_layout = device.createPipelineLayout(layout_info); present_pipeline_layout = device.createPipelineLayout(layout_info);
} }
void RendererVulkan::BuildPipelines() { void RendererVulkan::BuildPipelines() {
const vk::VertexInputBindingDescription binding = {.binding = 0, const vk::VertexInputBindingDescription binding = {
.binding = 0,
.stride = sizeof(ScreenRectVertex), .stride = sizeof(ScreenRectVertex),
.inputRate = vk::VertexInputRate::eVertex}; .inputRate = vk::VertexInputRate::eVertex,
};
const std::array attributes = { const std::array attributes = {
vk::VertexInputAttributeDescription{.location = 0, vk::VertexInputAttributeDescription{
.location = 0,
.binding = 0, .binding = 0,
.format = vk::Format::eR32G32Sfloat, .format = vk::Format::eR32G32Sfloat,
.offset = offsetof(ScreenRectVertex, position)}, .offset = offsetof(ScreenRectVertex, position),
vk::VertexInputAttributeDescription{.location = 1, },
vk::VertexInputAttributeDescription{
.location = 1,
.binding = 0, .binding = 0,
.format = vk::Format::eR32G32Sfloat, .format = vk::Format::eR32G32Sfloat,
.offset = offsetof(ScreenRectVertex, tex_coord)}}; .offset = offsetof(ScreenRectVertex, tex_coord),
},
};
const vk::PipelineVertexInputStateCreateInfo vertex_input_info = { const vk::PipelineVertexInputStateCreateInfo vertex_input_info = {
.vertexBindingDescriptionCount = 1, .vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &binding, .pVertexBindingDescriptions = &binding,
.vertexAttributeDescriptionCount = static_cast<u32>(attributes.size()), .vertexAttributeDescriptionCount = static_cast<u32>(attributes.size()),
.pVertexAttributeDescriptions = attributes.data()}; .pVertexAttributeDescriptions = attributes.data(),
};
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {
.topology = vk::PrimitiveTopology::eTriangleStrip, .primitiveRestartEnable = false}; .topology = vk::PrimitiveTopology::eTriangleStrip,
.primitiveRestartEnable = false,
};
const vk::PipelineRasterizationStateCreateInfo raster_state = { const vk::PipelineRasterizationStateCreateInfo raster_state = {
.depthClampEnable = false, .depthClampEnable = false,
@@ -377,21 +403,26 @@ void RendererVulkan::BuildPipelines() {
.cullMode = vk::CullModeFlagBits::eNone, .cullMode = vk::CullModeFlagBits::eNone,
.frontFace = vk::FrontFace::eClockwise, .frontFace = vk::FrontFace::eClockwise,
.depthBiasEnable = false, .depthBiasEnable = false,
.lineWidth = 1.0f}; .lineWidth = 1.0f,
};
const vk::PipelineMultisampleStateCreateInfo multisampling = { const vk::PipelineMultisampleStateCreateInfo multisampling = {
.rasterizationSamples = vk::SampleCountFlagBits::e1, .sampleShadingEnable = false}; .rasterizationSamples = vk::SampleCountFlagBits::e1,
.sampleShadingEnable = false,
};
const vk::PipelineColorBlendAttachmentState colorblend_attachment = { const vk::PipelineColorBlendAttachmentState colorblend_attachment = {
.blendEnable = false, .blendEnable = false,
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA}; vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
};
const vk::PipelineColorBlendStateCreateInfo color_blending = { const vk::PipelineColorBlendStateCreateInfo color_blending = {
.logicOpEnable = false, .logicOpEnable = false,
.attachmentCount = 1, .attachmentCount = 1,
.pAttachments = &colorblend_attachment, .pAttachments = &colorblend_attachment,
.blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f}}; .blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f},
};
const vk::Viewport placeholder_viewport = vk::Viewport{0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; const vk::Viewport placeholder_viewport = vk::Viewport{0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
const vk::Rect2D placeholder_scissor = vk::Rect2D{{0, 0}, {1, 1}}; const vk::Rect2D placeholder_scissor = vk::Rect2D{{0, 0}, {1, 1}};
@@ -402,27 +433,36 @@ void RendererVulkan::BuildPipelines() {
.pScissors = &placeholder_scissor, .pScissors = &placeholder_scissor,
}; };
const std::array dynamic_states = {vk::DynamicState::eViewport, vk::DynamicState::eScissor}; const std::array dynamic_states = {
vk::DynamicState::eViewport,
vk::DynamicState::eScissor,
};
const vk::PipelineDynamicStateCreateInfo dynamic_info = { const vk::PipelineDynamicStateCreateInfo dynamic_info = {
.dynamicStateCount = static_cast<u32>(dynamic_states.size()), .dynamicStateCount = static_cast<u32>(dynamic_states.size()),
.pDynamicStates = dynamic_states.data()}; .pDynamicStates = dynamic_states.data(),
};
const vk::PipelineDepthStencilStateCreateInfo depth_info = {.depthTestEnable = false, const vk::PipelineDepthStencilStateCreateInfo depth_info = {
.depthTestEnable = false,
.depthWriteEnable = false, .depthWriteEnable = false,
.depthCompareOp = .depthCompareOp = vk::CompareOp::eAlways,
vk::CompareOp::eAlways,
.depthBoundsTestEnable = false, .depthBoundsTestEnable = false,
.stencilTestEnable = false}; .stencilTestEnable = false,
};
for (u32 i = 0; i < PRESENT_PIPELINES; i++) { for (u32 i = 0; i < PRESENT_PIPELINES; i++) {
const std::array shader_stages = { const std::array shader_stages = {
vk::PipelineShaderStageCreateInfo{.stage = vk::ShaderStageFlagBits::eVertex, vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eVertex,
.module = present_vertex_shader, .module = present_vertex_shader,
.pName = "main"}, .pName = "main",
vk::PipelineShaderStageCreateInfo{.stage = vk::ShaderStageFlagBits::eFragment, },
vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eFragment,
.module = present_shaders[i], .module = present_shaders[i],
.pName = "main"}, .pName = "main",
},
}; };
const vk::GraphicsPipelineCreateInfo pipeline_info = { const vk::GraphicsPipelineCreateInfo pipeline_info = {
@@ -437,7 +477,8 @@ void RendererVulkan::BuildPipelines() {
.pColorBlendState = &color_blending, .pColorBlendState = &color_blending,
.pDynamicState = &dynamic_info, .pDynamicState = &dynamic_info,
.layout = present_pipeline_layout, .layout = present_pipeline_layout,
.renderPass = renderpass_cache.GetPresentRenderpass()}; .renderPass = renderpass_cache.GetPresentRenderpass(),
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
if (const auto result = device.createGraphicsPipeline({}, pipeline_info); if (const auto result = device.createGraphicsPipeline({}, pipeline_info);
@@ -453,67 +494,80 @@ void RendererVulkan::BuildPipelines() {
void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture, void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
const GPU::Regs::FramebufferConfig& framebuffer) { const GPU::Regs::FramebufferConfig& framebuffer) {
TextureInfo old_texture = std::move(texture); TextureInfo old_texture = std::move(texture);
texture = TextureInfo{.alloc = runtime.Allocate( texture = TextureInfo{
framebuffer.width, framebuffer.height, .alloc =
runtime.Allocate(framebuffer.width, framebuffer.height,
VideoCore::PixelFormatFromGPUPixelFormat(framebuffer.color_format), VideoCore::PixelFormatFromGPUPixelFormat(framebuffer.color_format),
VideoCore::TextureType::Texture2D), VideoCore::TextureType::Texture2D),
.width = framebuffer.width, .width = framebuffer.width,
.height = framebuffer.height, .height = framebuffer.height,
.format = framebuffer.color_format}; .format = framebuffer.color_format,
};
// Recyle the old texture after allocation to avoid having duplicates of the same allocation in // Recyle the old texture after allocation to avoid having duplicates of the same allocation in
// the recycler // the recycler
if (old_texture.width != 0 && old_texture.height != 0) { if (old_texture.width != 0 && old_texture.height != 0) {
const HostTextureTag tag = {.format = old_texture.alloc.format, const HostTextureTag tag = {
.format = old_texture.alloc.format,
.width = old_texture.width, .width = old_texture.width,
.height = old_texture.height}; .height = old_texture.height,
};
runtime.Recycle(tag, std::move(old_texture.alloc)); runtime.Recycle(tag, std::move(old_texture.alloc));
} }
} }
void RendererVulkan::LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture) { void RendererVulkan::LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color_b,
const TextureInfo& texture) {
const vk::ClearColorValue clear_color = { const vk::ClearColorValue clear_color = {
.float32 = std::array{color_r / 255.0f, color_g / 255.0f, color_b / 255.0f, 1.0f}}; .float32 =
std::array{
color_r / 255.0f,
color_g / 255.0f,
color_b / 255.0f,
1.0f,
},
};
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
scheduler.Record([image = texture.alloc.image, scheduler.Record([image = texture.alloc.image, clear_color](vk::CommandBuffer render_cmdbuf,
clear_color](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer) {
const vk::ImageSubresourceRange range = {.aspectMask = vk::ImageAspectFlagBits::eColor, const vk::ImageSubresourceRange range = {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS, .levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS}; .layerCount = VK_REMAINING_ARRAY_LAYERS,
};
const vk::ImageMemoryBarrier pre_barrier = { const vk::ImageMemoryBarrier pre_barrier = {
.srcAccessMask = vk::AccessFlagBits::eShaderRead | .srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead,
vk::AccessFlagBits::eTransferRead,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite, .dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = image,
.subresourceRange = range .subresourceRange = range,
}; };
const vk::ImageMemoryBarrier post_barrier = { const vk::ImageMemoryBarrier post_barrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead,
vk::AccessFlagBits::eTransferRead,
.oldLayout = vk::ImageLayout::eTransferDstOptimal, .oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = image,
.subresourceRange = range .subresourceRange = range,
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier);
render_cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal, clear_color, range); render_cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal, clear_color,
range);
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
@@ -873,14 +927,19 @@ void RendererVulkan::SwapBuffers() {
} while (swapchain.NeedsRecreation()); } while (swapchain.NeedsRecreation());
scheduler.Record([layout](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { scheduler.Record([layout](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::Viewport viewport = {.x = 0.0f, const vk::Viewport viewport = {
.x = 0.0f,
.y = 0.0f, .y = 0.0f,
.width = static_cast<float>(layout.width), .width = static_cast<float>(layout.width),
.height = static_cast<float>(layout.height), .height = static_cast<float>(layout.height),
.minDepth = 0.0f, .minDepth = 0.0f,
.maxDepth = 1.0f}; .maxDepth = 1.0f,
};
const vk::Rect2D scissor = {.offset = {0, 0}, .extent = {layout.width, layout.height}}; const vk::Rect2D scissor = {
.offset = {0, 0},
.extent = {layout.width, layout.height},
};
render_cmdbuf.setViewport(0, viewport); render_cmdbuf.setViewport(0, viewport);
render_cmdbuf.setScissor(0, scissor); render_cmdbuf.setScissor(0, scissor);
@@ -888,20 +947,6 @@ void RendererVulkan::SwapBuffers() {
DrawScreens(layout, false); DrawScreens(layout, false);
/*renderpass_cache.ExitRenderpass();
scheduler.Record([](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::MemoryBarrier memory_write_barrier = {
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite,
.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
};
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion,
memory_write_barrier, {}, {});
});*/
const vk::Semaphore image_acquired = swapchain.GetImageAcquiredSemaphore(); const vk::Semaphore image_acquired = swapchain.GetImageAcquiredSemaphore();
const vk::Semaphore present_ready = swapchain.GetPresentReadySemaphore(); const vk::Semaphore present_ready = swapchain.GetPresentReadySemaphore();
scheduler.Flush(present_ready, image_acquired); scheduler.Flush(present_ready, image_acquired);

View File

@@ -6,14 +6,15 @@
#include "video_core/renderer_vulkan/vk_blit_helper.h" #include "video_core/renderer_vulkan/vk_blit_helper.h"
#include "video_core/renderer_vulkan/vk_descriptor_manager.h" #include "video_core/renderer_vulkan/vk_descriptor_manager.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h" #include "video_core/renderer_vulkan/vk_texture_runtime.h"
namespace Vulkan { namespace Vulkan {
BlitHelper::BlitHelper(const Instance& instance, Scheduler& scheduler, DescriptorManager& desc_manager) BlitHelper::BlitHelper(const Instance& instance, Scheduler& scheduler,
DescriptorManager& desc_manager)
: scheduler{scheduler}, desc_manager{desc_manager}, device{instance.GetDevice()} { : scheduler{scheduler}, desc_manager{desc_manager}, device{instance.GetDevice()} {
constexpr std::string_view cs_source = R"( constexpr std::string_view cs_source = R"(
#version 450 core #version 450 core
@@ -39,50 +40,66 @@ imageStore(color, dst_coord, uvec4(value));
Compile(cs_source, vk::ShaderStageFlagBits::eCompute, device, ShaderOptimization::High); Compile(cs_source, vk::ShaderStageFlagBits::eCompute, device, ShaderOptimization::High);
const std::array compute_layout_bindings = { const std::array compute_layout_bindings = {
vk::DescriptorSetLayoutBinding{.binding = 0, vk::DescriptorSetLayoutBinding{
.binding = 0,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute}, .stageFlags = vk::ShaderStageFlagBits::eCompute,
vk::DescriptorSetLayoutBinding{.binding = 1, },
vk::DescriptorSetLayoutBinding{
.binding = 1,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute}, .stageFlags = vk::ShaderStageFlagBits::eCompute,
vk::DescriptorSetLayoutBinding{.binding = 2, },
vk::DescriptorSetLayoutBinding{
.binding = 2,
.descriptorType = vk::DescriptorType::eStorageImage, .descriptorType = vk::DescriptorType::eStorageImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute}}; .stageFlags = vk::ShaderStageFlagBits::eCompute,
},
};
const vk::DescriptorSetLayoutCreateInfo compute_layout_info = { const vk::DescriptorSetLayoutCreateInfo compute_layout_info = {
.bindingCount = static_cast<u32>(compute_layout_bindings.size()), .bindingCount = static_cast<u32>(compute_layout_bindings.size()),
.pBindings = compute_layout_bindings.data()}; .pBindings = compute_layout_bindings.data(),
};
descriptor_layout = device.createDescriptorSetLayout(compute_layout_info); descriptor_layout = device.createDescriptorSetLayout(compute_layout_info);
const std::array update_template_entries = { const std::array update_template_entries = {
vk::DescriptorUpdateTemplateEntry{.dstBinding = 0, vk::DescriptorUpdateTemplateEntry{
.dstBinding = 0,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.offset = 0, .offset = 0,
.stride = sizeof(vk::DescriptorImageInfo)}, .stride = sizeof(vk::DescriptorImageInfo),
vk::DescriptorUpdateTemplateEntry{.dstBinding = 1, },
vk::DescriptorUpdateTemplateEntry{
.dstBinding = 1,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.offset = sizeof(vk::DescriptorImageInfo), .offset = sizeof(vk::DescriptorImageInfo),
.stride = 0}, .stride = 0,
vk::DescriptorUpdateTemplateEntry{.dstBinding = 2, },
vk::DescriptorUpdateTemplateEntry{
.dstBinding = 2,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eStorageImage, .descriptorType = vk::DescriptorType::eStorageImage,
.offset = 2 * sizeof(vk::DescriptorImageInfo), .offset = 2 * sizeof(vk::DescriptorImageInfo),
.stride = 0}}; .stride = 0,
},
};
const vk::DescriptorUpdateTemplateCreateInfo template_info = { const vk::DescriptorUpdateTemplateCreateInfo template_info = {
.descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()), .descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()),
.pDescriptorUpdateEntries = update_template_entries.data(), .pDescriptorUpdateEntries = update_template_entries.data(),
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet, .templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
.descriptorSetLayout = descriptor_layout}; .descriptorSetLayout = descriptor_layout,
};
update_template = device.createDescriptorUpdateTemplate(template_info); update_template = device.createDescriptorUpdateTemplate(template_info);
@@ -92,18 +109,25 @@ imageStore(color, dst_coord, uvec4(value));
.size = sizeof(Common::Vec2i), .size = sizeof(Common::Vec2i),
}; };
const vk::PipelineLayoutCreateInfo layout_info = {.setLayoutCount = 1, const vk::PipelineLayoutCreateInfo layout_info = {
.setLayoutCount = 1,
.pSetLayouts = &descriptor_layout, .pSetLayouts = &descriptor_layout,
.pushConstantRangeCount = 1, .pushConstantRangeCount = 1,
.pPushConstantRanges = &push_range}; .pPushConstantRanges = &push_range,
};
compute_pipeline_layout = device.createPipelineLayout(layout_info); compute_pipeline_layout = device.createPipelineLayout(layout_info);
const vk::PipelineShaderStageCreateInfo compute_stage = { const vk::PipelineShaderStageCreateInfo compute_stage = {
.stage = vk::ShaderStageFlagBits::eCompute, .module = compute_shader, .pName = "main"}; .stage = vk::ShaderStageFlagBits::eCompute,
.module = compute_shader,
.pName = "main",
};
const vk::ComputePipelineCreateInfo compute_info = {.stage = compute_stage, const vk::ComputePipelineCreateInfo compute_info = {
.layout = compute_pipeline_layout}; .stage = compute_stage,
.layout = compute_pipeline_layout,
};
if (const auto result = device.createComputePipeline({}, compute_info); if (const auto result = device.createComputePipeline({}, compute_info);
result.result == vk::Result::eSuccess) { result.result == vk::Result::eSuccess) {
@@ -125,19 +149,26 @@ BlitHelper::~BlitHelper() {
void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest, void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest,
const VideoCore::TextureBlit& blit) { const VideoCore::TextureBlit& blit) {
const std::array textures = { const std::array textures = {
vk::DescriptorImageInfo{.imageView = source.GetDepthView(), vk::DescriptorImageInfo{
.imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal}, .imageView = source.GetDepthView(),
vk::DescriptorImageInfo{.imageView = source.GetStencilView(), .imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal,
.imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal}, },
vk::DescriptorImageInfo{.imageView = dest.GetImageView(), vk::DescriptorImageInfo{
.imageLayout = vk::ImageLayout::eGeneral}}; .imageView = source.GetStencilView(),
.imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal,
},
vk::DescriptorImageInfo{
.imageView = dest.GetImageView(),
.imageLayout = vk::ImageLayout::eGeneral,
},
};
vk::DescriptorSet set = desc_manager.AllocateSet(descriptor_layout); vk::DescriptorSet set = desc_manager.AllocateSet(descriptor_layout);
device.updateDescriptorSetWithTemplate(set, update_template, textures[0]); device.updateDescriptorSetWithTemplate(set, update_template, textures[0]);
scheduler.Record([this, set, blit, scheduler.Record([this, set, blit, src_image = source.alloc.image,
src_image = source.alloc.image, dst_image = dest.alloc.image](vk::CommandBuffer render_cmdbuf,
dst_image = dest.alloc.image](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer) {
const std::array pre_barriers = { const std::array pre_barriers = {
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | .srcAccessMask = vk::AccessFlagBits::eShaderWrite |
@@ -150,8 +181,8 @@ void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = src_image, .image = src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eDepth | .aspectMask =
vk::ImageAspectFlagBits::eStencil, vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS, .levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@@ -173,8 +204,7 @@ void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
}, },
} }};
};
const std::array post_barriers = { const std::array post_barriers = {
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eShaderRead, .srcAccessMask = vk::AccessFlagBits::eShaderRead,
@@ -186,8 +216,8 @@ void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = src_image, .image = src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eDepth | .aspectMask =
vk::ImageAspectFlagBits::eStencil, vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS, .levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@@ -209,13 +239,13 @@ void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
}, },
} }};
};
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers); vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers);
render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout, 0, set, {}); render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout,
0, set, {});
render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline); render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline);
const auto src_offset = Common::MakeVec(blit.src_rect.left, blit.src_rect.bottom); const auto src_offset = Common::MakeVec(blit.src_rect.left, blit.src_rect.bottom);

View File

@@ -15,26 +15,57 @@ struct Bindings {
}; };
constexpr static std::array RASTERIZER_SETS = { constexpr static std::array RASTERIZER_SETS = {
Bindings{// Utility set Bindings{
.bindings = {vk::DescriptorType::eUniformBuffer, vk::DescriptorType::eUniformBuffer, // Utility set
.bindings =
{
vk::DescriptorType::eUniformBuffer,
vk::DescriptorType::eUniformBuffer,
vk::DescriptorType::eUniformTexelBuffer, vk::DescriptorType::eUniformTexelBuffer,
vk::DescriptorType::eUniformTexelBuffer, vk::DescriptorType::eUniformTexelBuffer,
vk::DescriptorType::eUniformTexelBuffer}, vk::DescriptorType::eUniformTexelBuffer,
.binding_count = 5}, },
Bindings{// Texture set .binding_count = 5,
.bindings = {vk::DescriptorType::eSampledImage, vk::DescriptorType::eSampledImage, },
vk::DescriptorType::eSampledImage, vk::DescriptorType::eSampledImage}, Bindings{
.binding_count = 4}, // Texture set
Bindings{// Sampler set .bindings =
.bindings = {vk::DescriptorType::eSampler, vk::DescriptorType::eSampler, {
vk::DescriptorType::eSampler, vk::DescriptorType::eSampler}, vk::DescriptorType::eSampledImage,
.binding_count = 4}, vk::DescriptorType::eSampledImage,
Bindings{// Shadow set vk::DescriptorType::eSampledImage,
.bindings = {vk::DescriptorType::eStorageImage, vk::DescriptorType::eStorageImage, vk::DescriptorType::eSampledImage,
vk::DescriptorType::eStorageImage, vk::DescriptorType::eStorageImage, },
vk::DescriptorType::eStorageImage, vk::DescriptorType::eStorageImage, .binding_count = 4,
vk::DescriptorType::eStorageImage}, },
.binding_count = 4}}; Bindings{
// Sampler set
.bindings =
{
vk::DescriptorType::eSampler,
vk::DescriptorType::eSampler,
vk::DescriptorType::eSampler,
vk::DescriptorType::eSampler,
},
.binding_count = 4,
},
Bindings{
// Shadow set
.bindings =
{
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
},
.binding_count = 4, // TODO: Combine cube faces to a single storage image
// some android devices only expose up to four storage
// slots per pipeline
},
};
constexpr vk::ShaderStageFlags ToVkStageFlags(vk::DescriptorType type) { constexpr vk::ShaderStageFlags ToVkStageFlags(vk::DescriptorType type) {
vk::ShaderStageFlags flags; vk::ShaderStageFlags flags;
@@ -66,7 +97,7 @@ DescriptorManager::DescriptorManager(const Instance& instance, Scheduler& schedu
} }
DescriptorManager::~DescriptorManager() { DescriptorManager::~DescriptorManager() {
vk::Device device = instance.GetDevice(); const vk::Device device = instance.GetDevice();
device.destroyPipelineLayout(pipeline_layout); device.destroyPipelineLayout(pipeline_layout);
for (u32 i = 0; i < MAX_DESCRIPTOR_SETS; i++) { for (u32 i = 0; i < MAX_DESCRIPTOR_SETS; i++) {
@@ -89,7 +120,7 @@ void DescriptorManager::BindDescriptorSets() {
descriptor_set_dirty.fill(true); descriptor_set_dirty.fill(true);
} }
vk::Device device = instance.GetDevice(); const vk::Device device = instance.GetDevice();
std::array<vk::DescriptorSet, MAX_DESCRIPTOR_SETS> bound_sets; std::array<vk::DescriptorSet, MAX_DESCRIPTOR_SETS> bound_sets;
for (u32 i = 0; i < MAX_DESCRIPTOR_SETS; i++) { for (u32 i = 0; i < MAX_DESCRIPTOR_SETS; i++) {
if (descriptor_set_dirty[i]) { if (descriptor_set_dirty[i]) {
@@ -116,51 +147,59 @@ void DescriptorManager::BuildLayouts() {
std::array<vk::DescriptorSetLayoutBinding, MAX_DESCRIPTORS> set_bindings; std::array<vk::DescriptorSetLayoutBinding, MAX_DESCRIPTORS> set_bindings;
std::array<vk::DescriptorUpdateTemplateEntry, MAX_DESCRIPTORS> update_entries; std::array<vk::DescriptorUpdateTemplateEntry, MAX_DESCRIPTORS> update_entries;
vk::Device device = instance.GetDevice(); const vk::Device device = instance.GetDevice();
for (u32 i = 0; i < MAX_DESCRIPTOR_SETS; i++) { for (u32 i = 0; i < MAX_DESCRIPTOR_SETS; i++) {
const auto& set = RASTERIZER_SETS[i]; const auto& set = RASTERIZER_SETS[i];
for (u32 j = 0; j < set.binding_count; j++) { for (u32 j = 0; j < set.binding_count; j++) {
vk::DescriptorType type = set.bindings[j]; const vk::DescriptorType type = set.bindings[j];
set_bindings[j] = vk::DescriptorSetLayoutBinding{.binding = j, set_bindings[j] = vk::DescriptorSetLayoutBinding{
.binding = j,
.descriptorType = type, .descriptorType = type,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = ToVkStageFlags(type)}; .stageFlags = ToVkStageFlags(type),
};
update_entries[j] = update_entries[j] = vk::DescriptorUpdateTemplateEntry{
vk::DescriptorUpdateTemplateEntry{.dstBinding = j, .dstBinding = j,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = type, .descriptorType = type,
.offset = j * sizeof(DescriptorData), .offset = j * sizeof(DescriptorData),
.stride = 0}; .stride = 0,
};
} }
const vk::DescriptorSetLayoutCreateInfo layout_info = {.bindingCount = set.binding_count, const vk::DescriptorSetLayoutCreateInfo layout_info = {
.pBindings = set_bindings.data()}; .bindingCount = set.binding_count,
.pBindings = set_bindings.data(),
};
descriptor_set_layouts[i] = device.createDescriptorSetLayout(layout_info); descriptor_set_layouts[i] = device.createDescriptorSetLayout(layout_info);
const vk::DescriptorUpdateTemplateCreateInfo template_info = { const vk::DescriptorUpdateTemplateCreateInfo template_info = {
.descriptorUpdateEntryCount = set.binding_count, .descriptorUpdateEntryCount = set.binding_count,
.pDescriptorUpdateEntries = update_entries.data(), .pDescriptorUpdateEntries = update_entries.data(),
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet, .templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
.descriptorSetLayout = descriptor_set_layouts[i]}; .descriptorSetLayout = descriptor_set_layouts[i],
};
update_templates[i] = device.createDescriptorUpdateTemplate(template_info); update_templates[i] = device.createDescriptorUpdateTemplate(template_info);
} }
const vk::PipelineLayoutCreateInfo layout_info = {.setLayoutCount = MAX_DESCRIPTOR_SETS, const vk::PipelineLayoutCreateInfo layout_info = {
.setLayoutCount = MAX_DESCRIPTOR_SETS,
.pSetLayouts = descriptor_set_layouts.data(), .pSetLayouts = descriptor_set_layouts.data(),
.pushConstantRangeCount = 0, .pushConstantRangeCount = 0,
.pPushConstantRanges = nullptr}; .pPushConstantRanges = nullptr,
};
pipeline_layout = device.createPipelineLayout(layout_info); pipeline_layout = device.createPipelineLayout(layout_info);
} }
vk::DescriptorSet DescriptorManager::AllocateSet(vk::DescriptorSetLayout layout) { vk::DescriptorSet DescriptorManager::AllocateSet(vk::DescriptorSetLayout layout) {
vk::Device device = instance.GetDevice(); const vk::Device device = instance.GetDevice();
const vk::DescriptorSetAllocateInfo alloc_info = { const vk::DescriptorSetAllocateInfo alloc_info = {
.descriptorPool = current_pool, .descriptorSetCount = 1, .pSetLayouts = &layout}; .descriptorPool = current_pool,
.descriptorSetCount = 1,
.pSetLayouts = &layout,
};
try { try {
return device.allocateDescriptorSets(alloc_info)[0]; return device.allocateDescriptorSets(alloc_info)[0];

View File

@@ -4,16 +4,17 @@
#include "video_core/renderer_vulkan/vk_descriptor_manager.h" #include "video_core/renderer_vulkan/vk_descriptor_manager.h"
#include "video_core/renderer_vulkan/vk_format_reinterpreter.h" #include "video_core/renderer_vulkan/vk_format_reinterpreter.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h" #include "video_core/renderer_vulkan/vk_texture_runtime.h"
namespace Vulkan { namespace Vulkan {
D24S8toRGBA8::D24S8toRGBA8(const Instance& instance, Scheduler& scheduler, D24S8toRGBA8::D24S8toRGBA8(const Instance& instance, Scheduler& scheduler,
DescriptorManager& desc_manager, TextureRuntime& runtime) DescriptorManager& desc_manager, TextureRuntime& runtime)
: FormatReinterpreterBase{instance, scheduler, desc_manager, runtime}, device{instance.GetDevice()} { : FormatReinterpreterBase{instance, scheduler, desc_manager, runtime},
device{instance.GetDevice()} {
constexpr std::string_view cs_source = R"( constexpr std::string_view cs_source = R"(
#version 450 core #version 450 core
#extension GL_EXT_samplerless_texture_functions : require #extension GL_EXT_samplerless_texture_functions : require
@@ -38,50 +39,64 @@ imageStore(color, tex_coord, vec4(components) / (exp2(8.0) - 1.0));
Compile(cs_source, vk::ShaderStageFlagBits::eCompute, device, ShaderOptimization::High); Compile(cs_source, vk::ShaderStageFlagBits::eCompute, device, ShaderOptimization::High);
const std::array compute_layout_bindings = { const std::array compute_layout_bindings = {
vk::DescriptorSetLayoutBinding{.binding = 0, vk::DescriptorSetLayoutBinding{
.binding = 0,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute}, .stageFlags = vk::ShaderStageFlagBits::eCompute,
vk::DescriptorSetLayoutBinding{.binding = 1, },
vk::DescriptorSetLayoutBinding{
.binding = 1,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute}, .stageFlags = vk::ShaderStageFlagBits::eCompute,
vk::DescriptorSetLayoutBinding{.binding = 2, },
vk::DescriptorSetLayoutBinding{
.binding = 2,
.descriptorType = vk::DescriptorType::eStorageImage, .descriptorType = vk::DescriptorType::eStorageImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute}}; .stageFlags = vk::ShaderStageFlagBits::eCompute,
},
};
const vk::DescriptorSetLayoutCreateInfo compute_layout_info = { const vk::DescriptorSetLayoutCreateInfo compute_layout_info = {
.bindingCount = static_cast<u32>(compute_layout_bindings.size()), .bindingCount = static_cast<u32>(compute_layout_bindings.size()),
.pBindings = compute_layout_bindings.data()}; .pBindings = compute_layout_bindings.data(),
};
descriptor_layout = device.createDescriptorSetLayout(compute_layout_info); descriptor_layout = device.createDescriptorSetLayout(compute_layout_info);
const std::array update_template_entries = { const std::array update_template_entries = {
vk::DescriptorUpdateTemplateEntry{.dstBinding = 0, vk::DescriptorUpdateTemplateEntry{
.dstBinding = 0,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.offset = 0, .offset = 0,
.stride = sizeof(vk::DescriptorImageInfo)}, .stride = sizeof(vk::DescriptorImageInfo),
vk::DescriptorUpdateTemplateEntry{.dstBinding = 1, },
vk::DescriptorUpdateTemplateEntry{
.dstBinding = 1,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.offset = sizeof(vk::DescriptorImageInfo), .offset = sizeof(vk::DescriptorImageInfo),
.stride = 0}, },
vk::DescriptorUpdateTemplateEntry{.dstBinding = 2, vk::DescriptorUpdateTemplateEntry{
.dstBinding = 2,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eStorageImage, .descriptorType = vk::DescriptorType::eStorageImage,
.offset = 2 * sizeof(vk::DescriptorImageInfo), .offset = 2 * sizeof(vk::DescriptorImageInfo),
.stride = 0}}; },
};
const vk::DescriptorUpdateTemplateCreateInfo template_info = { const vk::DescriptorUpdateTemplateCreateInfo template_info = {
.descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()), .descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()),
.pDescriptorUpdateEntries = update_template_entries.data(), .pDescriptorUpdateEntries = update_template_entries.data(),
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet, .templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
.descriptorSetLayout = descriptor_layout}; .descriptorSetLayout = descriptor_layout,
};
update_template = device.createDescriptorUpdateTemplate(template_info); update_template = device.createDescriptorUpdateTemplate(template_info);
@@ -91,18 +106,25 @@ imageStore(color, tex_coord, vec4(components) / (exp2(8.0) - 1.0));
.size = sizeof(Common::Vec2i), .size = sizeof(Common::Vec2i),
}; };
const vk::PipelineLayoutCreateInfo layout_info = {.setLayoutCount = 1, const vk::PipelineLayoutCreateInfo layout_info = {
.setLayoutCount = 1,
.pSetLayouts = &descriptor_layout, .pSetLayouts = &descriptor_layout,
.pushConstantRangeCount = 1, .pushConstantRangeCount = 1,
.pPushConstantRanges = &push_range}; .pPushConstantRanges = &push_range,
};
compute_pipeline_layout = device.createPipelineLayout(layout_info); compute_pipeline_layout = device.createPipelineLayout(layout_info);
const vk::PipelineShaderStageCreateInfo compute_stage = { const vk::PipelineShaderStageCreateInfo compute_stage = {
.stage = vk::ShaderStageFlagBits::eCompute, .module = compute_shader, .pName = "main"}; .stage = vk::ShaderStageFlagBits::eCompute,
.module = compute_shader,
.pName = "main",
};
const vk::ComputePipelineCreateInfo compute_info = {.stage = compute_stage, const vk::ComputePipelineCreateInfo compute_info = {
.layout = compute_pipeline_layout}; .stage = compute_stage,
.layout = compute_pipeline_layout,
};
if (const auto result = device.createComputePipeline({}, compute_info); if (const auto result = device.createComputePipeline({}, compute_info);
result.result == vk::Result::eSuccess) { result.result == vk::Result::eSuccess) {
@@ -124,20 +146,27 @@ D24S8toRGBA8::~D24S8toRGBA8() {
void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surface& dest, void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surface& dest,
VideoCore::Rect2D dst_rect) { VideoCore::Rect2D dst_rect) {
const std::array textures = { const std::array textures = {
vk::DescriptorImageInfo{.imageView = source.GetDepthView(), vk::DescriptorImageInfo{
.imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal}, .imageView = source.GetDepthView(),
vk::DescriptorImageInfo{.imageView = source.GetStencilView(), .imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal,
.imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal}, },
vk::DescriptorImageInfo{.imageView = dest.GetImageView(), vk::DescriptorImageInfo{
.imageLayout = vk::ImageLayout::eGeneral}}; .imageView = source.GetStencilView(),
.imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal,
},
vk::DescriptorImageInfo{
.imageView = dest.GetImageView(),
.imageLayout = vk::ImageLayout::eGeneral,
},
};
vk::DescriptorSet set = desc_manager.AllocateSet(descriptor_layout); vk::DescriptorSet set = desc_manager.AllocateSet(descriptor_layout);
device.updateDescriptorSetWithTemplate(set, update_template, textures[0]); device.updateDescriptorSetWithTemplate(set, update_template, textures[0]);
runtime.GetRenderpassCache().ExitRenderpass(); runtime.GetRenderpassCache().ExitRenderpass();
scheduler.Record([this, set, src_rect, scheduler.Record([this, set, src_rect, src_image = source.alloc.image,
src_image = source.alloc.image, dst_image = dest.alloc.image](vk::CommandBuffer render_cmdbuf,
dst_image = dest.alloc.image](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer) {
const vk::ImageMemoryBarrier pre_barrier = { const vk::ImageMemoryBarrier pre_barrier = {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | .srcAccessMask = vk::AccessFlagBits::eShaderWrite |
vk::AccessFlagBits::eDepthStencilAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite |
@@ -149,8 +178,7 @@ void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surf
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = src_image, .image = src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eDepth | .aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
vk::ImageAspectFlagBits::eStencil,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS, .levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@@ -168,8 +196,8 @@ void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surf
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = src_image, .image = src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eDepth | .aspectMask =
vk::ImageAspectFlagBits::eStencil, vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS, .levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@@ -191,13 +219,14 @@ void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surf
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
}, },
} }};
};
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier);
render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout, 0, set, {}); render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout,
0, set, {});
render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline); render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline);
const auto src_offset = Common::MakeVec(src_rect.left, src_rect.bottom); const auto src_offset = Common::MakeVec(src_rect.left, src_rect.bottom);

View File

@@ -76,7 +76,8 @@ vk::Format ToVkFormat(VideoCore::PixelFormat format) {
} }
[[nodiscard]] vk::DebugUtilsMessengerCreateInfoEXT MakeDebugUtilsMessengerInfo() { [[nodiscard]] vk::DebugUtilsMessengerCreateInfoEXT MakeDebugUtilsMessengerInfo() {
return {.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo | return vk::DebugUtilsMessengerCreateInfoEXT{
.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose, vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose,
@@ -84,7 +85,8 @@ vk::Format ToVkFormat(VideoCore::PixelFormat format) {
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::eDeviceAddressBinding | vk::DebugUtilsMessageTypeFlagBitsEXT::eDeviceAddressBinding |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance, vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
.pfnUserCallback = DebugHandler}; .pfnUserCallback = DebugHandler,
};
} }
std::vector<std::string> GetSupportedExtensions(vk::PhysicalDevice physical) { std::vector<std::string> GetSupportedExtensions(vk::PhysicalDevice physical) {
@@ -99,7 +101,6 @@ std::vector<std::string> GetSupportedExtensions(vk::PhysicalDevice physical) {
Instance::Instance(bool validation, bool dump_command_buffers) Instance::Instance(bool validation, bool dump_command_buffers)
: enable_validation{validation}, dump_command_buffers{dump_command_buffers} { : enable_validation{validation}, dump_command_buffers{dump_command_buffers} {
// Fetch instance independant function pointers
auto vkGetInstanceProcAddr = auto vkGetInstanceProcAddr =
dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
@@ -110,19 +111,16 @@ Instance::Instance(bool validation, bool dump_command_buffers)
// Use required platform-specific flags // Use required platform-specific flags
auto flags = GetInstanceFlags(); auto flags = GetInstanceFlags();
const vk::ApplicationInfo application_info = {.pApplicationName = "Citra", const vk::ApplicationInfo application_info = {
.pApplicationName = "Citra",
.applicationVersion = VK_MAKE_VERSION(1, 0, 0), .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "Citra Vulkan", .pEngineName = "Citra Vulkan",
.engineVersion = VK_MAKE_VERSION(1, 0, 0), .engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = VK_API_VERSION_1_0}; .apiVersion = VK_API_VERSION_1_0,
};
std::array<const char*, 3> layers; std::array<const char*, 2> layers;
#ifdef ANDROID
u32 layer_count = 1;
layers[0] = "VK_LAYER_KHRONOS_timeline_semaphore";
#else
u32 layer_count = 0; u32 layer_count = 0;
#endif
if (enable_validation) { if (enable_validation) {
layers[layer_count++] = "VK_LAYER_KHRONOS_validation"; layers[layer_count++] = "VK_LAYER_KHRONOS_validation";
@@ -132,13 +130,15 @@ Instance::Instance(bool validation, bool dump_command_buffers)
} }
const vk::StructureChain instance_chain = { const vk::StructureChain instance_chain = {
vk::InstanceCreateInfo{.flags = flags, vk::InstanceCreateInfo{
.flags = flags,
.pApplicationInfo = &application_info, .pApplicationInfo = &application_info,
.enabledLayerCount = layer_count, .enabledLayerCount = layer_count,
.ppEnabledLayerNames = layers.data(), .ppEnabledLayerNames = layers.data(),
.enabledExtensionCount = static_cast<u32>(extensions.size()), .enabledExtensionCount = static_cast<u32>(extensions.size()),
.ppEnabledExtensionNames = extensions.data()}, .ppEnabledExtensionNames = extensions.data(),
MakeDebugUtilsMessengerInfo()}; },
};
instance = vk::createInstance(instance_chain.get()); instance = vk::createInstance(instance_chain.get());
@@ -156,7 +156,7 @@ Instance::Instance(bool validation, bool dump_command_buffers)
Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index) Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
: enable_validation{Settings::values.renderer_debug}, : enable_validation{Settings::values.renderer_debug},
dump_command_buffers{Settings::values.dump_command_buffers} { dump_command_buffers{Settings::values.dump_command_buffers} {
auto window_info = window.GetWindowInfo(); const Frontend::EmuWindow::WindowSystemInfo window_info = window.GetWindowInfo();
// Fetch instance independant function pointers // Fetch instance independant function pointers
auto vkGetInstanceProcAddr = auto vkGetInstanceProcAddr =
@@ -176,11 +176,13 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
return; return;
} }
const vk::ApplicationInfo application_info = {.pApplicationName = "Citra", const vk::ApplicationInfo application_info = {
.pApplicationName = "Citra",
.applicationVersion = VK_MAKE_VERSION(1, 0, 0), .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "Citra Vulkan", .pEngineName = "Citra Vulkan",
.engineVersion = VK_MAKE_VERSION(1, 0, 0), .engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = available_version}; .apiVersion = available_version,
};
std::array<const char*, 3> layers; std::array<const char*, 3> layers;
#ifdef ANDROID #ifdef ANDROID
@@ -198,13 +200,16 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
} }
const vk::StructureChain instance_chain = { const vk::StructureChain instance_chain = {
vk::InstanceCreateInfo{.flags = flags, vk::InstanceCreateInfo{
.flags = flags,
.pApplicationInfo = &application_info, .pApplicationInfo = &application_info,
.enabledLayerCount = layer_count, .enabledLayerCount = layer_count,
.ppEnabledLayerNames = layers.data(), .ppEnabledLayerNames = layers.data(),
.enabledExtensionCount = static_cast<u32>(extensions.size()), .enabledExtensionCount = static_cast<u32>(extensions.size()),
.ppEnabledExtensionNames = extensions.data()}, .ppEnabledExtensionNames = extensions.data(),
MakeDebugUtilsMessengerInfo()}; },
MakeDebugUtilsMessengerInfo(),
};
try { try {
instance = vk::createInstance(instance_chain.get()); instance = vk::createInstance(instance_chain.get());
@@ -335,13 +340,15 @@ void Instance::CreateFormatTable() {
} }
const u32 index = static_cast<u32>(pixel_format); const u32 index = static_cast<u32>(pixel_format);
format_table[index] = FormatTraits{.transfer_support = supports_transfer, format_table[index] = FormatTraits{
.transfer_support = supports_transfer,
.blit_support = supports_blit, .blit_support = supports_blit,
.attachment_support = supports_attachment, .attachment_support = supports_attachment,
.storage_support = supports_storage, .storage_support = supports_storage,
.usage = best_usage, .usage = best_usage,
.native = format, .native = format,
.fallback = fallback}; .fallback = fallback,
};
} }
} }
@@ -431,12 +438,17 @@ bool Instance::CreateDevice() {
static constexpr float queue_priorities[] = {1.0f}; static constexpr float queue_priorities[] = {1.0f};
const std::array queue_infos = { const std::array queue_infos = {
vk::DeviceQueueCreateInfo{.queueFamilyIndex = graphics_queue_family_index, vk::DeviceQueueCreateInfo{
.queueFamilyIndex = graphics_queue_family_index,
.queueCount = 1, .queueCount = 1,
.pQueuePriorities = queue_priorities}, .pQueuePriorities = queue_priorities,
vk::DeviceQueueCreateInfo{.queueFamilyIndex = present_queue_family_index, },
vk::DeviceQueueCreateInfo{
.queueFamilyIndex = present_queue_family_index,
.queueCount = 1, .queueCount = 1,
.pQueuePriorities = queue_priorities}}; .pQueuePriorities = queue_priorities,
},
};
const u32 queue_count = graphics_queue_family_index != present_queue_family_index ? 2u : 1u; const u32 queue_count = graphics_queue_family_index != present_queue_family_index ? 2u : 1u;
const vk::StructureChain device_chain = { const vk::StructureChain device_chain = {
@@ -447,7 +459,9 @@ bool Instance::CreateDevice() {
.ppEnabledExtensionNames = enabled_extensions.data(), .ppEnabledExtensionNames = enabled_extensions.data(),
}, },
vk::PhysicalDeviceFeatures2{ vk::PhysicalDeviceFeatures2{
.features = {.robustBufferAccess = features.robustBufferAccess, .features =
{
.robustBufferAccess = features.robustBufferAccess,
.geometryShader = features.geometryShader, .geometryShader = features.geometryShader,
.dualSrcBlend = features.dualSrcBlend, .dualSrcBlend = features.dualSrcBlend,
.logicOp = features.logicOp, .logicOp = features.logicOp,
@@ -456,14 +470,14 @@ bool Instance::CreateDevice() {
.samplerAnisotropy = features.samplerAnisotropy, .samplerAnisotropy = features.samplerAnisotropy,
.fragmentStoresAndAtomics = features.fragmentStoresAndAtomics, .fragmentStoresAndAtomics = features.fragmentStoresAndAtomics,
.shaderStorageImageMultisample = features.shaderStorageImageMultisample, .shaderStorageImageMultisample = features.shaderStorageImageMultisample,
.shaderClipDistance = features.shaderClipDistance}}, .shaderClipDistance = features.shaderClipDistance,
},
},
feature_chain.get<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>(), feature_chain.get<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>(),
feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(), feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(),
feature_chain.get<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>(), feature_chain.get<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>(),
feature_chain.get<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>() feature_chain.get<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>()};
};
// Create logical device
try { try {
device = physical_device.createDevice(device_chain.get()); device = physical_device.createDevice(device_chain.get());
} catch (vk::ExtensionNotPresentError& err) { } catch (vk::ExtensionNotPresentError& err) {
@@ -484,13 +498,16 @@ bool Instance::CreateDevice() {
void Instance::CreateAllocator() { void Instance::CreateAllocator() {
const VmaVulkanFunctions functions = { const VmaVulkanFunctions functions = {
.vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr, .vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr,
.vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr}; .vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr,
};
const VmaAllocatorCreateInfo allocator_info = {.physicalDevice = physical_device, const VmaAllocatorCreateInfo allocator_info = {
.physicalDevice = physical_device,
.device = device, .device = device,
.pVulkanFunctions = &functions, .pVulkanFunctions = &functions,
.instance = instance, .instance = instance,
.vulkanApiVersion = VK_API_VERSION_1_1}; .vulkanApiVersion = VK_API_VERSION_1_1,
};
if (VkResult result = vmaCreateAllocator(&allocator_info, &allocator); result != VK_SUCCESS) { if (VkResult result = vmaCreateAllocator(&allocator_info, &allocator); result != VK_SUCCESS) {
LOG_CRITICAL(Render_Vulkan, "Failed to initialize VMA with error {}", result); LOG_CRITICAL(Render_Vulkan, "Failed to initialize VMA with error {}", result);

View File

@@ -7,12 +7,13 @@
namespace Vulkan { namespace Vulkan {
MasterSemaphore::MasterSemaphore(const Instance& instance) : device{instance.GetDevice()} { MasterSemaphore::MasterSemaphore(const Instance& instance) : device{instance.GetDevice()} {
const vk::StructureChain semaphore_chain = {vk::SemaphoreCreateInfo{}, const vk::StructureChain semaphore_chain = {
vk::SemaphoreCreateInfo{},
vk::SemaphoreTypeCreateInfoKHR{ vk::SemaphoreTypeCreateInfoKHR{
.semaphoreType = vk::SemaphoreType::eTimeline, .semaphoreType = vk::SemaphoreType::eTimeline,
.initialValue = 0, .initialValue = 0,
}}; },
};
semaphore = device.createSemaphore(semaphore_chain.get()); semaphore = device.createSemaphore(semaphore_chain.get());
} }

View File

@@ -4,10 +4,10 @@
#pragma once #pragma once
#include <atomic> #include <atomic>
#include <limits>
#include <deque> #include <deque>
#include <vector> #include <limits>
#include <thread> #include <thread>
#include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_common.h" #include "video_core/renderer_vulkan/vk_common.h"

View File

@@ -32,15 +32,32 @@ u32 AttribBytes(Pica::PipelineRegs::VertexAttributeFormat format, u32 size) {
} }
vk::Format ToVkAttributeFormat(Pica::PipelineRegs::VertexAttributeFormat format, u32 size) { vk::Format ToVkAttributeFormat(Pica::PipelineRegs::VertexAttributeFormat format, u32 size) {
constexpr std::array attribute_formats = { static constexpr std::array attribute_formats = {
std::array{vk::Format::eR8Sint, vk::Format::eR8G8Sint, vk::Format::eR8G8B8Sint, std::array{
vk::Format::eR8G8B8A8Sint}, vk::Format::eR8Sint,
std::array{vk::Format::eR8Uint, vk::Format::eR8G8Uint, vk::Format::eR8G8B8Uint, vk::Format::eR8G8Sint,
vk::Format::eR8G8B8A8Uint}, vk::Format::eR8G8B8Sint,
std::array{vk::Format::eR16Sint, vk::Format::eR16G16Sint, vk::Format::eR16G16B16Sint, vk::Format::eR8G8B8A8Sint,
vk::Format::eR16G16B16A16Sint}, },
std::array{vk::Format::eR32Sfloat, vk::Format::eR32G32Sfloat, vk::Format::eR32G32B32Sfloat, std::array{
vk::Format::eR32G32B32A32Sfloat}}; vk::Format::eR8Uint,
vk::Format::eR8G8Uint,
vk::Format::eR8G8B8Uint,
vk::Format::eR8G8B8A8Uint,
},
std::array{
vk::Format::eR16Sint,
vk::Format::eR16G16Sint,
vk::Format::eR16G16B16Sint,
vk::Format::eR16G16B16A16Sint,
},
std::array{
vk::Format::eR32Sfloat,
vk::Format::eR32G32Sfloat,
vk::Format::eR32G32B32Sfloat,
vk::Format::eR32G32B32A32Sfloat,
},
};
ASSERT(size <= 4); ASSERT(size <= 4);
return attribute_formats[static_cast<u32>(format)][size - 1]; return attribute_formats[static_cast<u32>(format)][size - 1];
@@ -126,7 +143,10 @@ void PipelineCache::LoadDiskCache() {
const std::string cache_file_path = fmt::format("{}{:x}{:x}.bin", GetPipelineCacheDir(), const std::string cache_file_path = fmt::format("{}{:x}{:x}.bin", GetPipelineCacheDir(),
instance.GetVendorID(), instance.GetDeviceID()); instance.GetVendorID(), instance.GetDeviceID());
vk::PipelineCacheCreateInfo cache_info = {.initialDataSize = 0, .pInitialData = nullptr}; vk::PipelineCacheCreateInfo cache_info = {
.initialDataSize = 0,
.pInitialData = nullptr,
};
std::vector<u8> cache_data; std::vector<u8> cache_data;
FileUtil::IOFile cache_file{cache_file_path, "r"}; FileUtil::IOFile cache_file{cache_file_path, "r"};
@@ -289,29 +309,46 @@ void PipelineCache::UseFragmentShader(const Pica::Regs& regs) {
void PipelineCache::BindTexture(u32 binding, vk::ImageView image_view) { void PipelineCache::BindTexture(u32 binding, vk::ImageView image_view) {
const vk::DescriptorImageInfo image_info = { const vk::DescriptorImageInfo image_info = {
.imageView = image_view, .imageLayout = vk::ImageLayout::eGeneral}; .imageView = image_view,
.imageLayout = vk::ImageLayout::eGeneral,
};
desc_manager.SetBinding(1, binding, DescriptorData{image_info}); desc_manager.SetBinding(1, binding, DescriptorData{image_info});
} }
void PipelineCache::BindStorageImage(u32 binding, vk::ImageView image_view) { void PipelineCache::BindStorageImage(u32 binding, vk::ImageView image_view) {
const vk::DescriptorImageInfo image_info = {.imageView = image_view, const vk::DescriptorImageInfo image_info = {
.imageLayout = vk::ImageLayout::eGeneral}; .imageView = image_view,
.imageLayout = vk::ImageLayout::eGeneral,
};
desc_manager.SetBinding(3, binding, DescriptorData{image_info}); desc_manager.SetBinding(3, binding, DescriptorData{image_info});
} }
void PipelineCache::BindBuffer(u32 binding, vk::Buffer buffer, u32 offset, u32 size) { void PipelineCache::BindBuffer(u32 binding, vk::Buffer buffer, u32 offset, u32 size) {
const DescriptorData data = { const DescriptorData data = {
.buffer_info = vk::DescriptorBufferInfo{.buffer = buffer, .offset = offset, .range = size}}; .buffer_info =
vk::DescriptorBufferInfo{
.buffer = buffer,
.offset = offset,
.range = size,
},
};
desc_manager.SetBinding(0, binding, data); desc_manager.SetBinding(0, binding, data);
} }
void PipelineCache::BindTexelBuffer(u32 binding, vk::BufferView buffer_view) { void PipelineCache::BindTexelBuffer(u32 binding, vk::BufferView buffer_view) {
const DescriptorData data = {.buffer_view = buffer_view}; const DescriptorData data = {
.buffer_view = buffer_view,
};
desc_manager.SetBinding(0, binding, data); desc_manager.SetBinding(0, binding, data);
} }
void PipelineCache::BindSampler(u32 binding, vk::Sampler sampler) { void PipelineCache::BindSampler(u32 binding, vk::Sampler sampler) {
const DescriptorData data = {.image_info = vk::DescriptorImageInfo{.sampler = sampler}}; const DescriptorData data = {
.image_info =
vk::DescriptorImageInfo{
.sampler = sampler,
},
};
desc_manager.SetBinding(2, binding, data); desc_manager.SetBinding(2, binding, data);
} }
@@ -411,18 +448,21 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info) {
} }
vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) { vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
vk::Device device = instance.GetDevice(); const vk::Device device = instance.GetDevice();
u32 shader_count = 0; u32 shader_count = 0;
std::array<vk::PipelineShaderStageCreateInfo, MAX_SHADER_STAGES> shader_stages; std::array<vk::PipelineShaderStageCreateInfo, MAX_SHADER_STAGES> shader_stages;
for (std::size_t i = 0; i < current_shaders.size(); i++) { for (std::size_t i = 0; i < current_shaders.size(); i++) {
vk::ShaderModule shader = current_shaders[i]; const vk::ShaderModule shader = current_shaders[i];
if (!shader) { if (!shader) {
continue; continue;
} }
shader_stages[shader_count++] = vk::PipelineShaderStageCreateInfo{ shader_stages[shader_count++] = vk::PipelineShaderStageCreateInfo{
.stage = ToVkShaderStage(i), .module = shader, .pName = "main"}; .stage = ToVkShaderStage(i),
.module = shader,
.pName = "main",
};
} }
/** /**
@@ -438,7 +478,8 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.binding = binding.binding, .binding = binding.binding,
.stride = binding.stride, .stride = binding.stride,
.inputRate = binding.fixed.Value() ? vk::VertexInputRate::eInstance .inputRate = binding.fixed.Value() ? vk::VertexInputRate::eInstance
: vk::VertexInputRate::eVertex}; : vk::VertexInputRate::eVertex,
};
} }
u32 emulated_attrib_count = 0; u32 emulated_attrib_count = 0;
@@ -453,7 +494,8 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.location = attrib.location, .location = attrib.location,
.binding = attrib.binding, .binding = attrib.binding,
.format = is_supported ? format : ToVkAttributeFormat(attrib.type, 2), .format = is_supported ? format : ToVkAttributeFormat(attrib.type, 2),
.offset = attrib.offset}; .offset = attrib.offset,
};
// When the requested 3-component vertex format is unsupported by the hardware // When the requested 3-component vertex format is unsupported by the hardware
// is it emulated by breaking it into a vec2 + vec1. These are combined to a vec3 // is it emulated by breaking it into a vec2 + vec1. These are combined to a vec3
@@ -466,7 +508,8 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.location = location, .location = location,
.binding = attrib.binding, .binding = attrib.binding,
.format = ToVkAttributeFormat(attrib.type, 1), .format = ToVkAttributeFormat(attrib.type, 1),
.offset = attrib.offset + AttribBytes(attrib.type, 2)}; .offset = attrib.offset + AttribBytes(attrib.type, 2),
};
} }
} }
@@ -475,11 +518,13 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.pVertexBindingDescriptions = bindings.data(), .pVertexBindingDescriptions = bindings.data(),
.vertexAttributeDescriptionCount = .vertexAttributeDescriptionCount =
info.vertex_layout.attribute_count + emulated_attrib_count, info.vertex_layout.attribute_count + emulated_attrib_count,
.pVertexAttributeDescriptions = attributes.data()}; .pVertexAttributeDescriptions = attributes.data(),
};
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {
.topology = PicaToVK::PrimitiveTopology(info.rasterization.topology), .topology = PicaToVK::PrimitiveTopology(info.rasterization.topology),
.primitiveRestartEnable = false}; .primitiveRestartEnable = false,
};
const vk::PipelineRasterizationStateCreateInfo raster_state = { const vk::PipelineRasterizationStateCreateInfo raster_state = {
.depthClampEnable = false, .depthClampEnable = false,
@@ -487,10 +532,13 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.cullMode = PicaToVK::CullMode(info.rasterization.cull_mode), .cullMode = PicaToVK::CullMode(info.rasterization.cull_mode),
.frontFace = PicaToVK::FrontFace(info.rasterization.cull_mode), .frontFace = PicaToVK::FrontFace(info.rasterization.cull_mode),
.depthBiasEnable = false, .depthBiasEnable = false,
.lineWidth = 1.0f}; .lineWidth = 1.0f,
};
const vk::PipelineMultisampleStateCreateInfo multisampling = { const vk::PipelineMultisampleStateCreateInfo multisampling = {
.rasterizationSamples = vk::SampleCountFlagBits::e1, .sampleShadingEnable = false}; .rasterizationSamples = vk::SampleCountFlagBits::e1,
.sampleShadingEnable = false,
};
const vk::PipelineColorBlendAttachmentState colorblend_attachment = { const vk::PipelineColorBlendAttachmentState colorblend_attachment = {
.blendEnable = info.blending.blend_enable.Value(), .blendEnable = info.blending.blend_enable.Value(),
@@ -500,19 +548,30 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.srcAlphaBlendFactor = PicaToVK::BlendFunc(info.blending.src_alpha_blend_factor), .srcAlphaBlendFactor = PicaToVK::BlendFunc(info.blending.src_alpha_blend_factor),
.dstAlphaBlendFactor = PicaToVK::BlendFunc(info.blending.dst_alpha_blend_factor), .dstAlphaBlendFactor = PicaToVK::BlendFunc(info.blending.dst_alpha_blend_factor),
.alphaBlendOp = PicaToVK::BlendEquation(info.blending.alpha_blend_eq), .alphaBlendOp = PicaToVK::BlendEquation(info.blending.alpha_blend_eq),
.colorWriteMask = static_cast<vk::ColorComponentFlags>(info.blending.color_write_mask)}; .colorWriteMask = static_cast<vk::ColorComponentFlags>(info.blending.color_write_mask),
};
const vk::PipelineColorBlendStateCreateInfo color_blending = { const vk::PipelineColorBlendStateCreateInfo color_blending = {
.logicOpEnable = !info.blending.blend_enable.Value() && !instance.NeedsLogicOpEmulation(), .logicOpEnable = !info.blending.blend_enable.Value() && !instance.NeedsLogicOpEmulation(),
.logicOp = PicaToVK::LogicOp(info.blending.logic_op.Value()), .logicOp = PicaToVK::LogicOp(info.blending.logic_op.Value()),
.attachmentCount = 1, .attachmentCount = 1,
.pAttachments = &colorblend_attachment, .pAttachments = &colorblend_attachment,
.blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f}}; .blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f},
};
const vk::Viewport viewport = { const vk::Viewport viewport = {
.x = 0.0f, .y = 0.0f, .width = 1.0f, .height = 1.0f, .minDepth = 0.0f, .maxDepth = 1.0f}; .x = 0.0f,
.y = 0.0f,
.width = 1.0f,
.height = 1.0f,
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
const vk::Rect2D scissor = {.offset = {0, 0}, .extent = {1, 1}}; const vk::Rect2D scissor = {
.offset = {0, 0},
.extent = {1, 1},
};
const vk::PipelineViewportStateCreateInfo viewport_info = { const vk::PipelineViewportStateCreateInfo viewport_info = {
.viewportCount = 1, .viewportCount = 1,
@@ -542,13 +601,15 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
const vk::PipelineDynamicStateCreateInfo dynamic_info = { const vk::PipelineDynamicStateCreateInfo dynamic_info = {
.dynamicStateCount = extended_dynamic_states ? static_cast<u32>(dynamic_states.size()) : 6u, .dynamicStateCount = extended_dynamic_states ? static_cast<u32>(dynamic_states.size()) : 6u,
.pDynamicStates = dynamic_states.data()}; .pDynamicStates = dynamic_states.data(),
};
const vk::StencilOpState stencil_op_state = { const vk::StencilOpState stencil_op_state = {
.failOp = PicaToVK::StencilOp(info.depth_stencil.stencil_fail_op), .failOp = PicaToVK::StencilOp(info.depth_stencil.stencil_fail_op),
.passOp = PicaToVK::StencilOp(info.depth_stencil.stencil_pass_op), .passOp = PicaToVK::StencilOp(info.depth_stencil.stencil_pass_op),
.depthFailOp = PicaToVK::StencilOp(info.depth_stencil.stencil_depth_fail_op), .depthFailOp = PicaToVK::StencilOp(info.depth_stencil.stencil_depth_fail_op),
.compareOp = PicaToVK::CompareFunc(info.depth_stencil.stencil_compare_op)}; .compareOp = PicaToVK::CompareFunc(info.depth_stencil.stencil_compare_op),
};
const vk::PipelineDepthStencilStateCreateInfo depth_info = { const vk::PipelineDepthStencilStateCreateInfo depth_info = {
.depthTestEnable = static_cast<u32>(info.depth_stencil.depth_test_enable.Value()), .depthTestEnable = static_cast<u32>(info.depth_stencil.depth_test_enable.Value()),
@@ -557,7 +618,8 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.depthBoundsTestEnable = false, .depthBoundsTestEnable = false,
.stencilTestEnable = static_cast<u32>(info.depth_stencil.stencil_test_enable.Value()), .stencilTestEnable = static_cast<u32>(info.depth_stencil.stencil_test_enable.Value()),
.front = stencil_op_state, .front = stencil_op_state,
.back = stencil_op_state}; .back = stencil_op_state,
};
const vk::GraphicsPipelineCreateInfo pipeline_info = { const vk::GraphicsPipelineCreateInfo pipeline_info = {
.stageCount = shader_count, .stageCount = shader_count,
@@ -572,7 +634,8 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.pDynamicState = &dynamic_info, .pDynamicState = &dynamic_info,
.layout = desc_manager.GetPipelineLayout(), .layout = desc_manager.GetPipelineLayout(),
.renderPass = .renderPass =
renderpass_cache.GetRenderpass(info.color_attachment, info.depth_attachment, false)}; renderpass_cache.GetRenderpass(info.color_attachment, info.depth_attachment, false),
};
if (const auto result = device.createGraphicsPipeline(pipeline_cache, pipeline_info); if (const auto result = device.createGraphicsPipeline(pipeline_cache, pipeline_info);
result.result == vk::Result::eSuccess) { result.result == vk::Result::eSuccess) {

View File

@@ -26,17 +26,23 @@ constexpr u32 INDEX_BUFFER_SIZE = 16 * 1024 * 1024;
constexpr u32 UNIFORM_BUFFER_SIZE = 16 * 1024 * 1024; constexpr u32 UNIFORM_BUFFER_SIZE = 16 * 1024 * 1024;
constexpr u32 TEXTURE_BUFFER_SIZE = 512 * 1024; constexpr u32 TEXTURE_BUFFER_SIZE = 512 * 1024;
constexpr std::array TEXTURE_BUFFER_LF_FORMATS = {vk::Format::eR32G32Sfloat}; constexpr std::array TEXTURE_BUFFER_LF_FORMATS = {
vk::Format::eR32G32Sfloat,
};
constexpr std::array TEXTURE_BUFFER_FORMATS = {vk::Format::eR32G32Sfloat, constexpr std::array TEXTURE_BUFFER_FORMATS = {
vk::Format::eR32G32B32A32Sfloat}; vk::Format::eR32G32Sfloat,
vk::Format::eR32G32B32A32Sfloat,
};
constexpr VideoCore::SurfaceParams NULL_PARAMS = {.width = 1, constexpr VideoCore::SurfaceParams NULL_PARAMS = {
.width = 1,
.height = 1, .height = 1,
.stride = 1, .stride = 1,
.texture_type = VideoCore::TextureType::Texture2D, .texture_type = VideoCore::TextureType::Texture2D,
.pixel_format = VideoCore::PixelFormat::RGBA8, .pixel_format = VideoCore::PixelFormat::RGBA8,
.type = VideoCore::SurfaceType::Color}; .type = VideoCore::SurfaceType::Color,
};
constexpr vk::ImageUsageFlags NULL_USAGE = vk::ImageUsageFlagBits::eSampled | constexpr vk::ImageUsageFlags NULL_USAGE = vk::ImageUsageFlagBits::eSampled |
vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferSrc |
@@ -85,7 +91,8 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instan
.min_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear, .min_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear,
.mip_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear, .mip_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear,
.wrap_s = Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder, .wrap_s = Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder,
.wrap_t = Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder}; .wrap_t = Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder,
};
default_sampler = CreateSampler(default_sampler_info); default_sampler = CreateSampler(default_sampler_info);
@@ -265,8 +272,8 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
SetupFixedAttribs(); SetupFixedAttribs();
// Bind the generated bindings // Bind the generated bindings
scheduler.Record([this, vertex_offsets = binding_offsets]( scheduler.Record([this, vertex_offsets = binding_offsets](vk::CommandBuffer render_cmdbuf,
vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer) {
render_cmdbuf.bindVertexBuffers(0, vertex_buffers, vertex_offsets); render_cmdbuf.bindVertexBuffers(0, vertex_buffers, vertex_offsets);
}); });
} }
@@ -435,8 +442,8 @@ void RasterizerVulkan::SetupIndexArray() {
index_buffer.Commit(index_buffer_size); index_buffer.Commit(index_buffer_size);
scheduler.Record([this, index_offset = index_offset, index_type = index_type]( scheduler.Record([this, index_offset = index_offset,
vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { index_type = index_type](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
render_cmdbuf.bindIndexBuffer(index_buffer.GetHandle(), index_offset, index_type); render_cmdbuf.bindIndexBuffer(index_buffer.GetHandle(), index_offset, index_type);
}); });
} }
@@ -548,7 +555,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
// nothing. Always sample from the base level until mipmaps for texture cubes are // nothing. Always sample from the base level until mipmaps for texture cubes are
// implemented // implemented
const bool skip_mipmap = config.type == Pica::TexturingRegs::TextureConfig::TextureCube; const bool skip_mipmap = config.type == Pica::TexturingRegs::TextureConfig::TextureCube;
info = SamplerInfo{.mag_filter = config.mag_filter, info = SamplerInfo{
.mag_filter = config.mag_filter,
.min_filter = config.min_filter, .min_filter = config.min_filter,
.mip_filter = config.mip_filter, .mip_filter = config.mip_filter,
.wrap_s = config.wrap_s, .wrap_s = config.wrap_s,
@@ -556,7 +564,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.border_color = config.border_color.raw, .border_color = config.border_color.raw,
.lod_min = skip_mipmap ? 0.f : static_cast<float>(config.lod.min_level), .lod_min = skip_mipmap ? 0.f : static_cast<float>(config.lod.min_level),
.lod_max = skip_mipmap ? 0.f : static_cast<float>(config.lod.max_level), .lod_max = skip_mipmap ? 0.f : static_cast<float>(config.lod.max_level),
.lod_bias = static_cast<float>(config.lod.bias)}; .lod_bias = static_cast<float>(config.lod.bias),
};
// Search the cache and bind the appropriate sampler // Search the cache and bind the appropriate sampler
if (auto it = samplers.find(info); it != samplers.end()) { if (auto it = samplers.find(info); it != samplers.end()) {
@@ -711,7 +720,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.renderpass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment, .renderpass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
pipeline_info.depth_attachment, false), pipeline_info.depth_attachment, false),
.width = width, .width = width,
.height = height}; .height = height,
};
auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info, vk::Framebuffer{}); auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info, vk::Framebuffer{});
if (new_framebuffer) { if (new_framebuffer) {
@@ -721,9 +731,11 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
const RenderpassState renderpass_info = { const RenderpassState renderpass_info = {
.renderpass = framebuffer_info.renderpass, .renderpass = framebuffer_info.renderpass,
.framebuffer = it->second, .framebuffer = it->second,
.render_area = vk::Rect2D{.offset = {static_cast<s32>(draw_rect.left), .render_area =
static_cast<s32>(draw_rect.bottom)}, vk::Rect2D{
.extent = {draw_rect.GetWidth(), draw_rect.GetHeight()}}, .offset = {static_cast<s32>(draw_rect.left), static_cast<s32>(draw_rect.bottom)},
.extent = {draw_rect.GetWidth(), draw_rect.GetHeight()},
},
.clear = {}, .clear = {},
}; };
@@ -1086,8 +1098,11 @@ vk::Sampler RasterizerVulkan::CreateSampler(const SamplerInfo& info) {
const auto color = PicaToVK::ColorRGBA8(info.border_color); const auto color = PicaToVK::ColorRGBA8(info.border_color);
const vk::SamplerCustomBorderColorCreateInfoEXT border_color_info = { const vk::SamplerCustomBorderColorCreateInfoEXT border_color_info = {
.customBorderColor = .customBorderColor =
vk::ClearColorValue{.float32 = std::array{color[0], color[1], color[2], color[3]}}, vk::ClearColorValue{
.format = vk::Format::eUndefined}; .float32 = std::array{color[0], color[1], color[2], color[3]},
},
.format = vk::Format::eUndefined,
};
const vk::SamplerCreateInfo sampler_info = { const vk::SamplerCreateInfo sampler_info = {
.pNext = use_border_color ? &border_color_info : nullptr, .pNext = use_border_color ? &border_color_info : nullptr,
@@ -1105,7 +1120,8 @@ vk::Sampler RasterizerVulkan::CreateSampler(const SamplerInfo& info) {
.maxLod = info.lod_max, .maxLod = info.lod_max,
.borderColor = .borderColor =
use_border_color ? vk::BorderColor::eFloatCustomEXT : vk::BorderColor::eIntOpaqueBlack, use_border_color ? vk::BorderColor::eFloatCustomEXT : vk::BorderColor::eIntOpaqueBlack,
.unnormalizedCoordinates = false}; .unnormalizedCoordinates = false,
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
return device.createSampler(sampler_info); return device.createSampler(sampler_info);
@@ -1123,12 +1139,14 @@ vk::Framebuffer RasterizerVulkan::CreateFramebuffer(const FramebufferInfo& info)
attachments[attachment_count++] = info.depth; attachments[attachment_count++] = info.depth;
} }
const vk::FramebufferCreateInfo framebuffer_info = {.renderPass = info.renderpass, const vk::FramebufferCreateInfo framebuffer_info = {
.renderPass = info.renderpass,
.attachmentCount = attachment_count, .attachmentCount = attachment_count,
.pAttachments = attachments.data(), .pAttachments = attachments.data(),
.width = info.width, .width = info.width,
.height = info.height, .height = info.height,
.layers = 1}; .layers = 1,
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
return device.createFramebuffer(framebuffer_info); return device.createFramebuffer(framebuffer_info);

View File

@@ -61,11 +61,11 @@ RenderpassCache::RenderpassCache(const Instance& instance, Scheduler& scheduler)
continue; continue;
} }
cached_renderpasses[color][depth][0] = CreateRenderPass( cached_renderpasses[color][depth][0] =
color_format, depth_format, vk::AttachmentLoadOp::eLoad, CreateRenderPass(color_format, depth_format, vk::AttachmentLoadOp::eLoad,
vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
cached_renderpasses[color][depth][1] = CreateRenderPass( cached_renderpasses[color][depth][1] =
color_format, depth_format, vk::AttachmentLoadOp::eClear, CreateRenderPass(color_format, depth_format, vk::AttachmentLoadOp::eClear,
vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
} }
} }
@@ -100,11 +100,13 @@ void RenderpassCache::EnterRenderpass(const RenderpassState& state) {
render_cmdbuf.endRenderPass(); render_cmdbuf.endRenderPass();
} }
const vk::RenderPassBeginInfo renderpass_begin_info = {.renderPass = state.renderpass, const vk::RenderPassBeginInfo renderpass_begin_info = {
.renderPass = state.renderpass,
.framebuffer = state.framebuffer, .framebuffer = state.framebuffer,
.renderArea = state.render_area, .renderArea = state.render_area,
.clearValueCount = 1, .clearValueCount = 1,
.pClearValues = &state.clear}; .pClearValues = &state.clear,
};
render_cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline); render_cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
}); });
@@ -160,17 +162,20 @@ vk::RenderPass RenderpassCache::CreateRenderPass(vk::Format color, vk::Format de
vk::AttachmentReference depth_attachment_ref{}; vk::AttachmentReference depth_attachment_ref{};
if (color != vk::Format::eUndefined) { if (color != vk::Format::eUndefined) {
attachments[attachment_count] = attachments[attachment_count] = vk::AttachmentDescription{
vk::AttachmentDescription{.format = color, .format = color,
.loadOp = load_op, .loadOp = load_op,
.storeOp = vk::AttachmentStoreOp::eStore, .storeOp = vk::AttachmentStoreOp::eStore,
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare, .stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare, .stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
.initialLayout = initial_layout, .initialLayout = initial_layout,
.finalLayout = final_layout}; .finalLayout = final_layout,
};
color_attachment_ref = vk::AttachmentReference{ color_attachment_ref = vk::AttachmentReference{
.attachment = attachment_count++, .layout = vk::ImageLayout::eGeneral}; .attachment = attachment_count++,
.layout = vk::ImageLayout::eGeneral,
};
use_color = true; use_color = true;
} }
@@ -183,34 +188,38 @@ vk::RenderPass RenderpassCache::CreateRenderPass(vk::Format color, vk::Format de
.stencilLoadOp = load_op, .stencilLoadOp = load_op,
.stencilStoreOp = vk::AttachmentStoreOp::eStore, .stencilStoreOp = vk::AttachmentStoreOp::eStore,
.initialLayout = vk::ImageLayout::eGeneral, .initialLayout = vk::ImageLayout::eGeneral,
.finalLayout = vk::ImageLayout::eGeneral}; .finalLayout = vk::ImageLayout::eGeneral,
};
depth_attachment_ref = depth_attachment_ref = vk::AttachmentReference{
vk::AttachmentReference{.attachment = attachment_count++, .attachment = attachment_count++,
.layout = vk::ImageLayout::eGeneral}; .layout = vk::ImageLayout::eGeneral,
};
use_depth = true; use_depth = true;
} }
// We also require only one subpass // We also require only one subpass
const vk::SubpassDescription subpass = {.pipelineBindPoint = vk::PipelineBindPoint::eGraphics, const vk::SubpassDescription subpass = {
.pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
.inputAttachmentCount = 0, .inputAttachmentCount = 0,
.pInputAttachments = nullptr, .pInputAttachments = nullptr,
.colorAttachmentCount = use_color ? 1u : 0u, .colorAttachmentCount = use_color ? 1u : 0u,
.pColorAttachments = &color_attachment_ref, .pColorAttachments = &color_attachment_ref,
.pResolveAttachments = 0, .pResolveAttachments = 0,
.pDepthStencilAttachment = .pDepthStencilAttachment = use_depth ? &depth_attachment_ref : nullptr,
use_depth ? &depth_attachment_ref : nullptr}; };
const vk::RenderPassCreateInfo renderpass_info = {.attachmentCount = attachment_count, const vk::RenderPassCreateInfo renderpass_info = {
.attachmentCount = attachment_count,
.pAttachments = attachments.data(), .pAttachments = attachments.data(),
.subpassCount = 1, .subpassCount = 1,
.pSubpasses = &subpass, .pSubpasses = &subpass,
.dependencyCount = 0, .dependencyCount = 0,
.pDependencies = nullptr}; .pDependencies = nullptr,
};
// Create the renderpass const vk::Device device = instance.GetDevice();
vk::Device device = instance.GetDevice();
return device.createRenderPass(renderpass_info); return device.createRenderPass(renderpass_info);
} }

View File

@@ -86,7 +86,8 @@ void CommandPool::Allocate(std::size_t begin, std::size_t end) {
const vk::CommandPoolCreateInfo pool_create_info = { const vk::CommandPoolCreateInfo pool_create_info = {
.flags = vk::CommandPoolCreateFlagBits::eTransient | .flags = vk::CommandPoolCreateFlagBits::eTransient |
vk::CommandPoolCreateFlagBits::eResetCommandBuffer, vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
.queueFamilyIndex = instance.GetGraphicsQueueFamilyIndex()}; .queueFamilyIndex = instance.GetGraphicsQueueFamilyIndex(),
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
pool.handle = device.createCommandPool(pool_create_info); pool.handle = device.createCommandPool(pool_create_info);
@@ -94,7 +95,8 @@ void CommandPool::Allocate(std::size_t begin, std::size_t end) {
const vk::CommandBufferAllocateInfo buffer_alloc_info = { const vk::CommandBufferAllocateInfo buffer_alloc_info = {
.commandPool = pool.handle, .commandPool = pool.handle,
.level = vk::CommandBufferLevel::ePrimary, .level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = COMMAND_BUFFER_POOL_SIZE}; .commandBufferCount = COMMAND_BUFFER_POOL_SIZE,
};
auto buffers = device.allocateCommandBuffers(buffer_alloc_info); auto buffers = device.allocateCommandBuffers(buffer_alloc_info);
std::copy(buffers.begin(), buffers.end(), pool.cmdbufs.begin()); std::copy(buffers.begin(), buffers.end(), pool.cmdbufs.begin());
@@ -126,17 +128,19 @@ void DescriptorPool::Allocate(std::size_t begin, std::size_t end) {
vk::DescriptorPool& pool = pools.emplace_back(); vk::DescriptorPool& pool = pools.emplace_back();
// Choose a sane pool size good for most games // Choose a sane pool size good for most games
static constexpr std::array<vk::DescriptorPoolSize, 5> pool_sizes = { static constexpr std::array<vk::DescriptorPoolSize, 5> pool_sizes = {{
{{vk::DescriptorType::eUniformBuffer, 4096}, {vk::DescriptorType::eUniformBuffer, 4096},
{vk::DescriptorType::eSampledImage, 4096}, {vk::DescriptorType::eSampledImage, 4096},
{vk::DescriptorType::eSampler, 4096}, {vk::DescriptorType::eSampler, 4096},
{vk::DescriptorType::eUniformTexelBuffer, 2048}, {vk::DescriptorType::eUniformTexelBuffer, 2048},
{vk::DescriptorType::eStorageImage, 1024}}}; {vk::DescriptorType::eStorageImage, 1024},
}};
const vk::DescriptorPoolCreateInfo descriptor_pool_info = { const vk::DescriptorPoolCreateInfo descriptor_pool_info = {
.maxSets = 8192, .maxSets = 8192,
.poolSizeCount = static_cast<u32>(pool_sizes.size()), .poolSizeCount = static_cast<u32>(pool_sizes.size()),
.pPoolSizes = pool_sizes.data()}; .pPoolSizes = pool_sizes.data(),
};
pool = instance.GetDevice().createDescriptorPool(descriptor_pool_info); pool = instance.GetDevice().createDescriptorPool(descriptor_pool_info);
} }

View File

@@ -139,9 +139,8 @@ void Scheduler::SubmitExecution(vk::Semaphore signal_semaphore, vk::Semaphore wa
renderer.FlushBuffers(); renderer.FlushBuffers();
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
Record([signal_semaphore, wait_semaphore, Record([signal_semaphore, wait_semaphore, handle, signal_value,
handle, signal_value, this](vk::CommandBuffer render_cmdbuf, this](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer upload_cmdbuf) {
vk::CommandBuffer upload_cmdbuf) {
MICROPROFILE_SCOPE(Vulkan_Submit); MICROPROFILE_SCOPE(Vulkan_Submit);
upload_cmdbuf.end(); upload_cmdbuf.end();
render_cmdbuf.end(); render_cmdbuf.end();

View File

@@ -1768,7 +1768,8 @@ layout (set = 0, binding = 0, std140) uniform vs_config {
out += fmt::format("vec4 vs_out_attr{};\n", i); out += fmt::format("vec4 vs_out_attr{};\n", i);
} }
const auto semantic = [&config = config.state](VSOutputAttributes::Semantic slot_semantic) -> std::string { const auto semantic =
[&config = config.state](VSOutputAttributes::Semantic slot_semantic) -> std::string {
const u32 slot = static_cast<u32>(slot_semantic); const u32 slot = static_cast<u32>(slot_semantic);
const u32 attrib = config.semantic_maps[slot].attribute_index; const u32 attrib = config.semantic_maps[slot].attribute_index;
const u32 comp = config.semantic_maps[slot].component_index; const u32 comp = config.semantic_maps[slot].component_index;
@@ -1795,8 +1796,9 @@ layout (set = 0, binding = 0, std140) uniform vs_config {
out += " normquat = GetVertexQuaternion();\n"; out += " normquat = GetVertexQuaternion();\n";
out += " vec4 vtx_color = vec4(" + semantic(VSOutputAttributes::COLOR_R) + ", " + out += " vec4 vtx_color = vec4(" + semantic(VSOutputAttributes::COLOR_R) + ", " +
semantic(VSOutputAttributes::COLOR_G) + ", " + semantic(VSOutputAttributes::COLOR_B) + semantic(VSOutputAttributes::COLOR_G) + ", " +
", " + semantic(VSOutputAttributes::COLOR_A) + ");\n"; semantic(VSOutputAttributes::COLOR_B) + ", " +
semantic(VSOutputAttributes::COLOR_A) + ");\n";
out += " primary_color = min(abs(vtx_color), vec4(1.0));\n\n"; out += " primary_color = min(abs(vtx_color), vec4(1.0));\n\n";
out += " texcoord0 = vec2(" + semantic(VSOutputAttributes::TEXCOORD0_U) + ", " + out += " texcoord0 = vec2(" + semantic(VSOutputAttributes::TEXCOORD0_U) + ", " +

View File

@@ -150,8 +150,8 @@ struct PicaFSConfig : Common::HashableStruct<PicaFSConfigState> {
* PICA vertex/geometry shader. * PICA vertex/geometry shader.
*/ */
struct PicaShaderConfigCommon { struct PicaShaderConfigCommon {
void Init(const Pica::RasterizerRegs& rasterizer, void Init(const Pica::RasterizerRegs& rasterizer, const Pica::ShaderRegs& regs,
const Pica::ShaderRegs& regs, Pica::Shader::ShaderSetup& setup); Pica::Shader::ShaderSetup& setup);
u64 program_hash; u64 program_hash;
u64 swizzle_hash; u64 swizzle_hash;
@@ -183,8 +183,8 @@ struct PicaShaderConfigCommon {
* shader. * shader.
*/ */
struct PicaVSConfig : Common::HashableStruct<PicaShaderConfigCommon> { struct PicaVSConfig : Common::HashableStruct<PicaShaderConfigCommon> {
explicit PicaVSConfig(const Pica::RasterizerRegs& rasterizer, explicit PicaVSConfig(const Pica::RasterizerRegs& rasterizer, const Pica::ShaderRegs& regs,
const Pica::ShaderRegs& regs, Pica::Shader::ShaderSetup& setup) { Pica::Shader::ShaderSetup& setup) {
state.Init(rasterizer, regs, setup); state.Init(rasterizer, regs, setup);
} }
explicit PicaVSConfig(const PicaShaderConfigCommon& conf) { explicit PicaVSConfig(const PicaShaderConfigCommon& conf) {

View File

@@ -59,9 +59,10 @@ StagingBuffer::StagingBuffer(const Instance& instance, u32 size, bool readback)
const VmaAllocationCreateFlags flags = const VmaAllocationCreateFlags flags =
readback ? VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT readback ? VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT
: VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; : VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
const VmaAllocationCreateInfo alloc_create_info = {.flags = const VmaAllocationCreateInfo alloc_create_info = {
flags | VMA_ALLOCATION_CREATE_MAPPED_BIT, .flags = flags | VMA_ALLOCATION_CREATE_MAPPED_BIT,
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST}; .usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
};
VkBuffer unsafe_buffer = VK_NULL_HANDLE; VkBuffer unsafe_buffer = VK_NULL_HANDLE;
VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info); VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info);
@@ -88,11 +89,15 @@ StreamBuffer::StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 s
bool readback) bool readback)
: instance{instance}, scheduler{scheduler}, staging{instance, size, readback}, usage{usage}, : instance{instance}, scheduler{scheduler}, staging{instance, size, readback}, usage{usage},
total_size{size}, bucket_size{size / BUCKET_COUNT}, readback{readback} { total_size{size}, bucket_size{size / BUCKET_COUNT}, readback{readback} {
const vk::BufferCreateInfo buffer_info = {
.size = total_size, .usage = usage | vk::BufferUsageFlagBits::eTransferDst};
const VmaAllocationCreateInfo alloc_create_info = {.usage = const vk::BufferCreateInfo buffer_info = {
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE}; .size = total_size,
.usage = usage | vk::BufferUsageFlagBits::eTransferDst,
};
const VmaAllocationCreateInfo alloc_create_info = {
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
};
VkBuffer unsafe_buffer = VK_NULL_HANDLE; VkBuffer unsafe_buffer = VK_NULL_HANDLE;
VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info); VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info);
@@ -109,7 +114,11 @@ StreamBuffer::StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 s
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
for (std::size_t i = 0; i < view_formats.size(); i++) { for (std::size_t i = 0; i < view_formats.size(); i++) {
const vk::BufferViewCreateInfo view_info = { const vk::BufferViewCreateInfo view_info = {
.buffer = gpu_buffer, .format = view_formats[i], .offset = 0, .range = total_size}; .buffer = gpu_buffer,
.format = view_formats[i],
.offset = 0,
.range = total_size,
};
views[i] = device.createBufferView(view_info); views[i] = device.createBufferView(view_info);
} }
@@ -171,7 +180,10 @@ void StreamBuffer::Flush() {
scheduler.Record([this, flush_start, flush_size](vk::CommandBuffer, scheduler.Record([this, flush_start, flush_size](vk::CommandBuffer,
vk::CommandBuffer upload_cmdbuf) { vk::CommandBuffer upload_cmdbuf) {
const vk::BufferCopy copy_region = { const vk::BufferCopy copy_region = {
.srcOffset = flush_start, .dstOffset = flush_start, .size = flush_size}; .srcOffset = flush_start,
.dstOffset = flush_start,
.size = flush_size,
};
upload_cmdbuf.copyBuffer(staging.buffer, gpu_buffer, copy_region); upload_cmdbuf.copyBuffer(staging.buffer, gpu_buffer, copy_region);
@@ -182,7 +194,8 @@ void StreamBuffer::Flush() {
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = gpu_buffer, .buffer = gpu_buffer,
.offset = flush_start, .offset = flush_start,
.size = flush_size}; .size = flush_size,
};
upload_cmdbuf.pipelineBarrier( upload_cmdbuf.pipelineBarrier(
vk::PipelineStageFlagBits::eTransfer, MakePipelineStage(usage), vk::PipelineStageFlagBits::eTransfer, MakePipelineStage(usage),

View File

@@ -69,7 +69,8 @@ void Swapchain::Create() {
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eInherit, .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eInherit,
.presentMode = present_mode, .presentMode = present_mode,
.clipped = true, .clipped = true,
.oldSwapchain = swapchain}; .oldSwapchain = swapchain,
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
vk::SwapchainKHR new_swapchain = device.createSwapchainKHR(swapchain_info); vk::SwapchainKHR new_swapchain = device.createSwapchainKHR(swapchain_info);
@@ -111,11 +112,14 @@ void Swapchain::AcquireNextImage() {
MICROPROFILE_DEFINE(Vulkan_Present, "Vulkan", "Swapchain Present", MP_RGB(66, 185, 245)); MICROPROFILE_DEFINE(Vulkan_Present, "Vulkan", "Swapchain Present", MP_RGB(66, 185, 245));
void Swapchain::Present() { void Swapchain::Present() {
scheduler.Record([this, index = image_index](vk::CommandBuffer, vk::CommandBuffer) { scheduler.Record([this, index = image_index](vk::CommandBuffer, vk::CommandBuffer) {
const vk::PresentInfoKHR present_info = {.waitSemaphoreCount = 1, const vk::PresentInfoKHR present_info = {
.waitSemaphoreCount = 1,
.pWaitSemaphores = &present_ready[index], .pWaitSemaphores = &present_ready[index],
.swapchainCount = 1, .swapchainCount = 1,
.pSwapchains = &swapchain, .pSwapchains = &swapchain,
.pImageIndices = &index}; .pImageIndices = &index,
};
MICROPROFILE_SCOPE(Vulkan_Present); MICROPROFILE_SCOPE(Vulkan_Present);
vk::Queue present_queue = instance.GetPresentQueue(); vk::Queue present_queue = instance.GetPresentQueue();
try { try {
@@ -233,11 +237,15 @@ void Swapchain::SetupImages() {
.image = image, .image = image,
.viewType = vk::ImageViewType::e2D, .viewType = vk::ImageViewType::e2D,
.format = surface_format.format, .format = surface_format.format,
.subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1}}; .layerCount = 1,
},
};
image_views.push_back(device.createImageView(view_info)); image_views.push_back(device.createImageView(view_info));
@@ -247,7 +255,8 @@ void Swapchain::SetupImages() {
.pAttachments = &image_views.back(), .pAttachments = &image_views.back(),
.width = extent.width, .width = extent.width,
.height = extent.height, .height = extent.height,
.layers = 1}; .layers = 1,
};
framebuffers.push_back(device.createFramebuffer(framebuffer_info)); framebuffers.push_back(device.createFramebuffer(framebuffer_info));
} }

View File

@@ -55,14 +55,14 @@ namespace Vulkan {
[[nodiscard]] vk::ClearColorValue MakeClearColorValue(VideoCore::ClearValue clear) { [[nodiscard]] vk::ClearColorValue MakeClearColorValue(VideoCore::ClearValue clear) {
return vk::ClearColorValue{ return vk::ClearColorValue{
.float32 = std::array{clear.color[0], clear.color[1], clear.color[2], clear.color[3]} .float32 = std::array{clear.color[0], clear.color[1], clear.color[2], clear.color[3]},
}; };
} }
[[nodiscard]] vk::ClearDepthStencilValue MakeClearDepthStencilValue(VideoCore::ClearValue clear) { [[nodiscard]] vk::ClearDepthStencilValue MakeClearDepthStencilValue(VideoCore::ClearValue clear) {
return vk::ClearDepthStencilValue{ return vk::ClearDepthStencilValue{
.depth = clear.depth, .depth = clear.depth,
.stencil = clear.stencil .stencil = clear.stencil,
}; };
} }
@@ -142,14 +142,15 @@ TextureRuntime::~TextureRuntime() {
} }
StagingData TextureRuntime::FindStaging(u32 size, bool upload) { StagingData TextureRuntime::FindStaging(u32 size, bool upload) {
// Depth uploads require 4 byte alignment, doesn't hurt to do it for everyone
auto& buffer = upload ? upload_buffer : download_buffer; auto& buffer = upload ? upload_buffer : download_buffer;
auto [data, offset, invalidate] = buffer.Map(size); auto [data, offset, invalidate] = buffer.Map(size);
return StagingData{.buffer = buffer.GetStagingHandle(), return StagingData{
.buffer = buffer.GetStagingHandle(),
.size = size, .size = size,
.mapped = std::span<std::byte>{reinterpret_cast<std::byte*>(data), size}, .mapped = std::span<std::byte>{reinterpret_cast<std::byte*>(data), size},
.buffer_offset = offset}; .buffer_offset = offset,
};
} }
void TextureRuntime::FlushBuffers() { void TextureRuntime::FlushBuffers() {
@@ -192,11 +193,13 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
// The internal format does not provide enough guarantee of texture uniqueness // The internal format does not provide enough guarantee of texture uniqueness
// especially when many pixel formats fallback to RGBA8 // especially when many pixel formats fallback to RGBA8
ASSERT(pixel_format != VideoCore::PixelFormat::Invalid); ASSERT(pixel_format != VideoCore::PixelFormat::Invalid);
const HostTextureTag key = {.format = format, const HostTextureTag key = {
.format = format,
.pixel_format = pixel_format, .pixel_format = pixel_format,
.type = type, .type = type,
.width = width, .width = width,
.height = height}; .height = height,
};
// Attempt to recycle an unused allocation // Attempt to recycle an unused allocation
if (auto it = texture_recycler.find(key); it != texture_recycler.end()) { if (auto it = texture_recycler.find(key); it != texture_recycler.end()) {
@@ -215,14 +218,16 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
flags |= vk::ImageCreateFlagBits::eMutableFormat; flags |= vk::ImageCreateFlagBits::eMutableFormat;
} }
const vk::ImageCreateInfo image_info = {.flags = flags, const vk::ImageCreateInfo image_info = {
.flags = flags,
.imageType = vk::ImageType::e2D, .imageType = vk::ImageType::e2D,
.format = format, .format = format,
.extent = {width, height, 1}, .extent = {width, height, 1},
.mipLevels = alloc.levels, .mipLevels = alloc.levels,
.arrayLayers = alloc.layers, .arrayLayers = alloc.layers,
.samples = vk::SampleCountFlagBits::e1, .samples = vk::SampleCountFlagBits::e1,
.usage = usage}; .usage = usage,
};
const VmaAllocationCreateInfo alloc_info = { const VmaAllocationCreateInfo alloc_info = {
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
@@ -247,14 +252,19 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
type == VideoCore::TextureType::CubeMap ? vk::ImageViewType::eCube : vk::ImageViewType::e2D; type == VideoCore::TextureType::CubeMap ? vk::ImageViewType::eCube : vk::ImageViewType::e2D;
alloc.image = vk::Image{unsafe_image}; alloc.image = vk::Image{unsafe_image};
const vk::ImageViewCreateInfo view_info = {.image = alloc.image, const vk::ImageViewCreateInfo view_info = {
.image = alloc.image,
.viewType = view_type, .viewType = view_type,
.format = format, .format = format,
.subresourceRange = {.aspectMask = alloc.aspect, .subresourceRange =
{
.aspectMask = alloc.aspect,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = alloc.levels, .levelCount = alloc.levels,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = alloc.layers}}; .layerCount = alloc.layers,
},
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
alloc.image_view = device.createImageView(view_info); alloc.image_view = device.createImageView(view_info);
@@ -265,11 +275,15 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
.image = alloc.image, .image = alloc.image,
.viewType = view_type, .viewType = view_type,
.format = format, .format = format,
.subresourceRange = {.aspectMask = alloc.aspect, .subresourceRange =
{
.aspectMask = alloc.aspect,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = alloc.layers}}; .layerCount = alloc.layers,
},
};
alloc.base_view = device.createImageView(base_view_info); alloc.base_view = device.createImageView(base_view_info);
} }
@@ -280,11 +294,15 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
.image = alloc.image, .image = alloc.image,
.viewType = view_type, .viewType = view_type,
.format = format, .format = format,
.subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eDepth, .subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eDepth,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = alloc.levels, .levelCount = alloc.levels,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = alloc.layers}}; .layerCount = alloc.layers,
},
};
alloc.depth_view = device.createImageView(view_info); alloc.depth_view = device.createImageView(view_info);
view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eStencil; view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eStencil;
@@ -296,16 +314,20 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
.image = alloc.image, .image = alloc.image,
.viewType = view_type, .viewType = view_type,
.format = vk::Format::eR32Uint, .format = vk::Format::eR32Uint,
.subresourceRange = {.aspectMask = alloc.aspect, .subresourceRange =
{
.aspectMask = alloc.aspect,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = alloc.levels, .levelCount = alloc.levels,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = alloc.layers}}; .layerCount = alloc.layers,
},
};
alloc.storage_view = device.createImageView(storage_view_info); alloc.storage_view = device.createImageView(storage_view_info);
} }
scheduler.Record([image = alloc.image, scheduler.Record([image = alloc.image, aspect = alloc.aspect](vk::CommandBuffer,
aspect = alloc.aspect](vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) { vk::CommandBuffer upload_cmdbuf) {
const vk::ImageMemoryBarrier init_barrier = { const vk::ImageMemoryBarrier init_barrier = {
.srcAccessMask = vk::AccessFlagBits::eNone, .srcAccessMask = vk::AccessFlagBits::eNone,
.dstAccessMask = vk::AccessFlagBits::eNone, .dstAccessMask = vk::AccessFlagBits::eNone,
@@ -320,13 +342,12 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
.levelCount = VK_REMAINING_MIP_LEVELS, .levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}; };
upload_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, upload_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe,
vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTopOfPipe,
vk::DependencyFlagBits::eByRegion, {}, {}, init_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, init_barrier);
}); });
return alloc; return alloc;
@@ -380,14 +401,15 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
surface.type != VideoCore::SurfaceType::DepthStencil; surface.type != VideoCore::SurfaceType::DepthStencil;
if (clear.texture_rect == surface.GetScaledRect()) { if (clear.texture_rect == surface.GetScaledRect()) {
scheduler.Record([aspect = MakeAspect(surface.type), scheduler.Record([aspect = MakeAspect(surface.type), image = surface.alloc.image, value,
image = surface.alloc.image, is_color, clear](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
value, is_color, clear](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { const vk::ImageSubresourceRange range = {
const vk::ImageSubresourceRange range = {.aspectMask = aspect, .aspectMask = aspect,
.baseMipLevel = clear.texture_level, .baseMipLevel = clear.texture_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1}; .layerCount = 1,
};
const vk::ImageMemoryBarrier pre_barrier = { const vk::ImageMemoryBarrier pre_barrier = {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | .srcAccessMask = vk::AccessFlagBits::eShaderWrite |
@@ -406,12 +428,13 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}; };
const vk::ImageMemoryBarrier post_barrier = { const vk::ImageMemoryBarrier post_barrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite | .dstAccessMask =
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite |
vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentRead |
vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentRead |
@@ -428,7 +451,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
@@ -454,7 +477,8 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
return true; return true;
} }
void TextureRuntime::ClearTextureWithRenderpass(Surface& surface, const VideoCore::TextureClear& clear, void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
const VideoCore::TextureClear& clear,
VideoCore::ClearValue value) { VideoCore::ClearValue value) {
const bool is_color = surface.type != VideoCore::SurfaceType::Depth && const bool is_color = surface.type != VideoCore::SurfaceType::Depth &&
surface.type != VideoCore::SurfaceType::DepthStencil; surface.type != VideoCore::SurfaceType::DepthStencil;
@@ -470,29 +494,32 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface, const VideoCor
auto [it, new_framebuffer] = auto [it, new_framebuffer] =
clear_framebuffers.try_emplace(framebuffer_view, vk::Framebuffer{}); clear_framebuffers.try_emplace(framebuffer_view, vk::Framebuffer{});
if (new_framebuffer) { if (new_framebuffer) {
const vk::FramebufferCreateInfo framebuffer_info = {.renderPass = clear_renderpass, const vk::FramebufferCreateInfo framebuffer_info = {
.renderPass = clear_renderpass,
.attachmentCount = 1, .attachmentCount = 1,
.pAttachments = &framebuffer_view, .pAttachments = &framebuffer_view,
.width = surface.GetScaledWidth(), .width = surface.GetScaledWidth(),
.height = surface.GetScaledHeight(), .height = surface.GetScaledHeight(),
.layers = 1}; .layers = 1,
};
vk::Device device = instance.GetDevice(); it->second = instance.GetDevice().createFramebuffer(framebuffer_info);
it->second = device.createFramebuffer(framebuffer_info);
} }
const RenderpassState clear_info = { const RenderpassState clear_info = {
.renderpass = clear_renderpass, .renderpass = clear_renderpass,
.framebuffer = it->second, .framebuffer = it->second,
.render_area = vk::Rect2D{.offset = {static_cast<s32>(clear.texture_rect.left), .render_area =
vk::Rect2D{
.offset = {static_cast<s32>(clear.texture_rect.left),
static_cast<s32>(clear.texture_rect.bottom)}, static_cast<s32>(clear.texture_rect.bottom)},
.extent = {clear.texture_rect.GetWidth(), .extent = {clear.texture_rect.GetWidth(), clear.texture_rect.GetHeight()},
clear.texture_rect.GetHeight()}}, },
.clear = MakeClearValue(value) .clear = MakeClearValue(value),
}; };
scheduler.Record([aspect = MakeAspect(surface.type), scheduler.Record(
image = surface.alloc.image, [aspect = MakeAspect(surface.type), image = surface.alloc.image,
level = clear.texture_level](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { level = clear.texture_level](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::ImageMemoryBarrier pre_barrier = { const vk::ImageMemoryBarrier pre_barrier = {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | .srcAccessMask = vk::AccessFlagBits::eShaderWrite |
@@ -511,7 +538,7 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface, const VideoCor
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
@@ -522,9 +549,9 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface, const VideoCor
renderpass_cache.EnterRenderpass(clear_info); renderpass_cache.EnterRenderpass(clear_info);
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
scheduler.Record([aspect = MakeAspect(surface.type), scheduler.Record([aspect = MakeAspect(surface.type), image = surface.alloc.image,
image = surface.alloc.image, level = clear.texture_level](vk::CommandBuffer render_cmdbuf,
level = clear.texture_level](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer) {
const vk::ImageMemoryBarrier post_barrier = { const vk::ImageMemoryBarrier post_barrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite | .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite |
@@ -544,7 +571,7 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface, const VideoCor
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
@@ -557,21 +584,30 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
const VideoCore::TextureCopy& copy) { const VideoCore::TextureCopy& copy) {
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
scheduler.Record([src_image = source.alloc.image, scheduler.Record([src_image = source.alloc.image, dst_image = dest.alloc.image,
dst_image = dest.alloc.image, aspect = MakeAspect(source.type),
aspect = MakeAspect(source.type), copy](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { copy](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::ImageCopy image_copy = { const vk::ImageCopy image_copy = {
.srcSubresource = {.aspectMask = aspect, .srcSubresource =
{
.aspectMask = aspect,
.mipLevel = copy.src_level, .mipLevel = copy.src_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1}, .layerCount = 1,
.srcOffset = {static_cast<s32>(copy.src_offset.x), static_cast<s32>(copy.src_offset.y), 0}, },
.dstSubresource = {.aspectMask = aspect, .srcOffset = {static_cast<s32>(copy.src_offset.x), static_cast<s32>(copy.src_offset.y),
0},
.dstSubresource =
{
.aspectMask = aspect,
.mipLevel = copy.dst_level, .mipLevel = copy.dst_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1}, .layerCount = 1,
.dstOffset = {static_cast<s32>(copy.dst_offset.x), static_cast<s32>(copy.dst_offset.y), 0}, },
.extent = {copy.extent.width, copy.extent.height, 1}}; .dstOffset = {static_cast<s32>(copy.dst_offset.x), static_cast<s32>(copy.dst_offset.y),
0},
.extent = {copy.extent.width, copy.extent.height, 1},
};
const std::array pre_barriers = { const std::array pre_barriers = {
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
@@ -591,7 +627,7 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}, },
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | .srcAccessMask = vk::AccessFlagBits::eShaderWrite |
@@ -610,7 +646,7 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}, },
}; };
const std::array post_barriers = { const std::array post_barriers = {
@@ -628,11 +664,12 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}, },
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite | .dstAccessMask =
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite |
vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentRead |
vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentRead |
@@ -649,7 +686,7 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}, },
}; };
@@ -657,8 +694,8 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers); vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers);
render_cmdbuf.copyImage(src_image, vk::ImageLayout::eTransferSrcOptimal, render_cmdbuf.copyImage(src_image, vk::ImageLayout::eTransferSrcOptimal, dst_image,
dst_image, vk::ImageLayout::eTransferDstOptimal, image_copy); vk::ImageLayout::eTransferDstOptimal, image_copy);
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
@@ -672,30 +709,41 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
const VideoCore::TextureBlit& blit) { const VideoCore::TextureBlit& blit) {
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
scheduler.Record([src_image = source.alloc.image, scheduler.Record([src_image = source.alloc.image, aspect = MakeAspect(source.type),
aspect = MakeAspect(source.type), filter = MakeFilter(source.pixel_format), dst_image = dest.alloc.image,
filter = MakeFilter(source.pixel_format), blit](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
dst_image = dest.alloc.image, blit](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { const std::array source_offsets = {
const std::array source_offsets = {vk::Offset3D{static_cast<s32>(blit.src_rect.left), vk::Offset3D{static_cast<s32>(blit.src_rect.left),
static_cast<s32>(blit.src_rect.bottom), 0}, static_cast<s32>(blit.src_rect.bottom), 0},
vk::Offset3D{static_cast<s32>(blit.src_rect.right), vk::Offset3D{static_cast<s32>(blit.src_rect.right), static_cast<s32>(blit.src_rect.top),
static_cast<s32>(blit.src_rect.top), 1}}; 1},
};
const std::array dest_offsets = {vk::Offset3D{static_cast<s32>(blit.dst_rect.left), const std::array dest_offsets = {
vk::Offset3D{static_cast<s32>(blit.dst_rect.left),
static_cast<s32>(blit.dst_rect.bottom), 0}, static_cast<s32>(blit.dst_rect.bottom), 0},
vk::Offset3D{static_cast<s32>(blit.dst_rect.right), vk::Offset3D{static_cast<s32>(blit.dst_rect.right), static_cast<s32>(blit.dst_rect.top),
static_cast<s32>(blit.dst_rect.top), 1}}; 1},
};
const vk::ImageBlit blit_area = {.srcSubresource = {.aspectMask = aspect, const vk::ImageBlit blit_area = {
.srcSubresource =
{
.aspectMask = aspect,
.mipLevel = blit.src_level, .mipLevel = blit.src_level,
.baseArrayLayer = blit.src_layer, .baseArrayLayer = blit.src_layer,
.layerCount = 1}, .layerCount = 1,
},
.srcOffsets = source_offsets, .srcOffsets = source_offsets,
.dstSubresource = {.aspectMask = aspect, .dstSubresource =
{
.aspectMask = aspect,
.mipLevel = blit.dst_level, .mipLevel = blit.dst_level,
.baseArrayLayer = blit.dst_layer, .baseArrayLayer = blit.dst_layer,
.layerCount = 1}, .layerCount = 1,
.dstOffsets = dest_offsets}; },
.dstOffsets = dest_offsets,
};
const std::array read_barriers = { const std::array read_barriers = {
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
@@ -712,7 +760,7 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}, },
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eShaderRead | .srcAccessMask = vk::AccessFlagBits::eShaderRead |
@@ -731,9 +779,8 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
} }};
};
const std::array write_barriers = { const std::array write_barriers = {
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eNone, .srcAccessMask = vk::AccessFlagBits::eNone,
@@ -749,7 +796,7 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
}, },
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
@@ -765,17 +812,15 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
} },
} }};
};
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, read_barriers); vk::DependencyFlagBits::eByRegion, {}, {}, read_barriers);
render_cmdbuf.blitImage(src_image, vk::ImageLayout::eTransferSrcOptimal, render_cmdbuf.blitImage(src_image, vk::ImageLayout::eTransferSrcOptimal, dst_image,
dst_image, vk::ImageLayout::eTransferDstOptimal, blit_area, vk::ImageLayout::eTransferDstOptimal, blit_area, filter);
filter);
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
@@ -861,11 +906,13 @@ Surface::Surface(const VideoCore::SurfaceParams& params, vk::Format format,
Surface::~Surface() { Surface::~Surface() {
if (pixel_format != VideoCore::PixelFormat::Invalid) { if (pixel_format != VideoCore::PixelFormat::Invalid) {
const HostTextureTag tag = {.format = alloc.format, const HostTextureTag tag = {
.format = alloc.format,
.pixel_format = pixel_format, .pixel_format = pixel_format,
.type = texture_type, .type = texture_type,
.width = GetScaledWidth(), .width = GetScaledWidth(),
.height = GetScaledHeight()}; .height = GetScaledHeight(),
};
runtime.Recycle(tag, std::move(alloc)); runtime.Recycle(tag, std::move(alloc));
} }
@@ -886,8 +933,8 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
if (is_scaled) { if (is_scaled) {
ScaledUpload(upload, staging); ScaledUpload(upload, staging);
} else { } else {
scheduler.Record([aspect = alloc.aspect, image = alloc.image, scheduler.Record([aspect = alloc.aspect, image = alloc.image, format = alloc.format,
format = alloc.format, staging, upload](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { staging, upload](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
u32 num_copies = 1; u32 num_copies = 1;
std::array<vk::BufferImageCopy, 2> buffer_image_copies; std::array<vk::BufferImageCopy, 2> buffer_image_copies;
@@ -896,15 +943,20 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
.bufferOffset = staging.buffer_offset + upload.buffer_offset, .bufferOffset = staging.buffer_offset + upload.buffer_offset,
.bufferRowLength = rect.GetWidth(), .bufferRowLength = rect.GetWidth(),
.bufferImageHeight = rect.GetHeight(), .bufferImageHeight = rect.GetHeight(),
.imageSubresource = {.aspectMask = aspect, .imageSubresource =
{
.aspectMask = aspect,
.mipLevel = upload.texture_level, .mipLevel = upload.texture_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1}, .layerCount = 1,
},
.imageOffset = {static_cast<s32>(rect.left), static_cast<s32>(rect.bottom), 0}, .imageOffset = {static_cast<s32>(rect.left), static_cast<s32>(rect.bottom), 0},
.imageExtent = {rect.GetWidth(), rect.GetHeight(), 1}}; .imageExtent = {rect.GetWidth(), rect.GetHeight(), 1},
};
if (aspect & vk::ImageAspectFlagBits::eStencil) { if (aspect & vk::ImageAspectFlagBits::eStencil) {
buffer_image_copies[0].imageSubresource.aspectMask = vk::ImageAspectFlagBits::eDepth; buffer_image_copies[0].imageSubresource.aspectMask =
vk::ImageAspectFlagBits::eDepth;
vk::BufferImageCopy& stencil_copy = buffer_image_copies[1]; vk::BufferImageCopy& stencil_copy = buffer_image_copies[1];
stencil_copy = buffer_image_copies[0]; stencil_copy = buffer_image_copies[0];
stencil_copy.bufferOffset += UnpackDepthStencil(staging, format); stencil_copy.bufferOffset += UnpackDepthStencil(staging, format);
@@ -927,7 +979,8 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = image,
.subresourceRange = { .subresourceRange =
{
.aspectMask = aspect, .aspectMask = aspect,
.baseMipLevel = upload.texture_level, .baseMipLevel = upload.texture_level,
.levelCount = 1, .levelCount = 1,
@@ -943,7 +996,8 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = image,
.subresourceRange = { .subresourceRange =
{
.aspectMask = aspect, .aspectMask = aspect,
.baseMipLevel = upload.texture_level, .baseMipLevel = upload.texture_level,
.levelCount = 1, .levelCount = 1,
@@ -956,8 +1010,9 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, read_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, read_barrier);
render_cmdbuf.copyBufferToImage(staging.buffer, image, vk::ImageLayout::eTransferDstOptimal, render_cmdbuf.copyBufferToImage(staging.buffer, image,
num_copies, buffer_image_copies.data()); vk::ImageLayout::eTransferDstOptimal, num_copies,
buffer_image_copies.data());
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
@@ -987,19 +1042,23 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
if (is_scaled) { if (is_scaled) {
ScaledDownload(download, staging); ScaledDownload(download, staging);
} else { } else {
scheduler.Record([aspect = alloc.aspect, image = alloc.image, scheduler.Record([aspect = alloc.aspect, image = alloc.image, staging,
staging, download](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer){ download](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const VideoCore::Rect2D rect = download.texture_rect; const VideoCore::Rect2D rect = download.texture_rect;
const vk::BufferImageCopy buffer_image_copy = { const vk::BufferImageCopy buffer_image_copy = {
.bufferOffset = staging.buffer_offset + download.buffer_offset, .bufferOffset = staging.buffer_offset + download.buffer_offset,
.bufferRowLength = rect.GetWidth(), .bufferRowLength = rect.GetWidth(),
.bufferImageHeight = rect.GetHeight(), .bufferImageHeight = rect.GetHeight(),
.imageSubresource = {.aspectMask = aspect, .imageSubresource =
{
.aspectMask = aspect,
.mipLevel = download.texture_level, .mipLevel = download.texture_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1}, .layerCount = 1,
},
.imageOffset = {static_cast<s32>(rect.left), static_cast<s32>(rect.bottom), 0}, .imageOffset = {static_cast<s32>(rect.left), static_cast<s32>(rect.bottom), 0},
.imageExtent = {rect.GetWidth(), rect.GetHeight(), 1}}; .imageExtent = {rect.GetWidth(), rect.GetHeight(), 1},
};
const vk::ImageMemoryBarrier read_barrier = { const vk::ImageMemoryBarrier read_barrier = {
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite, .srcAccessMask = vk::AccessFlagBits::eMemoryWrite,
@@ -1009,7 +1068,8 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = image,
.subresourceRange = { .subresourceRange =
{
.aspectMask = aspect, .aspectMask = aspect,
.baseMipLevel = download.texture_level, .baseMipLevel = download.texture_level,
.levelCount = 1, .levelCount = 1,
@@ -1025,7 +1085,8 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = image,
.subresourceRange = { .subresourceRange =
{
.aspectMask = aspect, .aspectMask = aspect,
.baseMipLevel = download.texture_level, .baseMipLevel = download.texture_level,
.levelCount = 1, .levelCount = 1,
@@ -1045,10 +1106,9 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
render_cmdbuf.copyImageToBuffer(image, vk::ImageLayout::eTransferSrcOptimal, render_cmdbuf.copyImageToBuffer(image, vk::ImageLayout::eTransferSrcOptimal,
staging.buffer, buffer_image_copy); staging.buffer, buffer_image_copy);
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion, vk::DependencyFlagBits::eByRegion, memory_write_barrier, {}, image_write_barrier);
memory_write_barrier, {}, image_write_barrier);
}); });
runtime.download_buffer.Commit(staging.size); runtime.download_buffer.Commit(staging.size);
} }
@@ -1077,18 +1137,22 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const Sta
unscaled_params.res_scale = 1; unscaled_params.res_scale = 1;
Surface unscaled_surface{unscaled_params, runtime}; Surface unscaled_surface{unscaled_params, runtime};
const VideoCore::BufferTextureCopy unscaled_upload = {.buffer_offset = upload.buffer_offset, const VideoCore::BufferTextureCopy unscaled_upload = {
.buffer_offset = upload.buffer_offset,
.buffer_size = upload.buffer_size, .buffer_size = upload.buffer_size,
.texture_rect = unscaled_rect}; .texture_rect = unscaled_rect,
};
unscaled_surface.Upload(unscaled_upload, staging); unscaled_surface.Upload(unscaled_upload, staging);
const VideoCore::TextureBlit blit = {.src_level = 0, const VideoCore::TextureBlit blit = {
.src_level = 0,
.dst_level = upload.texture_level, .dst_level = upload.texture_level,
.src_layer = 0, .src_layer = 0,
.dst_layer = 0, .dst_layer = 0,
.src_rect = unscaled_rect, .src_rect = unscaled_rect,
.dst_rect = scaled_rect}; .dst_rect = scaled_rect,
};
runtime.BlitTextures(unscaled_surface, *this, blit); runtime.BlitTextures(unscaled_surface, *this, blit);
} }
@@ -1108,20 +1172,24 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
unscaled_params.res_scale = 1; unscaled_params.res_scale = 1;
Surface unscaled_surface{unscaled_params, runtime}; Surface unscaled_surface{unscaled_params, runtime};
const VideoCore::TextureBlit blit = {.src_level = download.texture_level, const VideoCore::TextureBlit blit = {
.src_level = download.texture_level,
.dst_level = 0, .dst_level = 0,
.src_layer = 0, .src_layer = 0,
.dst_layer = 0, .dst_layer = 0,
.src_rect = scaled_rect, .src_rect = scaled_rect,
.dst_rect = unscaled_rect}; .dst_rect = unscaled_rect,
};
// Blit the scaled rectangle to the unscaled texture // Blit the scaled rectangle to the unscaled texture
runtime.BlitTextures(*this, unscaled_surface, blit); runtime.BlitTextures(*this, unscaled_surface, blit);
const VideoCore::BufferTextureCopy unscaled_download = {.buffer_offset = download.buffer_offset, const VideoCore::BufferTextureCopy unscaled_download = {
.buffer_offset = download.buffer_offset,
.buffer_size = download.buffer_size, .buffer_size = download.buffer_size,
.texture_rect = unscaled_rect, .texture_rect = unscaled_rect,
.texture_level = 0}; .texture_level = 0,
};
unscaled_surface.Download(unscaled_download, staging); unscaled_surface.Download(unscaled_download, staging);
} }
@@ -1149,32 +1217,38 @@ void Surface::DepthStencilDownload(const VideoCore::BufferTextureCopy& download,
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eStorage, vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eStorage,
runtime}; runtime};
const VideoCore::TextureBlit blit = {.src_level = download.texture_level, const VideoCore::TextureBlit blit = {
.src_level = download.texture_level,
.dst_level = 0, .dst_level = 0,
.src_layer = 0, .src_layer = 0,
.dst_layer = 0, .dst_layer = 0,
.src_rect = scaled_rect, .src_rect = scaled_rect,
.dst_rect = r32_scaled_rect}; .dst_rect = r32_scaled_rect,
};
runtime.blit_helper.BlitD24S8ToR32(*this, r32_surface, blit); runtime.blit_helper.BlitD24S8ToR32(*this, r32_surface, blit);
// Blit the upper mip level to the lower one to scale without additional allocations // Blit the upper mip level to the lower one to scale without additional allocations
const bool is_scaled = res_scale != 1; const bool is_scaled = res_scale != 1;
if (is_scaled) { if (is_scaled) {
const VideoCore::TextureBlit r32_blit = {.src_level = 0, const VideoCore::TextureBlit r32_blit = {
.src_level = 0,
.dst_level = 1, .dst_level = 1,
.src_layer = 0, .src_layer = 0,
.dst_layer = 0, .dst_layer = 0,
.src_rect = r32_scaled_rect, .src_rect = r32_scaled_rect,
.dst_rect = unscaled_rect}; .dst_rect = unscaled_rect,
};
runtime.BlitTextures(r32_surface, r32_surface, r32_blit); runtime.BlitTextures(r32_surface, r32_surface, r32_blit);
} }
const VideoCore::BufferTextureCopy r32_download = {.buffer_offset = download.buffer_offset, const VideoCore::BufferTextureCopy r32_download = {
.buffer_offset = download.buffer_offset,
.buffer_size = download.buffer_size, .buffer_size = download.buffer_size,
.texture_rect = unscaled_rect, .texture_rect = unscaled_rect,
.texture_level = is_scaled ? 1u : 0u}; .texture_level = is_scaled ? 1u : 0u,
};
r32_surface.Download(r32_download, staging); r32_surface.Download(r32_download, staging);
} }