2020-01-08 23:24:26 +01:00
|
|
|
// Copyright 2019 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
#include <memory>
|
|
|
|
#include <optional>
|
|
|
|
#include <utility>
|
2020-04-20 00:41:54 +02:00
|
|
|
|
2020-01-08 23:24:26 +01:00
|
|
|
#include "common/alignment.h"
|
|
|
|
#include "common/assert.h"
|
|
|
|
#include "common/common_types.h"
|
2020-12-30 06:25:23 +01:00
|
|
|
#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
|
|
|
|
#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
|
2020-01-08 23:24:26 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
2020-12-26 05:19:46 +01:00
|
|
|
#include "video_core/vulkan_common/vulkan_device.h"
|
2020-12-25 01:30:11 +01:00
|
|
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
2020-01-08 23:24:26 +01:00
|
|
|
|
|
|
|
namespace Vulkan {
|
|
|
|
namespace {
|
2020-04-14 22:54:45 +02:00
|
|
|
VkPushConstantRange BuildComputePushConstantRange(std::size_t size) {
|
2020-07-16 23:23:53 +02:00
|
|
|
return {
|
|
|
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
|
|
.offset = 0,
|
|
|
|
.size = static_cast<u32>(size),
|
|
|
|
};
|
2020-03-27 05:33:21 +01:00
|
|
|
}
|
|
|
|
|
2020-04-14 22:54:45 +02:00
|
|
|
std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() {
|
2020-07-16 23:23:53 +02:00
|
|
|
return {{
|
|
|
|
{
|
|
|
|
.binding = 0,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
|
|
.pImmutableSamplers = nullptr,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.binding = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
|
|
.pImmutableSamplers = nullptr,
|
|
|
|
},
|
|
|
|
}};
|
2020-03-27 05:33:21 +01:00
|
|
|
}
|
|
|
|
|
2020-04-14 22:54:45 +02:00
|
|
|
VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
|
2020-07-16 23:23:53 +02:00
|
|
|
return {
|
|
|
|
.dstBinding = 0,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorCount = 2,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
|
|
.offset = 0,
|
|
|
|
.stride = sizeof(DescriptorUpdateEntry),
|
|
|
|
};
|
2020-03-27 05:33:21 +01:00
|
|
|
}
|
|
|
|
|
2020-01-08 23:24:26 +01:00
|
|
|
} // Anonymous namespace
|
|
|
|
|
2020-12-26 05:10:53 +01:00
|
|
|
VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool,
|
2020-03-27 05:33:21 +01:00
|
|
|
vk::Span<VkDescriptorSetLayoutBinding> bindings,
|
|
|
|
vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates,
|
2020-12-30 06:25:23 +01:00
|
|
|
vk::Span<VkPushConstantRange> push_constants,
|
|
|
|
std::span<const u32> code) {
|
2020-07-16 23:23:53 +02:00
|
|
|
descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout({
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.bindingCount = bindings.size(),
|
|
|
|
.pBindings = bindings.data(),
|
|
|
|
});
|
|
|
|
layout = device.GetLogical().CreatePipelineLayout({
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.setLayoutCount = 1,
|
|
|
|
.pSetLayouts = descriptor_set_layout.address(),
|
|
|
|
.pushConstantRangeCount = push_constants.size(),
|
|
|
|
.pPushConstantRanges = push_constants.data(),
|
|
|
|
});
|
2020-01-08 23:24:26 +01:00
|
|
|
if (!templates.empty()) {
|
2020-07-16 23:23:53 +02:00
|
|
|
descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR({
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.descriptorUpdateEntryCount = templates.size(),
|
|
|
|
.pDescriptorUpdateEntries = templates.data(),
|
|
|
|
.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR,
|
|
|
|
.descriptorSetLayout = *descriptor_set_layout,
|
|
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
|
|
.pipelineLayout = *layout,
|
|
|
|
.set = 0,
|
|
|
|
});
|
2020-01-08 23:24:26 +01:00
|
|
|
|
|
|
|
descriptor_allocator.emplace(descriptor_pool, *descriptor_set_layout);
|
|
|
|
}
|
2020-07-16 23:23:53 +02:00
|
|
|
module = device.GetLogical().CreateShaderModule({
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
2020-12-30 06:25:23 +01:00
|
|
|
.codeSize = static_cast<u32>(code.size_bytes()),
|
|
|
|
.pCode = code.data(),
|
2020-07-16 23:23:53 +02:00
|
|
|
});
|
|
|
|
pipeline = device.GetLogical().CreateComputePipeline({
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.stage =
|
|
|
|
{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
|
|
.module = *module,
|
|
|
|
.pName = "main",
|
|
|
|
.pSpecializationInfo = nullptr,
|
|
|
|
},
|
|
|
|
.layout = *layout,
|
|
|
|
.basePipelineHandle = nullptr,
|
|
|
|
.basePipelineIndex = 0,
|
|
|
|
});
|
2020-01-08 23:24:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
VKComputePass::~VKComputePass() = default;
|
|
|
|
|
2020-09-10 08:43:30 +02:00
|
|
|
VkDescriptorSet VKComputePass::CommitDescriptorSet(
|
|
|
|
VKUpdateDescriptorQueue& update_descriptor_queue) {
|
2020-01-08 23:24:26 +01:00
|
|
|
if (!descriptor_template) {
|
2020-03-27 05:33:21 +01:00
|
|
|
return nullptr;
|
2020-01-08 23:24:26 +01:00
|
|
|
}
|
2020-09-10 08:43:30 +02:00
|
|
|
const VkDescriptorSet set = descriptor_allocator->Commit();
|
2020-01-08 23:24:26 +01:00
|
|
|
update_descriptor_queue.Send(*descriptor_template, set);
|
|
|
|
return set;
|
|
|
|
}
|
|
|
|
|
2020-12-26 05:10:53 +01:00
|
|
|
Uint8Pass::Uint8Pass(const Device& device, VKScheduler& scheduler_,
|
2020-12-31 02:58:05 +01:00
|
|
|
VKDescriptorPool& descriptor_pool, StagingBufferPool& staging_buffer_pool_,
|
2020-12-05 10:51:14 +01:00
|
|
|
VKUpdateDescriptorQueue& update_descriptor_queue_)
|
2020-12-30 06:25:23 +01:00
|
|
|
: VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(),
|
|
|
|
BuildInputOutputDescriptorUpdateTemplate(), {}, VULKAN_UINT8_COMP_SPV),
|
2020-12-05 10:51:14 +01:00
|
|
|
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
|
|
|
|
update_descriptor_queue{update_descriptor_queue_} {}
|
2020-01-08 23:24:26 +01:00
|
|
|
|
|
|
|
Uint8Pass::~Uint8Pass() = default;
|
|
|
|
|
2021-01-17 00:48:58 +01:00
|
|
|
std::pair<VkBuffer, u32> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer,
|
|
|
|
u32 src_offset) {
|
2020-09-10 08:43:30 +02:00
|
|
|
const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16));
|
2021-01-17 00:48:58 +01:00
|
|
|
const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal);
|
2020-01-08 23:24:26 +01:00
|
|
|
|
|
|
|
update_descriptor_queue.Acquire();
|
2020-04-04 07:54:55 +02:00
|
|
|
update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices);
|
2021-01-17 00:48:58 +01:00
|
|
|
update_descriptor_queue.AddBuffer(staging.buffer, 0, staging_size);
|
2020-09-10 08:43:30 +02:00
|
|
|
const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue);
|
2020-01-08 23:24:26 +01:00
|
|
|
|
|
|
|
scheduler.RequestOutsideRenderPassOperationContext();
|
2021-01-17 00:48:58 +01:00
|
|
|
scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging.buffer, set,
|
2020-03-27 05:33:21 +01:00
|
|
|
num_vertices](vk::CommandBuffer cmdbuf) {
|
2020-01-08 23:24:26 +01:00
|
|
|
constexpr u32 dispatch_size = 1024;
|
2020-03-27 05:33:21 +01:00
|
|
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
|
|
|
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, set, {});
|
|
|
|
cmdbuf.Dispatch(Common::AlignUp(num_vertices, dispatch_size) / dispatch_size, 1, 1);
|
|
|
|
|
|
|
|
VkBufferMemoryBarrier barrier;
|
|
|
|
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
|
|
|
barrier.pNext = nullptr;
|
|
|
|
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
|
|
|
barrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
|
|
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
|
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
|
|
barrier.buffer = buffer;
|
|
|
|
barrier.offset = 0;
|
|
|
|
barrier.size = static_cast<VkDeviceSize>(num_vertices * sizeof(u16));
|
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
|
|
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {});
|
2020-01-08 23:24:26 +01:00
|
|
|
});
|
2021-01-17 00:48:58 +01:00
|
|
|
return {staging.buffer, 0};
|
2020-01-08 23:24:26 +01:00
|
|
|
}
|
|
|
|
|
2020-12-26 05:10:53 +01:00
|
|
|
QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_,
|
2020-12-05 10:51:14 +01:00
|
|
|
VKDescriptorPool& descriptor_pool_,
|
2020-12-31 02:58:05 +01:00
|
|
|
StagingBufferPool& staging_buffer_pool_,
|
2020-12-05 10:51:14 +01:00
|
|
|
VKUpdateDescriptorQueue& update_descriptor_queue_)
|
|
|
|
: VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(),
|
2020-04-14 22:54:45 +02:00
|
|
|
BuildInputOutputDescriptorUpdateTemplate(),
|
2020-12-30 06:25:23 +01:00
|
|
|
BuildComputePushConstantRange(sizeof(u32) * 2), VULKAN_QUAD_INDEXED_COMP_SPV),
|
2020-12-05 10:51:14 +01:00
|
|
|
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
|
|
|
|
update_descriptor_queue{update_descriptor_queue_} {}
|
2020-04-14 22:54:45 +02:00
|
|
|
|
|
|
|
QuadIndexedPass::~QuadIndexedPass() = default;
|
|
|
|
|
2021-01-17 00:48:58 +01:00
|
|
|
std::pair<VkBuffer, u32> QuadIndexedPass::Assemble(
|
2020-04-14 22:54:45 +02:00
|
|
|
Tegra::Engines::Maxwell3D::Regs::IndexFormat index_format, u32 num_vertices, u32 base_vertex,
|
2021-01-17 00:48:58 +01:00
|
|
|
VkBuffer src_buffer, u32 src_offset) {
|
2020-04-14 22:54:45 +02:00
|
|
|
const u32 index_shift = [index_format] {
|
|
|
|
switch (index_format) {
|
|
|
|
case Tegra::Engines::Maxwell3D::Regs::IndexFormat::UnsignedByte:
|
|
|
|
return 0;
|
|
|
|
case Tegra::Engines::Maxwell3D::Regs::IndexFormat::UnsignedShort:
|
|
|
|
return 1;
|
|
|
|
case Tegra::Engines::Maxwell3D::Regs::IndexFormat::UnsignedInt:
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return 2;
|
|
|
|
}();
|
|
|
|
const u32 input_size = num_vertices << index_shift;
|
|
|
|
const u32 num_tri_vertices = (num_vertices / 4) * 6;
|
|
|
|
|
|
|
|
const std::size_t staging_size = num_tri_vertices * sizeof(u32);
|
2021-01-17 00:48:58 +01:00
|
|
|
const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal);
|
2020-04-14 22:54:45 +02:00
|
|
|
|
|
|
|
update_descriptor_queue.Acquire();
|
|
|
|
update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size);
|
2021-01-17 00:48:58 +01:00
|
|
|
update_descriptor_queue.AddBuffer(staging.buffer, 0, staging_size);
|
2020-09-10 08:43:30 +02:00
|
|
|
const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue);
|
2020-04-14 22:54:45 +02:00
|
|
|
|
|
|
|
scheduler.RequestOutsideRenderPassOperationContext();
|
2021-01-17 00:48:58 +01:00
|
|
|
scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging.buffer, set,
|
2020-04-14 22:54:45 +02:00
|
|
|
num_tri_vertices, base_vertex, index_shift](vk::CommandBuffer cmdbuf) {
|
|
|
|
static constexpr u32 dispatch_size = 1024;
|
|
|
|
const std::array push_constants = {base_vertex, index_shift};
|
|
|
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
|
|
|
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, set, {});
|
|
|
|
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(push_constants),
|
|
|
|
&push_constants);
|
|
|
|
cmdbuf.Dispatch(Common::AlignUp(num_tri_vertices, dispatch_size) / dispatch_size, 1, 1);
|
|
|
|
|
|
|
|
VkBufferMemoryBarrier barrier;
|
|
|
|
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
|
|
|
barrier.pNext = nullptr;
|
|
|
|
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
|
|
|
barrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
|
|
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
|
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
|
|
barrier.buffer = buffer;
|
|
|
|
barrier.offset = 0;
|
|
|
|
barrier.size = static_cast<VkDeviceSize>(num_tri_vertices * sizeof(u32));
|
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
|
|
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {});
|
|
|
|
});
|
2021-01-17 00:48:58 +01:00
|
|
|
return {staging.buffer, 0};
|
2020-04-14 22:54:45 +02:00
|
|
|
}
|
|
|
|
|
2020-01-08 23:24:26 +01:00
|
|
|
} // namespace Vulkan
|