mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-07-11 02:44:45 -06:00
Merge d8e174e6c2 into c795c04301
This commit is contained in:
commit
703f38d555
@ -1,6 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include <sirit/sirit.h>
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_quad_rect.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
@ -12,8 +15,17 @@ using Sirit::Id;
|
||||
constexpr u32 SPIRV_VERSION_1_5 = 0x00010500;
|
||||
|
||||
struct QuadRectListEmitter : public Sirit::Module {
|
||||
explicit QuadRectListEmitter(const FragmentRuntimeInfo& fs_info_)
|
||||
: Sirit::Module{SPIRV_VERSION_1_5}, fs_info{fs_info_} {
|
||||
struct AuxParam {
|
||||
Id input;
|
||||
Id output;
|
||||
u32 location{};
|
||||
bool has_input{};
|
||||
};
|
||||
|
||||
explicit QuadRectListEmitter(const FragmentRuntimeInfo& fs_info_,
|
||||
u64 previous_stage_output_mask_)
|
||||
: Sirit::Module{SPIRV_VERSION_1_5}, fs_info{fs_info_},
|
||||
previous_stage_output_mask{previous_stage_output_mask_} {
|
||||
void_id = TypeVoid();
|
||||
bool_id = TypeBool();
|
||||
float_id = TypeFloat(32);
|
||||
@ -24,9 +36,11 @@ struct QuadRectListEmitter : public Sirit::Module {
|
||||
vec3_id = TypeVector(float_id, 3);
|
||||
vec4_id = TypeVector(float_id, 4);
|
||||
|
||||
float_zero = Constant(float_id, 0.0f);
|
||||
float_one = Constant(float_id, 1.0f);
|
||||
float_min_one = Constant(float_id, -1.0f);
|
||||
int_zero = Constant(int_id, 0);
|
||||
vec4_zero = ConstantComposite(vec4_id, float_zero, float_zero, float_zero, float_zero);
|
||||
|
||||
const Id float_arr{TypeArray(float_id, Constant(uint_id, 1U))};
|
||||
gl_per_vertex_type = TypeStruct(vec4_id, float_id, float_arr, float_arr);
|
||||
@ -115,17 +129,24 @@ struct QuadRectListEmitter : public Sirit::Module {
|
||||
const Id position{OpSelect(vec4_id, invocation_3, pos3, OpLoad(vec4_id, in_ptr))};
|
||||
OpStore(OpAccessChain(output_vec4, gl_out, invocation_id, Int(0)), position);
|
||||
|
||||
// Set attributes
|
||||
for (int i = 0; i < inputs.size(); i++) {
|
||||
// vec4 in_paramN3 = interpolate(bary_coord, in_paramN[0], in_paramN[1], in_paramN[2]);
|
||||
const Id v0{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], Int(0)))};
|
||||
const Id v1{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], Int(1)))};
|
||||
const Id v2{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], Int(2)))};
|
||||
const Id in_param3{interpolate(v0, v1, v2)};
|
||||
// out_paramN[gl_InvocationID] = gl_InvocationID == 3 ? in_paramN3 : in_paramN[index];
|
||||
const Id in_param{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], index))};
|
||||
const Id out_param{OpSelect(vec4_id, invocation_3, in_param3, in_param)};
|
||||
OpStore(OpAccessChain(output_vec4, outputs[i], invocation_id), out_param);
|
||||
// Set attributes. If a fragment input has no corresponding VS output, do not declare a
|
||||
// TCS input for it; synthesize a neutral value instead. This keeps the VS->TCS interface
|
||||
// valid while still producing a matching TCS->TES->FS interface.
|
||||
for (const auto& param : params) {
|
||||
Id out_param = vec4_zero;
|
||||
if (param.has_input) {
|
||||
// vec4 in_paramN3 = interpolate(bary_coord, in_paramN[0], in_paramN[1],
|
||||
// in_paramN[2]);
|
||||
const Id v0{OpLoad(vec4_id, OpAccessChain(input_vec4, param.input, Int(0)))};
|
||||
const Id v1{OpLoad(vec4_id, OpAccessChain(input_vec4, param.input, Int(1)))};
|
||||
const Id v2{OpLoad(vec4_id, OpAccessChain(input_vec4, param.input, Int(2)))};
|
||||
const Id in_param3{interpolate(v0, v1, v2)};
|
||||
// out_paramN[gl_InvocationID] = gl_InvocationID == 3 ? in_paramN3 :
|
||||
// in_paramN[index];
|
||||
const Id in_param{OpLoad(vec4_id, OpAccessChain(input_vec4, param.input, index))};
|
||||
out_param = OpSelect(vec4_id, invocation_3, in_param3, in_param);
|
||||
}
|
||||
OpStore(OpAccessChain(output_vec4, param.output, invocation_id), out_param);
|
||||
}
|
||||
|
||||
OpReturn();
|
||||
@ -161,10 +182,14 @@ struct QuadRectListEmitter : public Sirit::Module {
|
||||
const Id in_position{OpLoad(vec4_id, OpAccessChain(input_vec4, gl_in, index, Int(0)))};
|
||||
OpStore(OpAccessChain(output_vec4, gl_out, invocation_id, Int(0)), in_position);
|
||||
|
||||
for (int i = 0; i < inputs.size(); i++) {
|
||||
// out_paramN[gl_InvocationID] = in_paramN[gl_InvocationID];
|
||||
const Id in_param{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], index))};
|
||||
OpStore(OpAccessChain(output_vec4, outputs[i], invocation_id), in_param);
|
||||
for (const auto& param : params) {
|
||||
// out_paramN[gl_InvocationID] = in_paramN[gl_InvocationID], or zero if the
|
||||
// preceding VS does not export this location.
|
||||
Id in_param = vec4_zero;
|
||||
if (param.has_input) {
|
||||
in_param = OpLoad(vec4_id, OpAccessChain(input_vec4, param.input, index));
|
||||
}
|
||||
OpStore(OpAccessChain(output_vec4, param.output, invocation_id), in_param);
|
||||
}
|
||||
|
||||
OpReturn();
|
||||
@ -189,9 +214,9 @@ struct QuadRectListEmitter : public Sirit::Module {
|
||||
OpStore(OpAccessChain(output_vec4, gl_per_vertex, Int(0)), position);
|
||||
|
||||
// out_paramN = in_paramN[index];
|
||||
for (int i = 0; i < inputs.size(); i++) {
|
||||
const Id param{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], index))};
|
||||
OpStore(outputs[i], param);
|
||||
for (const auto& param : params) {
|
||||
const Id value{OpLoad(vec4_id, OpAccessChain(input_vec4, param.input, index))};
|
||||
OpStore(param.output, value);
|
||||
}
|
||||
|
||||
OpReturn();
|
||||
@ -235,6 +260,29 @@ private:
|
||||
AddLabel(OpLabel());
|
||||
}
|
||||
|
||||
u32 GetLocation(const FragmentRuntimeInfo::PsInput& input) const {
|
||||
return AuxTessAttributeLocation(input.param_index, fs_info.clip_distance_emulation);
|
||||
}
|
||||
|
||||
bool IsPreviousStageOutputAvailable(u32 location) const {
|
||||
return location < 64u && ((previous_stage_output_mask >> location) & 1ull) != 0;
|
||||
}
|
||||
|
||||
void AddClipDistanceParam(spv::ExecutionModel model) {
|
||||
if (!fs_info.clip_distance_emulation) {
|
||||
return;
|
||||
}
|
||||
AuxParam& param = params.emplace_back();
|
||||
param.location = 0;
|
||||
if (model == spv::ExecutionModel::TessellationEvaluation ||
|
||||
IsPreviousStageOutputAvailable(param.location)) {
|
||||
const Id float_arr{TypeArray(vec4_id, Int(32))};
|
||||
param.input = AddInput(float_arr);
|
||||
param.has_input = true;
|
||||
Decorate(param.input, spv::Decoration::Location, param.location);
|
||||
}
|
||||
}
|
||||
|
||||
void DefineOutputs(spv::ExecutionModel model) {
|
||||
if (model == spv::ExecutionModel::TessellationControl) {
|
||||
const Id gl_per_vertex_array{TypeArray(gl_per_vertex_type, Constant(uint_id, 4U))};
|
||||
@ -252,16 +300,12 @@ private:
|
||||
} else {
|
||||
gl_per_vertex = AddOutput(gl_per_vertex_type);
|
||||
}
|
||||
outputs.reserve(fs_info.num_inputs);
|
||||
for (int i = 0; i < fs_info.num_inputs; i++) {
|
||||
const auto& input = fs_info.inputs[i];
|
||||
if (input.IsDefault()) {
|
||||
continue;
|
||||
}
|
||||
outputs.emplace_back(AddOutput(model == spv::ExecutionModel::TessellationControl
|
||||
? TypeArray(vec4_id, Int(4))
|
||||
: vec4_id));
|
||||
Decorate(outputs.back(), spv::Decoration::Location, input.param_index);
|
||||
|
||||
for (auto& param : params) {
|
||||
param.output = AddOutput(model == spv::ExecutionModel::TessellationControl
|
||||
? TypeArray(vec4_id, Int(4))
|
||||
: vec4_id);
|
||||
Decorate(param.output, spv::Decoration::Location, param.location);
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,20 +319,30 @@ private:
|
||||
}
|
||||
const Id gl_per_vertex_array{TypeArray(gl_per_vertex_type, Constant(uint_id, 32U))};
|
||||
gl_in = AddInput(gl_per_vertex_array);
|
||||
|
||||
params.reserve(fs_info.num_inputs + (fs_info.clip_distance_emulation ? 1u : 0u));
|
||||
AddClipDistanceParam(model);
|
||||
|
||||
const Id float_arr{TypeArray(vec4_id, Int(32))};
|
||||
inputs.reserve(fs_info.num_inputs);
|
||||
for (int i = 0; i < fs_info.num_inputs; i++) {
|
||||
const auto& input = fs_info.inputs[i];
|
||||
if (input.IsDefault()) {
|
||||
continue;
|
||||
}
|
||||
inputs.emplace_back(AddInput(float_arr));
|
||||
Decorate(inputs.back(), spv::Decoration::Location, input.param_index);
|
||||
AuxParam& param = params.emplace_back();
|
||||
param.location = GetLocation(input);
|
||||
if (model == spv::ExecutionModel::TessellationEvaluation ||
|
||||
IsPreviousStageOutputAvailable(param.location)) {
|
||||
param.input = AddInput(float_arr);
|
||||
param.has_input = true;
|
||||
Decorate(param.input, spv::Decoration::Location, param.location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FragmentRuntimeInfo fs_info;
|
||||
u64 previous_stage_output_mask;
|
||||
Id main;
|
||||
Id void_id;
|
||||
Id bool_id;
|
||||
@ -299,9 +353,11 @@ private:
|
||||
Id vec2_id;
|
||||
Id vec3_id;
|
||||
Id vec4_id;
|
||||
Id float_zero;
|
||||
Id float_one;
|
||||
Id float_min_one;
|
||||
Id int_zero;
|
||||
Id vec4_zero;
|
||||
Id gl_per_vertex_type;
|
||||
Id gl_in;
|
||||
union {
|
||||
@ -314,13 +370,13 @@ private:
|
||||
Id gl_tess_coord;
|
||||
Id gl_invocation_id;
|
||||
};
|
||||
std::vector<Id> inputs;
|
||||
std::vector<Id> outputs;
|
||||
std::vector<AuxParam> params;
|
||||
std::vector<Id> interfaces;
|
||||
};
|
||||
|
||||
std::vector<u32> EmitAuxilaryTessShader(AuxShaderType type, const FragmentRuntimeInfo& fs_info) {
|
||||
QuadRectListEmitter ctx{fs_info};
|
||||
std::vector<u32> EmitAuxilaryTessShader(AuxShaderType type, const FragmentRuntimeInfo& fs_info,
|
||||
u64 previous_stage_output_mask) {
|
||||
QuadRectListEmitter ctx{fs_info, previous_stage_output_mask};
|
||||
switch (type) {
|
||||
case AuxShaderType::RectListTCS:
|
||||
ctx.EmitRectListTCS();
|
||||
|
||||
@ -18,7 +18,13 @@ enum class AuxShaderType : u32 {
|
||||
PassthroughTES,
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr u32 AuxTessAttributeLocation(u32 param_index,
|
||||
bool clip_distance_emulation) noexcept {
|
||||
return param_index + (clip_distance_emulation ? 1u : 0u);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<u32> EmitAuxilaryTessShader(AuxShaderType type,
|
||||
const FragmentRuntimeInfo& fs_info);
|
||||
const FragmentRuntimeInfo& fs_info,
|
||||
u64 previous_stage_output_mask = ~0ull);
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
||||
@ -46,13 +46,15 @@ struct BufferSpecialization {
|
||||
|
||||
struct ImageSpecialization {
|
||||
AmdGpu::ImageType type = AmdGpu::ImageType::Color2D;
|
||||
bool is_integer = false;
|
||||
AmdGpu::NumberClass num_class = AmdGpu::NumberClass::Float;
|
||||
AmdGpu::DataFormat data_format = AmdGpu::DataFormat::FormatInvalid;
|
||||
AmdGpu::NumberFormat num_format = AmdGpu::NumberFormat::Unorm;
|
||||
bool is_storage = false;
|
||||
bool is_cube = false;
|
||||
bool is_srgb = false;
|
||||
bool is_null = false;
|
||||
AmdGpu::CompMapping dst_select{};
|
||||
AmdGpu::NumberConversion num_conversion{};
|
||||
// FIXME any pipeline cache changes needed?
|
||||
u32 num_bindings = 0;
|
||||
|
||||
bool operator==(const ImageSpecialization&) const = default;
|
||||
@ -134,20 +136,30 @@ struct StageSpecialization {
|
||||
spec.element_size = sharp.element_size;
|
||||
}
|
||||
});
|
||||
ForEachSharp(binding, images, info->images,
|
||||
[&](auto& spec, const auto& desc, AmdGpu::Image sharp) {
|
||||
spec.type = sharp.GetViewType(desc.is_array);
|
||||
spec.is_integer = AmdGpu::IsInteger(sharp.GetNumberFmt());
|
||||
spec.is_storage = desc.is_written;
|
||||
spec.is_cube = sharp.IsCube();
|
||||
if (spec.is_storage) {
|
||||
spec.dst_select = sharp.DstSelect();
|
||||
} else {
|
||||
spec.is_srgb = sharp.GetNumberFmt() == AmdGpu::NumberFormat::Srgb;
|
||||
}
|
||||
spec.num_conversion = sharp.GetNumberConversion();
|
||||
spec.num_bindings = desc.NumBindings(*info);
|
||||
});
|
||||
for (const auto& desc : info->images) {
|
||||
auto& spec = images.emplace_back();
|
||||
const auto sharp = desc.GetSharp(*info);
|
||||
if (!sharp.Valid() || sharp.GetDataFmt() == AmdGpu::DataFormat::FormatInvalid) {
|
||||
binding++;
|
||||
continue;
|
||||
}
|
||||
bitset.set(binding++);
|
||||
const auto num_format = sharp.GetNumberFmt();
|
||||
spec.type = sharp.GetViewType(desc.is_array);
|
||||
spec.num_class = AmdGpu::GetNumberClass(num_format);
|
||||
spec.data_format = sharp.GetDataFmt();
|
||||
spec.num_format = num_format;
|
||||
spec.is_storage = desc.is_written;
|
||||
spec.is_cube = sharp.IsCube();
|
||||
spec.is_null = !sharp;
|
||||
if (spec.is_storage) {
|
||||
spec.dst_select = sharp.DstSelect();
|
||||
} else {
|
||||
spec.is_srgb = num_format == AmdGpu::NumberFormat::Srgb;
|
||||
}
|
||||
spec.num_conversion = sharp.GetNumberConversion();
|
||||
spec.num_bindings = desc.NumBindings(*info);
|
||||
}
|
||||
ForEachSharp(binding, fmasks, info->fmasks,
|
||||
[](auto& spec, const auto& desc, AmdGpu::Image sharp) {
|
||||
spec.width = sharp.width;
|
||||
@ -229,6 +241,10 @@ struct StageSpecialization {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bitset != other.bitset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 binding{};
|
||||
for (u32 i = 0; i < buffers.size(); i++) {
|
||||
if (other.bitset[binding++] && buffers[i] != other.buffers[i]) {
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_quad_rect.h"
|
||||
#include "shader_recompiler/info.h"
|
||||
#include "shader_recompiler/ir/attribute.h"
|
||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
@ -17,6 +19,53 @@ namespace Vulkan {
|
||||
|
||||
using Shader::Backend::SPIRV::AuxShaderType;
|
||||
|
||||
namespace {
|
||||
|
||||
u64 BuildAuxTessPreviousStageOutputMask(const Shader::Info* vs_info,
|
||||
const Shader::FragmentRuntimeInfo& fs_info) {
|
||||
if (!vs_info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 mask = 0;
|
||||
if (fs_info.clip_distance_emulation &&
|
||||
vs_info->stores.GetAny(Shader::IR::Attribute::ClipDistance)) {
|
||||
mask |= 1ull;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < Shader::IR::NumParams; ++i) {
|
||||
const auto param = Shader::IR::Attribute::Param0 + static_cast<int>(i);
|
||||
if (!vs_info->stores.GetAny(param)) {
|
||||
continue;
|
||||
}
|
||||
const u32 location =
|
||||
Shader::Backend::SPIRV::AuxTessAttributeLocation(i, fs_info.clip_distance_emulation);
|
||||
if (location < 64u) {
|
||||
mask |= 1ull << location;
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
void LogAuxTessMissingInputs(const Shader::FragmentRuntimeInfo& fs_info, u64 output_mask) {
|
||||
for (u32 i = 0; i < fs_info.num_inputs; ++i) {
|
||||
const auto& input = fs_info.inputs[i];
|
||||
if (input.IsDefault()) {
|
||||
continue;
|
||||
}
|
||||
const u32 location = Shader::Backend::SPIRV::AuxTessAttributeLocation(
|
||||
input.param_index, fs_info.clip_distance_emulation);
|
||||
if (location < 64u && ((output_mask >> location) & 1ull) == 0) {
|
||||
LOG_DEBUG(Render_Vulkan,
|
||||
"Aux tess input location {} for PS input {} has no VS output; "
|
||||
"synthesizing zero",
|
||||
location, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
static constexpr std::array LogicalStageToStageBit = {
|
||||
vk::ShaderStageFlagBits::eFragment,
|
||||
vk::ShaderStageFlagBits::eTessellationControl,
|
||||
@ -194,7 +243,12 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
const auto type = is_quad_list ? AuxShaderType::QuadListTCS : AuxShaderType::RectListTCS;
|
||||
if (!preloading) {
|
||||
const auto& fs_info = runtime_infos[u32(Shader::LogicalStage::Fragment)].fs_info;
|
||||
sdata.tcs = Shader::Backend::SPIRV::EmitAuxilaryTessShader(type, fs_info);
|
||||
const auto* vs_info = infos[u32(Shader::LogicalStage::Vertex)];
|
||||
const u64 previous_stage_output_mask =
|
||||
BuildAuxTessPreviousStageOutputMask(vs_info, fs_info);
|
||||
LogAuxTessMissingInputs(fs_info, previous_stage_output_mask);
|
||||
sdata.tcs = Shader::Backend::SPIRV::EmitAuxilaryTessShader(type, fs_info,
|
||||
previous_stage_output_mask);
|
||||
}
|
||||
shader_stages.emplace_back(vk::PipelineShaderStageCreateInfo{
|
||||
.stage = vk::ShaderStageFlagBits::eTessellationControl,
|
||||
|
||||
@ -12,9 +12,9 @@
|
||||
|
||||
namespace Serialization {
|
||||
/* You should increment versions below once corresponding serialization scheme is changed. */
|
||||
static constexpr u32 ShaderBinaryVersion = 2u;
|
||||
static constexpr u32 ShaderMetaVersion = 2u;
|
||||
static constexpr u32 PipelineKeyVersion = 2u;
|
||||
static constexpr u32 ShaderBinaryVersion = 3u;
|
||||
static constexpr u32 ShaderMetaVersion = 3u;
|
||||
static constexpr u32 PipelineKeyVersion = 3u;
|
||||
} // namespace Serialization
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
@ -20,6 +20,104 @@
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
namespace {
|
||||
|
||||
enum class VkFormatNumberClass {
|
||||
Float,
|
||||
Sint,
|
||||
Uint,
|
||||
Unknown,
|
||||
};
|
||||
|
||||
constexpr const char* NameOf(VkFormatNumberClass num_class) noexcept {
|
||||
switch (num_class) {
|
||||
case VkFormatNumberClass::Float:
|
||||
return "Float";
|
||||
case VkFormatNumberClass::Sint:
|
||||
return "Sint";
|
||||
case VkFormatNumberClass::Uint:
|
||||
return "Uint";
|
||||
case VkFormatNumberClass::Unknown:
|
||||
return "Unknown";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
constexpr VkFormatNumberClass GetFormatNumberClass(vk::Format format) noexcept {
|
||||
switch (format) {
|
||||
case vk::Format::eR8Uint:
|
||||
case vk::Format::eR8G8Uint:
|
||||
case vk::Format::eR8G8B8Uint:
|
||||
case vk::Format::eR8G8B8A8Uint:
|
||||
case vk::Format::eB8G8R8Uint:
|
||||
case vk::Format::eB8G8R8A8Uint:
|
||||
case vk::Format::eA8B8G8R8UintPack32:
|
||||
case vk::Format::eR16Uint:
|
||||
case vk::Format::eR16G16Uint:
|
||||
case vk::Format::eR16G16B16Uint:
|
||||
case vk::Format::eR16G16B16A16Uint:
|
||||
case vk::Format::eR32Uint:
|
||||
case vk::Format::eR32G32Uint:
|
||||
case vk::Format::eR32G32B32Uint:
|
||||
case vk::Format::eR32G32B32A32Uint:
|
||||
case vk::Format::eR64Uint:
|
||||
case vk::Format::eR64G64Uint:
|
||||
case vk::Format::eR64G64B64Uint:
|
||||
case vk::Format::eR64G64B64A64Uint:
|
||||
case vk::Format::eA2B10G10R10UintPack32:
|
||||
case vk::Format::eA2R10G10B10UintPack32:
|
||||
case vk::Format::eS8Uint:
|
||||
return VkFormatNumberClass::Uint;
|
||||
case vk::Format::eR8Sint:
|
||||
case vk::Format::eR8G8Sint:
|
||||
case vk::Format::eR8G8B8Sint:
|
||||
case vk::Format::eR8G8B8A8Sint:
|
||||
case vk::Format::eB8G8R8Sint:
|
||||
case vk::Format::eB8G8R8A8Sint:
|
||||
case vk::Format::eA8B8G8R8SintPack32:
|
||||
case vk::Format::eR16Sint:
|
||||
case vk::Format::eR16G16Sint:
|
||||
case vk::Format::eR16G16B16Sint:
|
||||
case vk::Format::eR16G16B16A16Sint:
|
||||
case vk::Format::eR32Sint:
|
||||
case vk::Format::eR32G32Sint:
|
||||
case vk::Format::eR32G32B32Sint:
|
||||
case vk::Format::eR32G32B32A32Sint:
|
||||
case vk::Format::eR64Sint:
|
||||
case vk::Format::eR64G64Sint:
|
||||
case vk::Format::eR64G64B64Sint:
|
||||
case vk::Format::eR64G64B64A64Sint:
|
||||
case vk::Format::eA2B10G10R10SintPack32:
|
||||
case vk::Format::eA2R10G10B10SintPack32:
|
||||
return VkFormatNumberClass::Sint;
|
||||
case vk::Format::eUndefined:
|
||||
return VkFormatNumberClass::Unknown;
|
||||
default:
|
||||
return VkFormatNumberClass::Float;
|
||||
}
|
||||
}
|
||||
|
||||
void LogImageViewNumberClassMismatch(const Shader::Info& stage,
|
||||
const VideoCore::TextureCache::ImageDesc& desc,
|
||||
const VideoCore::ImageView& image_view,
|
||||
VideoCore::ImageId image_id) {
|
||||
const auto expected = GetFormatNumberClass(desc.view_info.format);
|
||||
const auto actual = GetFormatNumberClass(image_view.format);
|
||||
if (expected == VkFormatNumberClass::Unknown || actual == VkFormatNumberClass::Unknown ||
|
||||
expected == actual) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Render_Vulkan,
|
||||
"Image numeric type mismatch before descriptor write: stage={} image_id={} "
|
||||
"expected={} requested_format={} actual={} actual_format={} storage={}",
|
||||
stage.stage, image_id.index, NameOf(expected), vk::to_string(desc.view_info.format),
|
||||
NameOf(actual), vk::to_string(image_view.format),
|
||||
desc.type == VideoCore::TextureCache::BindingType::Storage);
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
static Shader::PushData MakeUserData(const AmdGpu::Regs& regs) {
|
||||
// TODO(roamic): Add support for multiple viewports and geometry shaders when ViewportIndex
|
||||
// is encountered and implemented in the recompiler.
|
||||
@ -742,7 +840,12 @@ void Rasterizer::BindTextures(const Shader::Info& stage, Shader::Backend::Bindin
|
||||
if (instance.IsNullDescriptorSupported()) {
|
||||
image_infos.emplace_back(VK_NULL_HANDLE, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
|
||||
} else {
|
||||
auto& null_image_view = texture_cache.FindTexture(VideoCore::NULL_IMAGE_ID, desc);
|
||||
const auto null_format = desc.view_info.format != vk::Format::eUndefined
|
||||
? desc.view_info.format
|
||||
: desc.info.pixel_format;
|
||||
const auto null_image_id = texture_cache.GetNullImage(null_format);
|
||||
auto& null_image_view = texture_cache.FindTexture(null_image_id, desc);
|
||||
LogImageViewNumberClassMismatch(stage, desc, null_image_view, null_image_id);
|
||||
image_infos.emplace_back(VK_NULL_HANDLE, *null_image_view.image_view,
|
||||
vk::ImageLayout::eGeneral);
|
||||
}
|
||||
@ -757,6 +860,7 @@ void Rasterizer::BindTextures(const Shader::Info& stage, Shader::Backend::Bindin
|
||||
|
||||
auto& image = texture_cache.GetImage(image_id);
|
||||
auto& image_view = texture_cache.FindTexture(image_id, desc);
|
||||
LogImageViewNumberClassMismatch(stage, desc, image_view, image_id);
|
||||
|
||||
// The image is either bound as storage in a separate descriptor or bound as render
|
||||
// target in feedback loop. Depth images are excluded because they can't be bound as
|
||||
|
||||
@ -109,11 +109,12 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
|
||||
aspect = vk::ImageAspectFlagBits::eStencil;
|
||||
}
|
||||
|
||||
this->format = instance.GetSupportedFormat(format, image.format_features);
|
||||
const vk::ImageViewCreateInfo image_view_ci = {
|
||||
.pNext = &usage_ci,
|
||||
.image = image.GetImage(),
|
||||
.viewType = ConvertImageViewType(info.type),
|
||||
.format = instance.GetSupportedFormat(format, image.format_features),
|
||||
.format = this->format,
|
||||
.components = info.mapping,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect,
|
||||
@ -136,12 +137,14 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
|
||||
const auto view_aspect = aspect & vk::ImageAspectFlagBits::eDepth ? "Depth"
|
||||
: aspect & vk::ImageAspectFlagBits::eStencil ? "Stencil"
|
||||
: "Color";
|
||||
Vulkan::SetObjectName(
|
||||
instance.GetDevice(), *image_view, "ImageView {}x{}x{} {:#x}:{:#x} {}:{} {}:{} ({})",
|
||||
image.info.size.width, image.info.size.height, image.info.size.depth,
|
||||
image.info.guest_address, image.info.guest_size, info.range.base.level,
|
||||
info.range.base.level + info.range.extent.levels - 1, info.range.base.layer,
|
||||
info.range.base.layer + info.range.extent.layers - 1, view_aspect);
|
||||
Vulkan::SetObjectName(instance.GetDevice(), *image_view,
|
||||
"ImageView {}x{}x{} {:#x}:{:#x} {}:{} {}:{} ({}) req:{} view:{}",
|
||||
image.info.size.width, image.info.size.height, image.info.size.depth,
|
||||
image.info.guest_address, image.info.guest_size, info.range.base.level,
|
||||
info.range.base.level + info.range.extent.levels - 1,
|
||||
info.range.base.layer,
|
||||
info.range.base.layer + info.range.extent.layers - 1, view_aspect,
|
||||
vk::to_string(info.format), vk::to_string(this->format));
|
||||
}
|
||||
|
||||
ImageView::~ImageView() = default;
|
||||
|
||||
@ -52,6 +52,7 @@ struct ImageView {
|
||||
ImageView& operator=(ImageView&&) = default;
|
||||
|
||||
ImageViewInfo info;
|
||||
vk::Format format = vk::Format::eUndefined;
|
||||
vk::UniqueImageView image_view;
|
||||
};
|
||||
|
||||
|
||||
@ -105,6 +105,9 @@ public:
|
||||
/// Retrieves an image view with the properties of the specified image id.
|
||||
[[nodiscard]] ImageView& FindTexture(ImageId image_id, const ImageDesc& desc);
|
||||
|
||||
/// Gets or creates a null image for a particular Vulkan format.
|
||||
[[nodiscard]] ImageId GetNullImage(vk::Format format);
|
||||
|
||||
/// Retrieves the render target with specified properties
|
||||
[[nodiscard]] ImageView& FindRenderTarget(ImageId image_id, const ImageDesc& desc);
|
||||
|
||||
@ -268,9 +271,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets or creates a null image for a particular format.
|
||||
ImageId GetNullImage(vk::Format format);
|
||||
|
||||
/// Copies image memory back to CPU.
|
||||
void DownloadImageMemory(ImageId image_id);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user