Remove astc recompression method

This commit is contained in:
CamilleLaVey
2026-09-17 03:31:53 -04:00
parent 052a04e610
commit 86f826c313
16 changed files with 45 additions and 242 deletions
-1
View File
@@ -48,7 +48,6 @@ SWITCHABLE(AnisotropyMode, true);
SWITCHABLE(AntiAliasing, false);
SWITCHABLE(AspectRatio, true);
SWITCHABLE(AstcDecodeMode, true);
SWITCHABLE(AstcRecompression, true);
SWITCHABLE(AudioMode, true);
SWITCHABLE(CpuBackend, true);
SWITCHABLE(CpuAccuracy, true);
-7
View File
@@ -65,7 +65,6 @@ SWITCHABLE(AnisotropyMode, true);
SWITCHABLE(AntiAliasing, false);
SWITCHABLE(AspectRatio, true);
SWITCHABLE(AstcDecodeMode, true);
SWITCHABLE(AstcRecompression, true);
SWITCHABLE(AudioMode, true);
SWITCHABLE(CpuBackend, true);
SWITCHABLE(CpuAccuracy, true);
@@ -563,12 +562,6 @@ struct Values {
true,
true};
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
AstcRecompression::Uncompressed,
"astc_recompression",
Category::RendererAdvanced};
SwitchableSetting<bool> sync_memory_operations{linkage,
false,
"sync_memory_operations",
-1
View File
@@ -130,7 +130,6 @@ ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16);
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_90, Target_120);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(VramUsageMode, Conservative, Aggressive);
@@ -179,11 +179,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
"GPU: Use the GPU's compute shaders to decode ASTC textures (recommended).\n"
"CPU Asynchronously: Use the CPU to decode ASTC textures on demand. Eliminates"
"ASTC decoding\nstuttering but may present artifacts."));
INSERT(Settings, astc_recompression, tr("ASTC Recompression Method:"),
tr("Most GPUs lack support for ASTC textures and must decompress to an"
"intermediate format: RGBA8.\n"
"BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format,\n"
" saving VRAM but degrading image quality."));
INSERT(Settings, frame_pacing_mode, tr("Frame Pacing Mode (Vulkan only)"),
tr("Controls how the emulator manages frame pacing to reduce stuttering and make the "
"frame rate smoother and more consistent."));
@@ -379,13 +374,6 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent) {
PAIR(AstcDecodeMode, Gpu, tr("GPU")),
PAIR(AstcDecodeMode, CpuAsynchronous, tr("CPU Asynchronous")),
}});
translations->insert(
{Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
{
PAIR(AstcRecompression, Uncompressed, tr("Uncompressed (Best quality)")),
PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
}});
translations->insert({Settings::EnumMetadata<Settings::FramePacingMode>::Index(),
{
PAIR(FramePacingMode, Target_Auto, tr("Auto")),
-1
View File
@@ -262,6 +262,5 @@ Q_DECLARE_METATYPE(Settings::ResolutionSetup);
Q_DECLARE_METATYPE(Settings::ScalingFilter);
Q_DECLARE_METATYPE(Settings::AntiAliasing);
Q_DECLARE_METATYPE(Settings::RendererBackend);
Q_DECLARE_METATYPE(Settings::AstcRecompression);
Q_DECLARE_METATYPE(Settings::AstcDecodeMode);
Q_DECLARE_METATYPE(Settings::SpirvOptimizeMode);
+1 -3
View File
@@ -256,8 +256,6 @@ add_library(video_core STATIC
texture_cache/util.h
textures/astc.h
textures/astc.cpp
textures/bcn.cpp
textures/bcn.h
textures/decoders.cpp
textures/decoders.h
textures/texture.cpp
@@ -406,7 +404,7 @@ if (ENABLE_OPENGL)
endif()
target_link_libraries(video_core PUBLIC common core)
target_link_libraries(video_core PUBLIC shader_recompiler stb bc_decoder gpu_logging)
target_link_libraries(video_core PUBLIC shader_recompiler bc_decoder gpu_logging)
if (ENABLE_OPENGL)
target_link_libraries(video_core PUBLIC glad)
endif()
@@ -235,9 +235,7 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime,
const VideoCommon::ImageInfo& info) {
if (IsPixelFormatASTC(info.format) && info.size.depth == 1 && !runtime.HasNativeASTC()) {
return Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu &&
Settings::values.astc_recompression.GetValue() ==
Settings::AstcRecompression::Uncompressed;
return Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu;
}
// Disable other accelerated uploads for now as they don't implement swizzled uploads
return false;
@@ -442,23 +440,6 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
return GL_R32UI;
}
[[nodiscard]] bool IsAstcRecompressionEnabled() {
return Settings::values.astc_recompression.GetValue() !=
Settings::AstcRecompression::Uncompressed;
}
[[nodiscard]] GLenum SelectAstcFormat(PixelFormat format, bool is_srgb) {
switch (Settings::values.astc_recompression.GetValue()) {
case Settings::AstcRecompression::Bc1:
return is_srgb ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
break;
case Settings::AstcRecompression::Bc3:
return is_srgb ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
default:
return is_srgb ? GL_SRGB8_ALPHA8 : GL_RGBA8;
}
}
} // Anonymous namespace
TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& program_manager,
@@ -708,11 +689,6 @@ Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_,
gl_internal_format = is_srgb ? GL_SRGB8_ALPHA8 : GL_RGBA8;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
if (IsPixelFormatASTC(info.format) && IsAstcRecompressionEnabled()) {
gl_internal_format = SelectAstcFormat(info.format, is_srgb);
gl_format = GL_NONE;
}
} else {
const auto& tuple = MaxwellToGL::GetFormatTuple(info.format);
gl_internal_format = tuple.internal_format;
@@ -1109,10 +1085,6 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
if (True(image.flags & ImageFlagBits::Converted)) {
const bool is_srgb = IsPixelFormatSRGB(info.format);
internal_format = is_srgb ? GL_SRGB8_ALPHA8 : GL_RGBA8;
if (IsPixelFormatASTC(info.format) && IsAstcRecompressionEnabled()) {
internal_format = SelectAstcFormat(info.format, is_srgb);
}
} else {
internal_format = MaxwellToGL::GetFormatTuple(format).internal_format;
}
@@ -9,7 +9,6 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging.h"
#include "common/settings.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
#include "video_core/surface.h"
@@ -246,21 +245,11 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with
bool const is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format);
// Transcode on hardware that doesn't support ASTC natively
if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) {
switch (Settings::values.astc_recompression.GetValue()) {
case Settings::AstcRecompression::Uncompressed:
if (is_srgb) {
tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32;
} else {
tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
tuple.usage |= usage_storage;
}
break;
case Settings::AstcRecompression::Bc1:
tuple.format = is_srgb ? VK_FORMAT_BC1_RGBA_SRGB_BLOCK : VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
break;
case Settings::AstcRecompression::Bc3:
tuple.format = is_srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
break;
if (is_srgb) {
tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32;
} else {
tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
tuple.usage |= usage_storage;
}
}
if (!device.IsOptimalBcnSupported() && VideoCore::Surface::IsPixelFormatBCn(pixel_format)) {
@@ -155,9 +155,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
if (Settings::values.accelerate_astc.GetValue() != Settings::AstcDecodeMode::Gpu) {
return false;
}
return Settings::values.astc_recompression.GetValue() ==
Settings::AstcRecompression::Uncompressed &&
info.size.depth == 1;
return info.size.depth == 1;
}
[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info,
@@ -1880,8 +1878,9 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
case Settings::AstcDecodeMode::Gpu:
if (WillUseAcceleratedAstcDecode(runtime->device, info)) {
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
break;
}
break;
[[fallthrough]];
case Settings::AstcDecodeMode::CpuAsynchronous:
flags |= VideoCommon::ImageFlagBits::AsynchronousDecode;
break;
+1 -9
View File
@@ -6,7 +6,6 @@
#include "common/common_types.h"
#include "common/math_util.h"
#include "common/settings.h"
#include "video_core/surface.h"
namespace VideoCore::Surface {
@@ -469,14 +468,7 @@ u64 TranscodedAstcSize(u64 base_size, PixelFormat format) {
static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE;
const u64 uncompressed_size = (base_size * base_block_size) / BytesPerBlock(format);
switch (Settings::values.astc_recompression.GetValue()) {
case Settings::AstcRecompression::Bc1:
return uncompressed_size / 8;
case Settings::AstcRecompression::Bc3:
return uncompressed_size / 4;
default:
return uncompressed_size;
}
return uncompressed_size;
}
} // namespace VideoCore::Surface
@@ -95,6 +95,7 @@ struct ImageBase {
u32 scale_rating = 0;
u64 scale_tick = 0;
bool has_scaled = false;
u32 guest_data_checks = 0;
size_t channel = 0;
@@ -105,6 +106,7 @@ struct ImageBase {
VAddr cpu_addr_end = 0;
u64 modification_tick = 0;
u64 guest_data_hash = 0;
size_t lru_index = SIZE_MAX;
std::array<u32, MAX_MIP_LEVELS> mip_level_offsets{};
@@ -12,6 +12,7 @@
#include <boost/container/small_vector.hpp>
#include "common/alignment.h"
#include "common/cityhash.h"
#include "common/settings.h"
#include "common/slot_vector.h"
#include "video_core/control/channel_state.h"
@@ -1074,6 +1075,29 @@ void TextureCache<P>::DownloadImageIntoBuffer(typename TextureCache<P>::Image* i
}
}
template <class P>
bool TextureCache<P>::IsAstcDataUnchanged(Image& image) {
static constexpr u32 CHECK_THRESHOLD = 4;
if (False(image.flags & ImageFlagBits::Converted) ||
True(image.flags & ImageFlagBits::GpuModified) ||
!IsPixelFormatASTC(image.info.format)) {
return false;
}
if (image.guest_data_checks < CHECK_THRESHOLD) {
++image.guest_data_checks;
return false;
}
Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::UnsafeRead> guest_data(
*gpu_memory, image.gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(guest_data.data()),
image.guest_size_bytes);
if (image.guest_data_hash == hash) {
return true;
}
image.guest_data_hash = hash;
return false;
}
template <class P>
void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
if (False(image.flags & ImageFlagBits::CpuModified)) {
@@ -1085,6 +1109,10 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
TrackImage(image, image_id);
if (IsAstcDataUnchanged(image)) {
return;
}
if (image.info.num_samples > 1 && !runtime.CanUploadMSAA()) {
LOG_WARNING(HW_GPU, "MSAA image uploads are not implemented");
runtime.TransitionImageLayout(image);
@@ -298,6 +298,8 @@ private:
void RefreshContents(Image& image, ImageId image_id);
[[nodiscard]] bool IsAstcDataUnchanged(Image& image);
/// Upload data from guest to an image
template <typename StagingBuffer>
void UploadImageContents(Image& image, StagingBuffer& staging_buffer);
+2 -57
View File
@@ -22,7 +22,6 @@
#include "common/common_types.h"
#include "common/div_ceil.h"
#include "common/scratch_buffer.h"
#include "common/settings.h"
#include "video_core/compatible_formats.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/guest_memory.h"
@@ -34,7 +33,6 @@
#include "video_core/texture_cache/samples_helper.h"
#include "video_core/texture_cache/util.h"
#include "video_core/textures/astc.h"
#include "video_core/textures/bcn.h"
#include "video_core/textures/decoders.h"
namespace VideoCommon {
@@ -608,21 +606,6 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept {
return info.size.width * BytesPerBlock(info.format);
}
static constexpr Extent2D TILE_SIZE{1, 1};
if (IsPixelFormatASTC(info.format) && Settings::values.astc_recompression.GetValue() !=
Settings::AstcRecompression::Uncompressed) {
const u32 bpp_div =
Settings::values.astc_recompression.GetValue() == Settings::AstcRecompression::Bc1 ? 2
: 1;
// NumBlocksPerLayer doesn't account for this correctly, so we have to do it manually.
u32 output_size = 0;
for (s32 i = 0; i < info.resources.levels; i++) {
const auto mip_size = AdjustMipSize(info.size, i);
const u32 plane_dim =
Common::AlignUp(mip_size.width, 4U) * Common::AlignUp(mip_size.height, 4U);
output_size += (plane_dim * info.size.depth * info.resources.layers) / bpp_div;
}
return output_size;
}
return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers *
ConvertedBytesPerBlock(info.format);
}
@@ -925,7 +908,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output,
std::span<BufferImageCopy> copies) {
u32 output_offset = 0;
Common::ScratchBuffer<u8> decode_scratch;
const Extent2D tile_size = DefaultBlockSize(info.format);
for (BufferImageCopy& copy : copies) {
@@ -940,10 +922,7 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
const auto input_offset = input.subspan(copy.buffer_offset);
copy.buffer_offset = output_offset;
const auto recompression_setting = Settings::values.astc_recompression.GetValue();
const bool astc = IsPixelFormatASTC(info.format);
if (astc && recompression_setting == Settings::AstcRecompression::Uncompressed) {
if (IsPixelFormatASTC(info.format)) {
Tegra::Texture::ASTC::Decompress(
input_offset, copy.image_extent.width, copy.image_extent.height,
copy.image_subresource.num_layers * copy.image_extent.depth, tile_size.width,
@@ -952,36 +931,6 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
output_offset += copy.image_extent.width * copy.image_extent.height *
copy.image_extent.depth * copy.image_subresource.num_layers *
BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
} else if (astc) {
// BC1 uses 0.5 bytes per texel
// BC3 uses 1 byte per texel
const auto compress = recompression_setting == Settings::AstcRecompression::Bc1
? Tegra::Texture::BCN::CompressBC1
: Tegra::Texture::BCN::CompressBC3;
const auto bpp_div = recompression_setting == Settings::AstcRecompression::Bc1 ? 2 : 1;
const u32 plane_dim = copy.image_extent.width * copy.image_extent.height;
const u32 level_size = plane_dim * copy.image_extent.depth *
copy.image_subresource.num_layers *
BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
decode_scratch.resize_destructive(level_size);
Tegra::Texture::ASTC::Decompress(
input_offset, copy.image_extent.width, copy.image_extent.height,
copy.image_subresource.num_layers * copy.image_extent.depth, tile_size.width,
tile_size.height, decode_scratch);
compress(decode_scratch, copy.image_extent.width, copy.image_extent.height,
copy.image_subresource.num_layers * copy.image_extent.depth,
output.subspan(output_offset));
const u32 aligned_plane_dim = Common::AlignUp(copy.image_extent.width, 4) *
Common::AlignUp(copy.image_extent.height, 4);
copy.buffer_size =
(aligned_plane_dim * copy.image_extent.depth * copy.image_subresource.num_layers) /
bpp_div;
output_offset += static_cast<u32>(copy.buffer_size);
} else {
DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format);
output_offset += copy.image_extent.width * copy.image_extent.height *
@@ -995,11 +944,7 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
}
bool CanConvertFromGuest(const ImageInfo& info) {
if (!IsPixelFormatASTC(info.format) || info.type == ImageType::Linear) {
return false;
}
return Settings::values.astc_recompression.GetValue() ==
Settings::AstcRecompression::Uncompressed;
return IsPixelFormatASTC(info.format) && info.type != ImageType::Linear;
}
boost::container::small_vector<BufferImageCopy, 16> ConvertImageFromGuest(
-86
View File
@@ -1,86 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <stb_dxt.h>
#include <string.h>
#include "common/alignment.h"
#include "video_core/textures/bcn.h"
#include "video_core/textures/workers.h"
namespace Tegra::Texture::BCN {
using BCNCompressor = void(u8* block_output, const u8* block_input, bool any_alpha);
template <u32 BytesPerBlock, bool ThresholdAlpha = false>
void CompressBCN(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
std::span<uint8_t> output, BCNCompressor f) {
constexpr u8 alpha_threshold = 128;
constexpr u32 bytes_per_px = 4;
const u32 plane_dim = width * height;
Common::ThreadWorker& workers{GetThreadWorkers()};
for (u32 z = 0; z < depth; z++) {
for (u32 y = 0; y < height; y += 4) {
auto compress_row = [z, y, width, height, plane_dim, f, data, output]() {
for (u32 x = 0; x < width; x += 4) {
// Gather 4x4 block of RGBA texels
u8 input_colors[4][4][4];
bool any_alpha = false;
for (u32 j = 0; j < 4; j++) {
for (u32 i = 0; i < 4; i++) {
const size_t coord =
(z * plane_dim + (y + j) * width + (x + i)) * bytes_per_px;
if ((x + i < width) && (y + j < height)) {
if constexpr (ThresholdAlpha) {
if (data[coord + 3] >= alpha_threshold) {
input_colors[j][i][0] = data[coord + 0];
input_colors[j][i][1] = data[coord + 1];
input_colors[j][i][2] = data[coord + 2];
input_colors[j][i][3] = 255;
} else {
any_alpha = true;
memset(input_colors[j][i], 0, bytes_per_px);
}
} else {
memcpy(input_colors[j][i], &data[coord], bytes_per_px);
}
} else {
memset(input_colors[j][i], 0, bytes_per_px);
}
}
}
const u32 bytes_per_row = BytesPerBlock * Common::DivideUp(width, 4U);
const u32 bytes_per_plane = bytes_per_row * Common::DivideUp(height, 4U);
f(output.data() + z * bytes_per_plane + (y / 4) * bytes_per_row +
(x / 4) * BytesPerBlock,
reinterpret_cast<u8*>(input_colors), any_alpha);
}
};
workers.QueueWork(std::move(compress_row));
}
workers.WaitForRequests();
}
}
void CompressBC1(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
std::span<uint8_t> output) {
CompressBCN<8, true>(data, width, height, depth, output,
[](u8* block_output, const u8* block_input, bool any_alpha) {
stb_compress_bc1_block(block_output, block_input, any_alpha,
STB_DXT_NORMAL);
});
}
void CompressBC3(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
std::span<uint8_t> output) {
CompressBCN<16, false>(data, width, height, depth, output,
[](u8* block_output, const u8* block_input, bool any_alpha) {
stb_compress_bc3_block(block_output, block_input, STB_DXT_NORMAL);
});
}
} // namespace Tegra::Texture::BCN
-16
View File
@@ -1,16 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <span>
#include "common/common_types.h"
namespace Tegra::Texture::BCN {
void CompressBC1(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
void CompressBC3(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
} // namespace Tegra::Texture::BCN