[video_core/vic] Partial revert to fix Link Awakening's blue tint (#3348)

fixes link awakening intro screen on non-SSE 4.1

Signed-off-by: lizzie lizzie@eden-emu.dev
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3348
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2026-01-19 23:58:14 +01:00 committed by crueter
parent 872e03c9a6
commit 8663913510
No known key found for this signature in database
GPG Key ID: 425ACD2D4830EBC6
6 changed files with 51 additions and 44 deletions

View File

@ -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 yuzu/Citra Emulator Project // SPDX-FileCopyrightText: Copyright yuzu/Citra Emulator Project

View File

@ -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: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project

View File

@ -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 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
@ -485,8 +485,8 @@ void Vic::Blend(const ConfigStruct& config, const SlotStruct& slot, VideoPixelFo
source_bottom = (std::min)(source_bottom, out_surface_height); source_bottom = (std::min)(source_bottom, out_surface_height);
source_right = (std::min)(source_right, out_surface_width); source_right = (std::min)(source_right, out_surface_width);
auto const work_width = u32((std::max)(0, s32(source_right) - s32(source_left))); [[maybe_unused]] auto const work_width = u32((std::max)(0, s32(source_right) - s32(source_left)));
auto const work_height = u32((std::max)(0, s32(source_bottom) - s32(source_top))); [[maybe_unused]] auto const work_height = u32((std::max)(0, s32(source_bottom) - s32(source_top)));
// TODO Alpha blending. No games I've seen use more than a single surface or supply an alpha // TODO Alpha blending. No games I've seen use more than a single surface or supply an alpha
// below max, so it's ignored for now. // below max, so it's ignored for now.
@ -630,42 +630,49 @@ void Vic::Blend(const ConfigStruct& config, const SlotStruct& slot, VideoPixelFo
// | r1c0 r1c1 r1c2 r1c3 | * | G | = | G | // | r1c0 r1c1 r1c2 r1c3 | * | G | = | G |
// | r2c0 r2c1 r2c2 r2c3 | | B | | B | // | r2c0 r2c1 r2c2 r2c3 | | B | | B |
// | 1 | // | 1 |
auto const shift = s32(slot.color_matrix.matrix_r_shift.Value()); const auto r0c0 = s32(slot.color_matrix.matrix_coeff00.Value());
const auto r0c1 = s32(slot.color_matrix.matrix_coeff01.Value());
struct AliasedMatrixType { u64 m[4]; }; const auto r0c2 = s32(slot.color_matrix.matrix_coeff02.Value());
static_assert(sizeof(AliasedMatrixType) == sizeof(slot.color_matrix)); const auto r0c3 = s32(slot.color_matrix.matrix_coeff03.Value());
u64 const mat_mask = (1 << 20) - 1; const auto r1c0 = s32(slot.color_matrix.matrix_coeff10.Value());
auto const* amt = reinterpret_cast<AliasedMatrixType const*>(&slot.color_matrix); const auto r1c1 = s32(slot.color_matrix.matrix_coeff11.Value());
const auto r1c2 = s32(slot.color_matrix.matrix_coeff12.Value());
constexpr s32 shifts[4] = { 0, 20, 40, 60 }; const auto r1c3 = s32(slot.color_matrix.matrix_coeff13.Value());
s32 mr[4][4]; const auto r2c0 = s32(slot.color_matrix.matrix_coeff20.Value());
for (u32 j = 0; j < 3; ++j) const auto r2c1 = s32(slot.color_matrix.matrix_coeff21.Value());
for (u32 i = 0; i < 4; ++i) const auto r2c2 = s32(slot.color_matrix.matrix_coeff22.Value());
mr[j][i] = s32(s64(((amt->m[i] >> shifts[j]) & mat_mask) << (64 - 20)) >> (64 - 20)); const auto r2c3 = s32(slot.color_matrix.matrix_coeff23.Value());
const auto shift = s32(slot.color_matrix.matrix_r_shift.Value());
auto const clamp_min = s32(slot.config.soft_clamp_low.Value()); const auto clamp_min = s32(slot.config.soft_clamp_low.Value());
auto const clamp_max = s32(slot.config.soft_clamp_high.Value()); const auto clamp_max = s32(slot.config.soft_clamp_high.Value());
for (u32 y = 0; y < work_height; ++y) { auto MatMul = [&](const Pixel& in_pixel) -> std::tuple<s32, s32, s32, s32> {
auto const src = (y + source_top) * in_surface_width + source_left; auto r = s32(in_pixel.r);
auto const dst = (y + source_top) * out_surface_width + rect_left; auto g = s32(in_pixel.g);
for (u32 x = 0; x < work_width; ++x) { auto b = s32(in_pixel.b);
auto const& in_pixel = slot_surface[src + x]; r = in_pixel.r * r0c0 + in_pixel.g * r0c1 + in_pixel.b * r0c2;
auto& out_pixel = output_surface[dst + x]; g = in_pixel.r * r1c0 + in_pixel.g * r1c1 + in_pixel.b * r1c2;
s32 const mul_values[4] = { b = in_pixel.r * r2c0 + in_pixel.g * r2c1 + in_pixel.b * r2c2;
in_pixel.r * mr[0][0] + in_pixel.g * mr[1][1] + in_pixel.b * mr[0][2], r >>= shift;
in_pixel.r * mr[1][0] + in_pixel.g * mr[1][1] + in_pixel.b * mr[1][2], g >>= shift;
in_pixel.r * mr[2][0] + in_pixel.g * mr[2][1] + in_pixel.b * mr[2][2], b >>= shift;
s32(in_pixel.a) r += r0c3;
g += r1c3;
b += r2c3;
r >>= 8;
g >>= 8;
b >>= 8;
return {r, g, b, s32(in_pixel.a)};
}; };
s32 const mul_clamp[4] = { for (u32 y = source_top; y < source_bottom; y++) {
std::clamp(((mul_values[0] >> shift) + mr[0][3]) >> 8, clamp_min, clamp_max), const auto src{y * in_surface_width + source_left};
std::clamp(((mul_values[1] >> shift) + mr[1][3]) >> 8, clamp_min, clamp_max), const auto dst{y * out_surface_width + rect_left};
std::clamp(((mul_values[2] >> shift) + mr[2][3]) >> 8, clamp_min, clamp_max), for (u32 x = source_left; x < source_right; x++) {
std::clamp(mul_values[3], clamp_min, clamp_max) auto [r, g, b, a] = MatMul(slot_surface[src + x]);
}; r = std::clamp(r, clamp_min, clamp_max);
out_pixel = format == VideoPixelFormat::A8R8G8B8 g = std::clamp(g, clamp_min, clamp_max);
? Pixel(u16(mul_clamp[2]), u16(mul_clamp[1]), u16(mul_clamp[0]), u16(mul_clamp[3])) b = std::clamp(b, clamp_min, clamp_max);
: Pixel(u16(mul_clamp[0]), u16(mul_clamp[1]), u16(mul_clamp[2]), u16(mul_clamp[3])); a = std::clamp(a, clamp_min, clamp_max);
output_surface[dst + x] = {u16(r), u16(g), u16(b), u16(a)};
} }
} }
} }

View File

@ -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: 2023 yuzu Emulator Project // SPDX-FileCopyrightText: 2023 yuzu Emulator Project

View File

@ -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
// Qt on macOS doesn't define VMA shit // Qt on macOS doesn't define VMA shit

View File

@ -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: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project