Compare commits

...

27 Commits

Author SHA1 Message Date
lizzie 7b6eb6fb7a go eat shit fucking global memory 2026-02-01 23:16:41 +01:00
lizzie 36010d2538 bs2 2026-02-01 23:16:41 +01:00
lizzie c6189c791b force unquant vecs 2026-02-01 23:16:41 +01:00
lizzie 2950091828 pressure to NOT use global mem 2026-02-01 23:16:41 +01:00
lizzie 89fc2b94e6 small force emit constant shifts 2026-02-01 23:16:41 +01:00
lizzie 88eb1aab39 fix LDR 2026-02-01 23:16:41 +01:00
lizzie 624aff4e92 beware evil comp shit 2026-02-01 23:16:41 +01:00
lizzie 0a8c413708 bullshit3 2026-02-01 23:16:41 +01:00
lizzie 402fa3ae93 dont recall expensive branchy func 2026-02-01 23:16:41 +01:00
lizzie 6a5f86f201 i dont trust Mediatek handling signed or div/rem constants 2026-02-01 23:16:41 +01:00
lizzie 8d78acf8b6 mod6_table + mod8_table 2026-02-01 23:16:41 +01:00
lizzie 7ec09305d0 fx 2026-02-01 23:16:41 +01:00
lizzie 71d0b4f79b linear for num_partition num values upper boundset 2026-02-01 23:16:41 +01:00
lizzie d7e3fd7fe8 linearize GetBitLength 2026-02-01 23:16:41 +01:00
lizzie 5a10e95188 bullshit global memory reads 2026-02-01 23:16:41 +01:00
lizzie e78ab8eeef better replicate function 2026-02-01 23:16:41 +01:00
lizzie 0c3d3eb19d better replicate, better CEM get 2026-02-01 23:16:41 +01:00
lizzie 39ae39293f dc1 2026-02-01 23:16:41 +01:00
lizzie d44ce7b93b fix etc2/bc7 2026-02-01 23:16:41 +01:00
lizzie ea6344b031 fuckit, prepare for accelerate gpu 2026-02-01 23:16:41 +01:00
lizzie 3a7392d4be remove dead code1 2026-02-01 23:16:41 +01:00
lizzie 7d591b3bd9 better unrolled ver 2026-02-01 23:16:41 +01:00
lizzie 144e20800f FUCKCLANG 2026-02-01 23:16:41 +01:00
lizzie a7377f552a fix loicense 2026-02-01 23:16:41 +01:00
lizzie 39138fbdd2 [video_core] friendlier ASTC replicate function that doesn't trash cache
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-02-01 23:16:41 +01:00
crueter cd9527072d [frontend] fix nightly update checker again (#3446)
I ❤️ std::optional

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3446
2026-02-01 22:27:49 +01:00
PavelBARABANOV ffdaf7369a [android] add qlaunch button (#3439)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3439
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
Co-committed-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
2026-02-01 22:03:35 +01:00
27 changed files with 576 additions and 2460 deletions
@@ -36,6 +36,9 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
USE_CUSTOM_RTC("custom_rtc_enabled"),
BLACK_BACKGROUNDS("black_backgrounds"),
ENABLE_FOLDER_BUTTON("enable_folder_button"),
ENABLE_QLAUNCH_BUTTON("enable_qlaunch_button"),
ENABLE_UPDATE_CHECKS("enable_update_checks"),
JOYSTICK_REL_CENTER("joystick_rel_center"),
DPAD_SLIDE("dpad_slide"),
@@ -16,7 +16,6 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
RENDERER_BACKEND("backend"),
RENDERER_VRAM_USAGE_MODE("vram_usage_mode"),
RENDERER_NVDEC_EMULATION("nvdec_emulation"),
RENDERER_ASTC_DECODE_METHOD("accelerate_astc"),
RENDERER_ASTC_RECOMPRESSION("astc_recompression"),
RENDERER_ACCURACY("gpu_accuracy"),
RENDERER_RESOLUTION("resolution_setup"),
@@ -60,6 +60,11 @@ abstract class SettingsItem(
return NativeInput.getStyleIndex(0) != NpadStyleIndex.Handheld
}
// Can't edit enable_qlaunch_button if firmware is not available
if (setting.key == BooleanSetting.ENABLE_QLAUNCH_BUTTON.key) {
return NativeLibrary.isFirmwareAvailable()
}
// Can't edit settings that aren't saveable in per-game config even if they are switchable
if (NativeConfig.isPerGameConfigLoaded() && !setting.isSaveable) {
return false
@@ -320,15 +325,6 @@ abstract class SettingsItem(
valuesId = R.array.rendererNvdecValues
)
)
put(
SingleChoiceSetting(
IntSetting.RENDERER_ASTC_DECODE_METHOD,
titleId = R.string.accelerate_astc,
descriptionId = R.string.accelerate_astc_description,
choicesId = R.array.astcDecodingMethodNames,
valuesId = R.array.astcDecodingMethodValues
)
)
put(
SingleChoiceSetting(
IntSetting.RENDERER_ASTC_RECOMPRESSION,
@@ -794,6 +790,20 @@ abstract class SettingsItem(
descriptionId = R.string.enable_update_checks_description,
)
)
put(
SwitchSetting(
BooleanSetting.ENABLE_FOLDER_BUTTON,
titleId = R.string.enable_folder_button,
descriptionId = R.string.enable_folder_button_description,
)
)
put(
SwitchSetting(
BooleanSetting.ENABLE_QLAUNCH_BUTTON,
titleId = R.string.enable_qlaunch_button,
descriptionId = R.string.enable_qlaunch_button_description,
)
)
put(
SingleChoiceSetting(
IntSetting.APP_LANGUAGE,
@@ -268,7 +268,6 @@ class SettingsFragmentPresenter(
add(IntSetting.DMA_ACCURACY.key)
add(IntSetting.MAX_ANISOTROPY.key)
add(IntSetting.RENDERER_VRAM_USAGE_MODE.key)
add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key)
add(IntSetting.RENDERER_ASTC_RECOMPRESSION.key)
add(BooleanSetting.SYNC_MEMORY_OPERATIONS.key)
@@ -1191,6 +1190,13 @@ class SettingsFragmentPresenter(
descriptionId = R.string.use_black_backgrounds_description
)
)
add(HeaderSetting(R.string.buttons))
add(BooleanSetting.ENABLE_FOLDER_BUTTON.key)
add(BooleanSetting.ENABLE_QLAUNCH_BUTTON.key)
if (!NativeLibrary.isFirmwareAvailable()) {
BooleanSetting.ENABLE_QLAUNCH_BUTTON.setBoolean(false)
}
}
}
@@ -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
package org.yuzu.yuzu_emu.ui
@@ -13,6 +13,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.PopupMenu
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
@@ -27,10 +28,14 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.adapters.GameAdapter
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.model.AppletInfo
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
@@ -173,10 +178,16 @@ class GamesFragment : Fragment() {
setupTopView()
updateButtonsVisibility()
binding.addDirectory.setOnClickListener {
getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
}
binding.launchQlaunch?.setOnClickListener {
launchQLaunch()
}
setInsets()
}
@@ -445,6 +456,47 @@ class GamesFragment : Fragment() {
}
}
private fun launchQLaunch() {
try {
val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.QLaunch.entryId)
if (appletPath.isEmpty()) {
Toast.makeText(
requireContext(),
R.string.applets_error_applet,
Toast.LENGTH_SHORT
).show()
return
}
NativeLibrary.setCurrentAppletId(AppletInfo.QLaunch.appletId)
val qlaunchGame = Game(
title = getString(R.string.qlaunch_applet),
path = appletPath
)
val action = HomeNavigationDirections.actionGlobalEmulationActivity(qlaunchGame)
findNavController().navigate(action)
} catch (e: Exception) {
Toast.makeText(
requireContext(),
"Failed to launch QLaunch: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
private fun updateButtonsVisibility() {
val showQLaunch = BooleanSetting.ENABLE_QLAUNCH_BUTTON.getBoolean()
val showFolder = BooleanSetting.ENABLE_FOLDER_BUTTON.getBoolean()
val isFirmwareAvailable = NativeLibrary.isFirmwareAvailable()
val shouldShowQLaunch = showQLaunch && isFirmwareAvailable
binding.launchQlaunch.visibility = if (shouldShowQLaunch) View.VISIBLE else View.GONE
binding.addDirectory.visibility = if (showFolder) View.VISIBLE else View.GONE
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
@@ -498,6 +550,13 @@ class GamesFragment : Fragment() {
mlpFab.rightMargin = rightInset + fabPadding
binding.addDirectory.layoutParams = mlpFab
binding.launchQlaunch?.let { qlaunchButton ->
val mlpQLaunch = qlaunchButton.layoutParams as ViewGroup.MarginLayoutParams
mlpQLaunch.leftMargin = leftInset + fabPadding
mlpQLaunch.bottomMargin = barInsets.bottom + fabPadding
qlaunchButton.layoutParams = mlpQLaunch
}
val navInsets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
val gestureInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
val bottomInset = maxOf(navInsets.bottom, gestureInsets.bottom, cutoutInsets.bottom)
@@ -65,6 +65,10 @@ namespace AndroidSettings {
Settings::Setting<s32> app_language{linkage, 0, "app_language", Settings::Category::Android};
Settings::Setting<bool> enable_update_checks{linkage, true, "enable_update_checks",
Settings::Category::Android};
Settings::Setting<bool> enable_folder_button{linkage, true, "enable_folder_button",
Settings::Category::Android};
Settings::Setting<bool> enable_qlaunch_button{linkage, false, "enable_qlaunch_button",
Settings::Category::Android};
// Input/performance overlay settings
std::vector<OverlayControlData> overlay_control_data;
@@ -220,6 +220,23 @@
android:textColor="?attr/colorOnPrimary"
app:backgroundTint="?attr/colorPrimary"
app:iconTint="?attr/colorOnPrimary"
app:rippleColor="#99FFFFFF"
/>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/launch_qlaunch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="Launch QLaunch"
android:text="@string/qlaunch_applet"
app:icon="@drawable/ic_home"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:textColor="?attr/colorOnPrimary"
app:backgroundTint="?attr/colorPrimary"
app:iconTint="?attr/colorOnPrimary"
app:rippleColor="#99FFFFFF"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -214,6 +214,22 @@
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/launch_qlaunch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="Launch QLaunch"
android:text="@string/qlaunch_applet"
app:icon="@drawable/ic_home"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:textColor="?attr/colorOnPrimary"
app:backgroundTint="?attr/colorPrimary"
app:iconTint="?attr/colorOnPrimary"
app:rippleColor="#99FFFFFF"
/>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/add_directory"
android:layout_width="wrap_content"
@@ -227,6 +243,7 @@
android:textColor="?attr/colorOnPrimary"
app:backgroundTint="?attr/colorPrimary"
app:iconTint="?attr/colorOnPrimary"
app:rippleColor="#99FFFFFF"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
+4 -14
View File
@@ -123,25 +123,13 @@
<item>1</item> <!-- Aggressive -->
</integer-array>
<!-- ASTC Decoding Method Choices -->
<string-array name="astcDecodingMethodNames">
<item>@string/accelerate_astc_cpu</item>
<item>@string/accelerate_astc_gpu</item>
<item>@string/accelerate_astc_async</item>
</string-array>
<!-- ASTC Decoding Method Values -->
<integer-array name="astcDecodingMethodValues">
<item>0</item> <!-- CPU -->
<item>1</item> <!-- GPU -->
<item>2</item> <!-- CPU Asynchronously -->
</integer-array>
<!-- ASTC Recompression Method Choices -->
<string-array name="astcRecompressionMethodNames">
<item>@string/astc_recompression_uncompressed</item>
<item>@string/astc_recompression_bc1</item>
<item>@string/astc_recompression_bc3</item>
<item>@string/astc_recompression_bc7</item>
<item>@string/astc_recompression_etc2</item>
</string-array>
<!-- ASTC Recompression Method Values -->
@@ -149,6 +137,8 @@
<item>0</item> <!-- Uncompressed -->
<item>1</item> <!-- BC1 -->
<item>2</item> <!-- BC3 -->
<item>3</item> <!-- BC7 -->
<item>4</item> <!-- ETC2 -->
</integer-array>
<!-- NVDEC Emulation Choices -->
@@ -1033,6 +1033,8 @@
<string name="astc_recompression_uncompressed">Uncompressed</string>
<string name="astc_recompression_bc1" translatable="false">BC1</string>
<string name="astc_recompression_bc3" translatable="false">BC3</string>
<string name="astc_recompression_bc7" translatable="false">BC7</string>
<string name="astc_recompression_etc2" translatable="false">ETC2</string>
<!-- ASTC Recompression Method Choices -->
<string name="vram_usage_conservative">Conservative</string>
@@ -1163,6 +1165,12 @@
<string name="use_black_backgrounds">Black backgrounds</string>
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
<!-- Buttons -->
<string name="enable_folder_button">Folder</string>
<string name="enable_folder_button_description">Show the button to add game folders</string>
<string name="enable_qlaunch_button">QLaunch</string>
<string name="enable_qlaunch_button_description">Show the button to launch QLaunch</string>
<!-- App Language -->
<string name="app_language">App Language</string>
<string name="app_language_description">Change the language of the app interface</string>
-9
View File
@@ -430,15 +430,6 @@ struct Values {
#endif
"max_anisotropy",
Category::RendererAdvanced};
SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
#ifdef ANDROID
AstcDecodeMode::Cpu,
#else
AstcDecodeMode::Gpu,
#endif
"accelerate_astc",
Category::RendererAdvanced};
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
AstcRecompression::Uncompressed,
"astc_recompression",
+1 -1
View File
@@ -128,7 +128,7 @@ 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, X32, X64, None);
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3, Bc7, Etc2);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
+1 -2
View File
@@ -176,6 +176,5 @@ std::optional<UpdateChecker::Update> UpdateChecker::GetUpdate() {
}
empty:
return UpdateChecker::Update{};
return std::nullopt;
}
+4 -10
View File
@@ -209,14 +209,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
tr("Specifies how videos should be decoded.\nIt can either use the CPU or the GPU for "
"decoding, or perform no decoding at all (black screen on videos).\n"
"In most cases, GPU decoding provides the best performance."));
INSERT(Settings,
accelerate_astc,
tr("ASTC Decoding Method:"),
tr("This option controls how ASTC textures should be decoded.\n"
"CPU: Use the CPU for decoding.\n"
"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,
@@ -490,8 +482,10 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
{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)")),
PAIR(AstcRecompression, Bc1, tr("BC1")),
PAIR(AstcRecompression, Bc3, tr("BC3")),
PAIR(AstcRecompression, Bc7, tr("BC7")),
PAIR(AstcRecompression, Etc2, tr("ETC2")),
}});
translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
{
-2
View File
@@ -279,8 +279,6 @@ add_library(video_core STATIC
texture_cache/types.h
texture_cache/util.cpp
texture_cache/util.h
textures/astc.h
textures/astc.cpp
textures/bcn.cpp
textures/bcn.h
textures/decoders.cpp
+1 -1
View File
@@ -90,7 +90,7 @@ if ("${GLSLANGVALIDATOR}" STREQUAL "GLSLANGVALIDATOR-NOTFOUND")
message(FATAL_ERROR "Required program `glslangValidator` not found.")
endif()
set(GLSL_FLAGS "")
set(GLSL_FLAGS "-Os")
set(SPIR_V_VERSION "spirv1.3")
set(QUIET_FLAG "--quiet")
File diff suppressed because it is too large Load Diff
@@ -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 2019 yuzu Emulator Project
@@ -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 true;
}
// Disable other accelerated uploads for now as they don't implement swizzled uploads
return false;
@@ -266,15 +264,6 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
return format_info.compatibility_class == store_class;
}
[[nodiscard]] bool CanBeDecodedAsync(const TextureCacheRuntime& runtime,
const VideoCommon::ImageInfo& info) {
if (IsPixelFormatASTC(info.format) && !runtime.HasNativeASTC()) {
return Settings::values.accelerate_astc.GetValue() ==
Settings::AstcDecodeMode::CpuAsynchronous;
}
return false;
}
[[nodiscard]] CopyOrigin MakeCopyOrigin(VideoCommon::Offset3D offset,
VideoCommon::SubresourceLayers subresource, GLenum target) {
switch (target) {
@@ -443,18 +432,15 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
}
[[nodiscard]] bool IsAstcRecompressionEnabled() {
return Settings::values.astc_recompression.GetValue() !=
Settings::AstcRecompression::Uncompressed;
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;
}
@@ -693,12 +679,9 @@ bool TextureCacheRuntime::HasNativeASTC() const noexcept {
return device.HasASTC();
}
Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_, GPUVAddr gpu_addr_,
VAddr cpu_addr_)
Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_, GPUVAddr gpu_addr_, VAddr cpu_addr_)
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), runtime{&runtime_} {
if (CanBeDecodedAsync(*runtime, info)) {
flags |= ImageFlagBits::AsynchronousDecode;
} else if (CanBeAccelerated(*runtime, info)) {
if (CanBeAccelerated(*runtime, info)) {
flags |= ImageFlagBits::AcceleratedUpload;
}
if (IsConverted(runtime->device, info.format, info.type)) {
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -25,14 +28,11 @@
#include "video_core/texture_cache/accelerated_swizzle.h"
#include "video_core/texture_cache/types.h"
#include "video_core/texture_cache/util.h"
#include "video_core/textures/astc.h"
#include "video_core/textures/decoders.h"
namespace OpenGL {
using namespace HostShaders;
using namespace Tegra::Texture::ASTC;
using VideoCommon::Extent2D;
using VideoCommon::Extent3D;
using VideoCommon::ImageCopy;
@@ -141,10 +141,8 @@ void UtilShaders::BlockLinearUpload2D(Image& image, const StagingBufferMap& map,
glUniform1ui(5, params.x_shift);
glUniform1ui(6, params.block_height);
glUniform1ui(7, params.block_height_mask);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset,
image.guest_size_bytes - swizzle.buffer_offset);
glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
GL_WRITE_ONLY, store_format);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset, image.guest_size_bytes - swizzle.buffer_offset);
glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0, GL_WRITE_ONLY, store_format);
glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
}
program_manager.RestoreGuestCompute();
@@ -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 2019 yuzu Emulator Project
@@ -251,6 +251,12 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with
case Settings::AstcRecompression::Bc3:
tuple.format = is_srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
break;
case Settings::AstcRecompression::Bc7:
tuple.format = is_srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
break;
case Settings::AstcRecompression::Etc2:
tuple.format = is_srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
break;
}
}
// Transcode on hardware that doesn't support BCn natively
@@ -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 2019 yuzu Emulator Project
@@ -538,16 +538,16 @@ ASTCDecoderPass::ASTCDecoderPass(const Device& device_, Scheduler& scheduler_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_,
MemoryAllocator& memory_allocator_)
: ComputePass(device_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS,
ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO,
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(AstcPushConstants)>, ASTC_DECODER_COMP_SPV),
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
compute_pass_descriptor_queue{compute_pass_descriptor_queue_}, memory_allocator{
memory_allocator_} {}
ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO,
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(AstcPushConstants)>, ASTC_DECODER_COMP_SPV)
, scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}
, compute_pass_descriptor_queue{compute_pass_descriptor_queue_}, memory_allocator{memory_allocator_}
{}
ASTCDecoderPass::~ASTCDecoderPass() = default;
void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
std::span<const VideoCommon::SwizzleParameters> swizzles) {
void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, std::span<const VideoCommon::SwizzleParameters> swizzles) {
ASSERT(image.info.size.depth == 1);
using namespace VideoCommon::Accelerated;
const std::array<u32, 2> block_dims{
VideoCore::Surface::DefaultBlockWidth(image.info.format),
@@ -558,13 +558,11 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
const VkImageAspectFlags aspect_mask = image.AspectMask();
const VkImage vk_image = image.Handle();
const bool is_initialized = image.ExchangeInitialization();
scheduler.Record([vk_pipeline, vk_image, aspect_mask,
is_initialized](vk::CommandBuffer cmdbuf) {
scheduler.Record([vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
const VkImageMemoryBarrier image_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = static_cast<VkAccessFlags>(is_initialized ? VK_ACCESS_SHADER_WRITE_BIT
: VK_ACCESS_NONE),
.srcAccessMask = VkAccessFlags(is_initialized ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_NONE),
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
@@ -579,9 +577,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
: VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
});
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
@@ -591,8 +587,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
const u32 num_dispatches_z = image.info.resources.layers;
compute_pass_descriptor_queue.Acquire();
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
image.guest_size_bytes - swizzle.buffer_offset);
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset, image.guest_size_bytes - swizzle.buffer_offset);
compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
@@ -601,8 +596,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
ASSERT(params.bytes_per_block_log2 == 4);
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, block_dims,
params, descriptor_data](vk::CommandBuffer cmdbuf) {
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, block_dims, params, descriptor_data](vk::CommandBuffer cmdbuf) {
const AstcPushConstants uniforms{
.blocks_dims = block_dims,
.layer_stride = params.layer_stride,
@@ -637,8 +631,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, image_barrier);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, image_barrier);
});
}
@@ -848,13 +848,11 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
RenderPassCache& render_pass_cache_,
DescriptorPool& descriptor_pool,
ComputePassDescriptorQueue& compute_pass_descriptor_queue)
: device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_},
staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_},
render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info} {
if (Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu) {
astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
compute_pass_descriptor_queue, memory_allocator);
}
: device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_}
, staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_}
, render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info}
{
astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, compute_pass_descriptor_queue, memory_allocator);
if (device.IsStorageImageMultisampleSupported()) {
msaa_copy_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, compute_pass_descriptor_queue);
}
@@ -1562,20 +1560,8 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
runtime->ViewFormats(info.format))),
aspect_mask(ImageAspectMask(info.format)) {
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
switch (Settings::values.accelerate_astc.GetValue()) {
case Settings::AstcDecodeMode::Gpu:
if (Settings::values.astc_recompression.GetValue() ==
Settings::AstcRecompression::Uncompressed &&
info.size.depth == 1) {
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
}
break;
case Settings::AstcDecodeMode::CpuAsynchronous:
flags |= VideoCommon::ImageFlagBits::AsynchronousDecode;
break;
default:
break;
}
ASSERT(info.size.depth == 1 && "ASTC Image depth >1 isn't supported");
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
flags |= VideoCommon::ImageFlagBits::Converted;
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
}
@@ -1588,13 +1574,10 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
}
current_image = &Image::original_image;
storage_image_views.resize(info.resources.levels);
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported() &&
Settings::values.astc_recompression.GetValue() ==
Settings::AstcRecompression::Uncompressed) {
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
const auto& device = runtime->device.GetLogical();
for (s32 level = 0; level < info.resources.levels; ++level) {
storage_image_views[level] =
MakeStorageView(device, level, *original_image, VK_FORMAT_A8B8G8R8_UNORM_PACK32);
storage_image_views[level] = MakeStorageView(device, level, *original_image, VK_FORMAT_A8B8G8R8_UNORM_PACK32);
}
}
}
@@ -2452,19 +2435,16 @@ void TextureCacheRuntime::AccelerateImageUpload(
std::span<const VideoCommon::SwizzleParameters> swizzles,
u32 z_start, u32 z_count) {
if (IsPixelFormatASTC(image.info.format)) {
if (IsPixelFormatASTC(image.info.format)
&& image.info.type == ImageType::e2D) {
return astc_decoder_pass->Assemble(image, map, swizzles);
}
if (bl3d_unswizzle_pass &&
IsPixelFormatBCn(image.info.format) &&
image.info.type == ImageType::e3D &&
image.info.resources.levels == 1 &&
image.info.resources.layers == 1) {
if (IsPixelFormatBCn(image.info.format)
&& image.info.type == ImageType::e3D
&& image.info.resources.levels == 1
&& image.info.resources.layers == 1) {
return bl3d_unswizzle_pass->Unswizzle(image, map, swizzles, z_start, z_count);
}
ASSERT(false);
}
+6 -4
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: 2014 Citra Emulator Project
@@ -444,15 +444,17 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
u64 TranscodedAstcSize(u64 base_size, PixelFormat format) {
constexpr u64 RGBA8_PIXEL_SIZE = 4;
const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) *
static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE;
const u64 base_block_size = u64(DefaultBlockWidth(format)) * 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;
case Settings::AstcRecompression::Bc7:
return uncompressed_size / 4;
case Settings::AstcRecompression::Etc2:
return uncompressed_size / 4; //6=RGB, 4=RGBA
default:
return uncompressed_size;
}
+3 -8
View File
@@ -2317,13 +2317,10 @@ ImageViewId TextureCache<P>::FindOrEmplaceImageView(ImageId image_id, const Imag
template <class P>
void TextureCache<P>::RegisterImage(ImageId image_id) {
ImageBase& image = slot_images[image_id];
ASSERT_MSG(False(image.flags & ImageFlagBits::Registered),
"Trying to register an already registered image");
ASSERT(False(image.flags & ImageFlagBits::Registered) && "Trying to register an already registered image");
image.flags |= ImageFlagBits::Registered;
u64 tentative_size = (std::max)(image.guest_size_bytes, image.unswizzled_size_bytes);
if ((IsPixelFormatASTC(image.info.format) &&
True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
True(image.flags & ImageFlagBits::Converted)) {
if ((IsPixelFormatASTC(image.info.format) && True(image.flags & ImageFlagBits::AcceleratedUpload)) || True(image.flags & ImageFlagBits::Converted)) {
tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
}
total_used_memory += Common::AlignUp(tentative_size, 1024);
@@ -2495,9 +2492,7 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) {
total_used_memory -= GetScaledImageSizeBytes(image);
}
u64 tentative_size = (std::max)(image.guest_size_bytes, image.unswizzled_size_bytes);
if ((IsPixelFormatASTC(image.info.format) &&
True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
True(image.flags & ImageFlagBits::Converted)) {
if ((IsPixelFormatASTC(image.info.format) && True(image.flags & ImageFlagBits::AcceleratedUpload)) || True(image.flags & ImageFlagBits::Converted)) {
tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
}
total_used_memory -= Common::AlignUp(tentative_size, 1024);
+9 -63
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
@@ -33,7 +33,6 @@
#include "video_core/texture_cache/formatter.h"
#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"
@@ -608,23 +607,18 @@ 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;
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);
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);
return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * ConvertedBytesPerBlock(info.format);
}
u32 CalculateLayerStride(const ImageInfo& info) noexcept {
@@ -922,8 +916,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;
@@ -939,56 +932,9 @@ 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) {
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, output.subspan(output_offset));
output_offset += copy.image_extent.width * copy.image_extent.height *
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 *
copy.image_subresource.num_layers *
ConvertedBytesPerBlock(info.format);
}
ASSERT(!IsPixelFormatASTC(info.format) && "CPU ASTC decoder is phased out");
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);
copy.buffer_row_length = mip_size.width;
copy.buffer_image_height = mip_size.height;
}
File diff suppressed because it is too large Load Diff
-11
View File
@@ -1,11 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace Tegra::Texture::ASTC {
void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
uint32_t block_width, uint32_t block_height, std::span<uint8_t> output);
} // namespace Tegra::Texture::ASTC