Merge branch 'master' into vulkan

This commit is contained in:
Triang3l
2021-06-08 12:15:34 +03:00
607 changed files with 452347 additions and 127070 deletions

View File

@@ -606,8 +606,7 @@ Shader* VulkanCommandProcessor::LoadShader(xenos::ShaderType shader_type,
uint32_t guest_address,
const uint32_t* host_address,
uint32_t dword_count) {
return pipeline_cache_->LoadShader(shader_type, guest_address, host_address,
dword_count);
return pipeline_cache_->LoadShader(shader_type, host_address, dword_count);
}
bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
@@ -620,24 +619,23 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
BeginSubmission(true);
// Vertex shader analysis.
auto vertex_shader = static_cast<VulkanShader*>(active_vertex_shader());
if (!vertex_shader) {
// Always need a vertex shader.
return false;
}
pipeline_cache_->AnalyzeShaderUcode(*vertex_shader);
// 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;
// Shader modifications.
SpirvShaderTranslator::Modification vertex_shader_modification =
pipeline_cache_->GetCurrentVertexShaderModification(
*vertex_shader, Shader::HostVertexShaderType::kVertex);
SpirvShaderTranslator::Modification pixel_shader_modification =
SpirvShaderTranslator::Modification(0);
VulkanRenderTargetCache::FramebufferKey framebuffer_key;
if (!render_target_cache_->UpdateRenderTargets(framebuffer_key)) {
@@ -654,6 +652,13 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
return false;
}
// Translate the shaders.
VulkanShader::VulkanTranslation* vertex_shader_translation =
static_cast<VulkanShader::VulkanTranslation*>(
vertex_shader->GetOrCreateTranslation(
vertex_shader_modification.value));
VulkanShader::VulkanTranslation* pixel_shader_translation = nullptr;
// Update the graphics pipeline, and if the new graphics pipeline has a
// different layout, invalidate incompatible descriptor sets before updating
// current_graphics_pipeline_layout_.
@@ -723,10 +728,9 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// interlocks case completely - apply the viewport and the scissor offset
// directly to pixel address and to things like ps_param_gen.
draw_util::GetHostViewportInfo(
regs, 1.0f, 1.0f, false,
float(device_properties.limits.maxViewportDimensions[0]),
float(device_properties.limits.maxViewportDimensions[1]), true, false,
viewport_info);
regs, 1, false, device_properties.limits.maxViewportDimensions[0],
device_properties.limits.maxViewportDimensions[1], true, false, false,
false, viewport_info);
// Update fixed-function dynamic state.
UpdateFixedFunctionState(viewport_info);
@@ -1288,10 +1292,17 @@ void VulkanCommandProcessor::UpdateFixedFunctionState(
// Viewport.
VkViewport viewport;
viewport.x = viewport_info.left;
viewport.y = viewport_info.top;
viewport.width = viewport_info.width;
viewport.height = viewport_info.height;
if (!viewport_info.xy_extent[0] || !viewport_info.xy_extent[1]) {
viewport.x = -1;
viewport.y = -1;
viewport.width = 1;
viewport.height = 1;
} else {
viewport.x = float(viewport_info.xy_offset[0]);
viewport.y = float(viewport_info.xy_offset[1]);
viewport.width = float(viewport_info.xy_extent[0]);
viewport.height = float(viewport_info.xy_extent[1]);
}
viewport.minDepth = viewport_info.z_min;
viewport.maxDepth = viewport_info.z_max;
ff_viewport_update_needed_ |= ff_viewport_.x != viewport.x;
@@ -1310,10 +1321,10 @@ void VulkanCommandProcessor::UpdateFixedFunctionState(
draw_util::Scissor scissor;
draw_util::GetScissor(regs, scissor);
VkRect2D scissor_rect;
scissor_rect.offset.x = int32_t(scissor.left * pixel_size_x);
scissor_rect.offset.y = int32_t(scissor.top * pixel_size_y);
scissor_rect.extent.width = scissor.width * pixel_size_x;
scissor_rect.extent.height = scissor.height * pixel_size_y;
scissor_rect.offset.x = int32_t(scissor.offset[0]);
scissor_rect.offset.y = int32_t(scissor.offset[1]);
scissor_rect.extent.width = scissor.extent[0];
scissor_rect.extent.height = scissor.extent[1];
ff_scissor_update_needed_ |= ff_scissor_.offset.x != scissor_rect.offset.x;
ff_scissor_update_needed_ |= ff_scissor_.offset.y != scissor_rect.offset.y;
ff_scissor_update_needed_ |=

View File

@@ -18,6 +18,7 @@
#include "xenia/base/math.h"
#include "xenia/base/profiling.h"
#include "xenia/base/xxhash.h"
#include "xenia/gpu/draw_util.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/registers.h"
@@ -82,7 +83,6 @@ void VulkanPipelineCache::ClearCache() {
}
VulkanShader* VulkanPipelineCache::LoadShader(xenos::ShaderType shader_type,
uint32_t guest_address,
const uint32_t* host_address,
uint32_t dword_count) {
// Hash the input memory and lookup the shader.
@@ -93,7 +93,6 @@ VulkanShader* VulkanPipelineCache::LoadShader(xenos::ShaderType shader_type,
// Shader has been previously loaded.
return it->second;
}
// 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.
@@ -101,53 +100,34 @@ VulkanShader* VulkanPipelineCache::LoadShader(xenos::ShaderType shader_type,
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;
SpirvShaderTranslator::Modification
VulkanPipelineCache::GetCurrentVertexShaderModification(
const Shader& shader,
Shader::HostVertexShaderType host_vertex_shader_type) const {
assert_true(shader.type() == xenos::ShaderType::kVertex);
assert_true(shader.is_ucode_analyzed());
const auto& regs = register_file_;
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
return SpirvShaderTranslator::Modification(
shader_translator_->GetDefaultVertexShaderModification(
shader.GetDynamicAddressableRegisterCount(sq_program_cntl.vs_num_reg),
host_vertex_shader_type));
}
bool VulkanPipelineCache::EnsureShadersTranslated(
VulkanShader::VulkanTranslation* vertex_shader,
VulkanShader::VulkanTranslation* pixel_shader) {
const RegisterFile& regs = register_file_;
SpirvShaderTranslator::Modification
VulkanPipelineCache::GetCurrentPixelShaderModification(
const Shader& shader) const {
assert_true(shader.type() == xenos::ShaderType::kPixel);
assert_true(shader.is_ucode_analyzed());
const auto& regs = register_file_;
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
// Edge flags are not supported yet (because polygon primitives are not).
assert_true(sq_program_cntl.vs_export_mode !=
xenos::VertexShaderExportMode::kPosition2VectorsEdge &&
sq_program_cntl.vs_export_mode !=
xenos::VertexShaderExportMode::kPosition2VectorsEdgeKill);
assert_false(sq_program_cntl.gen_index_vtx);
if (!vertex_shader->is_translated()) {
if (!TranslateShader(*shader_translator_, *vertex_shader,
sq_program_cntl)) {
XELOGE("Failed to translate the vertex shader!");
return false;
}
}
if (pixel_shader != nullptr && !pixel_shader->is_translated()) {
if (!TranslateShader(*shader_translator_, *pixel_shader, sq_program_cntl)) {
XELOGE("Failed to translate the pixel shader!");
return false;
}
}
return true;
return SpirvShaderTranslator::Modification(
shader_translator_->GetDefaultPixelShaderModification(
shader.GetDynamicAddressableRegisterCount(
sq_program_cntl.ps_num_reg)));
}
bool VulkanPipelineCache::ConfigurePipeline(
@@ -160,6 +140,38 @@ bool VulkanPipelineCache::ConfigurePipeline(
SCOPE_profile_cpu_f("gpu");
#endif // XE_UI_VULKAN_FINE_GRAINED_DRAW_SCOPES
// Ensure shaders are translated - needed now for GetCurrentStateDescription.
// Edge flags are not supported yet (because polygon primitives are not).
assert_true(register_file_.Get<reg::SQ_PROGRAM_CNTL>().vs_export_mode !=
xenos::VertexShaderExportMode::kPosition2VectorsEdge &&
register_file_.Get<reg::SQ_PROGRAM_CNTL>().vs_export_mode !=
xenos::VertexShaderExportMode::kPosition2VectorsEdgeKill);
assert_false(register_file_.Get<reg::SQ_PROGRAM_CNTL>().gen_index_vtx);
if (!vertex_shader->is_translated()) {
vertex_shader->shader().AnalyzeUcode(ucode_disasm_buffer_);
if (!TranslateAnalyzedShader(*shader_translator_, *vertex_shader)) {
XELOGE("Failed to translate the vertex shader!");
return false;
}
}
if (!vertex_shader->is_valid()) {
// Translation attempted previously, but not valid.
return false;
}
if (pixel_shader != nullptr) {
if (!pixel_shader->is_translated()) {
pixel_shader->shader().AnalyzeUcode(ucode_disasm_buffer_);
if (!TranslateAnalyzedShader(*shader_translator_, *pixel_shader)) {
XELOGE("Failed to translate the pixel shader!");
return false;
}
}
if (!pixel_shader->is_valid()) {
// Translation attempted previously, but not valid.
return false;
}
}
PipelineDescription description;
if (!GetCurrentStateDescription(vertex_shader, pixel_shader, render_pass_key,
description)) {
@@ -179,9 +191,6 @@ bool VulkanPipelineCache::ConfigurePipeline(
}
// Create the pipeline if not the latest and not already existing.
if (!EnsureShadersTranslated(vertex_shader, pixel_shader)) {
return false;
}
const PipelineLayoutProvider* pipeline_layout =
command_processor_.GetPipelineLayout(0, 0);
if (!pipeline_layout) {
@@ -207,12 +216,12 @@ bool VulkanPipelineCache::ConfigurePipeline(
return true;
}
bool VulkanPipelineCache::TranslateShader(
bool VulkanPipelineCache::TranslateAnalyzedShader(
SpirvShaderTranslator& translator,
VulkanShader::VulkanTranslation& translation, reg::SQ_PROGRAM_CNTL cntl) {
VulkanShader::VulkanTranslation& translation) {
// Perform translation.
// If this fails the shader will be marked as invalid and ignored later.
if (!translator.Translate(translation, cntl)) {
if (!translator.TranslateAnalyzedShader(translation)) {
XELOGE("Shader {:016X} translation failed; marking as ignored",
translation.shader().ucode_data_hash());
return false;
@@ -283,7 +292,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
primitive_restart_allowed && pa_su_sc_mode_cntl.multi_prim_ib_ena;
// TODO(Triang3l): Tessellation.
bool primitive_polygonal = xenos::IsPrimitivePolygonal(false, primitive_type);
bool primitive_polygonal = draw_util::IsPrimitivePolygonal(regs);
if (primitive_polygonal) {
// Vulkan only allows the polygon mode to be set for both faces - pick the
// most special one (more likely to represent the developer's deliberate

View File

@@ -52,18 +52,21 @@ class VulkanPipelineCache {
void ClearCache();
VulkanShader* LoadShader(xenos::ShaderType shader_type,
uint32_t guest_address, const uint32_t* host_address,
uint32_t dword_count);
const uint32_t* host_address, uint32_t dword_count);
// Analyze shader microcode on the translator thread.
void AnalyzeShaderUcode(Shader& shader) {
shader.AnalyzeUcode(ucode_disasm_buffer_);
}
// 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::VulkanTranslation* vertex_shader,
VulkanShader::VulkanTranslation* pixel_shader);
// Retrieves the shader modification for the current state. The shader must
// have microcode analyzed.
SpirvShaderTranslator::Modification
VulkanPipelineCache::GetCurrentVertexShaderModification(
const Shader& shader,
Shader::HostVertexShaderType host_vertex_shader_type) const;
SpirvShaderTranslator::Modification
VulkanPipelineCache::GetCurrentPixelShaderModification(
const Shader& shader) const;
// TODO(Triang3l): Return a deferred creation handle.
bool ConfigurePipeline(VulkanShader::VulkanTranslation* vertex_shader,
@@ -105,10 +108,10 @@ class VulkanPipelineCache {
XEPACKEDSTRUCT(PipelineDescription, {
uint64_t vertex_shader_hash;
uint64_t vertex_shader_modification;
// 0 if no pixel shader.
uint64_t pixel_shader_hash;
uint32_t vertex_shader_modification;
uint32_t pixel_shader_modification;
uint64_t pixel_shader_modification;
VulkanRenderTargetCache::RenderPassKey render_pass_key;
// Input assembly.
@@ -159,9 +162,8 @@ class VulkanPipelineCache {
};
// Can be called from multiple threads.
bool TranslateShader(SpirvShaderTranslator& translator,
VulkanShader::VulkanTranslation& translation,
reg::SQ_PROGRAM_CNTL cntl);
bool TranslateAnalyzedShader(SpirvShaderTranslator& translator,
VulkanShader::VulkanTranslation& translation);
bool GetCurrentStateDescription(
const VulkanShader::VulkanTranslation* vertex_shader,
@@ -181,6 +183,8 @@ class VulkanPipelineCache {
DevicePipelineFeatures device_pipeline_features_;
// Temporary storage for AnalyzeUcode calls on the processor thread.
StringBuffer ucode_disasm_buffer_;
// Reusable shader translator on the command processor thread.
std::unique_ptr<SpirvShaderTranslator> shader_translator_;

View File

@@ -58,7 +58,7 @@ VulkanShader::VulkanShader(xenos::ShaderType shader_type, uint64_t data_hash,
provider_(provider) {}
Shader::Translation* VulkanShader::CreateTranslationInstance(
uint32_t modification) {
uint64_t modification) {
return new VulkanTranslation(*this, modification);
}

View File

@@ -24,7 +24,7 @@ class VulkanShader : public Shader {
public:
class VulkanTranslation : public Translation {
public:
VulkanTranslation(VulkanShader& shader, uint32_t modification)
VulkanTranslation(VulkanShader& shader, uint64_t modification)
: Translation(shader, modification) {}
~VulkanTranslation() override;
@@ -40,7 +40,7 @@ class VulkanShader : public Shader {
const ui::vulkan::VulkanProvider& provider);
protected:
Translation* CreateTranslationInstance(uint32_t modification) override;
Translation* CreateTranslationInstance(uint64_t modification) override;
private:
const ui::vulkan::VulkanProvider& provider_;

View File

@@ -418,7 +418,7 @@ bool VulkanSharedMemory::UploadRanges(
break;
}
MakeRangeValid(upload_range_start << page_size_log2(),
uint32_t(upload_buffer_size), false);
uint32_t(upload_buffer_size), false, false);
std::memcpy(
upload_buffer_mapping,
memory().TranslatePhysical(upload_range_start << page_size_log2()),