Fix native EFB readback blits on BGRA surfaces and their Y clamp

The shared blit shader clamps the sampled Y to flags.z..w, but the
native readback uniform set flags.w to 0, so every row sampled row 0.
The blit pipeline was also built only for the surface format, while the
readback draws into an RGBA8 texture; on a BGRA surface (the usual
Linux/Vulkan choice) the pipeline and attachment formats disagree, which
release builds no longer catch because Dawn validation is skipped.

Build blit pipelines for RGBA8, BGRA8 and the surface format, and pick
one by destination format. The Quest 1 simple blit path is unchanged.

From upstream patchzyy/Wiicompiled 6f14bde (#244, KartPad batch).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wg7mB8ogCWmp9GH19Uc82B
This commit is contained in:
Claude committed 2026-10-05 13:31:08 +00:00
1 parent 4407013d61
commit a23fd087ee
2 files changed
+21 -6

No files matched your search

+2 -1
View File
@@ -109,8 +109,9 @@ void ensure_native_texture(PendingCopy& pending, TextureHandle* cache = nullptr)
*cache = pending.nativeTexture;
}
}
// The shared blit shader clamps Y to flags.z/w; preserve the full source.
const std::array nativeBlitUniform{
0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 64.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 64.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
};
pending.nativeBlitUniform = push_uniform(nativeBlitUniform);
}
+19 -5
View File
@@ -422,7 +422,7 @@ static wgpu::BindGroupLayout g_depthBindGroupLayout;
static wgpu::Sampler g_nearestSampler;
static wgpu::Sampler g_linearSampler;
static absl::flat_hash_map<GXTexFmt, wgpu::RenderPipeline> g_pipelines;
static wgpu::RenderPipeline g_blitPipeline;
static absl::flat_hash_map<wgpu::TextureFormat, wgpu::RenderPipeline> g_blitPipelines;
static wgpu::RenderPipeline g_quest1BlitPipeline;
static bool quest1_simple_blit() noexcept {
@@ -549,9 +549,15 @@ void initialize() {
};
g_depthBindGroupLayout = g_device.CreateBindGroupLayout(&depthBindGroupLayoutDescriptor);
g_blitPipeline = create_pipeline(
{GX_TF_RGBA8, FragPassthrough, webgpu::g_graphicsConfig.surfaceConfiguration.format, "TexCopyConv Blit"},
// Native RAM readback uses RGBA even when the EFB/surface uses BGRA.
// Build both variants here; frame workers only read the completed map.
for (const auto format : {wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureFormat::BGRA8Unorm,
webgpu::g_graphicsConfig.surfaceConfiguration.format}) {
if (format != wgpu::TextureFormat::Undefined && !g_blitPipelines.contains(format)) {
g_blitPipelines[format] = create_pipeline({GX_TF_RGBA8, FragPassthrough, format, "TexCopyConv Blit"},
ShaderPreamble, g_bindGroupLayout);
}
}
g_quest1BlitPipeline = create_pipeline(
{GX_TF_RGBA8, {}, webgpu::g_graphicsConfig.surfaceConfiguration.format, "Quest 1 Simple TexCopy Blit"},
SimpleBlitShader, g_bindGroupLayout);
@@ -585,7 +591,7 @@ void initialize() {
void shutdown() {
g_pipelines.clear();
g_blitPipeline = {};
g_blitPipelines.clear();
g_quest1BlitPipeline = {};
g_bindGroupLayout = {};
g_depthBindGroupLayout = {};
@@ -678,7 +684,15 @@ void run(const wgpu::CommandEncoder& cmd, const ConvRequest& req) {
}
void blit(const wgpu::CommandEncoder& cmd, const ConvRequest& req) {
execute(cmd, req, quest1_simple_blit() ? g_quest1BlitPipeline : g_blitPipeline);
if (quest1_simple_blit()) {
execute(cmd, req, g_quest1BlitPipeline);
return;
}
const auto it = g_blitPipelines.find(req.dst->format);
if (it == g_blitPipelines.end()) {
Log.fatal("Unsupported blit destination format {}", static_cast<int>(req.dst->format));
}
execute(cmd, req, it->second);
}
} // namespace aurora::gfx::tex_copy_conv