Compare commits

..

8 Commits

Author SHA1 Message Date
lizzie 5e230b4257 license 2026-08-29 08:57:57 +02:00
lizzie e72f528bd8 fx 2026-08-29 08:57:57 +02:00
lizzie 99c77fe4cc x5 faster anchordIndex for BC7 2026-08-29 08:57:57 +02:00
lizzie 6b7aff1a70 better anchorIndex 2026-08-29 08:57:57 +02:00
lizzie 5f6017467b better table set 2026-08-29 08:57:57 +02:00
lizzie 3ab734bc61 oops bcn format 2026-08-29 08:57:57 +02:00
lizzie bcb739c9c0 fix ffs 2026-08-29 08:57:57 +02:00
lizzie 29e2d09ebf [bcn] ternary compose and simplify subsetIndex & anchordIndex 2026-08-29 08:57:57 +02:00
16 changed files with 400 additions and 740 deletions
+11 -27
View File
@@ -43,7 +43,6 @@ This guide will walk you through adding a new boolean toggle setting to Eden's c
Firstly add your desired toggle:
Example: `src/common/setting.h`
```cpp
SwitchableSetting<bool> your_setting_name{linkage, false, "your_setting_name", Category::RendererExtensions};
```
@@ -68,7 +67,6 @@ Common Categories:
Add the toggle to the Qt UI, where you wish for it to appear and place it there.
Example: `src/qt_common/config/shared_translation.cpp`
```cpp
INSERT(Settings,
your_setting_name,
@@ -93,7 +91,6 @@ INSERT(Settings,
Add where it should be in the settings.
Example: `src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt`
```kts
RENDERER_YOUR_SETTING_NAME("your_setting_name"),
```
@@ -109,7 +106,6 @@ RENDERER_YOUR_SETTING_NAME("your_setting_name"),
Add the toggle to the Kotlin (Android) UI
Example: `src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt`
```kts
put(
SwitchSetting(
@@ -127,7 +123,6 @@ put(
Add your setting within the right category.
Example: `src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt`
```kts
add(BooleanSetting.RENDERER_YOUR_SETTING_NAME.key)
```
@@ -142,7 +137,6 @@ add(BooleanSetting.RENDERER_YOUR_SETTING_NAME.key)
Add your setting and description in the appropriate place.
Example: `src/android/app/src/main/res/values/strings.xml`
```xml
<string name="your_setting_name">Your Setting Display Name</string>
<string name="your_setting_name_description">Detailed description of what this setting does. Explain any caveats, requirements, or warnings here.</string>
@@ -156,7 +150,6 @@ Now the UI part is done find a place in the code for the toggle,
And use it to your heart's desire!
Example:
```cpp
const bool your_value = Settings::values.your_setting_name.GetValue();
@@ -203,31 +196,25 @@ Common advantages recap:
#### Accessing Debug Knobs (dev side)
Use the `Settings::GetDebugKnobAt(u8 i)` function to check if a specific bit is set:
Use the `Settings::getDebugKnobAt(u8 i)` function to check if a specific bit is set:
```cpp
//cpp side
#include "common/settings.h"
//To use it as a general purpose uint var:
unsigned int debug_knobs = Settings::values.debug_knobs.GetValue();
// Check if bit 0 is set
bool feature_enabled = Settings::GetDebugKnobAt(0);
bool feature_enabled = Settings::getDebugKnobAt(0);
// Check if bit 15 is set
bool another_feature = Settings::GetDebugKnobAt(15);
bool another_feature = Settings::getDebugKnobAt(15);
```
```kts
//kotlin side
import org.yuzu.yuzu_emu.features.settings.model.Settings
//To use it as a general purpose uint var
val debug_knobs: Int = UShortSetting.DEBUG_KNOBS.getInt()
// Check if bit x is set
bool feature_enabled = Settings.GetDebugKnobAt(x); //x as integer from 0 to 15
bool feature_enabled = Settings.getDebugKnobAt(x); //x as integer from 0 to 15
```
The function returns `true` if the specified bit (0-15) is set in the `debug_knobs` value, `false` otherwise.
@@ -260,7 +247,6 @@ There are two main confusions when talking about knobs:
Sometimes when an user reports: knobs 1 and 2 gets better performance, dev may get confuse whether he means the knobs 1 and 2 literally, or the 1st and 2nd knobs (knobs 0 and 1).
Debug knobs are **zero-based**, which means:
* The first knob is the knob(0) (or knob0 henceforth), and the last one is the 15 (knob15, likewise)
* You can talk: "knob0 is enabled/disabled", "In this video i was using only knobs 0 and 2", etc.
@@ -273,7 +259,6 @@ Whenever you're instructing tests or reporting results, be precise about whether
ALWAYS use the word in PLURAL (knobs), without mentioning which one, to refer to the setting, aka multiple knobs at once:
Examples:
- **knobs=0**: no knobs enabled
- **knobs=1**: knob0 enabled, others disabled
- **knobs=2**: knob1 enabled, others disabled
@@ -285,7 +270,6 @@ Examples:
Use the word in SINGULAR (knob), or in plural but referring which ones, when meaning multiple knobs at once:
Examples:
- **knob0**: knob 0 enabled, others disabled
- **knob1**: knob 1 enabled, others disabled
- **knobs 0 and 1**: knobs 0 and 1 enabled, others disabled
@@ -298,12 +282,12 @@ Examples:
```cpp
void SomeFunction() {
if (Settings::GetDebugKnobAt(0)) {
if (Settings::getDebugKnobAt(0)) {
LOG_DEBUG(Common, "Debug feature 0 is enabled");
// Additional debug code here
}
if (Settings::GetDebugKnobAt(1)) {
if (Settings::getDebugKnobAt(1)) {
LOG_DEBUG(Common, "Debug feature 1 is enabled");
// Different debug behavior
}
@@ -315,7 +299,7 @@ void SomeFunction() {
```cpp
bool UseOptimizedPath() {
// Skip optimization if debug bit 2 is set for testing
return !Settings::GetDebugKnobAt(2);
return !Settings::getDebugKnobAt(2);
}
```
@@ -324,13 +308,13 @@ bool UseOptimizedPath() {
```cpp
void ExperimentalFeature() {
static constexpr u8 EXPERIMENTAL_FEATURE_BIT = 3;
if (!Settings::GetDebugKnobAt(EXPERIMENTAL_FEATURE_BIT)) {
if (!Settings::getDebugKnobAt(EXPERIMENTAL_FEATURE_BIT)) {
// Fallback to stable implementation
StableImplementation();
return;
}
// Experimental implementation
ExperimentalImplementation();
}
+329 -544
View File
File diff suppressed because it is too large Load Diff
+12 -32
View File
@@ -1,43 +1,23 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
// Copyright 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <cstdint>
namespace bcn {
/**
* @brief Decodes a BC1 encoded image to R8G8B8A8
*/
void DecodeBc1(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC2 encoded image to R8G8B8A8
*/
void DecodeBc2(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC3 encoded image to R8G8B8A8
*/
void DecodeBc3(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC4 encoded image to R8
*/
/// @brief Decodes a BC1 encoded image to R8G8B8A8
void DecodeBc1(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/// @brief Decodes a BC2 encoded image to R8G8B8A8
void DecodeBc2(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
//// @brief Decodes a BC3 encoded image to R8G8B8A8
void DecodeBc3(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/// @brief Decodes a BC4 encoded image to R8
void DecodeBc4(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC5 encoded image to R8G8
*/
//// @brief Decodes a BC5 encoded image to R8G8
void DecodeBc5(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC6 encoded image to R16G16B16A16
*/
//// @brief Decodes a BC6 encoded image to R16G16B16A16
void DecodeBc6(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC7 encoded image to R8G8B8A8
*/
void DecodeBc7(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/// @brief Decodes a BC7 encoded image to R8G8B8A8
void DecodeBc7(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
}
@@ -220,7 +220,7 @@ object NativeLibrary {
external fun refreshThreadPolicies()
external fun GetDebugKnobAt(index: Int): Boolean
external fun getDebugKnobAt(index: Int): Boolean
/**
* Set the current speed limit to the configured turbo speed.
@@ -35,8 +35,8 @@ object Settings {
fun getPlayerString(player: Int): String =
YuzuApplication.appContext.getString(R.string.preferences_player, player)
fun GetDebugKnobAt(index: Int): Boolean {
return org.yuzu.yuzu_emu.NativeLibrary.GetDebugKnobAt(index)
fun getDebugKnobAt(index: Int): Boolean {
return org.yuzu.yuzu_emu.NativeLibrary.getDebugKnobAt(index)
}
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
@@ -11,7 +11,8 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
enum class ShortSetting(override val key: String) : AbstractShortSetting {
RENDERER_SPEED_LIMIT("speed_limit"),
RENDERER_TURBO_SPEED_LIMIT("turbo_speed_limit"),
RENDERER_SLOW_SPEED_LIMIT("slow_speed_limit")
RENDERER_SLOW_SPEED_LIMIT("slow_speed_limit"),
DEBUG_KNOBS("debug_knobs")
;
override fun getShort(needsGlobal: Boolean): Short = NativeConfig.getShort(key, needsGlobal)
@@ -28,4 +29,4 @@ enum class ShortSetting(override val key: String) : AbstractShortSetting {
override fun getValueAsString(needsGlobal: Boolean): String = getShort(needsGlobal).toString()
override fun reset() = NativeConfig.setShort(key, defaultValue)
}
}
@@ -1,30 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.model
import org.yuzu.yuzu_emu.utils.NativeConfig
enum class UShortSetting(override val key: String) : AbstractIntSetting {
DEBUG_KNOBS("debug_knobs")
;
override fun getInt(needsGlobal: Boolean): Int =
NativeConfig.getUnsignedShort(key, needsGlobal)
override fun setInt(value: Int) {
if (NativeConfig.isPerGameConfigLoaded()) {
global = false
}
NativeConfig.setUnsignedShort(key, value)
}
override val defaultValue: Int by lazy { NativeConfig.getDefaultToString(key).toInt() }
override fun getValueAsString(needsGlobal: Boolean): String = getInt(needsGlobal).toString()
override fun reset() = NativeConfig.setUnsignedShort(key, defaultValue)
}
@@ -20,7 +20,6 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.model.UShortSetting
import org.yuzu.yuzu_emu.network.NetDataValidators
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
import org.yuzu.yuzu_emu.utils.NativeConfig
@@ -1035,7 +1034,7 @@ abstract class SettingsItem(
)
put(
SpinBoxSetting(
UShortSetting.DEBUG_KNOBS,
ShortSetting.DEBUG_KNOBS,
titleId = R.string.debug_knobs,
descriptionId = R.string.debug_knobs_description,
valueHint = R.string.debug_knobs_hint,
@@ -25,7 +25,6 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.model.UShortSetting
import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
@@ -1327,7 +1326,7 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.general))
add(UShortSetting.DEBUG_KNOBS.key)
add(ShortSetting.DEBUG_KNOBS.key)
add(StringSetting.PROGRAM_ARGS.key)
if (!NativeConfig.isPerGameConfigLoaded()) {
@@ -80,12 +80,6 @@ object NativeConfig {
@Synchronized
external fun setShort(key: String, value: Short)
@Synchronized
external fun getUnsignedShort(key: String, needsGlobal: Boolean): Int
@Synchronized
external fun setUnsignedShort(key: String, value: Int)
@Synchronized
external fun getInt(key: String, needsGlobal: Boolean): Int
+2 -2
View File
@@ -1300,8 +1300,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_refreshThreadPolicies(JNIEnv* env, jo
Common::RefreshThreadPolicies();
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_GetDebugKnobAt(JNIEnv* env, jobject jobj, jint index) {
return static_cast<jboolean>(Settings::GetDebugKnobAt(static_cast<u8>(index)));
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_getDebugKnobAt(JNIEnv* env, jobject jobj, jint index) {
return static_cast<jboolean>(Settings::getDebugKnobAt(static_cast<u8>(index)));
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setTurboSpeedLimit(JNIEnv *env, jobject jobj, jboolean enabled) {
@@ -130,25 +130,6 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setShort(JNIEnv* env, jobject ob
setting->SetValue(value);
}
jint Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getUnsignedShort(JNIEnv* env, jobject obj,
jstring jkey,
jboolean needGlobal) {
auto setting = getSetting<u16>(env, jkey);
if (setting == nullptr) {
return -1;
}
return static_cast<jint>(setting->GetValue(static_cast<bool>(needGlobal)));
}
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setUnsignedShort(JNIEnv* env, jobject obj,
jstring jkey, jint value) {
auto setting = getSetting<u16>(env, jkey);
if (setting == nullptr) {
return;
}
setting->SetValue(static_cast<u16>(value));
}
jint Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getInt(JNIEnv* env, jobject obj, jstring jkey,
jboolean needGlobal) {
auto setting = getSetting<int>(env, jkey);
+1 -1
View File
@@ -146,7 +146,7 @@ void LogSettings() {
#undef LOG_PATH
}
bool GetDebugKnobAt(u8 i) {
bool getDebugKnobAt(u8 i) {
return (values.debug_knobs.GetValue() & (1 << (i & 0xF))) != 0;
}
+2 -2
View File
@@ -904,7 +904,7 @@ struct Values {
0,
65535,
"debug_knobs",
Category::System,
Category::Debugging,
Specialization::Countable,
true,
true};
@@ -947,7 +947,7 @@ constexpr u32 MAX_FRAME_GEN_MULTIPLIER = 4;
[[nodiscard]] size_t FrameGenMaxGenerations();
bool GetDebugKnobAt(u8 i);
bool getDebugKnobAt(u8 i);
void UpdateGPUAccuracy();
bool IsGPULevelHigh();
+25 -51
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-FileCopyrightText: Copyright 2020 yuzu Emulator Project
@@ -9,6 +9,7 @@
#include <span>
#include <bc_decoder.h>
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/texture_cache/decode_bc.h"
@@ -22,11 +23,8 @@ using VideoCore::Surface::PixelFormat;
constexpr bool IsSigned(PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM:
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT:
return true;
default:
return false;
@@ -62,9 +60,28 @@ u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
}
}
template <auto decompress, PixelFormat pixel_format>
void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
bool is_signed = false) {
void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy, VideoCore::Surface::PixelFormat pixel_format) {
auto const f = [pixel_format]{
switch (pixel_format) {
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC1_RGBA_SRGB: return &bcn::DecodeBc1;
case PixelFormat::BC2_UNORM:
case PixelFormat::BC2_SRGB: return &bcn::DecodeBc2;
case PixelFormat::BC3_UNORM:
case PixelFormat::BC3_SRGB: return &bcn::DecodeBc3;
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM: return &bcn::DecodeBc4;
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM: return &bcn::DecodeBc5;
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT: return &bcn::DecodeBc6;
case PixelFormat::BC7_SRGB:
case PixelFormat::BC7_UNORM: return &bcn::DecodeBc7;
default:
UNREACHABLE_MSG("Unimplemented BCn decompression {}", pixel_format);
return &bcn::DecodeBc1;
}
}();
const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
const u32 block_size = BlockSize(pixel_format);
const u32 width = copy.image_extent.width;
@@ -82,11 +99,7 @@ void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferIma
for (u32 x = 0; x < width; x += block_width) {
const u8* src = input.data() + src_offset;
u8* const dst = output.data() + dst_offset;
if constexpr (IsSigned(pixel_format)) {
decompress(src, dst, x, y, width, height, is_signed);
} else {
decompress(src, dst, x, y, width, height);
}
f(src, dst, x, y, width, height, IsSigned(pixel_format));
src_offset += block_size;
dst_offset += block_width * out_bpp;
}
@@ -96,43 +109,4 @@ void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferIma
}
}
void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
VideoCore::Surface::PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC1_RGBA_SRGB:
DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, copy);
break;
case PixelFormat::BC2_UNORM:
case PixelFormat::BC2_SRGB:
DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, copy);
break;
case PixelFormat::BC3_UNORM:
case PixelFormat::BC3_SRGB:
DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, copy);
break;
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
input, output, copy, pixel_format == PixelFormat::BC4_SNORM);
break;
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM:
DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
input, output, copy, pixel_format == PixelFormat::BC5_SNORM);
break;
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT:
DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
input, output, copy, pixel_format == PixelFormat::BC6H_SFLOAT);
break;
case PixelFormat::BC7_SRGB:
case PixelFormat::BC7_UNORM:
DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, copy);
break;
default:
LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);
}
}
} // namespace VideoCommon
+10 -17
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-FileCopyrightText: Copyright 2020 yuzu Emulator Project
@@ -922,8 +922,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
return copies;
}
void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output,
std::span<BufferImageCopy> copies) {
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;
@@ -955,10 +954,10 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
} 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;
auto const compress = recompression_setting == Settings::AstcRecompression::Bc1
? Tegra::Texture::BCN::CompressBC1
: Tegra::Texture::BCN::CompressBC3;
const auto bpp_div = compress == Tegra::Texture::BCN::CompressBC1 ? 2 : 1;
const u32 plane_dim = copy.image_extent.width * copy.image_extent.height;
const u32 level_size = plane_dim * copy.image_extent.depth *
@@ -975,18 +974,12 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
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);
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 += 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 *
copy.image_subresource.num_layers *
ConvertedBytesPerBlock(info.format);
output_offset += copy.image_extent.width * copy.image_extent.height * copy.image_subresource.num_layers * ConvertedBytesPerBlock(info.format);
}
copy.buffer_row_length = mip_size.width;