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