Support reverse RGBA16F render targets

This commit is contained in:
nmzik
2026-07-17 12:54:28 +02:00
parent dd58deae15
commit 0abe03af94
13 changed files with 245 additions and 16 deletions
+26
View File
@@ -104,6 +104,32 @@ enum class ChannelOrder : uint32_t {
kAltReversed = 3,
};
// Maps a shader's logical RGBA export to the host color-attachment components. Two bits per
// component keep this cheap to carry in shader and pipeline keys.
struct ColorComponentMapping {
uint8_t packed = 0xe4u; // RGBA: 0, 1, 2, 3
[[nodiscard]] constexpr uint32_t Map(uint32_t component) const {
return component < 4u ? (packed >> (component * 2u)) & 0x3u : component;
}
[[nodiscard]] constexpr uint32_t ApplyMask(uint32_t mask) const {
uint32_t mapped = 0;
for (uint32_t component = 0; component < 4u; component++) {
mapped |= ((mask >> component) & 1u) << Map(component);
}
return mapped;
}
[[nodiscard]] constexpr bool IsIdentity() const { return packed == 0xe4u; }
bool operator==(const ColorComponentMapping&) const = default;
};
static_assert(sizeof(ColorComponentMapping) == sizeof(uint8_t));
inline constexpr ColorComponentMapping ColorMappingAbgr {0x1bu}; // 3, 2, 1, 0
enum class DepthFormat : uint32_t {
kInvalid = 0,
kZ16 = 1,
@@ -92,6 +92,9 @@ RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat, Prospero::ChannelOrder::kStandard)) {
return {VK_FORMAT_R16G16B16A16_SFLOAT, 8};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat, Prospero::ChannelOrder::kReversed)) {
return {VK_FORMAT_R16G16B16A16_SFLOAT, 8, Prospero::ColorMappingAbgr};
}
if (is(Prospero::ChannelLayout::k32, Prospero::ChannelType::kFloat, Prospero::ChannelOrder::kStandard)) {
return {VK_FORMAT_R32_SFLOAT, 4};
}
@@ -3,6 +3,7 @@
#include "common/abi.h"
#include "common/common.h"
#include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/guest_gpu/tile.h"
#include "graphics/host_gpu/utils.h"
@@ -47,8 +48,9 @@ enum class TextureUploadDestination { MipLevels, MipAtlas };
enum class TextureUploadSliceLayout { MipChainPerSlice, MipLevelPerSlice };
struct RenderTargetFormatInfo {
VkFormat format = VK_FORMAT_UNDEFINED;
uint32_t bytes_per_element = 0;
VkFormat format = VK_FORMAT_UNDEFINED;
uint32_t bytes_per_element = 0;
Prospero::ColorComponentMapping export_mapping;
};
struct TextureUploadLayout {
@@ -285,7 +285,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
mask = 0x0f;
}
r->target_slot = rt_slot;
r->target_slot = rt_slot;
r->export_mapping = {};
if (rt.base.addr == 0 || mask == 0) {
if (graphics_debug_dump_enabled()) {
@@ -479,6 +480,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
r->extent = view_extent;
r->base_mip_level = rt.view.current_mip_level;
r->buffer_size = backing_size;
r->export_mapping = rt_format.export_mapping;
} else {
const auto layout = static_cast<Prospero::ChannelLayout>(rt.info.format);
const auto type = static_cast<Prospero::ChannelType>(rt.info.channel_type);
@@ -82,10 +82,10 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
const HW::BlendColor& bclr = ctx->GetBlendColor();
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
for (uint32_t i = 0; i < color_count; i++) {
color_mask[i] =
(colors[i].vulkan_buffer != nullptr
? render_target_mask_slot(ctx->GetRenderTargetMask(), colors[i].target_slot)
: 0);
color_mask[i] = (colors[i].vulkan_buffer != nullptr
? colors[i].export_mapping.ApplyMask(render_target_mask_slot(
ctx->GetRenderTargetMask(), colors[i].target_slot))
: 0);
}
const HW::ModeControl& mc = ctx->GetModeControl();
@@ -748,6 +748,12 @@ static void RefreshShaders(HW::Context* ctx, HW::Shader* sh_ctx, const DrawCallI
state->vs_shader = {};
state->ps_shader = {};
state->ps_input_info = {};
std::array<Prospero::ColorComponentMapping, RENDER_COLOR_ATTACHMENTS_MAX>
target_export_mapping {};
for (uint32_t i = 0; i < state->color_count; i++) {
target_export_mapping[state->color_info[i].target_slot] =
state->color_info[i].export_mapping;
}
EXIT_IF(g_render_ctx == nullptr || g_render_ctx->GetGraphicCtx() == nullptr);
const auto lane_mask_mode = SelectGraphicsLaneMaskMode(*g_render_ctx->GetGraphicCtx(), 64u);
@@ -766,7 +772,8 @@ static void RefreshShaders(HW::Context* ctx, HW::Shader* sh_ctx, const DrawCallI
LogDrawPhase(draw.name, "ShaderCompileInfoPS");
}
if (!ShaderCompileInfoPS(&pixel_shader_info, &shader_regs, lane_mask_mode,
&state->vs_input_info, &state->ps_input_info, &state->ps_shader)) {
&state->vs_input_info, target_export_mapping, &state->ps_input_info,
&state->ps_shader)) {
EXIT("ShaderCompileInfoPS failed for draw %s\n", draw.name);
}
}
@@ -4,6 +4,7 @@
#include "common/abi.h"
#include "common/assert.h"
#include "common/common.h"
#include "graphics/guest_gpu/gpu_defs.h"
#include <cstdint>
#include <string>
@@ -241,6 +242,7 @@ struct RenderColorInfo {
uint64_t base_addr = 0;
uint64_t buffer_size = 0;
uint32_t target_slot = 0;
Prospero::ColorComponentMapping export_mapping;
bool color_clear_enable = false;
VkClearColorValue color_clear_value {};
};
@@ -50,6 +50,23 @@ uint32_t EmitExportVec4F32(EmitterState* state, const IR::Instruction& inst) {
return vec;
}
uint32_t ApplyMrtExportMapping(EmitterState* state, const IR::Instruction& inst, uint32_t value) {
if (inst.export_info.kind != IR::ExportTargetKind::Mrt || state->pixel_input_info == nullptr ||
inst.export_info.index >= state->pixel_input_info->target_export_mapping.size()) {
return value;
}
const auto mapping = state->pixel_input_info->target_export_mapping[inst.export_info.index];
if (mapping.IsIdentity()) {
return value;
}
const auto mapped = state->builder.AllocateId();
state->builder.AddFunction({OpVectorShuffle, state->vec4_float_type, mapped, value, value,
mapping.Map(0), mapping.Map(1), mapping.Map(2), mapping.Map(3)});
return mapped;
}
bool ExportWritesData(const IR::Instruction& inst) {
switch (inst.export_info.kind) {
case IR::ExportTargetKind::Null:
@@ -97,7 +114,7 @@ void EmitExport(EmitterState* state, const IR::Instruction& inst) {
return;
}
const auto value = EmitExportVec4F32(state, inst);
const auto value = ApplyMrtExportMapping(state, inst, EmitExportVec4F32(state, inst));
if (inst.export_info.kind == IR::ExportTargetKind::Position) {
const auto pointer = state->builder.AllocateId();
state->builder.AddFunction({OpAccessChain, state->ptr_output_vec4_float, pointer, variable,
@@ -135,6 +135,7 @@ enum : uint32_t {
OpArrayLength = 68,
OpDecorate = 71,
OpMemberDecorate = 72,
OpVectorShuffle = 79,
OpCompositeConstruct = 80,
OpCompositeExtract = 81,
OpSampledImage = 86,
+18 -5
View File
@@ -791,10 +791,11 @@ static bool ShaderGetStaticInputInfoVS(const HW::VertexShaderInfo* regs,
return true;
}
static void ShaderGetStaticInputInfoPS(const HW::PixelShaderInfo* regs,
const HW::ShaderRegisters* sh,
const ShaderVertexInputInfo* vs_info,
ShaderPixelInputInfo* ps_info) {
static void ShaderGetStaticInputInfoPS(
const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh,
const ShaderVertexInputInfo* vs_info,
std::span<const Prospero::ColorComponentMapping, 8> target_export_mapping,
ShaderPixelInputInfo* ps_info) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(vs_info == nullptr);
@@ -834,6 +835,9 @@ static void ShaderGetStaticInputInfoPS(const HW::PixelShaderInfo* regs,
for (int i = 0; i < 8; i++) {
ps_info->target_output_mode[i] = sh->target_output_mode[i];
ps_info->target_export_mapping[i] =
sh->target_output_mode[i] != 0 ? target_export_mapping[i]
: Prospero::ColorComponentMapping {};
}
ps_info->mrt_output_mask = 0;
}
@@ -1105,11 +1109,12 @@ bool ShaderCompileInfoVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegis
bool ShaderCompileInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh,
ShaderLaneMaskMode lane_mask_mode, const ShaderVertexInputInfo* vs_info,
std::span<const Prospero::ColorComponentMapping, 8> target_export_mapping,
ShaderPixelInputInfo* ps_info, std::span<const uint32_t>* spirv) {
EXIT_IF(spirv == nullptr);
*spirv = {};
ShaderGetStaticInputInfoPS(regs, sh, vs_info, ps_info);
ShaderGetStaticInputInfoPS(regs, sh, vs_info, target_export_mapping, ps_info);
const auto shader_hash =
regs->ps_regs.chksum != 0 ? regs->ps_regs.chksum : regs->ps_regs.data_addr;
const auto program_id = ShaderGetIdPS(regs, ps_info, false);
@@ -1632,6 +1637,14 @@ ShaderId ShaderGetIdPS(const HW::PixelShaderInfo* regs, const ShaderPixelInputIn
for (auto mode: input_info->target_output_mode) {
ret.ids.push_back(mode);
}
for (uint32_t base = 0; base < input_info->target_export_mapping.size(); base += 4u) {
uint32_t packed = 0;
for (uint32_t i = 0; i < 4u; i++) {
packed |= static_cast<uint32_t>(input_info->target_export_mapping[base + i].packed)
<< (i * 8u);
}
ret.ids.push_back(packed);
}
ret.ids.push_back(input_info->mrt_output_mask);
for (uint32_t i = 0; i < input_info->input_num; i++) {
+4
View File
@@ -3,8 +3,10 @@
#include "common/abi.h"
#include "common/common.h"
#include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/shader/shaderBindings.h"
#include <array>
#include <memory>
#include <span>
#include <string>
@@ -98,6 +100,7 @@ struct ShaderPixelInputInfo {
uint32_t input_num = 0;
uint32_t ps_system_input_base = 0;
uint8_t target_output_mode[8] = {};
std::array<Prospero::ColorComponentMapping, 8> target_export_mapping = {};
uint32_t mrt_output_mask = 0;
uint32_t descriptor_set = 0;
bool ps_pos_x = false;
@@ -227,6 +230,7 @@ bool ShaderCompileInfoVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegis
std::span<const uint32_t>* spirv);
bool ShaderCompileInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh,
ShaderLaneMaskMode lane_mask_mode, const ShaderVertexInputInfo* vs_info,
std::span<const Prospero::ColorComponentMapping, 8> target_export_mapping,
ShaderPixelInputInfo* input_info, std::span<const uint32_t>* spirv);
bool ShaderCompileInfoCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh,
ShaderComputeInputInfo* input_info, std::span<const uint32_t>* spirv);