mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 08:41:20 +00:00
Support reverse RGBA16F render targets
This commit is contained in:
1 parent
dd58deae15
commit
0abe03af94
13 files changed
+245
-16
No files matched your search
@@ -104,6 +104,32 @@ enum class ChannelOrder : uint32_t {
|
|||||||
kAltReversed = 3,
|
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 {
|
enum class DepthFormat : uint32_t {
|
||||||
kInvalid = 0,
|
kInvalid = 0,
|
||||||
kZ16 = 1,
|
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)) {
|
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat, Prospero::ChannelOrder::kStandard)) {
|
||||||
return {VK_FORMAT_R16G16B16A16_SFLOAT, 8};
|
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)) {
|
if (is(Prospero::ChannelLayout::k32, Prospero::ChannelType::kFloat, Prospero::ChannelOrder::kStandard)) {
|
||||||
return {VK_FORMAT_R32_SFLOAT, 4};
|
return {VK_FORMAT_R32_SFLOAT, 4};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "common/abi.h"
|
#include "common/abi.h"
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
|
#include "graphics/guest_gpu/gpu_defs.h"
|
||||||
#include "graphics/guest_gpu/tile.h"
|
#include "graphics/guest_gpu/tile.h"
|
||||||
#include "graphics/host_gpu/utils.h"
|
#include "graphics/host_gpu/utils.h"
|
||||||
|
|
||||||
@@ -47,8 +48,9 @@ enum class TextureUploadDestination { MipLevels, MipAtlas };
|
|||||||
enum class TextureUploadSliceLayout { MipChainPerSlice, MipLevelPerSlice };
|
enum class TextureUploadSliceLayout { MipChainPerSlice, MipLevelPerSlice };
|
||||||
|
|
||||||
struct RenderTargetFormatInfo {
|
struct RenderTargetFormatInfo {
|
||||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||||
uint32_t bytes_per_element = 0;
|
uint32_t bytes_per_element = 0;
|
||||||
|
Prospero::ColorComponentMapping export_mapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextureUploadLayout {
|
struct TextureUploadLayout {
|
||||||
|
|||||||
@@ -285,7 +285,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
|||||||
mask = 0x0f;
|
mask = 0x0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->target_slot = rt_slot;
|
r->target_slot = rt_slot;
|
||||||
|
r->export_mapping = {};
|
||||||
|
|
||||||
if (rt.base.addr == 0 || mask == 0) {
|
if (rt.base.addr == 0 || mask == 0) {
|
||||||
if (graphics_debug_dump_enabled()) {
|
if (graphics_debug_dump_enabled()) {
|
||||||
@@ -479,6 +480,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
|||||||
r->extent = view_extent;
|
r->extent = view_extent;
|
||||||
r->base_mip_level = rt.view.current_mip_level;
|
r->base_mip_level = rt.view.current_mip_level;
|
||||||
r->buffer_size = backing_size;
|
r->buffer_size = backing_size;
|
||||||
|
r->export_mapping = rt_format.export_mapping;
|
||||||
} else {
|
} else {
|
||||||
const auto layout = static_cast<Prospero::ChannelLayout>(rt.info.format);
|
const auto layout = static_cast<Prospero::ChannelLayout>(rt.info.format);
|
||||||
const auto type = static_cast<Prospero::ChannelType>(rt.info.channel_type);
|
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();
|
const HW::BlendColor& bclr = ctx->GetBlendColor();
|
||||||
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||||
for (uint32_t i = 0; i < color_count; i++) {
|
for (uint32_t i = 0; i < color_count; i++) {
|
||||||
color_mask[i] =
|
color_mask[i] = (colors[i].vulkan_buffer != nullptr
|
||||||
(colors[i].vulkan_buffer != nullptr
|
? colors[i].export_mapping.ApplyMask(render_target_mask_slot(
|
||||||
? render_target_mask_slot(ctx->GetRenderTargetMask(), colors[i].target_slot)
|
ctx->GetRenderTargetMask(), colors[i].target_slot))
|
||||||
: 0);
|
: 0);
|
||||||
}
|
}
|
||||||
const HW::ModeControl& mc = ctx->GetModeControl();
|
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->vs_shader = {};
|
||||||
state->ps_shader = {};
|
state->ps_shader = {};
|
||||||
state->ps_input_info = {};
|
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);
|
EXIT_IF(g_render_ctx == nullptr || g_render_ctx->GetGraphicCtx() == nullptr);
|
||||||
const auto lane_mask_mode = SelectGraphicsLaneMaskMode(*g_render_ctx->GetGraphicCtx(), 64u);
|
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");
|
LogDrawPhase(draw.name, "ShaderCompileInfoPS");
|
||||||
}
|
}
|
||||||
if (!ShaderCompileInfoPS(&pixel_shader_info, &shader_regs, lane_mask_mode,
|
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);
|
EXIT("ShaderCompileInfoPS failed for draw %s\n", draw.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "common/abi.h"
|
#include "common/abi.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
|
#include "graphics/guest_gpu/gpu_defs.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -241,6 +242,7 @@ struct RenderColorInfo {
|
|||||||
uint64_t base_addr = 0;
|
uint64_t base_addr = 0;
|
||||||
uint64_t buffer_size = 0;
|
uint64_t buffer_size = 0;
|
||||||
uint32_t target_slot = 0;
|
uint32_t target_slot = 0;
|
||||||
|
Prospero::ColorComponentMapping export_mapping;
|
||||||
bool color_clear_enable = false;
|
bool color_clear_enable = false;
|
||||||
VkClearColorValue color_clear_value {};
|
VkClearColorValue color_clear_value {};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,6 +50,23 @@ uint32_t EmitExportVec4F32(EmitterState* state, const IR::Instruction& inst) {
|
|||||||
return vec;
|
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) {
|
bool ExportWritesData(const IR::Instruction& inst) {
|
||||||
switch (inst.export_info.kind) {
|
switch (inst.export_info.kind) {
|
||||||
case IR::ExportTargetKind::Null:
|
case IR::ExportTargetKind::Null:
|
||||||
@@ -97,7 +114,7 @@ void EmitExport(EmitterState* state, const IR::Instruction& inst) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto value = EmitExportVec4F32(state, inst);
|
const auto value = ApplyMrtExportMapping(state, inst, EmitExportVec4F32(state, inst));
|
||||||
if (inst.export_info.kind == IR::ExportTargetKind::Position) {
|
if (inst.export_info.kind == IR::ExportTargetKind::Position) {
|
||||||
const auto pointer = state->builder.AllocateId();
|
const auto pointer = state->builder.AllocateId();
|
||||||
state->builder.AddFunction({OpAccessChain, state->ptr_output_vec4_float, pointer, variable,
|
state->builder.AddFunction({OpAccessChain, state->ptr_output_vec4_float, pointer, variable,
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ enum : uint32_t {
|
|||||||
OpArrayLength = 68,
|
OpArrayLength = 68,
|
||||||
OpDecorate = 71,
|
OpDecorate = 71,
|
||||||
OpMemberDecorate = 72,
|
OpMemberDecorate = 72,
|
||||||
|
OpVectorShuffle = 79,
|
||||||
OpCompositeConstruct = 80,
|
OpCompositeConstruct = 80,
|
||||||
OpCompositeExtract = 81,
|
OpCompositeExtract = 81,
|
||||||
OpSampledImage = 86,
|
OpSampledImage = 86,
|
||||||
|
|||||||
@@ -791,10 +791,11 @@ static bool ShaderGetStaticInputInfoVS(const HW::VertexShaderInfo* regs,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShaderGetStaticInputInfoPS(const HW::PixelShaderInfo* regs,
|
static void ShaderGetStaticInputInfoPS(
|
||||||
const HW::ShaderRegisters* sh,
|
const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh,
|
||||||
const ShaderVertexInputInfo* vs_info,
|
const ShaderVertexInputInfo* vs_info,
|
||||||
ShaderPixelInputInfo* ps_info) {
|
std::span<const Prospero::ColorComponentMapping, 8> target_export_mapping,
|
||||||
|
ShaderPixelInputInfo* ps_info) {
|
||||||
KYTY_PROFILER_FUNCTION();
|
KYTY_PROFILER_FUNCTION();
|
||||||
|
|
||||||
EXIT_IF(vs_info == nullptr);
|
EXIT_IF(vs_info == nullptr);
|
||||||
@@ -834,6 +835,9 @@ static void ShaderGetStaticInputInfoPS(const HW::PixelShaderInfo* regs,
|
|||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
ps_info->target_output_mode[i] = sh->target_output_mode[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;
|
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,
|
bool ShaderCompileInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh,
|
||||||
ShaderLaneMaskMode lane_mask_mode, const ShaderVertexInputInfo* vs_info,
|
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) {
|
ShaderPixelInputInfo* ps_info, std::span<const uint32_t>* spirv) {
|
||||||
EXIT_IF(spirv == nullptr);
|
EXIT_IF(spirv == nullptr);
|
||||||
*spirv = {};
|
*spirv = {};
|
||||||
|
|
||||||
ShaderGetStaticInputInfoPS(regs, sh, vs_info, ps_info);
|
ShaderGetStaticInputInfoPS(regs, sh, vs_info, target_export_mapping, ps_info);
|
||||||
const auto shader_hash =
|
const auto shader_hash =
|
||||||
regs->ps_regs.chksum != 0 ? regs->ps_regs.chksum : regs->ps_regs.data_addr;
|
regs->ps_regs.chksum != 0 ? regs->ps_regs.chksum : regs->ps_regs.data_addr;
|
||||||
const auto program_id = ShaderGetIdPS(regs, ps_info, false);
|
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) {
|
for (auto mode: input_info->target_output_mode) {
|
||||||
ret.ids.push_back(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);
|
ret.ids.push_back(input_info->mrt_output_mask);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < input_info->input_num; i++) {
|
for (uint32_t i = 0; i < input_info->input_num; i++) {
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
#include "common/abi.h"
|
#include "common/abi.h"
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
|
#include "graphics/guest_gpu/gpu_defs.h"
|
||||||
#include "graphics/shader/shaderBindings.h"
|
#include "graphics/shader/shaderBindings.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -98,6 +100,7 @@ struct ShaderPixelInputInfo {
|
|||||||
uint32_t input_num = 0;
|
uint32_t input_num = 0;
|
||||||
uint32_t ps_system_input_base = 0;
|
uint32_t ps_system_input_base = 0;
|
||||||
uint8_t target_output_mode[8] = {};
|
uint8_t target_output_mode[8] = {};
|
||||||
|
std::array<Prospero::ColorComponentMapping, 8> target_export_mapping = {};
|
||||||
uint32_t mrt_output_mask = 0;
|
uint32_t mrt_output_mask = 0;
|
||||||
uint32_t descriptor_set = 0;
|
uint32_t descriptor_set = 0;
|
||||||
bool ps_pos_x = false;
|
bool ps_pos_x = false;
|
||||||
@@ -227,6 +230,7 @@ bool ShaderCompileInfoVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegis
|
|||||||
std::span<const uint32_t>* spirv);
|
std::span<const uint32_t>* spirv);
|
||||||
bool ShaderCompileInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh,
|
bool ShaderCompileInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh,
|
||||||
ShaderLaneMaskMode lane_mask_mode, const ShaderVertexInputInfo* vs_info,
|
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);
|
ShaderPixelInputInfo* input_info, std::span<const uint32_t>* spirv);
|
||||||
bool ShaderCompileInfoCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh,
|
bool ShaderCompileInfoCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh,
|
||||||
ShaderComputeInputInfo* input_info, std::span<const uint32_t>* spirv);
|
ShaderComputeInputInfo* input_info, std::span<const uint32_t>* spirv);
|
||||||
|
|||||||
@@ -8676,6 +8676,51 @@ bool CacheFault(void *opaque, PageFaultAccess access, uint64_t vaddr,
|
|||||||
context->texture->InvalidateMemory(access, vaddr, size, phase);
|
context->texture->InvalidateMemory(access, vaddr, size, phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[noreturn]] void RunReverseRenderTargetDeathCase() {
|
||||||
|
(void)TextureGetRenderTargetFormat(12u, 7u, 3u);
|
||||||
|
std::_Exit(0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckReverseRenderTargetFormatContract() {
|
||||||
|
const auto format = TextureGetRenderTargetFormat(12u, 7u, 2u);
|
||||||
|
Require("ReverseRenderTarget", "exact format",
|
||||||
|
format.format == VK_FORMAT_R16G16B16A16_SFLOAT &&
|
||||||
|
format.bytes_per_element == 8u &&
|
||||||
|
format.export_mapping == Prospero::ColorMappingAbgr,
|
||||||
|
"exact reverse RGBA16F render-target tuple was rejected");
|
||||||
|
Require("ReverseRenderTarget", "write masks",
|
||||||
|
format.export_mapping.ApplyMask(0x1u) == 0x8u &&
|
||||||
|
format.export_mapping.ApplyMask(0x2u) == 0x4u &&
|
||||||
|
format.export_mapping.ApplyMask(0x4u) == 0x2u &&
|
||||||
|
format.export_mapping.ApplyMask(0x8u) == 0x1u &&
|
||||||
|
format.export_mapping.ApplyMask(0xfu) == 0xfu,
|
||||||
|
"reverse RGBA16F component mask was not mapped exactly once");
|
||||||
|
|
||||||
|
char path[MAX_PATH]{};
|
||||||
|
Require("ReverseRenderTarget", "host",
|
||||||
|
GetModuleFileNameA(nullptr, path, MAX_PATH) != 0,
|
||||||
|
"GetModuleFileName failed");
|
||||||
|
std::string command = std::string("\"") + path + "\" --reverse-rt-death";
|
||||||
|
std::vector<char> mutable_command(command.begin(), command.end());
|
||||||
|
mutable_command.push_back('\0');
|
||||||
|
STARTUPINFOA startup{sizeof(startup)};
|
||||||
|
PROCESS_INFORMATION process{};
|
||||||
|
Require("ReverseRenderTarget", "host",
|
||||||
|
CreateProcessA(nullptr, mutable_command.data(), nullptr, nullptr, FALSE,
|
||||||
|
CREATE_NO_WINDOW, nullptr, nullptr, &startup, &process) != 0,
|
||||||
|
"CreateProcess failed");
|
||||||
|
Require("ReverseRenderTarget", "host",
|
||||||
|
WaitForSingleObject(process.hProcess, 10000) == WAIT_OBJECT_0,
|
||||||
|
"unsupported adjacent render-target tuple timed out");
|
||||||
|
DWORD exit_code = 0;
|
||||||
|
const bool exited = GetExitCodeProcess(process.hProcess, &exit_code) != 0;
|
||||||
|
CloseHandle(process.hThread);
|
||||||
|
CloseHandle(process.hProcess);
|
||||||
|
Require("ReverseRenderTarget", "hard failure", exited && exit_code == 321,
|
||||||
|
"adjacent unproven render-target tuple did not retain the fatal guard");
|
||||||
|
std::printf("[host] %-32s ok\n", "ReverseRenderTargetFormat");
|
||||||
|
}
|
||||||
|
|
||||||
[[noreturn]] void RunImageViewDeathCase(const char *kind) {
|
[[noreturn]] void RunImageViewDeathCase(const char *kind) {
|
||||||
if (std::strcmp(kind, "sampled") == 0) {
|
if (std::strcmp(kind, "sampled") == 0) {
|
||||||
(void)SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM,
|
(void)SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
@@ -11729,6 +11774,13 @@ int main(int argc, char **argv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||||
|
if (argc == 2 && std::strcmp(argv[1], "--reverse-rt-death") == 0) {
|
||||||
|
RunReverseRenderTargetDeathCase();
|
||||||
|
}
|
||||||
|
if (argc == 2 && std::strcmp(argv[1], "--reverse-rt-only") == 0) {
|
||||||
|
CheckReverseRenderTargetFormatContract();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--image-overlap-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--image-overlap-only") == 0) {
|
||||||
CheckImageOverlapResolution();
|
CheckImageOverlapResolution();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -11802,6 +11854,7 @@ int main(int argc, char **argv) {
|
|||||||
if (argc == 3 && std::strcmp(argv[1], "--metadata-descriptor-death") == 0) {
|
if (argc == 3 && std::strcmp(argv[1], "--metadata-descriptor-death") == 0) {
|
||||||
RunMetadataDescriptorDeathCase(argv[2]);
|
RunMetadataDescriptorDeathCase(argv[2]);
|
||||||
}
|
}
|
||||||
|
CheckReverseRenderTargetFormatContract();
|
||||||
CheckSampledColorViews();
|
CheckSampledColorViews();
|
||||||
CheckSampledDepthResource();
|
CheckSampledDepthResource();
|
||||||
CheckSampledDepthDescriptor();
|
CheckSampledDepthDescriptor();
|
||||||
|
|||||||
+101
-2
@@ -4,6 +4,7 @@
|
|||||||
#include "common/threads.h"
|
#include "common/threads.h"
|
||||||
#include "graphics/guest_gpu/hardwareContext.h"
|
#include "graphics/guest_gpu/hardwareContext.h"
|
||||||
#include "graphics/guest_gpu/pm4.h"
|
#include "graphics/guest_gpu/pm4.h"
|
||||||
|
#include "graphics/host_gpu/objects/textureCommon.h"
|
||||||
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
|
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
|
||||||
#include "graphics/host_gpu/renderer/shaderSubgroup.h"
|
#include "graphics/host_gpu/renderer/shaderSubgroup.h"
|
||||||
#include "graphics/shader/recompiler/ExecMask.h"
|
#include "graphics/shader/recompiler/ExecMask.h"
|
||||||
@@ -135,6 +136,24 @@ uint32_t SpirvInstructionOpcodeCount(const std::vector<uint32_t>& binary, uint32
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SpirvContainsVectorShuffle(const std::vector<uint32_t>& binary,
|
||||||
|
const std::array<uint32_t, 4>& selectors) {
|
||||||
|
for (size_t i = 5; i < binary.size();) {
|
||||||
|
const uint32_t word = binary[i];
|
||||||
|
const uint32_t op = word & 0xffffu;
|
||||||
|
const uint32_t word_count = word >> 16u;
|
||||||
|
if (word_count == 0 || i + word_count > binary.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (op == 79u && word_count == 9u &&
|
||||||
|
std::equal(selectors.begin(), selectors.end(), binary.begin() + i + 5u)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
i += word_count;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool SpirvContainsCapability(const std::vector<uint32_t>& binary, uint32_t capability) {
|
bool SpirvContainsCapability(const std::vector<uint32_t>& binary, uint32_t capability) {
|
||||||
for (size_t i = 5; i < binary.size();) {
|
for (size_t i = 5; i < binary.size();) {
|
||||||
const uint32_t word = binary[i];
|
const uint32_t word = binary[i];
|
||||||
@@ -5696,6 +5715,82 @@ void TestNewShaderRecompilerExpPixelOutputs() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestRenderTargetReverseFloat16ExportMapping() {
|
||||||
|
const auto format =
|
||||||
|
TextureGetRenderTargetFormat(Prospero::GpuEnumValue(Prospero::ChannelLayout::k16_16_16_16),
|
||||||
|
Prospero::GpuEnumValue(Prospero::ChannelType::kFloat),
|
||||||
|
Prospero::GpuEnumValue(Prospero::ChannelOrder::kReversed));
|
||||||
|
Check(format.format == VK_FORMAT_R16G16B16A16_SFLOAT && format.bytes_per_element == 8u,
|
||||||
|
"reverse RGBA16F render target did not retain its native host format "
|
||||||
|
"and size");
|
||||||
|
Check(format.export_mapping == Prospero::ColorMappingAbgr &&
|
||||||
|
format.export_mapping.ApplyMask(0x1u) == 0x8u &&
|
||||||
|
format.export_mapping.ApplyMask(0x2u) == 0x4u &&
|
||||||
|
format.export_mapping.ApplyMask(0x4u) == 0x2u &&
|
||||||
|
format.export_mapping.ApplyMask(0x8u) == 0x1u &&
|
||||||
|
format.export_mapping.ApplyMask(0xfu) == 0xfu,
|
||||||
|
"reverse RGBA16F render-target export or write-mask mapping is "
|
||||||
|
"incorrect");
|
||||||
|
const auto legacy_alt = TextureGetRenderTargetFormat(
|
||||||
|
Prospero::GpuEnumValue(Prospero::ChannelLayout::k8_8_8_8),
|
||||||
|
Prospero::GpuEnumValue(Prospero::ChannelType::kUNorm),
|
||||||
|
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt));
|
||||||
|
Check(legacy_alt.format == VK_FORMAT_B8G8R8A8_UNORM && legacy_alt.export_mapping.IsIdentity(),
|
||||||
|
"legacy BGRA render target acquired a duplicate shader export mapping");
|
||||||
|
|
||||||
|
const uint32_t shader[] = {
|
||||||
|
EncodeExp0(0x00, 0xf),
|
||||||
|
EncodeExp1(0, 1, 2, 3), // MRT0
|
||||||
|
0xbf810000u,
|
||||||
|
};
|
||||||
|
ShaderPixelInputInfo identity_info;
|
||||||
|
ShaderPixelInputInfo reversed_info;
|
||||||
|
reversed_info.target_export_mapping[0] = format.export_mapping;
|
||||||
|
|
||||||
|
ShaderRecompiler::CompileOptions options;
|
||||||
|
options.stage = ShaderType::Pixel;
|
||||||
|
options.pixel_input_info = &identity_info;
|
||||||
|
ShaderRecompiler::CompileResult identity_result;
|
||||||
|
std::string error;
|
||||||
|
Check(ShaderRecompiler::TryRecompile(shader, options, &identity_result, &error), error.c_str());
|
||||||
|
Check(SpirvInstructionOpcodeCount(identity_result.spirv, 79u) == 0u,
|
||||||
|
"identity MRT export unexpectedly added a component shuffle");
|
||||||
|
|
||||||
|
options.pixel_input_info = &reversed_info;
|
||||||
|
ShaderRecompiler::CompileResult reversed_result;
|
||||||
|
Check(ShaderRecompiler::TryRecompile(shader, options, &reversed_result, &error), error.c_str());
|
||||||
|
Check(SpirvContainsVectorShuffle(reversed_result.spirv, {3u, 2u, 1u, 0u}),
|
||||||
|
"reverse MRT export did not emit a WZYX component shuffle");
|
||||||
|
CheckSpirvBinaryValidates(reversed_result.spirv);
|
||||||
|
|
||||||
|
HW::PixelShaderInfo regs {};
|
||||||
|
Check(ShaderGetIdPS(®s, &identity_info, false) !=
|
||||||
|
ShaderGetIdPS(®s, &reversed_info, false),
|
||||||
|
"pixel shader cache identity omitted the render-target export mapping");
|
||||||
|
|
||||||
|
regs.ps_regs.data_addr = reinterpret_cast<uint64_t>(shader);
|
||||||
|
regs.ps_regs.chksum = 0xf16ab6f000000001ull;
|
||||||
|
ShaderMappedData mapped {};
|
||||||
|
mapped.code_size_bytes = sizeof(shader);
|
||||||
|
ShaderMapUserData(regs.ps_regs.data_addr, mapped);
|
||||||
|
HW::ShaderRegisters sh {};
|
||||||
|
ShaderVertexInputInfo vs_info {};
|
||||||
|
vs_info.stage.program = std::make_shared<ShaderRecompiler::IR::Program>();
|
||||||
|
std::array<Prospero::ColorComponentMapping, 8> mappings {};
|
||||||
|
mappings[0] = format.export_mapping;
|
||||||
|
ShaderPixelInputInfo compiled_info {};
|
||||||
|
std::span<const uint32_t> compiled_spirv;
|
||||||
|
Check(ShaderCompileInfoPS(®s, &sh, ShaderLaneMaskMode::NativeWave, &vs_info, mappings,
|
||||||
|
&compiled_info, &compiled_spirv) &&
|
||||||
|
compiled_info.target_export_mapping[0].IsIdentity(),
|
||||||
|
"inactive reverse MRT mapping was not normalized out of the shader cache key");
|
||||||
|
sh.target_output_mode[0] = 4;
|
||||||
|
Check(ShaderCompileInfoPS(®s, &sh, ShaderLaneMaskMode::NativeWave, &vs_info, mappings,
|
||||||
|
&compiled_info, &compiled_spirv) &&
|
||||||
|
compiled_info.target_export_mapping[0] == format.export_mapping,
|
||||||
|
"active reverse MRT mapping was lost before shader specialization");
|
||||||
|
}
|
||||||
|
|
||||||
void TestNewShaderRecompilerEarlyZDisabledWhenPixelKillEnabled() {
|
void TestNewShaderRecompilerEarlyZDisabledWhenPixelKillEnabled() {
|
||||||
constexpr uint32_t ExecutionModeEarlyFragmentTests = 9;
|
constexpr uint32_t ExecutionModeEarlyFragmentTests = 9;
|
||||||
|
|
||||||
@@ -6510,10 +6605,11 @@ void TestPixelProgramCacheDescriptorSetIdentity() {
|
|||||||
}
|
}
|
||||||
ShaderVertexInputInfo vs_info {};
|
ShaderVertexInputInfo vs_info {};
|
||||||
vs_info.stage.program = std::move(vs_program);
|
vs_info.stage.program = std::move(vs_program);
|
||||||
|
const std::array<Prospero::ColorComponentMapping, 8> identity_mappings {};
|
||||||
ShaderPixelInputInfo ps_info {};
|
ShaderPixelInputInfo ps_info {};
|
||||||
std::span<const uint32_t> spirv;
|
std::span<const uint32_t> spirv;
|
||||||
Check(ShaderCompileInfoPS(®s, &sh, ShaderLaneMaskMode::NativeWave, &vs_info,
|
Check(ShaderCompileInfoPS(®s, &sh, ShaderLaneMaskMode::NativeWave, &vs_info,
|
||||||
&ps_info, &spirv),
|
identity_mappings, &ps_info, &spirv),
|
||||||
"pixel program-cache transition failed to compile");
|
"pixel program-cache transition failed to compile");
|
||||||
const auto expected_set = has_vs_descriptors ? 1u : 0u;
|
const auto expected_set = has_vs_descriptors ? 1u : 0u;
|
||||||
Check(ps_info.descriptor_set == expected_set && ps_info.stage.program != nullptr &&
|
Check(ps_info.descriptor_set == expected_set && ps_info.stage.program != nullptr &&
|
||||||
@@ -6537,9 +6633,11 @@ void TestPixelProgramCacheDescriptorSetIdentity() {
|
|||||||
auto compile_mask_mode = [&](ShaderLaneMaskMode mode) {
|
auto compile_mask_mode = [&](ShaderLaneMaskMode mode) {
|
||||||
ShaderVertexInputInfo vs_info {};
|
ShaderVertexInputInfo vs_info {};
|
||||||
vs_info.stage.program = std::make_shared<ShaderRecompiler::IR::Program>();
|
vs_info.stage.program = std::make_shared<ShaderRecompiler::IR::Program>();
|
||||||
|
const std::array<Prospero::ColorComponentMapping, 8> identity_mappings {};
|
||||||
ShaderPixelInputInfo ps_info {};
|
ShaderPixelInputInfo ps_info {};
|
||||||
std::span<const uint32_t> spirv;
|
std::span<const uint32_t> spirv;
|
||||||
Check(ShaderCompileInfoPS(&mask_regs, &sh, mode, &vs_info, &ps_info, &spirv),
|
Check(ShaderCompileInfoPS(&mask_regs, &sh, mode, &vs_info, identity_mappings, &ps_info,
|
||||||
|
&spirv),
|
||||||
"pixel lane-mask cache transition failed to compile");
|
"pixel lane-mask cache transition failed to compile");
|
||||||
Check(ps_info.stage.program != nullptr && ps_info.stage.program->lane_mask_mode == mode,
|
Check(ps_info.stage.program != nullptr && ps_info.stage.program->lane_mask_mode == mode,
|
||||||
"pixel program cache reused a different lane-mask lowering");
|
"pixel program cache reused a different lane-mask lowering");
|
||||||
@@ -6715,6 +6813,7 @@ int main() {
|
|||||||
TestNewShaderRecompilerVertexExportUsesLaneExecMask();
|
TestNewShaderRecompilerVertexExportUsesLaneExecMask();
|
||||||
TestNewShaderRecompilerPerInvocationMasks();
|
TestNewShaderRecompilerPerInvocationMasks();
|
||||||
TestNewShaderRecompilerExpPixelOutputs();
|
TestNewShaderRecompilerExpPixelOutputs();
|
||||||
|
TestRenderTargetReverseFloat16ExportMapping();
|
||||||
TestNewShaderRecompilerEarlyZDisabledWhenPixelKillEnabled();
|
TestNewShaderRecompilerEarlyZDisabledWhenPixelKillEnabled();
|
||||||
TestScalarProvenanceRealWideMoveLowering();
|
TestScalarProvenanceRealWideMoveLowering();
|
||||||
TestScalarProvenanceRealCarryAndScalarLoads();
|
TestScalarProvenanceRealCarryAndScalarLoads();
|
||||||
|
|||||||
Reference in new issue
Block a user