[video_core] Implement alpha copy

Co-authored-by: Eden Contributors <eden@eden-emu.dev>
Signed-off-by: Aleksandr Popovich <popovich@eden-emu.dev>
This commit is contained in:
Aleksandr Popovich 2025-07-13 19:33:58 -04:00 committed by crueter
parent be59b4f15f
commit 311a98c4fb
9 changed files with 118 additions and 5 deletions

View file

@ -21,6 +21,8 @@ set(SHADER_FILES
convert_abgr8_srgb_to_d24s8.frag convert_abgr8_srgb_to_d24s8.frag
convert_abgr8_to_d24s8.frag convert_abgr8_to_d24s8.frag
convert_abgr8_to_d32f.frag convert_abgr8_to_d32f.frag
convert_r8_to_abgr8.frag
convert_abgr8_to_r8.frag
convert_d32f_to_abgr8.frag convert_d32f_to_abgr8.frag
convert_d24s8_to_abgr8.frag convert_d24s8_to_abgr8.frag
convert_depth_to_float.frag convert_depth_to_float.frag

View file

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 450
layout(binding = 0) uniform sampler2D tex;
layout(location = 0) out float color;
void main() {
vec2 coord = gl_FragCoord.xy / vec2(textureSize(tex, 0));
float red = texture(tex, coord).r;
color = red;
}

View file

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 450
layout(binding = 0) uniform sampler2D tex;
layout(location = 0) out vec4 color;
void main() {
vec2 coord = gl_FragCoord.xy / vec2(textureSize(tex, 0));
float red = texture(tex, coord).r;
color = vec4(red, red, red, 1.0);
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -11,6 +14,7 @@
#include "video_core/host_shaders/convert_abgr8_to_d32f_frag_spv.h" #include "video_core/host_shaders/convert_abgr8_to_d32f_frag_spv.h"
#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
#include "video_core/host_shaders/convert_d32f_to_abgr8_frag_spv.h" #include "video_core/host_shaders/convert_d32f_to_abgr8_frag_spv.h"
#include "video_core/host_shaders/convert_r8_to_abgr8_frag_spv.h"
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" #include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h" #include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
@ -29,6 +33,7 @@
#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"
#include "video_core/host_shaders/convert_abgr8_srgb_to_d24s8_frag_spv.h" #include "video_core/host_shaders/convert_abgr8_srgb_to_d24s8_frag_spv.h"
#include "video_core/host_shaders/convert_abgr8_to_r8_frag_spv.h"
#include "video_core/host_shaders/convert_rgba8_to_bgra8_frag_spv.h" #include "video_core/host_shaders/convert_rgba8_to_bgra8_frag_spv.h"
#include "video_core/host_shaders/convert_yuv420_to_rgb_comp_spv.h" #include "video_core/host_shaders/convert_yuv420_to_rgb_comp_spv.h"
#include "video_core/host_shaders/convert_rgb_to_yuv420_comp_spv.h" #include "video_core/host_shaders/convert_rgb_to_yuv420_comp_spv.h"
@ -461,6 +466,8 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
convert_abgr8_to_d32f_frag(BuildShader(device, CONVERT_ABGR8_TO_D32F_FRAG_SPV)), convert_abgr8_to_d32f_frag(BuildShader(device, CONVERT_ABGR8_TO_D32F_FRAG_SPV)),
convert_abgr8_to_r8_frag(BuildShader(device, CONVERT_ABGR8_TO_R8_FRAG_SPV)),
convert_r8_to_abgr8_frag(BuildShader(device, CONVERT_R8_TO_ABGR8_FRAG_SPV)),
convert_d32f_to_abgr8_frag(BuildShader(device, CONVERT_D32F_TO_ABGR8_FRAG_SPV)), convert_d32f_to_abgr8_frag(BuildShader(device, CONVERT_D32F_TO_ABGR8_FRAG_SPV)),
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)), convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
@ -588,6 +595,20 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view); Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
} }
void BlitImageHelper::ConvertR8ToABGR8(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) {
ConvertPipelineColorTargetEx(convert_r8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
convert_r8_to_abgr8_frag);
Convert(*convert_r8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertABGR8ToR8(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) {
ConvertPipelineColorTargetEx(convert_abgr8_to_r8_pipeline, dst_framebuffer->RenderPass(),
convert_abgr8_to_r8_frag);
Convert(*convert_abgr8_to_r8_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) { const ImageView& src_image_view) {
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(), ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -65,6 +68,10 @@ public:
void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
void ConvertR8ToABGR8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
void ConvertABGR8ToR8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
void ConvertABGR8SRGBToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); void ConvertABGR8SRGBToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
@ -144,6 +151,8 @@ private:
vk::ShaderModule convert_float_to_depth_frag; vk::ShaderModule convert_float_to_depth_frag;
vk::ShaderModule convert_abgr8_to_d24s8_frag; vk::ShaderModule convert_abgr8_to_d24s8_frag;
vk::ShaderModule convert_abgr8_to_d32f_frag; vk::ShaderModule convert_abgr8_to_d32f_frag;
vk::ShaderModule convert_abgr8_to_r8_frag;
vk::ShaderModule convert_r8_to_abgr8_frag;
vk::ShaderModule convert_d32f_to_abgr8_frag; vk::ShaderModule convert_d32f_to_abgr8_frag;
vk::ShaderModule convert_d24s8_to_abgr8_frag; vk::ShaderModule convert_d24s8_to_abgr8_frag;
vk::ShaderModule convert_s8d24_to_abgr8_frag; vk::ShaderModule convert_s8d24_to_abgr8_frag;
@ -176,6 +185,8 @@ private:
vk::Pipeline convert_d32f_to_abgr8_pipeline; vk::Pipeline convert_d32f_to_abgr8_pipeline;
vk::Pipeline convert_d24s8_to_abgr8_pipeline; vk::Pipeline convert_d24s8_to_abgr8_pipeline;
vk::Pipeline convert_s8d24_to_abgr8_pipeline; vk::Pipeline convert_s8d24_to_abgr8_pipeline;
vk::Pipeline convert_r8_to_abgr8_pipeline;
vk::Pipeline convert_abgr8_to_r8_pipeline;
vk::Pipeline convert_abgr8_srgb_to_d24s8_pipeline; vk::Pipeline convert_abgr8_srgb_to_d24s8_pipeline;
vk::Pipeline convert_rgba_to_bgra_pipeline; vk::Pipeline convert_rgba_to_bgra_pipeline;
vk::Pipeline convert_yuv420_to_rgb_pipeline; vk::Pipeline convert_yuv420_to_rgb_pipeline;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@ -1219,8 +1222,16 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view); return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view);
} }
break; break;
case PixelFormat::R8_UNORM:
if (src_view.format == PixelFormat::A8B8G8R8_UNORM) {
return blit_image_helper.ConvertABGR8ToR8(dst, src_view);
}
break;
case PixelFormat::A8B8G8R8_UNORM: case PixelFormat::A8B8G8R8_UNORM:
if (src_view.format == PixelFormat::R8_UNORM) {
return blit_image_helper.ConvertR8ToABGR8(dst, src_view);
}
break;
case PixelFormat::A8B8G8R8_SNORM: case PixelFormat::A8B8G8R8_SNORM:
case PixelFormat::A8B8G8R8_SINT: case PixelFormat::A8B8G8R8_SINT:
case PixelFormat::A8B8G8R8_UINT: case PixelFormat::A8B8G8R8_UINT:
@ -1232,7 +1243,6 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
case PixelFormat::A2R10G10B10_UNORM: case PixelFormat::A2R10G10B10_UNORM:
case PixelFormat::A1B5G5R5_UNORM: case PixelFormat::A1B5G5R5_UNORM:
case PixelFormat::A5B5G5R1_UNORM: case PixelFormat::A5B5G5R1_UNORM:
case PixelFormat::R8_UNORM:
case PixelFormat::R8_SNORM: case PixelFormat::R8_SNORM:
case PixelFormat::R8_SINT: case PixelFormat::R8_SINT:
case PixelFormat::R8_UINT: case PixelFormat::R8_UINT:
@ -1325,6 +1335,7 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
default: default:
break; break;
} }
LOG_WARNING(Render_Vulkan, "Unimplemented texture conversion from {} to {} format type", src_view.format, dst_view.format);
} }
VkFormat TextureCacheRuntime::GetSupportedFormat(VkFormat requested_format, VkFormat TextureCacheRuntime::GetSupportedFormat(VkFormat requested_format,

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -237,6 +240,37 @@ SurfaceType GetFormatType(PixelFormat pixel_format) {
return SurfaceType::Invalid; return SurfaceType::Invalid;
} }
bool HasAlpha(PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::A8B8G8R8_UNORM:
case PixelFormat::A8B8G8R8_SNORM:
case PixelFormat::A8B8G8R8_SINT:
case PixelFormat::A8B8G8R8_UINT:
case PixelFormat::A1R5G5B5_UNORM:
case PixelFormat::A2B10G10R10_UNORM:
case PixelFormat::A2B10G10R10_UINT:
case PixelFormat::A2R10G10B10_UNORM:
case PixelFormat::A1B5G5R5_UNORM:
case PixelFormat::A5B5G5R1_UNORM:
case PixelFormat::R16G16B16A16_FLOAT:
case PixelFormat::R16G16B16A16_UNORM:
case PixelFormat::R16G16B16A16_SNORM:
case PixelFormat::R16G16B16A16_SINT:
case PixelFormat::R16G16B16A16_UINT:
case PixelFormat::R32G32B32A32_UINT:
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::B8G8R8A8_UNORM:
case PixelFormat::R32G32B32A32_FLOAT:
case PixelFormat::R32G32B32A32_SINT:
case PixelFormat::A8B8G8R8_SRGB:
case PixelFormat::BC1_RGBA_SRGB:
case PixelFormat::A4B4G4R4_UNORM:
return true;
default:
return false;
}
}
bool IsPixelFormatASTC(PixelFormat format) { bool IsPixelFormatASTC(PixelFormat format) {
switch (format) { switch (format) {
case PixelFormat::ASTC_2D_4X4_UNORM: case PixelFormat::ASTC_2D_4X4_UNORM:

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -503,6 +506,8 @@ PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format);
SurfaceType GetFormatType(PixelFormat pixel_format); SurfaceType GetFormatType(PixelFormat pixel_format);
bool HasAlpha(PixelFormat pixel_format);
bool IsPixelFormatASTC(PixelFormat format); bool IsPixelFormatASTC(PixelFormat format);
bool IsPixelFormatBCn(PixelFormat format); bool IsPixelFormatBCn(PixelFormat format);

View file

@ -26,6 +26,7 @@ namespace VideoCommon {
using Tegra::Texture::TICEntry; using Tegra::Texture::TICEntry;
using Tegra::Texture::TSCEntry; using Tegra::Texture::TSCEntry;
using VideoCore::Surface::GetFormatType; using VideoCore::Surface::GetFormatType;
using VideoCore::Surface::HasAlpha;
using VideoCore::Surface::PixelFormat; using VideoCore::Surface::PixelFormat;
using VideoCore::Surface::SurfaceType; using VideoCore::Surface::SurfaceType;
using namespace Common::Literals; using namespace Common::Literals;
@ -2398,7 +2399,7 @@ void TextureCache<P>::CopyImage(ImageId dst_id, ImageId src_id, std::vector<Imag
} }
const auto dst_format_type = GetFormatType(dst.info.format); const auto dst_format_type = GetFormatType(dst.info.format);
const auto src_format_type = GetFormatType(src.info.format); const auto src_format_type = GetFormatType(src.info.format);
if (src_format_type == dst_format_type) { if (src_format_type == dst_format_type && HasAlpha(src.info.format) == HasAlpha(dst.info.format)) {
if constexpr (HAS_EMULATED_COPIES) { if constexpr (HAS_EMULATED_COPIES) {
if (!runtime.CanImageBeCopied(dst, src)) { if (!runtime.CanImageBeCopied(dst, src)) {
return runtime.EmulateCopyImage(dst, src, copies); return runtime.EmulateCopyImage(dst, src, copies);
@ -2406,8 +2407,8 @@ void TextureCache<P>::CopyImage(ImageId dst_id, ImageId src_id, std::vector<Imag
} }
return runtime.CopyImage(dst, src, copies); return runtime.CopyImage(dst, src, copies);
} }
UNIMPLEMENTED_IF(dst.info.type != ImageType::e2D); UNIMPLEMENTED_IF(dst.info.type != ImageType::e2D && dst.info.type != ImageType::Linear);
UNIMPLEMENTED_IF(src.info.type != ImageType::e2D); UNIMPLEMENTED_IF(src.info.type != ImageType::e2D && dst.info.type != ImageType::Linear);
if (runtime.ShouldReinterpret(dst, src)) { if (runtime.ShouldReinterpret(dst, src)) {
return runtime.ReinterpretImage(dst, src, copies); return runtime.ReinterpretImage(dst, src, copies);
} }