video_core: support for multi-layered outputs

This commit is contained in:
polyproxy 2025-03-01 17:33:44 +01:00
parent db868ea400
commit 4b514e05b7
No known key found for this signature in database
GPG key ID: B8ADC8F57BA18DBA
11 changed files with 44 additions and 13 deletions

View file

@ -268,6 +268,9 @@ void SetupCapabilities(const Info& info, const Profile& profile, EmitContext& ct
if (info.has_image_query) {
ctx.AddCapability(spv::Capability::ImageQuery);
}
if (info.has_layer_output) {
ctx.AddCapability(spv::Capability::ShaderLayer);
}
if (info.uses_lane_id) {
ctx.AddCapability(spv::Capability::GroupNonUniform);
}

View file

@ -76,7 +76,11 @@ Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) {
case IR::Attribute::Position0: {
return ctx.OpAccessChain(ctx.output_f32, ctx.output_position, ctx.ConstU32(element));
}
case IR::Attribute::Position1:
case IR::Attribute::Position1: {
ASSERT(ctx.stage == Stage::Geometry || ctx.stage == Stage::Vertex);
ASSERT_MSG(element == 2u, "Unsupported pos1 export");
return ctx.output_layer;
}
case IR::Attribute::Position2:
case IR::Attribute::Position3: {
const u32 index = u32(attr) - u32(IR::Attribute::Position1);
@ -106,11 +110,12 @@ std::pair<Id, bool> OutputAttrComponentType(EmitContext& ctx, IR::Attribute attr
}
switch (attr) {
case IR::Attribute::Position0:
case IR::Attribute::Position1:
case IR::Attribute::Position2:
case IR::Attribute::Position3:
case IR::Attribute::Depth:
return {ctx.F32[1], false};
case IR::Attribute::Position1:
return {ctx.S32[1], true};
default:
throw NotImplementedException("Write attribute {}", attr);
}
@ -337,10 +342,6 @@ Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, u32 comp) {
}
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 auto component_type{OutputAttrComponentType(ctx, attr)};
if (component_type.second) {

View file

@ -508,6 +508,9 @@ void EmitContext::DefineOutputs() {
cull_distances =
DefineVariable(type, spv::BuiltIn::CullDistance, spv::StorageClass::Output);
}
if (info.has_layer_output) {
output_layer = DefineVariable(S32[1], spv::BuiltIn::Layer, spv::StorageClass::Output);
}
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;
if (num_attrs > 0) {
@ -578,6 +581,10 @@ void EmitContext::DefineOutputs() {
cull_distances =
DefineVariable(type, spv::BuiltIn::CullDistance, spv::StorageClass::Output);
}
if (info.has_layer_output) {
output_layer = DefineVariable(S32[1], spv::BuiltIn::Layer, spv::StorageClass::Output);
}
for (u32 i = 0; i < IR::NumParams; i++) {
const IR::Attribute param{IR::Attribute::Param0 + i};
if (!info.stores.GetAny(param)) {
@ -607,6 +614,9 @@ void EmitContext::DefineOutputs() {
break;
case LogicalStage::Geometry: {
output_position = DefineVariable(F32[4], spv::BuiltIn::Position, spv::StorageClass::Output);
if (info.has_layer_output) {
output_layer = DefineVariable(S32[1], spv::BuiltIn::Layer, spv::StorageClass::Output);
}
for (u32 attr_id = 0; attr_id < info.gs_copy_data.num_attrs; attr_id++) {
const Id id{DefineOutput(F32[4], attr_id)};

View file

@ -183,6 +183,7 @@ public:
boost::container::small_vector<Id, 16> interfaces;
Id output_position{};
Id output_layer{};
Id primitive_id{};
Id vertex_index{};
Id instance_id{};

View file

@ -196,6 +196,7 @@ struct Info {
bool has_discard{};
bool has_image_gather{};
bool has_image_query{};
bool has_layer_output{};
bool uses_lane_id{};
bool uses_group_quad{};
bool uses_group_ballot{};

View file

@ -11,9 +11,15 @@ void Visit(Info& info, const IR::Inst& inst) {
case IR::Opcode::GetAttributeU32:
info.loads.Set(inst.Arg(0).Attribute(), inst.Arg(1).U32());
break;
case IR::Opcode::SetAttribute:
info.stores.Set(inst.Arg(0).Attribute(), inst.Arg(2).U32());
case IR::Opcode::SetAttribute: {
const IR::Attribute attr = inst.Arg(0).Attribute();
const u32 comp = inst.Arg(2).U32();
if (attr == IR::Attribute::Position1 && comp == 2u) {
info.has_layer_output = true;
}
info.stores.Set(attr, comp);
break;
}
case IR::Opcode::GetUserData:
info.ud_mask.Set(inst.Arg(0).ScalarReg());
break;

View file

@ -365,6 +365,7 @@ bool Instance::CreateDevice() {
.separateDepthStencilLayouts = vk12_features.separateDepthStencilLayouts,
.hostQueryReset = vk12_features.hostQueryReset,
.timelineSemaphore = vk12_features.timelineSemaphore,
.shaderOutputLayer = vk12_features.shaderOutputLayer,
},
// Vulkan 1.3 promoted extensions
vk::PhysicalDeviceDynamicRenderingFeaturesKHR{

View file

@ -162,7 +162,7 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) {
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.height = std::min<u32>(state.height, std::max(image.info.size.height >> mip, 1u));
state.color_attachments[state.num_color_attachments++] = {
state.color_attachments[state.num_color_attachments] = {
.imageView = *image_view.image_view,
.imageLayout = vk::ImageLayout::eUndefined,
.loadOp = is_clear ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad,
@ -170,6 +170,8 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) {
.clearValue =
is_clear ? LiverpoolToVK::ColorBufferClearValue(col_buf) : vk::ClearValue{},
};
state.cb_slices[state.num_color_attachments] = image_view.info.range.extent.layers;
state.num_color_attachments++;
}
if ((regs.depth_control.depth_enable && regs.depth_buffer.DepthValid()) ||
@ -196,6 +198,7 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) {
state.has_depth = regs.depth_buffer.DepthValid();
state.has_stencil = regs.depth_buffer.StencilValid();
if (state.has_depth) {
state.depth_slices = image_view.info.range.extent.layers;
state.depth_attachment = {
.imageView = *image_view.image_view,
.imageLayout = vk::ImageLayout::eUndefined,

View file

@ -34,18 +34,21 @@ void Scheduler::BeginRendering(const RenderState& new_state) {
is_rendering = true;
render_state = new_state;
const auto width =
const u32 width =
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;
const u32 cb_layers = *std::max_element(render_state.cb_slices.begin(), render_state.cb_slices.end());
const u32 layers = std::max<u32>(cb_layers, render_state.depth_slices);
const vk::RenderingInfo rendering_info = {
.renderArea =
{
.offset = {0, 0},
.extent = {width, height},
},
.layerCount = 1,
.layerCount = layers,
.colorAttachmentCount = render_state.num_color_attachments,
.pColorAttachments = render_state.num_color_attachments > 0
? render_state.color_attachments.data()

View file

@ -27,6 +27,8 @@ struct RenderState {
bool has_stencil{};
u32 width = std::numeric_limits<u32>::max();
u32 height = std::numeric_limits<u32>::max();
std::array<u32, 8> cb_slices{1};
u32 depth_slices{0};
bool operator==(const RenderState& other) const noexcept {
return std::memcmp(this, &other, sizeof(RenderState)) == 0;

View file

@ -436,9 +436,9 @@ ImageView& TextureCache::FindDepthTarget(BaseDesc& desc) {
const ImageId image_id = FindImage(desc);
Image& image = slot_images[image_id];
image.flags |= ImageFlagBits::GpuModified;
image.flags &= ~ImageFlagBits::Dirty;
image.usage.depth_target = 1u;
image.usage.stencil = image.info.HasStencil();
UpdateImage(image_id);
// Register meta data for this depth buffer
if (!(image.flags & ImageFlagBits::MetaRegistered)) {