2022-04-23 10:59:50 +02:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2020-01-07 01:25:14 +01:00
|
|
|
|
2021-06-02 07:15:07 +02:00
|
|
|
#include <algorithm>
|
2020-01-07 01:25:14 +01:00
|
|
|
#include <vector>
|
|
|
|
|
2021-02-17 04:59:28 +01:00
|
|
|
#include <boost/container/small_vector.hpp>
|
|
|
|
|
2021-03-19 23:28:31 +01:00
|
|
|
#include "video_core/renderer_vulkan/pipeline_helper.h"
|
2021-07-28 00:15:32 +02:00
|
|
|
#include "video_core/renderer_vulkan/pipeline_statistics.h"
|
2021-02-17 04:59:28 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
2020-01-07 01:25:14 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
2021-06-06 05:11:36 +02:00
|
|
|
#include "video_core/shader_notify.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-07 01:25:14 +01:00
|
|
|
|
|
|
|
namespace Vulkan {
|
2021-02-17 04:59:28 +01:00
|
|
|
|
2021-05-23 09:28:34 +02:00
|
|
|
using Shader::ImageBufferDescriptor;
|
2021-10-16 06:30:43 +02:00
|
|
|
using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET;
|
2021-05-23 09:28:34 +02:00
|
|
|
using Tegra::Texture::TexturePair;
|
|
|
|
|
2021-04-25 06:04:49 +02:00
|
|
|
ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool,
|
2022-06-26 06:51:37 +02:00
|
|
|
UpdateDescriptorQueue& update_descriptor_queue_,
|
2021-06-06 05:11:36 +02:00
|
|
|
Common::ThreadWorker* thread_worker,
|
2021-07-28 00:15:32 +02:00
|
|
|
PipelineStatistics* pipeline_statistics,
|
2021-06-06 05:11:36 +02:00
|
|
|
VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_,
|
2021-04-01 06:36:22 +02:00
|
|
|
vk::ShaderModule spv_module_)
|
2021-04-25 06:04:49 +02:00
|
|
|
: device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_},
|
2021-03-19 23:28:31 +01:00
|
|
|
spv_module(std::move(spv_module_)) {
|
2021-06-06 05:11:36 +02:00
|
|
|
if (shader_notify) {
|
|
|
|
shader_notify->MarkShaderBuilding();
|
|
|
|
}
|
2021-06-02 07:15:07 +02:00
|
|
|
std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(),
|
|
|
|
uniform_buffer_sizes.begin());
|
|
|
|
|
2021-07-28 00:15:32 +02:00
|
|
|
auto func{[this, &descriptor_pool, shader_notify, pipeline_statistics] {
|
2021-06-17 02:14:57 +02:00
|
|
|
DescriptorLayoutBuilder builder{device};
|
2021-04-25 06:04:49 +02:00
|
|
|
builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT);
|
2021-04-01 08:15:28 +02:00
|
|
|
|
2021-06-17 02:14:57 +02:00
|
|
|
descriptor_set_layout = builder.CreateDescriptorSetLayout(false);
|
2021-04-25 06:04:49 +02:00
|
|
|
pipeline_layout = builder.CreatePipelineLayout(*descriptor_set_layout);
|
|
|
|
descriptor_update_template =
|
2021-06-17 02:14:57 +02:00
|
|
|
builder.CreateTemplate(*descriptor_set_layout, *pipeline_layout, false);
|
2021-04-25 06:04:49 +02:00
|
|
|
descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, info);
|
2021-04-01 06:36:22 +02:00
|
|
|
const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.requiredSubgroupSize = GuestWarpSize,
|
|
|
|
};
|
2021-07-28 00:15:32 +02:00
|
|
|
VkPipelineCreateFlags flags{};
|
|
|
|
if (device.IsKhrPipelineEexecutablePropertiesEnabled()) {
|
|
|
|
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
|
|
|
|
}
|
2021-04-01 06:36:22 +02:00
|
|
|
pipeline = device.GetLogical().CreateComputePipeline({
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
2021-07-28 00:15:32 +02:00
|
|
|
.flags = flags,
|
2021-04-01 06:36:22 +02:00
|
|
|
.stage{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
|
.pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr,
|
|
|
|
.flags = 0,
|
|
|
|
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
|
|
.module = *spv_module,
|
|
|
|
.pName = "main",
|
|
|
|
.pSpecializationInfo = nullptr,
|
|
|
|
},
|
|
|
|
.layout = *pipeline_layout,
|
|
|
|
.basePipelineHandle = 0,
|
|
|
|
.basePipelineIndex = 0,
|
|
|
|
});
|
2021-07-28 00:15:32 +02:00
|
|
|
if (pipeline_statistics) {
|
|
|
|
pipeline_statistics->Collect(*pipeline);
|
|
|
|
}
|
2022-04-07 20:32:40 +02:00
|
|
|
std::scoped_lock lock{build_mutex};
|
2021-04-04 02:41:49 +02:00
|
|
|
is_built = true;
|
|
|
|
build_condvar.notify_one();
|
2021-06-06 05:11:36 +02:00
|
|
|
if (shader_notify) {
|
|
|
|
shader_notify->MarkShaderComplete();
|
|
|
|
}
|
2021-04-01 06:36:22 +02:00
|
|
|
}};
|
|
|
|
if (thread_worker) {
|
|
|
|
thread_worker->QueueWork(std::move(func));
|
|
|
|
} else {
|
|
|
|
func();
|
|
|
|
}
|
2021-03-19 23:28:31 +01:00
|
|
|
}
|
2021-02-17 04:59:28 +01:00
|
|
|
|
2021-04-01 06:36:22 +02:00
|
|
|
void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
|
2022-06-26 06:34:24 +02:00
|
|
|
Tegra::MemoryManager& gpu_memory, Scheduler& scheduler,
|
2021-04-01 06:36:22 +02:00
|
|
|
BufferCache& buffer_cache, TextureCache& texture_cache) {
|
|
|
|
update_descriptor_queue.Acquire();
|
|
|
|
|
2021-06-02 07:15:07 +02:00
|
|
|
buffer_cache.SetComputeUniformBufferState(info.constant_buffer_mask, &uniform_buffer_sizes);
|
2021-02-17 04:59:28 +01:00
|
|
|
buffer_cache.UnbindComputeStorageBuffers();
|
2021-04-01 06:36:22 +02:00
|
|
|
size_t ssbo_index{};
|
2021-02-17 04:59:28 +01:00
|
|
|
for (const auto& desc : info.storage_buffers_descriptors) {
|
|
|
|
ASSERT(desc.count == 1);
|
2021-04-04 02:41:49 +02:00
|
|
|
buffer_cache.BindComputeStorageBuffer(ssbo_index, desc.cbuf_index, desc.cbuf_offset,
|
|
|
|
desc.is_written);
|
2021-04-01 06:36:22 +02:00
|
|
|
++ssbo_index;
|
2021-02-17 04:59:28 +01:00
|
|
|
}
|
2020-01-07 01:25:14 +01:00
|
|
|
|
2021-03-08 22:31:53 +01:00
|
|
|
texture_cache.SynchronizeComputeDescriptors();
|
|
|
|
|
|
|
|
static constexpr size_t max_elements = 64;
|
2021-07-28 07:47:06 +02:00
|
|
|
boost::container::static_vector<VideoCommon::ImageViewInOut, max_elements> views;
|
2021-03-19 23:28:31 +01:00
|
|
|
boost::container::static_vector<VkSampler, max_elements> samplers;
|
2021-03-08 22:31:53 +01:00
|
|
|
|
2021-04-21 00:48:45 +02:00
|
|
|
const auto& qmd{kepler_compute.launch_description};
|
|
|
|
const auto& cbufs{qmd.const_buffer_config};
|
|
|
|
const bool via_header_index{qmd.linked_tsc != 0};
|
2021-04-22 21:17:59 +02:00
|
|
|
const auto read_handle{[&](const auto& desc, u32 index) {
|
2021-04-21 00:48:45 +02:00
|
|
|
ASSERT(((qmd.const_buffer_enable_mask >> desc.cbuf_index) & 1) != 0);
|
2021-04-22 21:17:59 +02:00
|
|
|
const u32 index_offset{index << desc.size_shift};
|
|
|
|
const u32 offset{desc.cbuf_offset + index_offset};
|
2021-04-23 07:38:02 +02:00
|
|
|
const GPUVAddr addr{cbufs[desc.cbuf_index].Address() + offset};
|
2021-04-21 00:48:45 +02:00
|
|
|
if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> ||
|
|
|
|
std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) {
|
|
|
|
if (desc.has_secondary) {
|
|
|
|
ASSERT(((qmd.const_buffer_enable_mask >> desc.secondary_cbuf_index) & 1) != 0);
|
2021-04-22 21:17:59 +02:00
|
|
|
const u32 secondary_offset{desc.secondary_cbuf_offset + index_offset};
|
2021-04-21 00:48:45 +02:00
|
|
|
const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() +
|
2021-04-22 21:17:59 +02:00
|
|
|
secondary_offset};
|
2021-04-21 00:48:45 +02:00
|
|
|
const u32 lhs_raw{gpu_memory.Read<u32>(addr)};
|
|
|
|
const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)};
|
2021-05-23 09:28:34 +02:00
|
|
|
return TexturePair(lhs_raw | rhs_raw, via_header_index);
|
2021-04-21 00:48:45 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-23 09:28:34 +02:00
|
|
|
return TexturePair(gpu_memory.Read<u32>(addr), via_header_index);
|
2021-04-06 07:56:15 +02:00
|
|
|
}};
|
2021-07-28 07:47:06 +02:00
|
|
|
const auto add_image{[&](const auto& desc, bool blacklist) {
|
2021-04-22 21:17:59 +02:00
|
|
|
for (u32 index = 0; index < desc.count; ++index) {
|
2021-05-23 09:28:34 +02:00
|
|
|
const auto handle{read_handle(desc, index)};
|
2021-07-28 07:47:06 +02:00
|
|
|
views.push_back({
|
|
|
|
.index = handle.first,
|
|
|
|
.blacklist = blacklist,
|
|
|
|
.id = {},
|
|
|
|
});
|
2021-04-22 21:17:59 +02:00
|
|
|
}
|
2021-04-15 02:36:36 +02:00
|
|
|
}};
|
2021-07-28 07:47:06 +02:00
|
|
|
for (const auto& desc : info.texture_buffer_descriptors) {
|
|
|
|
add_image(desc, false);
|
|
|
|
}
|
|
|
|
for (const auto& desc : info.image_buffer_descriptors) {
|
|
|
|
add_image(desc, false);
|
|
|
|
}
|
2021-04-06 07:56:15 +02:00
|
|
|
for (const auto& desc : info.texture_descriptors) {
|
2021-04-22 21:17:59 +02:00
|
|
|
for (u32 index = 0; index < desc.count; ++index) {
|
2021-05-23 09:28:34 +02:00
|
|
|
const auto handle{read_handle(desc, index)};
|
2021-07-28 07:47:06 +02:00
|
|
|
views.push_back({handle.first});
|
2021-03-08 22:31:53 +01:00
|
|
|
|
2021-05-23 09:28:34 +02:00
|
|
|
Sampler* const sampler = texture_cache.GetComputeSampler(handle.second);
|
2021-04-22 21:17:59 +02:00
|
|
|
samplers.push_back(sampler->Handle());
|
|
|
|
}
|
2021-03-08 22:31:53 +01:00
|
|
|
}
|
2021-07-26 09:33:00 +02:00
|
|
|
for (const auto& desc : info.image_descriptors) {
|
2021-08-01 07:26:02 +02:00
|
|
|
add_image(desc, desc.is_written);
|
2021-07-26 09:33:00 +02:00
|
|
|
}
|
2021-07-28 07:47:06 +02:00
|
|
|
texture_cache.FillComputeImageViews(std::span(views.data(), views.size()));
|
2021-03-08 22:31:53 +01:00
|
|
|
|
2021-04-07 01:14:55 +02:00
|
|
|
buffer_cache.UnbindComputeTextureBuffers();
|
|
|
|
size_t index{};
|
2021-04-15 02:36:36 +02:00
|
|
|
const auto add_buffer{[&](const auto& desc) {
|
2021-05-23 09:28:34 +02:00
|
|
|
constexpr bool is_image = std::is_same_v<decltype(desc), const ImageBufferDescriptor&>;
|
2021-04-24 02:24:30 +02:00
|
|
|
for (u32 i = 0; i < desc.count; ++i) {
|
2021-04-22 21:17:59 +02:00
|
|
|
bool is_written{false};
|
2021-05-23 09:28:34 +02:00
|
|
|
if constexpr (is_image) {
|
2021-04-22 21:17:59 +02:00
|
|
|
is_written = desc.is_written;
|
|
|
|
}
|
2021-07-28 07:47:06 +02:00
|
|
|
ImageView& image_view = texture_cache.GetImageView(views[index].id);
|
2021-04-22 21:17:59 +02:00
|
|
|
buffer_cache.BindComputeTextureBuffer(index, image_view.GpuAddr(),
|
|
|
|
image_view.BufferSize(), image_view.format,
|
2021-05-23 09:28:34 +02:00
|
|
|
is_written, is_image);
|
2021-04-22 21:17:59 +02:00
|
|
|
++index;
|
2021-04-15 02:36:36 +02:00
|
|
|
}
|
|
|
|
}};
|
|
|
|
std::ranges::for_each(info.texture_buffer_descriptors, add_buffer);
|
|
|
|
std::ranges::for_each(info.image_buffer_descriptors, add_buffer);
|
|
|
|
|
2021-04-07 01:14:55 +02:00
|
|
|
buffer_cache.UpdateComputeBuffers();
|
|
|
|
buffer_cache.BindHostComputeBuffers();
|
|
|
|
|
2021-10-16 06:30:43 +02:00
|
|
|
RescalingPushConstant rescaling;
|
2021-04-07 01:14:55 +02:00
|
|
|
const VkSampler* samplers_it{samplers.data()};
|
2021-07-28 07:47:06 +02:00
|
|
|
const VideoCommon::ImageViewInOut* views_it{views.data()};
|
|
|
|
PushImageDescriptors(texture_cache, update_descriptor_queue, info, rescaling, samplers_it,
|
|
|
|
views_it);
|
2021-03-08 22:31:53 +01:00
|
|
|
|
2021-04-04 02:41:49 +02:00
|
|
|
if (!is_built.load(std::memory_order::relaxed)) {
|
2021-04-01 06:36:22 +02:00
|
|
|
// Wait for the pipeline to be built
|
2021-04-04 02:41:49 +02:00
|
|
|
scheduler.Record([this](vk::CommandBuffer) {
|
|
|
|
std::unique_lock lock{build_mutex};
|
|
|
|
build_condvar.wait(lock, [this] { return is_built.load(std::memory_order::relaxed); });
|
|
|
|
});
|
2021-04-01 06:36:22 +02:00
|
|
|
}
|
2021-04-25 06:04:49 +02:00
|
|
|
const void* const descriptor_data{update_descriptor_queue.UpdateData()};
|
2021-10-16 06:30:43 +02:00
|
|
|
const bool is_rescaling = !info.texture_descriptors.empty() || !info.image_descriptors.empty();
|
|
|
|
scheduler.Record([this, descriptor_data, is_rescaling,
|
|
|
|
rescaling_data = rescaling.Data()](vk::CommandBuffer cmdbuf) {
|
|
|
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
|
|
|
if (!descriptor_set_layout) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (is_rescaling) {
|
|
|
|
cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT,
|
|
|
|
RESCALING_LAYOUT_WORDS_OFFSET, sizeof(rescaling_data),
|
|
|
|
rescaling_data.data());
|
|
|
|
}
|
|
|
|
const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()};
|
|
|
|
const vk::Device& dev{device.GetLogical()};
|
|
|
|
dev.UpdateDescriptorSet(descriptor_set, *descriptor_update_template, descriptor_data);
|
|
|
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0,
|
|
|
|
descriptor_set, nullptr);
|
|
|
|
});
|
2021-02-17 04:59:28 +01:00
|
|
|
}
|
2020-01-07 01:25:14 +01:00
|
|
|
|
|
|
|
} // namespace Vulkan
|