Merge branch 'master' into vulkan

This commit is contained in:
Triang3l
2020-12-13 18:41:07 +03:00
parent c14e3770a2
commit 4617dc5569
115 changed files with 4290 additions and 3872 deletions

View File

@@ -627,6 +627,17 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
}
// TODO(Triang3l): Get a pixel shader.
VulkanShader* pixel_shader = nullptr;
SpirvShaderTranslator::Modification vertex_shader_modification;
SpirvShaderTranslator::Modification pixel_shader_modification;
if (!pipeline_cache_->GetCurrentShaderModifications(
vertex_shader_modification, pixel_shader_modification)) {
return false;
}
VulkanShader::VulkanTranslation* vertex_shader_translation =
static_cast<VulkanShader::VulkanTranslation*>(
vertex_shader->GetOrCreateTranslation(
vertex_shader_modification.value));
VulkanShader::VulkanTranslation* pixel_shader_translation = nullptr;
VulkanRenderTargetCache::FramebufferKey framebuffer_key;
if (!render_target_cache_->UpdateRenderTargets(framebuffer_key)) {
@@ -648,7 +659,8 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// current_graphics_pipeline_layout_.
VkPipeline pipeline;
const VulkanPipelineCache::PipelineLayoutProvider* pipeline_layout_provider;
if (!pipeline_cache_->ConfigurePipeline(vertex_shader, pixel_shader,
if (!pipeline_cache_->ConfigurePipeline(vertex_shader_translation,
pixel_shader_translation,
framebuffer_key.render_pass_key,
pipeline, pipeline_layout_provider)) {
return false;
@@ -713,7 +725,7 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
draw_util::GetHostViewportInfo(
regs, 1.0f, 1.0f, false,
float(device_properties.limits.maxViewportDimensions[0]),
float(device_properties.limits.maxViewportDimensions[1]), true,
float(device_properties.limits.maxViewportDimensions[1]), true, false,
viewport_info);
// Update fixed-function dynamic state.

View File

@@ -17,6 +17,8 @@
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/profiling.h"
#include "xenia/base/xxhash.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/registers.h"
#include "xenia/gpu/spirv_shader_translator.h"
@@ -84,7 +86,8 @@ VulkanShader* VulkanPipelineCache::LoadShader(xenos::ShaderType shader_type,
const uint32_t* host_address,
uint32_t dword_count) {
// Hash the input memory and lookup the shader.
uint64_t data_hash = XXH64(host_address, dword_count * sizeof(uint32_t), 0);
uint64_t data_hash =
XXH3_64bits(host_address, dword_count * sizeof(uint32_t));
auto it = shaders_.find(data_hash);
if (it != shaders_.end()) {
// Shader has been previously loaded.
@@ -94,16 +97,31 @@ VulkanShader* VulkanPipelineCache::LoadShader(xenos::ShaderType shader_type,
// Always create the shader and stash it away.
// We need to track it even if it fails translation so we know not to try
// again.
VulkanShader* shader =
new VulkanShader(shader_type, data_hash, host_address, dword_count);
VulkanShader* shader = new VulkanShader(
shader_type, data_hash, host_address, dword_count,
command_processor_.GetVulkanContext().GetVulkanProvider());
shaders_.emplace(data_hash, shader);
if (!cvars::dump_shaders.empty()) {
shader->DumpUcodeBinary(cvars::dump_shaders);
}
return shader;
}
bool VulkanPipelineCache::GetCurrentShaderModifications(
SpirvShaderTranslator::Modification& vertex_shader_modification_out,
SpirvShaderTranslator::Modification& pixel_shader_modification_out) const {
// TODO(Triang3l): Tessellation, depth output.
vertex_shader_modification_out = SpirvShaderTranslator::Modification(
shader_translator_->GetDefaultModification(xenos::ShaderType::kVertex));
pixel_shader_modification_out = SpirvShaderTranslator::Modification(
shader_translator_->GetDefaultModification(xenos::ShaderType::kPixel));
return true;
}
bool VulkanPipelineCache::EnsureShadersTranslated(
VulkanShader* vertex_shader, VulkanShader* pixel_shader,
Shader::HostVertexShaderType host_vertex_shader_type) {
VulkanShader::VulkanTranslation* vertex_shader,
VulkanShader::VulkanTranslation* pixel_shader) {
const RegisterFile& regs = register_file_;
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
@@ -133,7 +151,8 @@ bool VulkanPipelineCache::EnsureShadersTranslated(
}
bool VulkanPipelineCache::ConfigurePipeline(
VulkanShader* vertex_shader, VulkanShader* pixel_shader,
VulkanShader::VulkanTranslation* vertex_shader,
VulkanShader::VulkanTranslation* pixel_shader,
VulkanRenderTargetCache::RenderPassKey render_pass_key,
VkPipeline& pipeline_out,
const PipelineLayoutProvider*& pipeline_layout_out) {
@@ -160,8 +179,7 @@ bool VulkanPipelineCache::ConfigurePipeline(
}
// Create the pipeline if not the latest and not already existing.
if (!EnsureShadersTranslated(vertex_shader, pixel_shader,
Shader::HostVertexShaderType::kVertex)) {
if (!EnsureShadersTranslated(vertex_shader, pixel_shader)) {
return false;
}
const PipelineLayoutProvider* pipeline_layout =
@@ -189,24 +207,22 @@ bool VulkanPipelineCache::ConfigurePipeline(
return true;
}
bool VulkanPipelineCache::TranslateShader(SpirvShaderTranslator& translator,
VulkanShader& shader,
reg::SQ_PROGRAM_CNTL cntl) {
bool VulkanPipelineCache::TranslateShader(
SpirvShaderTranslator& translator,
VulkanShader::VulkanTranslation& translation, reg::SQ_PROGRAM_CNTL cntl) {
// Perform translation.
// If this fails the shader will be marked as invalid and ignored later.
// TODO(Triang3l): Host vertex shader type.
if (!translator.Translate(&shader, cntl,
Shader::HostVertexShaderType::kVertex)) {
if (!translator.Translate(translation, cntl)) {
XELOGE("Shader {:016X} translation failed; marking as ignored",
shader.ucode_data_hash());
translation.shader().ucode_data_hash());
return false;
}
return shader.InitializeShaderModule(
command_processor_.GetVulkanContext().GetVulkanProvider());
return translation.GetOrCreateShaderModule() != VK_NULL_HANDLE;
}
bool VulkanPipelineCache::GetCurrentStateDescription(
const VulkanShader* vertex_shader, const VulkanShader* pixel_shader,
const VulkanShader::VulkanTranslation* vertex_shader,
const VulkanShader::VulkanTranslation* pixel_shader,
VulkanRenderTargetCache::RenderPassKey render_pass_key,
PipelineDescription& description_out) const {
description_out.Reset();
@@ -215,9 +231,14 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
auto pa_su_sc_mode_cntl = regs.Get<reg::PA_SU_SC_MODE_CNTL>();
auto vgt_draw_initiator = regs.Get<reg::VGT_DRAW_INITIATOR>();
description_out.vertex_shader_hash = vertex_shader->ucode_data_hash();
description_out.pixel_shader_hash =
pixel_shader ? pixel_shader->ucode_data_hash() : 0;
description_out.vertex_shader_hash =
vertex_shader->shader().ucode_data_hash();
description_out.vertex_shader_modification = vertex_shader->modification();
if (pixel_shader) {
description_out.pixel_shader_hash =
pixel_shader->shader().ucode_data_hash();
description_out.pixel_shader_modification = pixel_shader->modification();
}
description_out.render_pass_key = render_pass_key;
xenos::PrimitiveType primitive_type = vgt_draw_initiator.prim_type;
@@ -321,11 +342,11 @@ bool VulkanPipelineCache::EnsurePipelineCreated(
if (creation_arguments.pixel_shader) {
XELOGGPU("Creating graphics pipeline state with VS {:016X}, PS {:016X}",
creation_arguments.vertex_shader->ucode_data_hash(),
creation_arguments.pixel_shader->ucode_data_hash());
creation_arguments.vertex_shader->shader().ucode_data_hash(),
creation_arguments.pixel_shader->shader().ucode_data_hash());
} else {
XELOGGPU("Creating graphics pipeline state with VS {:016X}",
creation_arguments.vertex_shader->ucode_data_hash());
creation_arguments.vertex_shader->shader().ucode_data_hash());
}
const PipelineDescription& description = creation_arguments.pipeline->first;
@@ -514,11 +535,11 @@ bool VulkanPipelineCache::EnsurePipelineCreated(
/* if (creation_arguments.pixel_shader) {
XELOGE(
"Failed to create graphics pipeline with VS {:016X}, PS {:016X}",
creation_arguments.vertex_shader->ucode_data_hash(),
creation_arguments.pixel_shader->ucode_data_hash());
creation_arguments.vertex_shader->shader().ucode_data_hash(),
creation_arguments.pixel_shader->shader().ucode_data_hash());
} else {
XELOGE("Failed to create graphics pipeline with VS {:016X}",
creation_arguments.vertex_shader->ucode_data_hash());
creation_arguments.vertex_shader->shader().ucode_data_hash());
} */
return false;
}

View File

@@ -16,9 +16,9 @@
#include <unordered_map>
#include <utility>
#include "third_party/xxhash/xxhash.h"
#include "xenia/base/hash.h"
#include "xenia/base/platform.h"
#include "xenia/base/xxhash.h"
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/spirv_shader_translator.h"
#include "xenia/gpu/vulkan/vulkan_render_target_cache.h"
@@ -55,14 +55,19 @@ class VulkanPipelineCache {
uint32_t guest_address, const uint32_t* host_address,
uint32_t dword_count);
// Retrieves the shader modifications for the current state, and returns
// whether they are valid.
bool GetCurrentShaderModifications(
SpirvShaderTranslator::Modification& vertex_shader_modification_out,
SpirvShaderTranslator::Modification& pixel_shader_modification_out) const;
// Translates shaders if needed, also making shader info up to date.
bool EnsureShadersTranslated(
VulkanShader* vertex_shader, VulkanShader* pixel_shader,
Shader::HostVertexShaderType host_vertex_shader_type);
bool EnsureShadersTranslated(VulkanShader::VulkanTranslation* vertex_shader,
VulkanShader::VulkanTranslation* pixel_shader);
// TODO(Triang3l): Return a deferred creation handle.
bool ConfigurePipeline(VulkanShader* vertex_shader,
VulkanShader* pixel_shader,
bool ConfigurePipeline(VulkanShader::VulkanTranslation* vertex_shader,
VulkanShader::VulkanTranslation* pixel_shader,
VulkanRenderTargetCache::RenderPassKey render_pass_key,
VkPipeline& pipeline_out,
const PipelineLayoutProvider*& pipeline_layout_out);
@@ -102,6 +107,8 @@ class VulkanPipelineCache {
uint64_t vertex_shader_hash;
// 0 if no pixel shader.
uint64_t pixel_shader_hash;
uint32_t vertex_shader_modification;
uint32_t pixel_shader_modification;
VulkanRenderTargetCache::RenderPassKey render_pass_key;
// Input assembly.
@@ -126,7 +133,7 @@ class VulkanPipelineCache {
return std::memcmp(this, &description, sizeof(*this)) == 0;
}
void Reset() { std::memset(this, 0, sizeof(*this)); }
uint64_t GetHash() const { return XXH64(this, sizeof(*this), 0); }
uint64_t GetHash() const { return XXH3_64bits(this, sizeof(*this)); }
struct Hasher {
size_t operator()(const PipelineDescription& description) const {
return size_t(description.GetHash());
@@ -146,17 +153,19 @@ class VulkanPipelineCache {
// creation threads, with everything needed from caches pre-looked-up.
struct PipelineCreationArguments {
std::pair<const PipelineDescription, Pipeline>* pipeline;
const VulkanShader* vertex_shader;
const VulkanShader* pixel_shader;
const VulkanShader::VulkanTranslation* vertex_shader;
const VulkanShader::VulkanTranslation* pixel_shader;
VkRenderPass render_pass;
};
// Can be called from multiple threads.
bool TranslateShader(SpirvShaderTranslator& translator, VulkanShader& shader,
bool TranslateShader(SpirvShaderTranslator& translator,
VulkanShader::VulkanTranslation& translation,
reg::SQ_PROGRAM_CNTL cntl);
bool GetCurrentStateDescription(
const VulkanShader* vertex_shader, const VulkanShader* pixel_shader,
const VulkanShader::VulkanTranslation* vertex_shader,
const VulkanShader::VulkanTranslation* pixel_shader,
VulkanRenderTargetCache::RenderPassKey render_pass_key,
PipelineDescription& description_out) const;

View File

@@ -14,7 +14,7 @@
#include <cstring>
#include <unordered_map>
#include "third_party/xxhash/xxhash.h"
#include "xenia/base/xxhash.h"
#include "xenia/gpu/register_file.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
@@ -49,7 +49,7 @@ class VulkanRenderTargetCache {
return std::memcmp(this, &key, sizeof(*this)) == 0;
}
void Reset() { std::memset(this, 0, sizeof(*this)); }
uint64_t GetHash() const { return XXH64(this, sizeof(*this), 0); }
uint64_t GetHash() const { return XXH3_64bits(this, sizeof(*this)); }
struct Hasher {
size_t operator()(const FramebufferKey& description) const {
return size_t(description.GetHash());

View File

@@ -11,22 +11,30 @@
#include <cstdint>
#include "xenia/ui/vulkan/vulkan_provider.h"
namespace xe {
namespace gpu {
namespace vulkan {
VulkanShader::VulkanShader(xenos::ShaderType shader_type, uint64_t data_hash,
const uint32_t* dword_ptr, uint32_t dword_count)
: Shader(shader_type, data_hash, dword_ptr, dword_count) {}
VulkanShader::VulkanTranslation::~VulkanTranslation() {
if (shader_module_) {
const ui::vulkan::VulkanProvider& provider =
static_cast<const VulkanShader&>(shader()).provider_;
provider.dfn().vkDestroyShaderModule(provider.device(), shader_module_,
nullptr);
}
}
bool VulkanShader::InitializeShaderModule(
const ui::vulkan::VulkanProvider& provider) {
VkShaderModule VulkanShader::VulkanTranslation::GetOrCreateShaderModule() {
if (!is_valid()) {
return false;
return VK_NULL_HANDLE;
}
if (shader_module_ != VK_NULL_HANDLE) {
return true;
return shader_module_;
}
const ui::vulkan::VulkanProvider& provider =
static_cast<const VulkanShader&>(shader()).provider_;
VkShaderModuleCreateInfo shader_module_create_info;
shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_module_create_info.pNext = nullptr;
@@ -37,10 +45,21 @@ bool VulkanShader::InitializeShaderModule(
if (provider.dfn().vkCreateShaderModule(provider.device(),
&shader_module_create_info, nullptr,
&shader_module_) != VK_SUCCESS) {
is_valid_ = false;
return false;
MakeInvalid();
return VK_NULL_HANDLE;
}
return true;
return shader_module_;
}
VulkanShader::VulkanShader(xenos::ShaderType shader_type, uint64_t data_hash,
const uint32_t* dword_ptr, uint32_t dword_count,
const ui::vulkan::VulkanProvider& provider)
: Shader(shader_type, data_hash, dword_ptr, dword_count),
provider_(provider) {}
Shader::Translation* VulkanShader::CreateTranslationInstance(
uint32_t modification) {
return new VulkanTranslation(*this, modification);
}
} // namespace vulkan

View File

@@ -22,14 +22,28 @@ namespace vulkan {
class VulkanShader : public Shader {
public:
VulkanShader(xenos::ShaderType shader_type, uint64_t data_hash,
const uint32_t* dword_ptr, uint32_t dword_count);
class VulkanTranslation : public Translation {
public:
VulkanTranslation(VulkanShader& shader, uint32_t modification)
: Translation(shader, modification) {}
~VulkanTranslation() override;
bool InitializeShaderModule(const ui::vulkan::VulkanProvider& provider);
VkShaderModule shader_module() const { return shader_module_; }
VkShaderModule GetOrCreateShaderModule();
VkShaderModule shader_module() const { return shader_module_; }
private:
VkShaderModule shader_module_ = VK_NULL_HANDLE;
};
VulkanShader(xenos::ShaderType shader_type, uint64_t data_hash,
const uint32_t* dword_ptr, uint32_t dword_count,
const ui::vulkan::VulkanProvider& provider);
protected:
Translation* CreateTranslationInstance(uint32_t modification) override;
private:
VkShaderModule shader_module_ = VK_NULL_HANDLE;
const ui::vulkan::VulkanProvider& provider_;
};
} // namespace vulkan