Merge branch 'master' into vulkan
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user