mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-05-14 04:17:03 +02:00
[VK, MacOS] Fix strict output type mismatch on Metal (MK8D/TOTK fix) (#3414)
Metal validation requires fragment shader output types to strictly match the render target format (e.g., writing float to RGBA32Uint is invalid). This commit: 1. Adds color_output_types to RuntimeInfo. 2. Detects Integer/SignedInteger render targets in the Vulkan backend (MoltenVK only). 3. Updates the SPIR-V emitter to declare the correct output type (Uint/Sint) and bitcast values accordingly. This fixes the VK_ERROR_INITIALIZATION_FAILED crash on macOS. Co-authored-by: crueter <crueter@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3414 Co-authored-by: rayman30 <silentbitdev@gmail.com> Co-committed-by: rayman30 <silentbitdev@gmail.com>
This commit is contained in:
parent
025bc799f7
commit
643f11d972
4 changed files with 42 additions and 4 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
|
@ -492,8 +492,22 @@ void EmitSetPatch(EmitContext& ctx, IR::Patch patch, Id value) {
|
||||||
|
|
||||||
void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) {
|
void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) {
|
||||||
const Id component_id{ctx.Const(component)};
|
const Id component_id{ctx.Const(component)};
|
||||||
const Id pointer{ctx.OpAccessChain(ctx.output_f32, ctx.frag_color.at(index), component_id)};
|
const AttributeType type{ctx.runtime_info.color_output_types[index]};
|
||||||
ctx.OpStore(pointer, value);
|
if (type == AttributeType::Float) {
|
||||||
|
const Id pointer{ctx.OpAccessChain(ctx.output_f32, ctx.frag_color.at(index), component_id)};
|
||||||
|
ctx.OpStore(pointer, value);
|
||||||
|
} else if (type == AttributeType::UnsignedInt) {
|
||||||
|
const Id pointer{ctx.OpAccessChain(ctx.output_u32, ctx.frag_color.at(index), component_id)};
|
||||||
|
ctx.OpStore(pointer, ctx.OpBitcast(ctx.U32[1], value));
|
||||||
|
} else if (type == AttributeType::SignedInt) {
|
||||||
|
const Id output_s32{ctx.TypePointer(spv::StorageClass::Output, ctx.S32[1])};
|
||||||
|
const Id pointer{ctx.OpAccessChain(output_s32, ctx.frag_color.at(index), component_id)};
|
||||||
|
ctx.OpStore(pointer, ctx.OpBitcast(ctx.S32[1], value));
|
||||||
|
} else {
|
||||||
|
// Disabled or unknown, treat as float
|
||||||
|
const Id pointer{ctx.OpAccessChain(ctx.output_f32, ctx.frag_color.at(index), component_id)};
|
||||||
|
ctx.OpStore(pointer, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetSampleMask(EmitContext& ctx, Id value) {
|
void EmitSetSampleMask(EmitContext& ctx, Id value) {
|
||||||
|
|
|
||||||
|
|
@ -1677,7 +1677,8 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
|
||||||
if (!info.stores_frag_color[index] && !profile.need_declared_frag_colors) {
|
if (!info.stores_frag_color[index] && !profile.need_declared_frag_colors) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
frag_color[index] = DefineOutput(*this, F32[4], std::nullopt);
|
const Id type{GetAttributeType(*this, runtime_info.color_output_types[index])};
|
||||||
|
frag_color[index] = DefineOutput(*this, type, std::nullopt);
|
||||||
Decorate(frag_color[index], spv::Decoration::Location, index);
|
Decorate(frag_color[index], spv::Decoration::Location, index);
|
||||||
Name(frag_color[index], fmt::format("frag_color{}", index));
|
Name(frag_color[index], fmt::format("frag_color{}", index));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
@ -104,6 +107,9 @@ struct RuntimeInfo {
|
||||||
/// Transform feedback state for each varying
|
/// Transform feedback state for each varying
|
||||||
std::array<TransformFeedbackVarying, 256> xfb_varyings{};
|
std::array<TransformFeedbackVarying, 256> xfb_varyings{};
|
||||||
u32 xfb_count{0};
|
u32 xfb_count{0};
|
||||||
|
|
||||||
|
/// Output types for each color attachment
|
||||||
|
std::array<AttributeType, 8> color_output_types{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Shader
|
} // namespace Shader
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#include "video_core/shader_cache.h"
|
#include "video_core/shader_cache.h"
|
||||||
#include "video_core/shader_environment.h"
|
#include "video_core/shader_environment.h"
|
||||||
#include "video_core/shader_notify.h"
|
#include "video_core/shader_notify.h"
|
||||||
|
#include "video_core/surface.h"
|
||||||
#include "video_core/vulkan_common/vulkan_device.h"
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
|
@ -238,6 +239,22 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
|
||||||
info.alpha_test_func = MaxwellToCompareFunction(
|
info.alpha_test_func = MaxwellToCompareFunction(
|
||||||
key.state.UnpackComparisonOp(key.state.alpha_test_func.Value()));
|
key.state.UnpackComparisonOp(key.state.alpha_test_func.Value()));
|
||||||
info.alpha_test_reference = std::bit_cast<float>(key.state.alpha_test_ref);
|
info.alpha_test_reference = std::bit_cast<float>(key.state.alpha_test_ref);
|
||||||
|
|
||||||
|
if (device.IsMoltenVK()) {
|
||||||
|
for (size_t i = 0; i < 8; ++i) {
|
||||||
|
const auto format = static_cast<Tegra::RenderTargetFormat>(key.state.color_formats[i]);
|
||||||
|
const auto pixel_format = VideoCore::Surface::PixelFormatFromRenderTargetFormat(format);
|
||||||
|
if (VideoCore::Surface::IsPixelFormatInteger(pixel_format)) {
|
||||||
|
if (VideoCore::Surface::IsPixelFormatSignedInteger(pixel_format)) {
|
||||||
|
info.color_output_types[i] = Shader::AttributeType::SignedInt;
|
||||||
|
} else {
|
||||||
|
info.color_output_types[i] = Shader::AttributeType::UnsignedInt;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info.color_output_types[i] = Shader::AttributeType::Float;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue