2020-01-07 01:18:38 +01:00
|
|
|
// Copyright 2019 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2020-01-07 01:55:06 +01:00
|
|
|
#include <algorithm>
|
2020-01-07 01:18:38 +01:00
|
|
|
#include <cstddef>
|
2020-01-07 01:55:06 +01:00
|
|
|
#include <memory>
|
2020-01-07 01:18:38 +01:00
|
|
|
#include <vector>
|
|
|
|
|
2020-01-07 01:55:06 +01:00
|
|
|
#include "common/microprofile.h"
|
|
|
|
#include "core/core.h"
|
|
|
|
#include "core/memory.h"
|
|
|
|
#include "video_core/engines/kepler_compute.h"
|
|
|
|
#include "video_core/engines/maxwell_3d.h"
|
|
|
|
#include "video_core/memory_manager.h"
|
|
|
|
#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
|
|
|
|
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
2020-01-07 01:18:38 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_device.h"
|
2020-01-07 01:55:06 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
2020-01-07 01:18:38 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
2020-01-07 01:55:06 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
2020-01-07 01:18:38 +01:00
|
|
|
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
2020-03-27 05:33:21 +01:00
|
|
|
#include "video_core/renderer_vulkan/wrapper.h"
|
2020-01-07 01:55:06 +01:00
|
|
|
#include "video_core/shader/compiler_settings.h"
|
2020-04-24 06:44:14 +02:00
|
|
|
#include "video_core/shader/memory_util.h"
|
2020-05-23 02:01:36 +02:00
|
|
|
#include "video_core/shader_cache.h"
|
2020-01-07 01:18:38 +01:00
|
|
|
|
|
|
|
namespace Vulkan {
|
|
|
|
|
2020-01-07 01:55:06 +01:00
|
|
|
MICROPROFILE_DECLARE(Vulkan_PipelineCache);
|
|
|
|
|
|
|
|
using Tegra::Engines::ShaderType;
|
2020-04-24 06:44:14 +02:00
|
|
|
using VideoCommon::Shader::GetShaderAddress;
|
|
|
|
using VideoCommon::Shader::GetShaderCode;
|
|
|
|
using VideoCommon::Shader::KERNEL_MAIN_OFFSET;
|
|
|
|
using VideoCommon::Shader::ProgramCode;
|
|
|
|
using VideoCommon::Shader::STAGE_MAIN_OFFSET;
|
2020-01-07 01:55:06 +01:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2020-03-27 05:33:21 +01:00
|
|
|
constexpr VkDescriptorType UNIFORM_BUFFER = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
|
|
constexpr VkDescriptorType STORAGE_BUFFER = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
|
|
|
constexpr VkDescriptorType UNIFORM_TEXEL_BUFFER = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
|
|
|
|
constexpr VkDescriptorType COMBINED_IMAGE_SAMPLER = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
2020-06-02 02:41:07 +02:00
|
|
|
constexpr VkDescriptorType STORAGE_TEXEL_BUFFER = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
|
2020-03-27 05:33:21 +01:00
|
|
|
constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
2020-02-23 06:35:16 +01:00
|
|
|
|
2020-01-07 01:55:06 +01:00
|
|
|
constexpr VideoCommon::Shader::CompilerSettings compiler_settings{
|
|
|
|
VideoCommon::Shader::CompileDepth::FullDecompile};
|
|
|
|
|
|
|
|
constexpr std::size_t GetStageFromProgram(std::size_t program) {
|
|
|
|
return program == 0 ? 0 : program - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr ShaderType GetStageFromProgram(Maxwell::ShaderProgram program) {
|
|
|
|
return static_cast<ShaderType>(GetStageFromProgram(static_cast<std::size_t>(program)));
|
|
|
|
}
|
|
|
|
|
|
|
|
ShaderType GetShaderType(Maxwell::ShaderProgram program) {
|
|
|
|
switch (program) {
|
|
|
|
case Maxwell::ShaderProgram::VertexB:
|
|
|
|
return ShaderType::Vertex;
|
|
|
|
case Maxwell::ShaderProgram::TesselationControl:
|
|
|
|
return ShaderType::TesselationControl;
|
|
|
|
case Maxwell::ShaderProgram::TesselationEval:
|
|
|
|
return ShaderType::TesselationEval;
|
|
|
|
case Maxwell::ShaderProgram::Geometry:
|
|
|
|
return ShaderType::Geometry;
|
|
|
|
case Maxwell::ShaderProgram::Fragment:
|
|
|
|
return ShaderType::Fragment;
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED_MSG("program={}", static_cast<u32>(program));
|
|
|
|
return ShaderType::Vertex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-27 05:33:21 +01:00
|
|
|
template <VkDescriptorType descriptor_type, class Container>
|
|
|
|
void AddBindings(std::vector<VkDescriptorSetLayoutBinding>& bindings, u32& binding,
|
|
|
|
VkShaderStageFlags stage_flags, const Container& container) {
|
2020-02-23 06:35:16 +01:00
|
|
|
const u32 num_entries = static_cast<u32>(std::size(container));
|
|
|
|
for (std::size_t i = 0; i < num_entries; ++i) {
|
|
|
|
u32 count = 1;
|
2020-03-27 05:33:21 +01:00
|
|
|
if constexpr (descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
|
2020-02-23 06:35:16 +01:00
|
|
|
// Combined image samplers can be arrayed.
|
2020-04-16 06:34:45 +02:00
|
|
|
count = container[i].size;
|
2020-02-23 06:35:16 +01:00
|
|
|
}
|
2020-07-17 00:32:29 +02:00
|
|
|
bindings.push_back({
|
|
|
|
.binding = binding++,
|
|
|
|
.descriptorType = descriptor_type,
|
|
|
|
.descriptorCount = count,
|
|
|
|
.stageFlags = stage_flags,
|
|
|
|
.pImmutableSamplers = nullptr,
|
|
|
|
});
|
2020-02-23 06:35:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-07 01:55:06 +01:00
|
|
|
u32 FillDescriptorLayout(const ShaderEntries& entries,
|
2020-03-27 05:33:21 +01:00
|
|
|
std::vector<VkDescriptorSetLayoutBinding>& bindings,
|
2020-01-07 01:55:06 +01:00
|
|
|
Maxwell::ShaderProgram program_type, u32 base_binding) {
|
|
|
|
const ShaderType stage = GetStageFromProgram(program_type);
|
2020-03-27 05:33:21 +01:00
|
|
|
const VkShaderStageFlags flags = MaxwellToVK::ShaderStage(stage);
|
2020-01-07 01:55:06 +01:00
|
|
|
|
|
|
|
u32 binding = base_binding;
|
2020-03-27 05:33:21 +01:00
|
|
|
AddBindings<UNIFORM_BUFFER>(bindings, binding, flags, entries.const_buffers);
|
|
|
|
AddBindings<STORAGE_BUFFER>(bindings, binding, flags, entries.global_buffers);
|
2020-06-02 02:41:07 +02:00
|
|
|
AddBindings<UNIFORM_TEXEL_BUFFER>(bindings, binding, flags, entries.uniform_texels);
|
2020-03-27 05:33:21 +01:00
|
|
|
AddBindings<COMBINED_IMAGE_SAMPLER>(bindings, binding, flags, entries.samplers);
|
2020-06-02 02:41:07 +02:00
|
|
|
AddBindings<STORAGE_TEXEL_BUFFER>(bindings, binding, flags, entries.storage_texels);
|
2020-03-27 05:33:21 +01:00
|
|
|
AddBindings<STORAGE_IMAGE>(bindings, binding, flags, entries.images);
|
2020-01-07 01:55:06 +01:00
|
|
|
return binding;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // Anonymous namespace
|
|
|
|
|
2020-04-23 01:52:29 +02:00
|
|
|
std::size_t GraphicsPipelineCacheKey::Hash() const noexcept {
|
2020-06-23 00:07:04 +02:00
|
|
|
const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), Size());
|
2020-04-23 01:52:29 +02:00
|
|
|
return static_cast<std::size_t>(hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GraphicsPipelineCacheKey::operator==(const GraphicsPipelineCacheKey& rhs) const noexcept {
|
2020-06-23 00:07:04 +02:00
|
|
|
return std::memcmp(&rhs, this, Size()) == 0;
|
2020-04-23 01:52:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t ComputePipelineCacheKey::Hash() const noexcept {
|
|
|
|
const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this);
|
|
|
|
return static_cast<std::size_t>(hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComputePipelineCacheKey::operator==(const ComputePipelineCacheKey& rhs) const noexcept {
|
|
|
|
return std::memcmp(&rhs, this, sizeof *this) == 0;
|
|
|
|
}
|
|
|
|
|
2020-05-23 02:01:36 +02:00
|
|
|
Shader::Shader(Core::System& system, Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr,
|
|
|
|
VideoCommon::Shader::ProgramCode program_code, u32 main_offset)
|
|
|
|
: gpu_addr{gpu_addr}, program_code{std::move(program_code)},
|
2020-04-06 01:18:00 +02:00
|
|
|
registry{stage, GetEngine(system, stage)}, shader_ir{this->program_code, main_offset,
|
|
|
|
compiler_settings, registry},
|
2020-01-07 01:55:06 +01:00
|
|
|
entries{GenerateShaderEntries(shader_ir)} {}
|
|
|
|
|
2020-05-23 02:01:36 +02:00
|
|
|
Shader::~Shader() = default;
|
2020-01-07 01:55:06 +01:00
|
|
|
|
2020-05-23 02:01:36 +02:00
|
|
|
Tegra::Engines::ConstBufferEngineInterface& Shader::GetEngine(Core::System& system,
|
|
|
|
Tegra::Engines::ShaderType stage) {
|
|
|
|
if (stage == ShaderType::Compute) {
|
2020-01-07 01:55:06 +01:00
|
|
|
return system.GPU().KeplerCompute();
|
|
|
|
} else {
|
|
|
|
return system.GPU().Maxwell3D();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VKPipelineCache::VKPipelineCache(Core::System& system, RasterizerVulkan& rasterizer,
|
|
|
|
const VKDevice& device, VKScheduler& scheduler,
|
|
|
|
VKDescriptorPool& descriptor_pool,
|
2020-02-23 07:51:37 +01:00
|
|
|
VKUpdateDescriptorQueue& update_descriptor_queue,
|
|
|
|
VKRenderPassCache& renderpass_cache)
|
2020-05-23 02:01:36 +02:00
|
|
|
: VideoCommon::ShaderCache<Shader>{rasterizer}, system{system}, device{device},
|
|
|
|
scheduler{scheduler}, descriptor_pool{descriptor_pool},
|
|
|
|
update_descriptor_queue{update_descriptor_queue}, renderpass_cache{renderpass_cache} {}
|
2020-01-07 01:55:06 +01:00
|
|
|
|
|
|
|
VKPipelineCache::~VKPipelineCache() = default;
|
|
|
|
|
2020-05-23 02:01:36 +02:00
|
|
|
std::array<Shader*, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() {
|
2020-01-07 01:55:06 +01:00
|
|
|
const auto& gpu = system.GPU().Maxwell3D();
|
|
|
|
|
2020-05-23 02:01:36 +02:00
|
|
|
std::array<Shader*, Maxwell::MaxShaderProgram> shaders{};
|
2020-01-07 01:55:06 +01:00
|
|
|
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
|
|
|
|
const auto program{static_cast<Maxwell::ShaderProgram>(index)};
|
|
|
|
|
|
|
|
// Skip stages that are not enabled
|
|
|
|
if (!gpu.regs.IsShaderConfigEnabled(index)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& memory_manager{system.GPU().MemoryManager()};
|
|
|
|
const GPUVAddr program_addr{GetShaderAddress(system, program)};
|
2020-04-06 01:18:00 +02:00
|
|
|
const std::optional cpu_addr = memory_manager.GpuToCpuAddress(program_addr);
|
|
|
|
ASSERT(cpu_addr);
|
2020-05-23 02:01:36 +02:00
|
|
|
|
|
|
|
Shader* result = cpu_addr ? TryGet(*cpu_addr) : null_shader.get();
|
|
|
|
if (!result) {
|
2020-04-06 01:18:00 +02:00
|
|
|
const auto host_ptr{memory_manager.GetPointer(program_addr)};
|
|
|
|
|
2020-01-07 01:55:06 +01:00
|
|
|
// No shader found - create a new one
|
2020-04-24 06:44:14 +02:00
|
|
|
constexpr u32 stage_offset = STAGE_MAIN_OFFSET;
|
2020-05-23 02:01:36 +02:00
|
|
|
const auto stage = static_cast<ShaderType>(index == 0 ? 0 : index - 1);
|
2020-04-24 06:44:14 +02:00
|
|
|
ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, false);
|
2020-05-23 02:01:36 +02:00
|
|
|
const std::size_t size_in_bytes = code.size() * sizeof(u64);
|
|
|
|
|
|
|
|
auto shader = std::make_unique<Shader>(system, stage, program_addr, std::move(code),
|
|
|
|
stage_offset);
|
|
|
|
result = shader.get();
|
2020-01-07 01:55:06 +01:00
|
|
|
|
2020-04-16 19:50:12 +02:00
|
|
|
if (cpu_addr) {
|
2020-05-23 02:01:36 +02:00
|
|
|
Register(std::move(shader), *cpu_addr, size_in_bytes);
|
2020-04-16 19:50:12 +02:00
|
|
|
} else {
|
2020-05-23 02:01:36 +02:00
|
|
|
null_shader = std::move(shader);
|
2020-04-16 19:50:12 +02:00
|
|
|
}
|
2020-01-07 01:55:06 +01:00
|
|
|
}
|
2020-05-23 02:01:36 +02:00
|
|
|
shaders[index] = result;
|
2020-01-07 01:55:06 +01:00
|
|
|
}
|
|
|
|
return last_shaders = shaders;
|
|
|
|
}
|
|
|
|
|
2020-07-30 21:41:11 +02:00
|
|
|
VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
|
2020-07-28 06:08:02 +02:00
|
|
|
const GraphicsPipelineCacheKey& key, VideoCommon::Shader::AsyncShaders& async_shaders) {
|
2020-01-07 01:55:06 +01:00
|
|
|
MICROPROFILE_SCOPE(Vulkan_PipelineCache);
|
|
|
|
|
|
|
|
if (last_graphics_pipeline && last_graphics_key == key) {
|
2020-07-30 21:41:11 +02:00
|
|
|
return last_graphics_pipeline;
|
2020-01-07 01:55:06 +01:00
|
|
|
}
|
|
|
|
last_graphics_key = key;
|
|
|
|
|
2020-07-28 06:08:02 +02:00
|
|
|
if (device.UseAsynchronousShaders()) {
|
|
|
|
auto work = async_shaders.GetCompletedWork();
|
2020-07-30 21:41:11 +02:00
|
|
|
for (auto& w : work) {
|
|
|
|
auto& entry = graphics_cache.at(w.pipeline->GetCacheKey());
|
|
|
|
entry = std::move(w.pipeline);
|
2020-07-28 06:08:02 +02:00
|
|
|
}
|
|
|
|
const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
|
|
|
|
if (is_cache_miss) {
|
|
|
|
LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
|
|
|
|
const auto [program, bindings] = DecompileShaders(key.fixed_state);
|
|
|
|
async_shaders.QueueVulkanShader(this, bindings, program, key.renderpass_params,
|
|
|
|
key.padding, key.shaders, key.fixed_state);
|
|
|
|
}
|
2020-07-30 21:41:11 +02:00
|
|
|
last_graphics_pipeline = graphics_cache.at(key).get();
|
|
|
|
return last_graphics_pipeline;
|
2020-07-28 06:08:02 +02:00
|
|
|
}
|
|
|
|
|
2020-01-07 01:55:06 +01:00
|
|
|
const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
|
|
|
|
auto& entry = pair->second;
|
|
|
|
if (is_cache_miss) {
|
|
|
|
LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
|
2020-07-28 06:08:02 +02:00
|
|
|
const auto [program, bindings] = DecompileShaders(key.fixed_state);
|
2020-01-07 01:55:06 +01:00
|
|
|
entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool,
|
|
|
|
update_descriptor_queue, renderpass_cache, key,
|
|
|
|
bindings, program);
|
|
|
|
}
|
2020-07-30 21:41:11 +02:00
|
|
|
last_graphics_pipeline = entry.get();
|
|
|
|
return last_graphics_pipeline;
|
2020-01-07 01:55:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCacheKey& key) {
|
|
|
|
MICROPROFILE_SCOPE(Vulkan_PipelineCache);
|
|
|
|
|
|
|
|
const auto [pair, is_cache_miss] = compute_cache.try_emplace(key);
|
|
|
|
auto& entry = pair->second;
|
|
|
|
if (!is_cache_miss) {
|
|
|
|
return *entry;
|
|
|
|
}
|
|
|
|
LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
|
|
|
|
|
|
|
|
auto& memory_manager = system.GPU().MemoryManager();
|
|
|
|
const auto program_addr = key.shader;
|
|
|
|
|
2020-04-06 01:18:00 +02:00
|
|
|
const auto cpu_addr = memory_manager.GpuToCpuAddress(program_addr);
|
|
|
|
ASSERT(cpu_addr);
|
|
|
|
|
2020-05-23 02:01:36 +02:00
|
|
|
Shader* shader = cpu_addr ? TryGet(*cpu_addr) : null_kernel.get();
|
2020-01-07 01:55:06 +01:00
|
|
|
if (!shader) {
|
|
|
|
// No shader found - create a new one
|
2020-04-06 01:18:00 +02:00
|
|
|
const auto host_ptr = memory_manager.GetPointer(program_addr);
|
2020-01-07 01:55:06 +01:00
|
|
|
|
2020-04-24 06:44:14 +02:00
|
|
|
ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, true);
|
2020-05-23 02:01:36 +02:00
|
|
|
const std::size_t size_in_bytes = code.size() * sizeof(u64);
|
|
|
|
|
|
|
|
auto shader_info = std::make_unique<Shader>(system, ShaderType::Compute, program_addr,
|
|
|
|
std::move(code), KERNEL_MAIN_OFFSET);
|
|
|
|
shader = shader_info.get();
|
|
|
|
|
2020-04-16 19:50:12 +02:00
|
|
|
if (cpu_addr) {
|
2020-05-23 02:01:36 +02:00
|
|
|
Register(std::move(shader_info), *cpu_addr, size_in_bytes);
|
2020-04-16 19:50:12 +02:00
|
|
|
} else {
|
2020-05-23 02:01:36 +02:00
|
|
|
null_kernel = std::move(shader_info);
|
2020-04-16 19:50:12 +02:00
|
|
|
}
|
2020-01-07 01:55:06 +01:00
|
|
|
}
|
|
|
|
|
2020-07-17 00:32:29 +02:00
|
|
|
const Specialization specialization{
|
2020-08-03 13:39:39 +02:00
|
|
|
.base_binding = 0,
|
2020-07-17 00:32:29 +02:00
|
|
|
.workgroup_size = key.workgroup_size,
|
|
|
|
.shared_memory_size = key.shared_memory_size,
|
2020-08-03 13:39:39 +02:00
|
|
|
.point_size = std::nullopt,
|
|
|
|
.enabled_attributes = {},
|
|
|
|
.attribute_types = {},
|
|
|
|
.ndc_minus_one_to_one = false,
|
2020-07-17 00:32:29 +02:00
|
|
|
};
|
2020-03-03 01:36:25 +01:00
|
|
|
const SPIRVShader spirv_shader{Decompile(device, shader->GetIR(), ShaderType::Compute,
|
|
|
|
shader->GetRegistry(), specialization),
|
|
|
|
shader->GetEntries()};
|
2020-01-07 01:55:06 +01:00
|
|
|
entry = std::make_unique<VKComputePipeline>(device, scheduler, descriptor_pool,
|
|
|
|
update_descriptor_queue, spirv_shader);
|
|
|
|
return *entry;
|
|
|
|
}
|
|
|
|
|
2020-05-23 02:01:36 +02:00
|
|
|
void VKPipelineCache::OnShaderRemoval(Shader* shader) {
|
2020-01-07 01:55:06 +01:00
|
|
|
bool finished = false;
|
|
|
|
const auto Finish = [&] {
|
|
|
|
// TODO(Rodrigo): Instead of finishing here, wait for the fences that use this pipeline and
|
|
|
|
// flush.
|
|
|
|
if (finished) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
finished = true;
|
|
|
|
scheduler.Finish();
|
|
|
|
};
|
|
|
|
|
|
|
|
const GPUVAddr invalidated_addr = shader->GetGpuAddr();
|
|
|
|
for (auto it = graphics_cache.begin(); it != graphics_cache.end();) {
|
|
|
|
auto& entry = it->first;
|
|
|
|
if (std::find(entry.shaders.begin(), entry.shaders.end(), invalidated_addr) ==
|
|
|
|
entry.shaders.end()) {
|
|
|
|
++it;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Finish();
|
|
|
|
it = graphics_cache.erase(it);
|
|
|
|
}
|
|
|
|
for (auto it = compute_cache.begin(); it != compute_cache.end();) {
|
|
|
|
auto& entry = it->first;
|
|
|
|
if (entry.shader != invalidated_addr) {
|
|
|
|
++it;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Finish();
|
|
|
|
it = compute_cache.erase(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-27 05:33:21 +01:00
|
|
|
std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>>
|
2020-07-28 06:08:02 +02:00
|
|
|
VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
|
2020-01-07 01:55:06 +01:00
|
|
|
auto& memory_manager = system.GPU().MemoryManager();
|
|
|
|
const auto& gpu = system.GPU().Maxwell3D();
|
|
|
|
|
|
|
|
Specialization specialization;
|
2020-06-23 00:07:04 +02:00
|
|
|
if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points ||
|
|
|
|
device.IsExtExtendedDynamicStateSupported()) {
|
2020-04-23 02:36:05 +02:00
|
|
|
float point_size;
|
2020-06-22 09:01:37 +02:00
|
|
|
std::memcpy(&point_size, &fixed_state.point_size, sizeof(float));
|
2020-04-23 02:36:05 +02:00
|
|
|
specialization.point_size = point_size;
|
|
|
|
ASSERT(point_size != 0.0f);
|
2020-01-07 01:55:06 +01:00
|
|
|
}
|
|
|
|
for (std::size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) {
|
2020-06-22 09:01:37 +02:00
|
|
|
const auto& attribute = fixed_state.attributes[i];
|
2020-05-13 09:32:41 +02:00
|
|
|
specialization.enabled_attributes[i] = attribute.enabled.Value() != 0;
|
|
|
|
specialization.attribute_types[i] = attribute.Type();
|
2020-01-07 01:55:06 +01:00
|
|
|
}
|
2020-06-22 09:01:37 +02:00
|
|
|
specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one;
|
2020-01-07 01:55:06 +01:00
|
|
|
|
|
|
|
SPIRVProgram program;
|
2020-03-27 05:33:21 +01:00
|
|
|
std::vector<VkDescriptorSetLayoutBinding> bindings;
|
2020-01-07 01:55:06 +01:00
|
|
|
|
|
|
|
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
|
|
|
|
const auto program_enum = static_cast<Maxwell::ShaderProgram>(index);
|
|
|
|
|
|
|
|
// Skip stages that are not enabled
|
|
|
|
if (!gpu.regs.IsShaderConfigEnabled(index)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const GPUVAddr gpu_addr = GetShaderAddress(system, program_enum);
|
2020-05-23 02:03:57 +02:00
|
|
|
const std::optional<VAddr> cpu_addr = memory_manager.GpuToCpuAddress(gpu_addr);
|
|
|
|
Shader* const shader = cpu_addr ? TryGet(*cpu_addr) : null_shader.get();
|
2020-01-07 01:55:06 +01:00
|
|
|
|
|
|
|
const std::size_t stage = index == 0 ? 0 : index - 1; // Stage indices are 0 - 5
|
2020-05-23 02:03:57 +02:00
|
|
|
const ShaderType program_type = GetShaderType(program_enum);
|
2020-01-07 01:55:06 +01:00
|
|
|
const auto& entries = shader->GetEntries();
|
2020-03-03 01:36:25 +01:00
|
|
|
program[stage] = {
|
|
|
|
Decompile(device, shader->GetIR(), program_type, shader->GetRegistry(), specialization),
|
|
|
|
entries};
|
2020-01-07 01:55:06 +01:00
|
|
|
|
|
|
|
if (program_enum == Maxwell::ShaderProgram::VertexA) {
|
|
|
|
// VertexB was combined with VertexA, so we skip the VertexB iteration
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
|
|
|
|
const u32 old_binding = specialization.base_binding;
|
|
|
|
specialization.base_binding =
|
|
|
|
FillDescriptorLayout(entries, bindings, program_enum, specialization.base_binding);
|
|
|
|
ASSERT(old_binding + entries.NumBindings() == specialization.base_binding);
|
|
|
|
}
|
|
|
|
return {std::move(program), std::move(bindings)};
|
|
|
|
}
|
|
|
|
|
2020-03-27 05:33:21 +01:00
|
|
|
template <VkDescriptorType descriptor_type, class Container>
|
|
|
|
void AddEntry(std::vector<VkDescriptorUpdateTemplateEntry>& template_entries, u32& binding,
|
2020-02-23 06:35:16 +01:00
|
|
|
u32& offset, const Container& container) {
|
|
|
|
static constexpr u32 entry_size = static_cast<u32>(sizeof(DescriptorUpdateEntry));
|
|
|
|
const u32 count = static_cast<u32>(std::size(container));
|
|
|
|
|
2020-03-27 05:33:21 +01:00
|
|
|
if constexpr (descriptor_type == COMBINED_IMAGE_SAMPLER) {
|
2020-02-23 06:35:16 +01:00
|
|
|
for (u32 i = 0; i < count; ++i) {
|
2020-04-16 06:34:45 +02:00
|
|
|
const u32 num_samplers = container[i].size;
|
2020-07-17 00:32:29 +02:00
|
|
|
template_entries.push_back({
|
|
|
|
.dstBinding = binding,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorCount = num_samplers,
|
|
|
|
.descriptorType = descriptor_type,
|
|
|
|
.offset = offset,
|
|
|
|
.stride = entry_size,
|
|
|
|
});
|
2020-03-27 05:33:21 +01:00
|
|
|
|
2020-02-23 06:35:16 +01:00
|
|
|
++binding;
|
|
|
|
offset += num_samplers * entry_size;
|
2020-01-07 01:18:38 +01:00
|
|
|
}
|
2020-02-23 06:35:16 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-01-07 01:18:38 +01:00
|
|
|
|
2020-06-02 02:41:07 +02:00
|
|
|
if constexpr (descriptor_type == UNIFORM_TEXEL_BUFFER ||
|
|
|
|
descriptor_type == STORAGE_TEXEL_BUFFER) {
|
|
|
|
// Nvidia has a bug where updating multiple texels at once causes the driver to crash.
|
|
|
|
// Note: Fixed in driver Windows 443.24, Linux 440.66.15
|
2020-02-23 06:35:16 +01:00
|
|
|
for (u32 i = 0; i < count; ++i) {
|
2020-07-17 00:32:29 +02:00
|
|
|
template_entries.push_back({
|
|
|
|
.dstBinding = binding + i,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = descriptor_type,
|
|
|
|
.offset = static_cast<std::size_t>(offset + i * entry_size),
|
|
|
|
.stride = entry_size,
|
|
|
|
});
|
2020-02-23 06:35:16 +01:00
|
|
|
}
|
|
|
|
} else if (count > 0) {
|
2020-07-17 00:32:29 +02:00
|
|
|
template_entries.push_back({
|
|
|
|
.dstBinding = binding,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorCount = count,
|
|
|
|
.descriptorType = descriptor_type,
|
|
|
|
.offset = offset,
|
|
|
|
.stride = entry_size,
|
|
|
|
});
|
2020-02-23 06:35:16 +01:00
|
|
|
}
|
|
|
|
offset += count * entry_size;
|
|
|
|
binding += count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FillDescriptorUpdateTemplateEntries(
|
|
|
|
const ShaderEntries& entries, u32& binding, u32& offset,
|
2020-03-27 05:33:21 +01:00
|
|
|
std::vector<VkDescriptorUpdateTemplateEntryKHR>& template_entries) {
|
|
|
|
AddEntry<UNIFORM_BUFFER>(template_entries, offset, binding, entries.const_buffers);
|
|
|
|
AddEntry<STORAGE_BUFFER>(template_entries, offset, binding, entries.global_buffers);
|
2020-06-02 02:41:07 +02:00
|
|
|
AddEntry<UNIFORM_TEXEL_BUFFER>(template_entries, offset, binding, entries.uniform_texels);
|
2020-03-27 05:33:21 +01:00
|
|
|
AddEntry<COMBINED_IMAGE_SAMPLER>(template_entries, offset, binding, entries.samplers);
|
2020-06-02 02:41:07 +02:00
|
|
|
AddEntry<STORAGE_TEXEL_BUFFER>(template_entries, offset, binding, entries.storage_texels);
|
2020-03-27 05:33:21 +01:00
|
|
|
AddEntry<STORAGE_IMAGE>(template_entries, offset, binding, entries.images);
|
2020-01-07 01:18:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Vulkan
|