This commit is contained in:
poly 2025-07-10 20:53:00 +02:00 committed by GitHub
commit 844dfad867
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 180 additions and 138 deletions

View File

@ -271,6 +271,9 @@ void SetupCapabilities(const Info& info, const Profile& profile, EmitContext& ct
if (info.has_image_query) { if (info.has_image_query) {
ctx.AddCapability(spv::Capability::ImageQuery); ctx.AddCapability(spv::Capability::ImageQuery);
} }
if (info.has_layer_output) {
ctx.AddCapability(spv::Capability::ShaderLayer);
}
if ((info.uses_image_atomic_float_min_max && profile.supports_image_fp32_atomic_min_max) || if ((info.uses_image_atomic_float_min_max && profile.supports_image_fp32_atomic_min_max) ||
(info.uses_buffer_atomic_float_min_max && profile.supports_buffer_fp32_atomic_min_max)) { (info.uses_buffer_atomic_float_min_max && profile.supports_buffer_fp32_atomic_min_max)) {
ctx.AddExtension("SPV_EXT_shader_atomic_float_min_max"); ctx.AddExtension("SPV_EXT_shader_atomic_float_min_max");

View File

@ -16,39 +16,6 @@
namespace Shader::Backend::SPIRV { namespace Shader::Backend::SPIRV {
namespace { namespace {
Id VsOutputAttrPointer(EmitContext& ctx, VsOutput output) {
switch (output) {
case VsOutput::ClipDist0:
case VsOutput::ClipDist1:
case VsOutput::ClipDist2:
case VsOutput::ClipDist3:
case VsOutput::ClipDist4:
case VsOutput::ClipDist5:
case VsOutput::ClipDist6:
case VsOutput::ClipDist7: {
const u32 index = u32(output) - u32(VsOutput::ClipDist0);
const Id clip_num{ctx.ConstU32(index)};
ASSERT_MSG(Sirit::ValidId(ctx.clip_distances), "Clip distance used but not defined");
return ctx.OpAccessChain(ctx.output_f32, ctx.clip_distances, clip_num);
}
case VsOutput::CullDist0:
case VsOutput::CullDist1:
case VsOutput::CullDist2:
case VsOutput::CullDist3:
case VsOutput::CullDist4:
case VsOutput::CullDist5:
case VsOutput::CullDist6:
case VsOutput::CullDist7: {
const u32 index = u32(output) - u32(VsOutput::CullDist0);
const Id cull_num{ctx.ConstU32(index)};
ASSERT_MSG(Sirit::ValidId(ctx.cull_distances), "Cull distance used but not defined");
return ctx.OpAccessChain(ctx.output_f32, ctx.cull_distances, cull_num);
}
default:
UNREACHABLE();
}
}
Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) { Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) {
if (IR::IsParam(attr)) { if (IR::IsParam(attr)) {
const u32 attr_index{u32(attr) - u32(IR::Attribute::Param0)}; const u32 attr_index{u32(attr) - u32(IR::Attribute::Param0)};
@ -76,19 +43,18 @@ Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) {
} }
} }
switch (attr) { switch (attr) {
case IR::Attribute::Position0: { case IR::Attribute::Position0:
return ctx.OpAccessChain(ctx.output_f32, ctx.output_position, ctx.ConstU32(element)); return ctx.OpAccessChain(ctx.output_f32, ctx.output_position, ctx.ConstU32(element));
} case IR::Attribute::ClipDistance:
case IR::Attribute::Position1: return ctx.OpAccessChain(ctx.output_f32, ctx.clip_distances, ctx.ConstU32(element));
case IR::Attribute::Position2: case IR::Attribute::CullDistance:
case IR::Attribute::Position3: { return ctx.OpAccessChain(ctx.output_f32, ctx.cull_distances, ctx.ConstU32(element));
const u32 index = u32(attr) - u32(IR::Attribute::Position1); case IR::Attribute::RenderTargetId:
return VsOutputAttrPointer(ctx, ctx.runtime_info.vs_info.outputs[index][element]); return ctx.output_layer;
}
case IR::Attribute::Depth: case IR::Attribute::Depth:
return ctx.frag_depth; return ctx.frag_depth;
default: default:
throw NotImplementedException("Write attribute {}", attr); UNREACHABLE_MSG("Write attribute {}", attr);
} }
} }
@ -109,13 +75,15 @@ std::pair<Id, bool> OutputAttrComponentType(EmitContext& ctx, IR::Attribute attr
} }
switch (attr) { switch (attr) {
case IR::Attribute::Position0: case IR::Attribute::Position0:
case IR::Attribute::Position1: case IR::Attribute::ClipDistance:
case IR::Attribute::Position2: case IR::Attribute::CullDistance:
case IR::Attribute::Position3:
case IR::Attribute::Depth: case IR::Attribute::Depth:
return {ctx.F32[1], false}; return {ctx.F32[1], false};
case IR::Attribute::RenderTargetId:
case IR::Attribute::ViewportId:
return {ctx.S32[1], true};
default: default:
throw NotImplementedException("Write attribute {}", attr); UNREACHABLE_MSG("Write attribute {}", attr);
} }
} }
} // Anonymous namespace } // Anonymous namespace
@ -350,14 +318,10 @@ Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, u32 comp) {
} }
void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, u32 element) { void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, u32 element) {
if (attr == IR::Attribute::Position1) {
LOG_WARNING(Render_Vulkan, "Ignoring pos1 export");
return;
}
const Id pointer{OutputAttrPointer(ctx, attr, element)}; const Id pointer{OutputAttrPointer(ctx, attr, element)};
const auto component_type{OutputAttrComponentType(ctx, attr)}; const auto [component_type, is_integer]{OutputAttrComponentType(ctx, attr)};
if (component_type.second) { if (is_integer) {
ctx.OpStore(pointer, ctx.OpBitcast(component_type.first, value)); ctx.OpStore(pointer, ctx.OpBitcast(component_type, value));
} else { } else {
ctx.OpStore(pointer, value); ctx.OpStore(pointer, value);
} }

View File

@ -556,23 +556,25 @@ void EmitContext::DefineInputs() {
} }
} }
void EmitContext::DefineVertexBlock() {
output_position = DefineVariable(F32[4], spv::BuiltIn::Position, spv::StorageClass::Output);
if (info.stores.GetAny(IR::Attribute::ClipDistance)) {
clip_distances = DefineVariable(TypeArray(F32[1], ConstU32(8U)), spv::BuiltIn::ClipDistance,
spv::StorageClass::Output);
}
if (info.stores.GetAny(IR::Attribute::CullDistance)) {
cull_distances = DefineVariable(TypeArray(F32[1], ConstU32(8U)), spv::BuiltIn::CullDistance,
spv::StorageClass::Output);
}
if (info.stores.GetAny(IR::Attribute::RenderTargetId)) {
output_layer = DefineVariable(S32[1], spv::BuiltIn::Layer, spv::StorageClass::Output);
}
}
void EmitContext::DefineOutputs() { void EmitContext::DefineOutputs() {
switch (l_stage) { switch (l_stage) {
case LogicalStage::Vertex: { case LogicalStage::Vertex: {
// No point in defining builtin outputs (i.e. position) unless next stage is fragment? DefineVertexBlock();
// Might cause problems linking with tcs
output_position = DefineVariable(F32[4], spv::BuiltIn::Position, spv::StorageClass::Output);
const bool has_extra_pos_stores = info.stores.Get(IR::Attribute::Position1) ||
info.stores.Get(IR::Attribute::Position2) ||
info.stores.Get(IR::Attribute::Position3);
if (has_extra_pos_stores) {
const Id type{TypeArray(F32[1], ConstU32(8U))};
clip_distances =
DefineVariable(type, spv::BuiltIn::ClipDistance, spv::StorageClass::Output);
cull_distances =
DefineVariable(type, spv::BuiltIn::CullDistance, spv::StorageClass::Output);
}
if (stage == Shader::Stage::Local && runtime_info.ls_info.links_with_tcs) { if (stage == Shader::Stage::Local && runtime_info.ls_info.links_with_tcs) {
const u32 num_attrs = Common::AlignUp(runtime_info.ls_info.ls_stride, 16) >> 4; const u32 num_attrs = Common::AlignUp(runtime_info.ls_info.ls_stride, 16) >> 4;
if (num_attrs > 0) { if (num_attrs > 0) {
@ -632,17 +634,7 @@ void EmitContext::DefineOutputs() {
break; break;
} }
case LogicalStage::TessellationEval: { case LogicalStage::TessellationEval: {
output_position = DefineVariable(F32[4], spv::BuiltIn::Position, spv::StorageClass::Output); DefineVertexBlock();
const bool has_extra_pos_stores = info.stores.Get(IR::Attribute::Position1) ||
info.stores.Get(IR::Attribute::Position2) ||
info.stores.Get(IR::Attribute::Position3);
if (has_extra_pos_stores) {
const Id type{TypeArray(F32[1], ConstU32(8U))};
clip_distances =
DefineVariable(type, spv::BuiltIn::ClipDistance, spv::StorageClass::Output);
cull_distances =
DefineVariable(type, spv::BuiltIn::CullDistance, spv::StorageClass::Output);
}
for (u32 i = 0; i < IR::NumParams; i++) { for (u32 i = 0; i < IR::NumParams; i++) {
const IR::Attribute param{IR::Attribute::Param0 + i}; const IR::Attribute param{IR::Attribute::Param0 + i};
if (!info.stores.GetAny(param)) { if (!info.stores.GetAny(param)) {
@ -682,8 +674,7 @@ void EmitContext::DefineOutputs() {
break; break;
} }
case LogicalStage::Geometry: { case LogicalStage::Geometry: {
output_position = DefineVariable(F32[4], spv::BuiltIn::Position, spv::StorageClass::Output); DefineVertexBlock();
for (u32 attr_id = 0; attr_id < info.gs_copy_data.num_attrs; attr_id++) { for (u32 attr_id = 0; attr_id < info.gs_copy_data.num_attrs; attr_id++) {
const Id id{DefineOutput(F32[4], attr_id)}; const Id id{DefineOutput(F32[4], attr_id)};
Name(id, fmt::format("out_attr{}", attr_id)); Name(id, fmt::format("out_attr{}", attr_id));

View File

@ -245,6 +245,7 @@ public:
boost::container::small_vector<Id, 16> interfaces; boost::container::small_vector<Id, 16> interfaces;
Id output_position{}; Id output_position{};
Id output_layer{};
Id primitive_id{}; Id primitive_id{};
Id vertex_index{}; Id vertex_index{};
Id instance_id{}; Id instance_id{};
@ -383,6 +384,7 @@ private:
void DefineArithmeticTypes(); void DefineArithmeticTypes();
void DefineInterfaces(); void DefineInterfaces();
void DefineInputs(); void DefineInputs();
void DefineVertexBlock();
void DefineOutputs(); void DefineOutputs();
void DefinePushDataBlock(); void DefinePushDataBlock();
void DefineBuffers(); void DefineBuffers();

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "shader_recompiler/frontend/translate/translate.h" #include "shader_recompiler/frontend/translate/translate.h"
#include "shader_recompiler/ir/position.h"
#include "shader_recompiler/ir/reinterpret.h" #include "shader_recompiler/ir/reinterpret.h"
#include "shader_recompiler/runtime_info.h" #include "shader_recompiler/runtime_info.h"
@ -126,8 +127,10 @@ void Translator::ExportCompressed(IR::Attribute attribute, u32 idx, const IR::U3
void Translator::ExportUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value) { void Translator::ExportUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value) {
if (IsMrt(attribute)) { if (IsMrt(attribute)) {
ExportMrtUncompressed(attribute, comp, value); return ExportMrtUncompressed(attribute, comp, value);
return; }
if (IsPosition(attribute)) {
return IR::ExportPosition(ir, runtime_info.vs_info, attribute, comp, value);
} }
ir.SetAttribute(attribute, value, comp); ir.SetAttribute(attribute, value, comp);
} }

View File

@ -317,6 +317,7 @@ private:
const PsColorBuffer& color_buffer); const PsColorBuffer& color_buffer);
void ExportMrtCompressed(IR::Attribute attribute, u32 idx, const IR::U32& value); void ExportMrtCompressed(IR::Attribute attribute, u32 idx, const IR::U32& value);
void ExportMrtUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value); void ExportMrtUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value);
void ExportPosition(IR::Attribute attribute, u32 comp, const IR::F32& value);
void ExportCompressed(IR::Attribute attribute, u32 idx, const IR::U32& value); void ExportCompressed(IR::Attribute attribute, u32 idx, const IR::U32& value);
void ExportUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value); void ExportUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value);

View File

@ -215,6 +215,7 @@ struct Info {
bool has_image_query{}; bool has_image_query{};
bool has_perspective_interp{}; bool has_perspective_interp{};
bool has_linear_interp{}; bool has_linear_interp{};
bool has_layer_output{};
bool uses_buffer_atomic_float_min_max{}; bool uses_buffer_atomic_float_min_max{};
bool uses_image_atomic_float_min_max{}; bool uses_image_atomic_float_min_max{};
bool uses_lane_id{}; bool uses_lane_id{};

View File

@ -4,6 +4,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "shader_recompiler/ir/ir_emitter.h" #include "shader_recompiler/ir/ir_emitter.h"
#include "shader_recompiler/ir/opcodes.h" #include "shader_recompiler/ir/opcodes.h"
#include "shader_recompiler/ir/position.h"
#include "shader_recompiler/ir/program.h" #include "shader_recompiler/ir/program.h"
#include "shader_recompiler/ir/reg.h" #include "shader_recompiler/ir/reg.h"
#include "shader_recompiler/recompiler.h" #include "shader_recompiler/recompiler.h"
@ -145,11 +146,12 @@ void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtim
ASSERT(it != info.gs_copy_data.attr_map.cend()); ASSERT(it != info.gs_copy_data.attr_map.cend());
const auto& [attr, comp] = it->second; const auto& [attr, comp] = it->second;
inst.ReplaceOpcode(IR::Opcode::SetAttribute); inst.Invalidate();
inst.ClearArgs(); if (IsPosition(attr)) {
inst.SetArg(0, IR::Value{attr}); ExportPosition(ir, runtime_info.gs_info, attr, comp, data);
inst.SetArg(1, data); } else {
inst.SetArg(2, ir.Imm32(comp)); ir.SetAttribute(attr, data, comp);
}
break; break;
} }
default: default:

View File

@ -157,6 +157,10 @@ void CollectShaderInfoPass(IR::Program& program, const Profile& profile) {
} }
} }
if (info.stores.GetAny(IR::Attribute::RenderTargetId)) {
info.has_layer_output = true;
}
// In case Flatbuf has not already been bound by IR and is needed // In case Flatbuf has not already been bound by IR and is needed
// to query buffer sizes, bind it now. // to query buffer sizes, bind it now.
if (!profile.supports_robust_buffer_access && !info.uses_dma) { if (!profile.supports_robust_buffer_access && !info.uses_dma) {

View File

@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "shader_recompiler/ir/ir_emitter.h"
#include "shader_recompiler/runtime_info.h"
namespace Shader::IR {
/// Maps special position export to builtin attribute stores
inline void ExportPosition(IREmitter& ir, const auto& stage, Attribute attribute, u32 comp,
const IR::F32& value) {
if (attribute == Attribute::Position0) {
ir.SetAttribute(attribute, value, comp);
return;
}
const u32 index = u32(attribute) - u32(Attribute::Position1);
const auto output = stage.outputs[index][comp];
switch (output) {
case Output::ClipDist0:
case Output::ClipDist1:
case Output::ClipDist2:
case Output::ClipDist3:
case Output::ClipDist4:
case Output::ClipDist5:
case Output::ClipDist6:
case Output::ClipDist7: {
const u32 index = u32(output) - u32(Output::ClipDist0);
ir.SetAttribute(IR::Attribute::ClipDistance, value, index);
break;
}
case Output::CullDist0:
case Output::CullDist1:
case Output::CullDist2:
case Output::CullDist3:
case Output::CullDist4:
case Output::CullDist5:
case Output::CullDist6:
case Output::CullDist7: {
const u32 index = u32(output) - u32(Output::CullDist0);
ir.SetAttribute(IR::Attribute::CullDistance, value, index);
break;
}
case Output::GsMrtIndex:
ir.SetAttribute(IR::Attribute::RenderTargetId, value);
break;
default:
UNREACHABLE_MSG("Unhandled output {} on attribute {}", u32(output), u32(attribute));
}
}
} // namespace Shader::IR

View File

@ -53,7 +53,7 @@ struct ExportRuntimeInfo {
auto operator<=>(const ExportRuntimeInfo&) const noexcept = default; auto operator<=>(const ExportRuntimeInfo&) const noexcept = default;
}; };
enum class VsOutput : u8 { enum class Output : u8 {
None, None,
PointSprite, PointSprite,
EdgeFlag, EdgeFlag,
@ -78,11 +78,11 @@ enum class VsOutput : u8 {
ClipDist6, ClipDist6,
ClipDist7, ClipDist7,
}; };
using VsOutputMap = std::array<VsOutput, 4>; using OutputMap = std::array<Output, 4>;
struct VertexRuntimeInfo { struct VertexRuntimeInfo {
u32 num_outputs; u32 num_outputs;
std::array<VsOutputMap, 3> outputs; std::array<OutputMap, 3> outputs;
bool emulate_depth_negative_one_to_one{}; bool emulate_depth_negative_one_to_one{};
bool clip_disable{}; bool clip_disable{};
// Domain // Domain
@ -143,6 +143,8 @@ struct HullRuntimeInfo {
static constexpr auto GsMaxOutputStreams = 4u; static constexpr auto GsMaxOutputStreams = 4u;
using GsOutputPrimTypes = std::array<AmdGpu::GsOutputPrimitiveType, GsMaxOutputStreams>; using GsOutputPrimTypes = std::array<AmdGpu::GsOutputPrimitiveType, GsMaxOutputStreams>;
struct GeometryRuntimeInfo { struct GeometryRuntimeInfo {
u32 num_outputs;
std::array<OutputMap, 3> outputs;
u32 num_invocations{}; u32 num_invocations{};
u32 output_vertices{}; u32 output_vertices{};
u32 in_vertex_data_size{}; u32 in_vertex_data_size{};

View File

@ -397,6 +397,7 @@ bool Instance::CreateDevice() {
.hostQueryReset = vk12_features.hostQueryReset, .hostQueryReset = vk12_features.hostQueryReset,
.timelineSemaphore = vk12_features.timelineSemaphore, .timelineSemaphore = vk12_features.timelineSemaphore,
.bufferDeviceAddress = vk12_features.bufferDeviceAddress, .bufferDeviceAddress = vk12_features.bufferDeviceAddress,
.shaderOutputLayer = vk12_features.shaderOutputLayer,
}, },
vk::PhysicalDeviceVulkan13Features{ vk::PhysicalDeviceVulkan13Features{
.robustImageAccess = vk13_features.robustImageAccess, .robustImageAccess = vk13_features.robustImageAccess,

View File

@ -23,8 +23,8 @@ extern std::unique_ptr<Vulkan::Presenter> presenter;
namespace Vulkan { namespace Vulkan {
using Shader::LogicalStage; using Shader::LogicalStage;
using Shader::Output;
using Shader::Stage; using Shader::Stage;
using Shader::VsOutput;
constexpr static auto SpirvVersion1_6 = 0x00010600U; constexpr static auto SpirvVersion1_6 = 0x00010600U;
@ -35,49 +35,55 @@ constexpr static std::array DescriptorHeapSizes = {
vk::DescriptorPoolSize{vk::DescriptorType::eSampler, 1024}, vk::DescriptorPoolSize{vk::DescriptorType::eSampler, 1024},
}; };
void GatherVertexOutputs(Shader::VertexRuntimeInfo& info, u32 MapOutputs(std::span<Shader::OutputMap, 3> outputs,
const AmdGpu::Liverpool::VsOutputControl& ctl) { const AmdGpu::Liverpool::VsOutputControl& ctl) {
const auto add_output = [&](VsOutput x, VsOutput y, VsOutput z, VsOutput w) { u32 num_outputs = 0;
if (x != VsOutput::None || y != VsOutput::None || z != VsOutput::None ||
w != VsOutput::None) { if (ctl.vs_out_misc_enable) {
info.outputs[info.num_outputs++] = Shader::VsOutputMap{x, y, z, w}; auto& misc_vec = outputs[num_outputs++];
} misc_vec[0] = ctl.use_vtx_point_size ? Output::PointSprite : Output::None;
}; misc_vec[1] = ctl.use_vtx_edge_flag
// VS_OUT_MISC_VEC ? Output::EdgeFlag
add_output(ctl.use_vtx_point_size ? VsOutput::PointSprite : VsOutput::None, : (ctl.use_vtx_gs_cut_flag ? Output::GsCutFlag : Output::None);
ctl.use_vtx_edge_flag misc_vec[2] = ctl.use_vtx_kill_flag
? VsOutput::EdgeFlag ? Output::KillFlag
: (ctl.use_vtx_gs_cut_flag ? VsOutput::GsCutFlag : VsOutput::None), : (ctl.use_vtx_render_target_idx ? Output::GsMrtIndex : Output::None);
ctl.use_vtx_kill_flag misc_vec[3] = ctl.use_vtx_viewport_idx ? Output::GsVpIndex : Output::None;
? VsOutput::KillFlag }
: (ctl.use_vtx_render_target_idx ? VsOutput::GsMrtIndex : VsOutput::None),
ctl.use_vtx_viewport_idx ? VsOutput::GsVpIndex : VsOutput::None); if (ctl.vs_out_ccdist0_enable) {
// VS_OUT_CCDIST0 auto& ccdist0 = outputs[num_outputs++];
add_output(ctl.IsClipDistEnabled(0) ccdist0[0] = ctl.IsClipDistEnabled(0)
? VsOutput::ClipDist0 ? Output::ClipDist0
: (ctl.IsCullDistEnabled(0) ? VsOutput::CullDist0 : VsOutput::None), : (ctl.IsCullDistEnabled(0) ? Output::CullDist0 : Output::None);
ctl.IsClipDistEnabled(1) ccdist0[1] = ctl.IsClipDistEnabled(1)
? VsOutput::ClipDist1 ? Output::ClipDist1
: (ctl.IsCullDistEnabled(1) ? VsOutput::CullDist1 : VsOutput::None), : (ctl.IsCullDistEnabled(1) ? Output::CullDist1 : Output::None);
ctl.IsClipDistEnabled(2) ccdist0[2] = ctl.IsClipDistEnabled(2)
? VsOutput::ClipDist2 ? Output::ClipDist2
: (ctl.IsCullDistEnabled(2) ? VsOutput::CullDist2 : VsOutput::None), : (ctl.IsCullDistEnabled(2) ? Output::CullDist2 : Output::None);
ctl.IsClipDistEnabled(3) ccdist0[3] = ctl.IsClipDistEnabled(3)
? VsOutput::ClipDist3 ? Output::ClipDist3
: (ctl.IsCullDistEnabled(3) ? VsOutput::CullDist3 : VsOutput::None)); : (ctl.IsCullDistEnabled(3) ? Output::CullDist3 : Output::None);
// VS_OUT_CCDIST1 }
add_output(ctl.IsClipDistEnabled(4)
? VsOutput::ClipDist4 if (ctl.vs_out_ccdist1_enable) {
: (ctl.IsCullDistEnabled(4) ? VsOutput::CullDist4 : VsOutput::None), auto& ccdist1 = outputs[num_outputs++];
ctl.IsClipDistEnabled(5) ccdist1[0] = ctl.IsClipDistEnabled(4)
? VsOutput::ClipDist5 ? Output::ClipDist4
: (ctl.IsCullDistEnabled(5) ? VsOutput::CullDist5 : VsOutput::None), : (ctl.IsCullDistEnabled(4) ? Output::CullDist4 : Output::None);
ctl.IsClipDistEnabled(6) ccdist1[1] = ctl.IsClipDistEnabled(5)
? VsOutput::ClipDist6 ? Output::ClipDist5
: (ctl.IsCullDistEnabled(6) ? VsOutput::CullDist6 : VsOutput::None), : (ctl.IsCullDistEnabled(5) ? Output::CullDist5 : Output::None);
ctl.IsClipDistEnabled(7) ccdist1[2] = ctl.IsClipDistEnabled(6)
? VsOutput::ClipDist7 ? Output::ClipDist6
: (ctl.IsCullDistEnabled(7) ? VsOutput::CullDist7 : VsOutput::None)); : (ctl.IsCullDistEnabled(6) ? Output::CullDist6 : Output::None);
ccdist1[3] = ctl.IsClipDistEnabled(7)
? Output::ClipDist7
: (ctl.IsCullDistEnabled(7) ? Output::CullDist7 : Output::None);
}
return num_outputs;
} }
const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalStage l_stage) { const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalStage l_stage) {
@ -121,7 +127,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS
} }
case Stage::Vertex: { case Stage::Vertex: {
BuildCommon(regs.vs_program); BuildCommon(regs.vs_program);
GatherVertexOutputs(info.vs_info, regs.vs_output_control); info.vs_info.num_outputs = MapOutputs(info.vs_info.outputs, regs.vs_output_control);
info.vs_info.emulate_depth_negative_one_to_one = info.vs_info.emulate_depth_negative_one_to_one =
!instance.IsDepthClipControlSupported() && !instance.IsDepthClipControlSupported() &&
regs.clipper_control.clip_space == Liverpool::ClipSpace::MinusWToW; regs.clipper_control.clip_space == Liverpool::ClipSpace::MinusWToW;
@ -136,6 +142,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS
case Stage::Geometry: { case Stage::Geometry: {
BuildCommon(regs.gs_program); BuildCommon(regs.gs_program);
auto& gs_info = info.gs_info; auto& gs_info = info.gs_info;
gs_info.num_outputs = MapOutputs(gs_info.outputs, regs.vs_output_control);
gs_info.output_vertices = regs.vgt_gs_max_vert_out; gs_info.output_vertices = regs.vgt_gs_max_vert_out;
gs_info.num_invocations = gs_info.num_invocations =
regs.vgt_gs_instance_cnt.IsEnabled() ? regs.vgt_gs_instance_cnt.count : 1; regs.vgt_gs_instance_cnt.IsEnabled() ? regs.vgt_gs_instance_cnt.count : 1;

View File

@ -162,6 +162,7 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) {
const auto mip = image_view.info.range.base.level; const auto mip = image_view.info.range.base.level;
state.width = std::min<u32>(state.width, std::max(image.info.size.width >> mip, 1u)); state.width = std::min<u32>(state.width, std::max(image.info.size.width >> mip, 1u));
state.height = std::min<u32>(state.height, std::max(image.info.size.height >> mip, 1u)); state.height = std::min<u32>(state.height, std::max(image.info.size.height >> mip, 1u));
state.num_layers = std::min<u32>(state.num_layers, image_view.info.range.extent.layers);
state.color_attachments[state.num_color_attachments++] = { state.color_attachments[state.num_color_attachments++] = {
.imageView = *image_view.image_view, .imageView = *image_view.image_view,
.imageLayout = vk::ImageLayout::eUndefined, .imageLayout = vk::ImageLayout::eUndefined,
@ -195,6 +196,7 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) {
state.height = std::min<u32>(state.height, image.info.size.height); state.height = std::min<u32>(state.height, image.info.size.height);
state.has_depth = regs.depth_buffer.DepthValid(); state.has_depth = regs.depth_buffer.DepthValid();
state.has_stencil = regs.depth_buffer.StencilValid(); state.has_stencil = regs.depth_buffer.StencilValid();
state.num_layers = std::min<u32>(state.num_layers, image_view.info.range.extent.layers);
if (state.has_depth) { if (state.has_depth) {
state.depth_attachment = { state.depth_attachment = {
.imageView = *image_view.image_view, .imageView = *image_view.image_view,
@ -218,6 +220,10 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) {
texture_cache.TouchMeta(htile_address, slice, false); texture_cache.TouchMeta(htile_address, slice, false);
} }
if (state.num_layers == std::numeric_limits<u32>::max()) {
state.num_layers = 1;
}
return state; return state;
} }

View File

@ -4,6 +4,7 @@
#include <mutex> #include <mutex>
#include "common/assert.h" #include "common/assert.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/logging/log.h"
#include "imgui/renderer/texture_manager.h" #include "imgui/renderer/texture_manager.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
@ -34,9 +35,9 @@ void Scheduler::BeginRendering(const RenderState& new_state) {
is_rendering = true; is_rendering = true;
render_state = new_state; render_state = new_state;
const auto width = const u32 width =
render_state.width != std::numeric_limits<u32>::max() ? render_state.width : 1; render_state.width != std::numeric_limits<u32>::max() ? render_state.width : 1;
const auto height = const u32 height =
render_state.height != std::numeric_limits<u32>::max() ? render_state.height : 1; render_state.height != std::numeric_limits<u32>::max() ? render_state.height : 1;
const vk::RenderingInfo rendering_info = { const vk::RenderingInfo rendering_info = {
@ -45,7 +46,7 @@ void Scheduler::BeginRendering(const RenderState& new_state) {
.offset = {0, 0}, .offset = {0, 0},
.extent = {width, height}, .extent = {width, height},
}, },
.layerCount = 1, .layerCount = render_state.num_layers,
.colorAttachmentCount = render_state.num_color_attachments, .colorAttachmentCount = render_state.num_color_attachments,
.pColorAttachments = render_state.num_color_attachments > 0 .pColorAttachments = render_state.num_color_attachments > 0
? render_state.color_attachments.data() ? render_state.color_attachments.data()

View File

@ -24,6 +24,7 @@ struct RenderState {
vk::RenderingAttachmentInfo depth_attachment{}; vk::RenderingAttachmentInfo depth_attachment{};
vk::RenderingAttachmentInfo stencil_attachment{}; vk::RenderingAttachmentInfo stencil_attachment{};
u32 num_color_attachments{}; u32 num_color_attachments{};
u32 num_layers = std::numeric_limits<u32>::max();
bool has_depth{}; bool has_depth{};
bool has_stencil{}; bool has_stencil{};
u32 width = std::numeric_limits<u32>::max(); u32 width = std::numeric_limits<u32>::max();