Merge branch 'master' of https://github.com/xenia-project/xenia into canary_experimental
This commit is contained in:
@@ -497,7 +497,7 @@ class D3D12RenderTargetCache final : public RenderTargetCache {
|
||||
TransferInvocation(const Transfer& transfer,
|
||||
const TransferShaderKey& shader_key)
|
||||
: transfer(transfer), shader_key(shader_key) {}
|
||||
bool operator<(const TransferInvocation& other_invocation) {
|
||||
bool operator<(const TransferInvocation& other_invocation) const {
|
||||
// TODO(Triang3l): See if it may be better to sort by the source in the
|
||||
// first place, especially when reading the same data multiple times (like
|
||||
// to write the stencil bits after depth) for better read locality.
|
||||
@@ -639,7 +639,7 @@ class D3D12RenderTargetCache final : public RenderTargetCache {
|
||||
DumpInvocation(const ResolveCopyDumpRectangle& rectangle,
|
||||
const DumpPipelineKey& pipeline_key)
|
||||
: rectangle(rectangle), pipeline_key(pipeline_key) {}
|
||||
bool operator<(const DumpInvocation& other_invocation) {
|
||||
bool operator<(const DumpInvocation& other_invocation) const {
|
||||
// Sort by the pipeline key primarily to reduce pipeline state (context)
|
||||
// switches.
|
||||
if (pipeline_key != other_invocation.pipeline_key) {
|
||||
|
||||
@@ -30,7 +30,6 @@ project("xenia-gpu-d3d12-trace-viewer")
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-cpu-backend-x64",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-d3d12",
|
||||
"xenia-hid",
|
||||
@@ -68,6 +67,11 @@ project("xenia-gpu-d3d12-trace-viewer")
|
||||
})
|
||||
end
|
||||
|
||||
filter("architecture:x86_64")
|
||||
links({
|
||||
"xenia-cpu-backend-x64",
|
||||
})
|
||||
|
||||
group("src")
|
||||
project("xenia-gpu-d3d12-trace-dump")
|
||||
uuid("686b859c-0046-44c4-a02c-41fc3fb75698")
|
||||
@@ -79,7 +83,6 @@ project("xenia-gpu-d3d12-trace-dump")
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-cpu-backend-x64",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-d3d12",
|
||||
"xenia-hid",
|
||||
@@ -115,3 +118,8 @@ project("xenia-gpu-d3d12-trace-dump")
|
||||
"1>scratch/stdout-trace-dump.txt",
|
||||
})
|
||||
end
|
||||
|
||||
filter("architecture:x86_64")
|
||||
links({
|
||||
"xenia-cpu-backend-x64",
|
||||
})
|
||||
|
||||
@@ -942,7 +942,7 @@ void PrimitiveProcessor::Get16BitResetIndexUsage(
|
||||
is_ffff_simd =
|
||||
_mm_or_si128(is_ffff_simd, _mm_cmpeq_epi16(source_simd, ffff_simd));
|
||||
#elif XE_ARCH_ARM64
|
||||
is_reset_simd = vcorrq_u16(
|
||||
is_reset_simd = vorrq_u16(
|
||||
is_reset_simd, vceqq_u16(source_simd, reset_index_guest_endian_simd));
|
||||
is_ffff_simd = vmaxq_u16(is_ffff_simd, source_simd);
|
||||
#else
|
||||
|
||||
@@ -374,8 +374,14 @@ void RenderTargetCache::InitializeCommon() {
|
||||
RenderTargetKey(), RenderTargetKey()));
|
||||
}
|
||||
|
||||
void RenderTargetCache::ShutdownCommon() {
|
||||
void RenderTargetCache::DestroyAllRenderTargets(bool shutting_down) {
|
||||
ownership_ranges_.clear();
|
||||
if (!shutting_down) {
|
||||
ownership_ranges_.emplace(
|
||||
std::piecewise_construct, std::forward_as_tuple(uint32_t(0)),
|
||||
std::forward_as_tuple(xenos::kEdramTileCount, RenderTargetKey(),
|
||||
RenderTargetKey(), RenderTargetKey()));
|
||||
}
|
||||
|
||||
for (const auto& render_target_pair : render_targets_) {
|
||||
if (render_target_pair.second) {
|
||||
@@ -385,6 +391,8 @@ void RenderTargetCache::ShutdownCommon() {
|
||||
render_targets_.clear();
|
||||
}
|
||||
|
||||
void RenderTargetCache::ShutdownCommon() { DestroyAllRenderTargets(true); }
|
||||
|
||||
void RenderTargetCache::ClearCache() {
|
||||
// Keep only render targets currently owning any EDRAM data.
|
||||
if (!render_targets_.empty()) {
|
||||
|
||||
@@ -193,6 +193,10 @@ class RenderTargetCache {
|
||||
// Call last in implementation-specific initialization (when things like path
|
||||
// are initialized by the implementation).
|
||||
void InitializeCommon();
|
||||
// May be called from the destructor, or from the implementation shutdown to
|
||||
// destroy all render targets before destroying what they depend on in the
|
||||
// implementation.
|
||||
void DestroyAllRenderTargets(bool shutting_down);
|
||||
// Call last in implementation-specific shutdown, also callable from the
|
||||
// destructor.
|
||||
void ShutdownCommon();
|
||||
|
||||
@@ -75,9 +75,6 @@ SpirvShaderTranslator::Features::Features(
|
||||
}
|
||||
}
|
||||
|
||||
const std::string SpirvShaderTranslator::kInterpolatorNamePrefix =
|
||||
"xe_interpolator_";
|
||||
|
||||
SpirvShaderTranslator::SpirvShaderTranslator(const Features& features)
|
||||
: features_(features) {}
|
||||
|
||||
@@ -164,6 +161,8 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||
type_float2_ = builder_->makeVectorType(type_float_, 2);
|
||||
type_float3_ = builder_->makeVectorType(type_float_, 3);
|
||||
type_float4_ = builder_->makeVectorType(type_float_, 4);
|
||||
type_interpolators_ = builder_->makeArrayType(
|
||||
type_float4_, builder_->makeUintConstant(xenos::kMaxInterpolators), 0);
|
||||
|
||||
const_int_0_ = builder_->makeIntConstant(0);
|
||||
id_vector_temp_.clear();
|
||||
@@ -257,8 +256,9 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||
"xe_uniform_system_constants");
|
||||
builder_->addDecoration(uniform_system_constants_,
|
||||
spv::DecorationDescriptorSet,
|
||||
kDescriptorSetSystemConstants);
|
||||
builder_->addDecoration(uniform_system_constants_, spv::DecorationBinding, 0);
|
||||
int(kDescriptorSetConstants));
|
||||
builder_->addDecoration(uniform_system_constants_, spv::DecorationBinding,
|
||||
int(kConstantBufferSystem));
|
||||
if (features_.spirv_version >= spv::Spv_1_4) {
|
||||
main_interface_.push_back(uniform_system_constants_);
|
||||
}
|
||||
@@ -285,12 +285,13 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||
uniform_float_constants_ = builder_->createVariable(
|
||||
spv::NoPrecision, spv::StorageClassUniform, type_float_constants,
|
||||
"xe_uniform_float_constants");
|
||||
builder_->addDecoration(uniform_float_constants_,
|
||||
spv::DecorationDescriptorSet,
|
||||
int(kDescriptorSetConstants));
|
||||
builder_->addDecoration(
|
||||
uniform_float_constants_, spv::DecorationDescriptorSet,
|
||||
int(is_pixel_shader() ? kDescriptorSetFloatConstantsPixel
|
||||
: kDescriptorSetFloatConstantsVertex));
|
||||
builder_->addDecoration(uniform_float_constants_, spv::DecorationBinding,
|
||||
0);
|
||||
uniform_float_constants_, spv::DecorationBinding,
|
||||
int(is_pixel_shader() ? kConstantBufferFloatPixel
|
||||
: kConstantBufferFloatVertex));
|
||||
if (features_.spirv_version >= spv::Spv_1_4) {
|
||||
main_interface_.push_back(uniform_float_constants_);
|
||||
}
|
||||
@@ -326,9 +327,9 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||
"xe_uniform_bool_loop_constants");
|
||||
builder_->addDecoration(uniform_bool_loop_constants_,
|
||||
spv::DecorationDescriptorSet,
|
||||
int(kDescriptorSetBoolLoopConstants));
|
||||
int(kDescriptorSetConstants));
|
||||
builder_->addDecoration(uniform_bool_loop_constants_, spv::DecorationBinding,
|
||||
0);
|
||||
int(kConstantBufferBoolLoop));
|
||||
if (features_.spirv_version >= spv::Spv_1_4) {
|
||||
main_interface_.push_back(uniform_bool_loop_constants_);
|
||||
}
|
||||
@@ -352,8 +353,9 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||
"xe_uniform_fetch_constants");
|
||||
builder_->addDecoration(uniform_fetch_constants_,
|
||||
spv::DecorationDescriptorSet,
|
||||
int(kDescriptorSetFetchConstants));
|
||||
builder_->addDecoration(uniform_fetch_constants_, spv::DecorationBinding, 0);
|
||||
int(kDescriptorSetConstants));
|
||||
builder_->addDecoration(uniform_fetch_constants_, spv::DecorationBinding,
|
||||
int(kConstantBufferFetch));
|
||||
if (features_.spirv_version >= spv::Spv_1_4) {
|
||||
main_interface_.push_back(uniform_fetch_constants_);
|
||||
}
|
||||
@@ -639,6 +641,16 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
||||
entry_point->addIdOperand(interface_id);
|
||||
}
|
||||
|
||||
// Specify the binding indices for samplers when the number of textures is
|
||||
// known, as samplers are located after images in the texture descriptor set.
|
||||
size_t texture_binding_count = texture_bindings_.size();
|
||||
size_t sampler_binding_count = sampler_bindings_.size();
|
||||
for (size_t i = 0; i < sampler_binding_count; ++i) {
|
||||
builder_->addDecoration(sampler_bindings_[i].variable,
|
||||
spv::DecorationBinding,
|
||||
int(texture_binding_count + i));
|
||||
}
|
||||
|
||||
// TODO(Triang3l): Avoid copy?
|
||||
std::vector<unsigned int> module_uints;
|
||||
builder_->dump(module_uints);
|
||||
@@ -1056,17 +1068,15 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
||||
main_interface_.push_back(input_vertex_index_);
|
||||
}
|
||||
|
||||
// Create the Xenia-specific outputs.
|
||||
// TODO(Triang3l): Change to an interpolator array.
|
||||
for (uint32_t i = 0; i < xenos::kMaxInterpolators; ++i) {
|
||||
spv::Id interpolator = builder_->createVariable(
|
||||
spv::NoPrecision, spv::StorageClassOutput, type_float4_,
|
||||
(kInterpolatorNamePrefix + std::to_string(i)).c_str());
|
||||
input_output_interpolators_[i] = interpolator;
|
||||
builder_->addDecoration(interpolator, spv::DecorationLocation, int(i));
|
||||
builder_->addDecoration(interpolator, spv::DecorationInvariant);
|
||||
main_interface_.push_back(interpolator);
|
||||
}
|
||||
// Create the interpolator output.
|
||||
input_output_interpolators_ =
|
||||
builder_->createVariable(spv::NoPrecision, spv::StorageClassOutput,
|
||||
type_interpolators_, "xe_out_interpolators");
|
||||
builder_->addDecoration(input_output_interpolators_, spv::DecorationLocation,
|
||||
0);
|
||||
builder_->addDecoration(input_output_interpolators_,
|
||||
spv::DecorationInvariant);
|
||||
main_interface_.push_back(input_output_interpolators_);
|
||||
|
||||
// Create the gl_PerVertex output for used system outputs.
|
||||
std::vector<spv::Id> struct_per_vertex_members;
|
||||
@@ -1095,7 +1105,12 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderInMain() {
|
||||
|
||||
// Zero the interpolators.
|
||||
for (uint32_t i = 0; i < xenos::kMaxInterpolators; ++i) {
|
||||
builder_->createStore(const_float4_0_, input_output_interpolators_[i]);
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(builder_->makeIntConstant(int(i)));
|
||||
builder_->createStore(const_float4_0_,
|
||||
builder_->createAccessChain(
|
||||
spv::StorageClassOutput,
|
||||
input_output_interpolators_, id_vector_temp_));
|
||||
}
|
||||
|
||||
// Load the vertex index or the tessellation parameters.
|
||||
@@ -1269,17 +1284,13 @@ void SpirvShaderTranslator::CompleteVertexOrTessEvalShaderInMain() {
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::StartFragmentShaderBeforeMain() {
|
||||
// Interpolator inputs.
|
||||
uint32_t interpolator_count =
|
||||
std::min(xenos::kMaxInterpolators, register_count());
|
||||
for (uint32_t i = 0; i < interpolator_count; ++i) {
|
||||
spv::Id interpolator = builder_->createVariable(
|
||||
spv::NoPrecision, spv::StorageClassInput, type_float4_,
|
||||
(kInterpolatorNamePrefix + std::to_string(i)).c_str());
|
||||
input_output_interpolators_[i] = interpolator;
|
||||
builder_->addDecoration(interpolator, spv::DecorationLocation, int(i));
|
||||
main_interface_.push_back(interpolator);
|
||||
}
|
||||
// Interpolator input.
|
||||
input_output_interpolators_ =
|
||||
builder_->createVariable(spv::NoPrecision, spv::StorageClassInput,
|
||||
type_interpolators_, "xe_in_interpolators");
|
||||
builder_->addDecoration(input_output_interpolators_, spv::DecorationLocation,
|
||||
0);
|
||||
main_interface_.push_back(input_output_interpolators_);
|
||||
|
||||
bool param_gen_needed = GetPsParamGenInterpolator() != UINT32_MAX;
|
||||
|
||||
@@ -1347,7 +1358,10 @@ void SpirvShaderTranslator::StartFragmentShaderInMain() {
|
||||
// Register array element.
|
||||
id_vector_temp_.push_back(builder_->makeIntConstant(int(i)));
|
||||
builder_->createStore(
|
||||
builder_->createLoad(input_output_interpolators_[i], spv::NoPrecision),
|
||||
builder_->createLoad(builder_->createAccessChain(
|
||||
spv::StorageClassInput,
|
||||
input_output_interpolators_, id_vector_temp_),
|
||||
spv::NoPrecision),
|
||||
builder_->createAccessChain(spv::StorageClassFunction,
|
||||
var_main_registers_, id_vector_temp_));
|
||||
}
|
||||
@@ -1824,7 +1838,12 @@ void SpirvShaderTranslator::StoreResult(const InstructionResult& result,
|
||||
} break;
|
||||
case InstructionStorageTarget::kInterpolator:
|
||||
assert_true(is_vertex_shader());
|
||||
target_pointer = input_output_interpolators_[result.storage_index];
|
||||
id_vector_temp_util_.clear();
|
||||
id_vector_temp_util_.push_back(
|
||||
builder_->makeIntConstant(int(result.storage_index)));
|
||||
target_pointer = builder_->createAccessChain(spv::StorageClassOutput,
|
||||
input_output_interpolators_,
|
||||
id_vector_temp_util_);
|
||||
break;
|
||||
case InstructionStorageTarget::kPosition:
|
||||
assert_true(is_vertex_shader());
|
||||
|
||||
@@ -131,6 +131,16 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||
float color_exp_bias[4];
|
||||
};
|
||||
|
||||
enum ConstantBuffer : uint32_t {
|
||||
kConstantBufferSystem,
|
||||
kConstantBufferFloatVertex,
|
||||
kConstantBufferFloatPixel,
|
||||
kConstantBufferBoolLoop,
|
||||
kConstantBufferFetch,
|
||||
|
||||
kConstantBufferCount,
|
||||
};
|
||||
|
||||
// The minimum limit for maxPerStageDescriptorStorageBuffers is 4, and for
|
||||
// maxStorageBufferRange it's 128 MB. These are the values of those limits on
|
||||
// Arm Mali as of November 2020. Xenia needs 512 MB shared memory to be bound,
|
||||
@@ -159,31 +169,28 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||
|
||||
// Never changed.
|
||||
kDescriptorSetSharedMemoryAndEdram,
|
||||
// Pretty rarely used and rarely changed - flow control constants.
|
||||
kDescriptorSetBoolLoopConstants,
|
||||
// May stay the same across many draws.
|
||||
kDescriptorSetSystemConstants,
|
||||
// Less frequently changed (per-material).
|
||||
kDescriptorSetFloatConstantsPixel,
|
||||
// Quite frequently changed (for one object drawn multiple times, for
|
||||
// instance - may contain projection matrices).
|
||||
kDescriptorSetFloatConstantsVertex,
|
||||
// Very frequently changed, especially for UI draws, and for models drawn in
|
||||
// multiple parts - contains vertex and texture fetch constants.
|
||||
kDescriptorSetFetchConstants,
|
||||
// Changed in case of changes in the data.
|
||||
kDescriptorSetConstants,
|
||||
|
||||
// Mutable part of the pipeline layout:
|
||||
kDescriptorSetMutableLayoutsStart,
|
||||
|
||||
// Rarely used at all, but may be changed at an unpredictable rate when
|
||||
// vertex textures are used.
|
||||
kDescriptorSetSamplersVertex = kDescriptorSetMutableLayoutsStart,
|
||||
kDescriptorSetTexturesVertex,
|
||||
// vertex textures are used (for example, for bones of an object, which may
|
||||
// consist of multiple draw commands with different materials).
|
||||
kDescriptorSetTexturesVertex = kDescriptorSetMutableLayoutsStart,
|
||||
// Per-material textures.
|
||||
kDescriptorSetSamplersPixel,
|
||||
kDescriptorSetTexturesPixel,
|
||||
|
||||
kDescriptorSetCount,
|
||||
};
|
||||
static_assert(
|
||||
kDescriptorSetCount <= 4,
|
||||
"The number of descriptor sets used by translated shaders must be within "
|
||||
"the minimum Vulkan maxBoundDescriptorSets requirement of 4, which is "
|
||||
"the limit on most GPUs used in Android devices - Arm Mali, Imagination "
|
||||
"PowerVR, Qualcomm Adreno 6xx and older, as well as on old PC Nvidia "
|
||||
"drivers");
|
||||
|
||||
// "Xenia Emulator Microcode Translator".
|
||||
// https://github.com/KhronosGroup/SPIRV-Headers/blob/c43a43c7cc3af55910b9bec2a71e3e8a622443cf/include/spirv/spir-v.xml#L79
|
||||
@@ -522,6 +529,8 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||
spv::Id type_float_vectors_[4];
|
||||
};
|
||||
|
||||
spv::Id type_interpolators_;
|
||||
|
||||
spv::Id const_int_0_;
|
||||
spv::Id const_int4_0_;
|
||||
spv::Id const_uint_0_;
|
||||
@@ -582,11 +591,12 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||
// PS, only when needed - bool.
|
||||
spv::Id input_front_facing_;
|
||||
|
||||
// In vertex or tessellation evaluation shaders - outputs, always
|
||||
// xenos::kMaxInterpolators.
|
||||
// In pixel shaders - inputs, min(xenos::kMaxInterpolators, register_count()).
|
||||
spv::Id input_output_interpolators_[xenos::kMaxInterpolators];
|
||||
static const std::string kInterpolatorNamePrefix;
|
||||
// VS output or PS input, only when needed - type_interpolators_.
|
||||
// The Qualcomm Adreno driver has strict requirements for stage linkage - if
|
||||
// this is an array in one stage, it must be an array in the other (in case of
|
||||
// Xenia, including geometry shaders); it must not be an array in one and just
|
||||
// elements in consecutive locations in another.
|
||||
spv::Id input_output_interpolators_;
|
||||
|
||||
enum OutputPerVertexMember : unsigned int {
|
||||
kOutputPerVertexMemberPosition,
|
||||
|
||||
@@ -2573,10 +2573,10 @@ size_t SpirvShaderTranslator::FindOrAddSamplerBinding(
|
||||
builder_->makeSamplerType(), name.str().c_str());
|
||||
builder_->addDecoration(
|
||||
new_sampler_binding.variable, spv::DecorationDescriptorSet,
|
||||
int(is_vertex_shader() ? kDescriptorSetSamplersVertex
|
||||
: kDescriptorSetSamplersPixel));
|
||||
builder_->addDecoration(new_sampler_binding.variable, spv::DecorationBinding,
|
||||
int(new_sampler_binding_index));
|
||||
int(is_vertex_shader() ? kDescriptorSetTexturesVertex
|
||||
: kDescriptorSetTexturesPixel));
|
||||
// The binding indices will be specified later after all textures are added as
|
||||
// samplers are located after images in the descriptor set.
|
||||
if (features_.spirv_version >= spv::Spv_1_4) {
|
||||
main_interface_.push_back(new_sampler_binding.variable);
|
||||
}
|
||||
|
||||
@@ -95,8 +95,8 @@ bool TraceDump::Setup() {
|
||||
// Create the emulator but don't initialize so we can setup the window.
|
||||
emulator_ = std::make_unique<Emulator>("", "", "", "");
|
||||
X_STATUS result = emulator_->Setup(
|
||||
nullptr, nullptr, nullptr, [this]() { return CreateGraphicsSystem(); },
|
||||
nullptr);
|
||||
nullptr, nullptr, false, nullptr,
|
||||
[this]() { return CreateGraphicsSystem(); }, nullptr);
|
||||
if (XFAILED(result)) {
|
||||
XELOGE("Failed to setup emulator: {:08X}", result);
|
||||
return false;
|
||||
|
||||
@@ -125,7 +125,7 @@ bool TraceViewer::Setup() {
|
||||
// Create the emulator but don't initialize so we can setup the window.
|
||||
emulator_ = std::make_unique<Emulator>("", "", "", "");
|
||||
X_STATUS result = emulator_->Setup(
|
||||
window_.get(), nullptr, nullptr,
|
||||
window_.get(), nullptr, false, nullptr,
|
||||
[this]() { return CreateGraphicsSystem(); }, nullptr);
|
||||
if (XFAILED(result)) {
|
||||
XELOGE("Failed to setup emulator: {:08X}", result);
|
||||
|
||||
@@ -34,7 +34,6 @@ project("xenia-gpu-vulkan-trace-viewer")
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-cpu-backend-x64",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-vulkan",
|
||||
"xenia-hid",
|
||||
@@ -66,6 +65,11 @@ project("xenia-gpu-vulkan-trace-viewer")
|
||||
"../../ui/windowed_app_main_"..platform_suffix..".cc",
|
||||
})
|
||||
|
||||
filter("architecture:x86_64")
|
||||
links({
|
||||
"xenia-cpu-backend-x64",
|
||||
})
|
||||
|
||||
filter("platforms:Linux")
|
||||
links({
|
||||
"X11",
|
||||
@@ -95,7 +99,6 @@ project("xenia-gpu-vulkan-trace-dump")
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-cpu-backend-x64",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-vulkan",
|
||||
"xenia-hid",
|
||||
@@ -126,6 +129,11 @@ project("xenia-gpu-vulkan-trace-dump")
|
||||
"../../base/console_app_main_"..platform_suffix..".cc",
|
||||
})
|
||||
|
||||
filter("architecture:x86_64")
|
||||
links({
|
||||
"xenia-cpu-backend-x64",
|
||||
})
|
||||
|
||||
filter("platforms:Linux")
|
||||
links({
|
||||
"X11",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -36,7 +36,7 @@
|
||||
#include "xenia/gpu/vulkan/vulkan_texture_cache.h"
|
||||
#include "xenia/gpu/xenos.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/ui/vulkan/single_type_descriptor_set_allocator.h"
|
||||
#include "xenia/ui/vulkan/linked_type_descriptor_set_allocator.h"
|
||||
#include "xenia/ui/vulkan/vulkan_presenter.h"
|
||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||
#include "xenia/ui/vulkan/vulkan_upload_buffer_pool.h"
|
||||
@@ -49,10 +49,6 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
public:
|
||||
// Single-descriptor layouts for use within a single frame.
|
||||
enum class SingleTransientDescriptorLayout {
|
||||
kUniformBufferGuestVertex,
|
||||
kUniformBufferFragment,
|
||||
kUniformBufferGuestShader,
|
||||
kUniformBufferSystemConstants,
|
||||
kUniformBufferCompute,
|
||||
kStorageBufferCompute,
|
||||
kCount,
|
||||
@@ -231,9 +227,9 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
VkDescriptorSet& descriptor_set_out);
|
||||
|
||||
// The returned reference is valid until a cache clear.
|
||||
VkDescriptorSetLayout GetTextureDescriptorSetLayout(bool is_samplers,
|
||||
bool is_vertex,
|
||||
size_t binding_count);
|
||||
VkDescriptorSetLayout GetTextureDescriptorSetLayout(bool is_vertex,
|
||||
size_t texture_count,
|
||||
size_t sampler_count);
|
||||
// The returned reference is valid until a cache clear.
|
||||
const VulkanPipelineCache::PipelineLayoutProvider* GetPipelineLayout(
|
||||
size_t texture_count_pixel, size_t sampler_count_pixel,
|
||||
@@ -298,12 +294,11 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
union TextureDescriptorSetLayoutKey {
|
||||
uint32_t key;
|
||||
struct {
|
||||
// 0 - sampled image descriptors, 1 - sampler descriptors.
|
||||
uint32_t is_samplers : 1;
|
||||
// If texture and sampler counts are both 0, use
|
||||
// descriptor_set_layout_empty_ instead as these are owning references.
|
||||
uint32_t texture_count : 16;
|
||||
uint32_t sampler_count : 15;
|
||||
uint32_t is_vertex : 1;
|
||||
// For 0, use descriptor_set_layout_empty_ instead as these are owning
|
||||
// references.
|
||||
uint32_t binding_count : 30;
|
||||
};
|
||||
|
||||
TextureDescriptorSetLayoutKey() : key(0) {
|
||||
@@ -354,40 +349,26 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
explicit PipelineLayout(
|
||||
VkPipelineLayout pipeline_layout,
|
||||
VkDescriptorSetLayout descriptor_set_layout_textures_vertex_ref,
|
||||
VkDescriptorSetLayout descriptor_set_layout_samplers_vertex_ref,
|
||||
VkDescriptorSetLayout descriptor_set_layout_textures_pixel_ref,
|
||||
VkDescriptorSetLayout descriptor_set_layout_samplers_pixel_ref)
|
||||
VkDescriptorSetLayout descriptor_set_layout_textures_pixel_ref)
|
||||
: pipeline_layout_(pipeline_layout),
|
||||
descriptor_set_layout_textures_vertex_ref_(
|
||||
descriptor_set_layout_textures_vertex_ref),
|
||||
descriptor_set_layout_samplers_vertex_ref_(
|
||||
descriptor_set_layout_samplers_vertex_ref),
|
||||
descriptor_set_layout_textures_pixel_ref_(
|
||||
descriptor_set_layout_textures_pixel_ref),
|
||||
descriptor_set_layout_samplers_pixel_ref_(
|
||||
descriptor_set_layout_samplers_pixel_ref) {}
|
||||
descriptor_set_layout_textures_pixel_ref) {}
|
||||
VkPipelineLayout GetPipelineLayout() const override {
|
||||
return pipeline_layout_;
|
||||
}
|
||||
VkDescriptorSetLayout descriptor_set_layout_textures_vertex_ref() const {
|
||||
return descriptor_set_layout_textures_vertex_ref_;
|
||||
}
|
||||
VkDescriptorSetLayout descriptor_set_layout_samplers_vertex_ref() const {
|
||||
return descriptor_set_layout_samplers_vertex_ref_;
|
||||
}
|
||||
VkDescriptorSetLayout descriptor_set_layout_textures_pixel_ref() const {
|
||||
return descriptor_set_layout_textures_pixel_ref_;
|
||||
}
|
||||
VkDescriptorSetLayout descriptor_set_layout_samplers_pixel_ref() const {
|
||||
return descriptor_set_layout_samplers_pixel_ref_;
|
||||
}
|
||||
|
||||
private:
|
||||
VkPipelineLayout pipeline_layout_;
|
||||
VkDescriptorSetLayout descriptor_set_layout_textures_vertex_ref_;
|
||||
VkDescriptorSetLayout descriptor_set_layout_samplers_vertex_ref_;
|
||||
VkDescriptorSetLayout descriptor_set_layout_textures_pixel_ref_;
|
||||
VkDescriptorSetLayout descriptor_set_layout_samplers_pixel_ref_;
|
||||
};
|
||||
|
||||
struct UsedSingleTransientDescriptor {
|
||||
@@ -458,16 +439,20 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
uint32_t used_texture_mask);
|
||||
bool UpdateBindings(const VulkanShader* vertex_shader,
|
||||
const VulkanShader* pixel_shader);
|
||||
// Allocates a descriptor set and fills the VkWriteDescriptorSet structure.
|
||||
// The descriptor set layout must be the one for the given is_samplers,
|
||||
// is_vertex, binding_count (from GetTextureDescriptorSetLayout - may be
|
||||
// Allocates a descriptor set and fills one or two VkWriteDescriptorSet
|
||||
// structure instances (for images and samplers).
|
||||
// The descriptor set layout must be the one for the given is_vertex,
|
||||
// texture_count, sampler_count (from GetTextureDescriptorSetLayout - may be
|
||||
// already available at the moment of the call, no need to locate it again).
|
||||
// Returns whether the allocation was successful.
|
||||
bool WriteTransientTextureBindings(
|
||||
bool is_samplers, bool is_vertex, uint32_t binding_count,
|
||||
// Returns how many VkWriteDescriptorSet structure instances have been
|
||||
// written, or 0 if there was a failure to allocate the descriptor set or no
|
||||
// bindings were requested.
|
||||
uint32_t WriteTransientTextureBindings(
|
||||
bool is_vertex, uint32_t texture_count, uint32_t sampler_count,
|
||||
VkDescriptorSetLayout descriptor_set_layout,
|
||||
const VkDescriptorImageInfo* image_info,
|
||||
VkWriteDescriptorSet& write_descriptor_set_out);
|
||||
const VkDescriptorImageInfo* texture_image_info,
|
||||
const VkDescriptorImageInfo* sampler_image_info,
|
||||
VkWriteDescriptorSet* descriptor_set_writes_out);
|
||||
|
||||
bool device_lost_ = false;
|
||||
|
||||
@@ -530,6 +515,7 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
VkDescriptorSetLayout descriptor_set_layout_empty_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descriptor_set_layout_shared_memory_and_edram_ =
|
||||
VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descriptor_set_layout_constants_ = VK_NULL_HANDLE;
|
||||
std::array<VkDescriptorSetLayout,
|
||||
size_t(SingleTransientDescriptorLayout::kCount)>
|
||||
descriptor_set_layouts_single_transient_{};
|
||||
@@ -543,19 +529,27 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
PipelineLayoutKey::Hasher>
|
||||
pipeline_layouts_;
|
||||
|
||||
ui::vulkan::SingleTypeDescriptorSetAllocator
|
||||
// No specific reason for 32768, just the "too much" descriptor count from
|
||||
// Direct3D 12 PIX warnings.
|
||||
static constexpr uint32_t kLinkedTypeDescriptorPoolSetCount = 32768;
|
||||
static const VkDescriptorPoolSize kDescriptorPoolSizeUniformBuffer;
|
||||
static const VkDescriptorPoolSize kDescriptorPoolSizeStorageBuffer;
|
||||
static const VkDescriptorPoolSize kDescriptorPoolSizeTextures[2];
|
||||
ui::vulkan::LinkedTypeDescriptorSetAllocator
|
||||
transient_descriptor_allocator_uniform_buffer_;
|
||||
ui::vulkan::SingleTypeDescriptorSetAllocator
|
||||
ui::vulkan::LinkedTypeDescriptorSetAllocator
|
||||
transient_descriptor_allocator_storage_buffer_;
|
||||
std::deque<UsedSingleTransientDescriptor> single_transient_descriptors_used_;
|
||||
std::array<std::vector<VkDescriptorSet>,
|
||||
size_t(SingleTransientDescriptorLayout::kCount)>
|
||||
single_transient_descriptors_free_;
|
||||
// <Usage frame, set>.
|
||||
std::deque<std::pair<uint64_t, VkDescriptorSet>>
|
||||
constants_transient_descriptors_used_;
|
||||
std::vector<VkDescriptorSet> constants_transient_descriptors_free_;
|
||||
|
||||
ui::vulkan::SingleTypeDescriptorSetAllocator
|
||||
transient_descriptor_allocator_sampled_image_;
|
||||
ui::vulkan::SingleTypeDescriptorSetAllocator
|
||||
transient_descriptor_allocator_sampler_;
|
||||
ui::vulkan::LinkedTypeDescriptorSetAllocator
|
||||
transient_descriptor_allocator_textures_;
|
||||
std::deque<UsedTextureTransientDescriptorSet>
|
||||
texture_transient_descriptor_sets_used_;
|
||||
std::unordered_map<TextureDescriptorSetLayoutKey,
|
||||
@@ -701,6 +695,11 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
|
||||
// Pipeline layout of the current guest graphics pipeline.
|
||||
const PipelineLayout* current_guest_graphics_pipeline_layout_;
|
||||
VkDescriptorBufferInfo current_constant_buffer_infos_
|
||||
[SpirvShaderTranslator::kConstantBufferCount];
|
||||
// Whether up-to-date data has been written to constant (uniform) buffers, and
|
||||
// the buffer infos in current_constant_buffer_infos_ point to them.
|
||||
uint32_t current_constant_buffers_up_to_date_;
|
||||
VkDescriptorSet current_graphics_descriptor_sets_
|
||||
[SpirvShaderTranslator::kDescriptorSetCount];
|
||||
// Whether descriptor sets in current_graphics_descriptor_sets_ point to
|
||||
|
||||
@@ -661,6 +661,12 @@ void VulkanRenderTargetCache::Shutdown(bool from_destructor) {
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
|
||||
VkDevice device = provider.device();
|
||||
|
||||
// Destroy all render targets before the descriptor set pool is destroyed -
|
||||
// may happen if shutting down the VulkanRenderTargetCache by destroying it,
|
||||
// so ShutdownCommon is called by the RenderTargetCache destructor, when it's
|
||||
// already too late.
|
||||
DestroyAllRenderTargets(true);
|
||||
|
||||
for (const auto& dump_pipeline_pair : dump_pipelines_) {
|
||||
// May be null to prevent recreation attempts.
|
||||
if (dump_pipeline_pair.second != VK_NULL_HANDLE) {
|
||||
|
||||
@@ -647,7 +647,7 @@ class VulkanRenderTargetCache final : public RenderTargetCache {
|
||||
TransferInvocation(const Transfer& transfer,
|
||||
const TransferShaderKey& shader_key)
|
||||
: transfer(transfer), shader_key(shader_key) {}
|
||||
bool operator<(const TransferInvocation& other_invocation) {
|
||||
bool operator<(const TransferInvocation& other_invocation) const {
|
||||
// TODO(Triang3l): See if it may be better to sort by the source in the
|
||||
// first place, especially when reading the same data multiple times (like
|
||||
// to write the stencil bits after depth) for better read locality.
|
||||
@@ -784,7 +784,7 @@ class VulkanRenderTargetCache final : public RenderTargetCache {
|
||||
DumpInvocation(const ResolveCopyDumpRectangle& rectangle,
|
||||
const DumpPipelineKey& pipeline_key)
|
||||
: rectangle(rectangle), pipeline_key(pipeline_key) {}
|
||||
bool operator<(const DumpInvocation& other_invocation) {
|
||||
bool operator<(const DumpInvocation& other_invocation) const {
|
||||
// Sort by the pipeline key primarily to reduce pipeline state (context)
|
||||
// switches.
|
||||
if (pipeline_key != other_invocation.pipeline_key) {
|
||||
|
||||
Reference in New Issue
Block a user