Compare commits

..

1 Commits

Author SHA1 Message Date
lizzie c3849bb7d7 [common/stb] remove unused I/O funcs from non-LTO builds, use common/stb.h on ns service
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-08-22 19:25:22 +00:00
12 changed files with 14 additions and 210 deletions
@@ -31,7 +31,6 @@ object GameHelper {
fun getGames(): List<Game> {
val games = mutableListOf<Game>()
val gamesByProgramId = mutableMapOf<String, Game>()
val context = YuzuApplication.appContext
preferences = PreferenceManager.getDefaultSharedPreferences(context)
@@ -64,7 +63,6 @@ object GameHelper {
addGamesRecursive(
games,
gamesByProgramId,
FileUtil.listFiles(gameDirUri),
scanDepth,
mountedContainerUris
@@ -138,7 +136,6 @@ object GameHelper {
private fun addGamesRecursive(
games: MutableList<Game>,
gamesByProgramId: MutableMap<String, Game>,
files: Array<MinimalDocumentFile>,
depth: Int,
mountedContainerUris: MutableSet<String>
@@ -151,7 +148,6 @@ object GameHelper {
if (it.isDirectory) {
addGamesRecursive(
games,
gamesByProgramId,
FileUtil.listFiles(it.uri),
depth - 1,
mountedContainerUris
@@ -160,9 +156,8 @@ object GameHelper {
val extension = FileUtil.getExtension(it.uri).lowercase()
val filePath = it.uri.toString()
val mountedContainer = externalContentExtensions.contains(extension) &&
mountedContainerUris.add(filePath)
if (mountedContainer) {
if (externalContentExtensions.contains(extension) &&
mountedContainerUris.add(filePath)) {
NativeLibrary.addGameFolderFileToFilesystemProvider(filePath)
}
@@ -170,20 +165,6 @@ object GameHelper {
val game = getGame(it.uri, true, false)
if (game != null) {
games.add(game)
if (game.programId != "0") {
gamesByProgramId[game.programId] = game
}
} else if (mountedContainer) {
GameMetadata.getProgramId(filePath).toLongOrNull()?.let { programId ->
gamesByProgramId[(programId and 0x800L.inv()).toString()]
}?.let { existingGame ->
NativeLibrary.getPatchesForFile(existingGame.path, existingGame.programId)
existingGame.version = GameMetadata.getVersion(
existingGame.path,
true
)
GameIconUtils.refreshGameIcon(existingGame)
}
}
}
}
@@ -1,6 +1,3 @@
// 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
@@ -27,15 +24,6 @@ import coil.request.Options
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.Game
import java.util.Collections
import java.util.WeakHashMap
private val gameIconHashes = Collections.synchronizedMap(mutableMapOf<String, Int>())
private val gameIconTargets = Collections.synchronizedMap(WeakHashMap<ImageView, GameIconTarget>())
private fun Game.iconCacheKey(): String = "$path|$version"
private data class GameIconTarget(val game: Game, var iconHash: Int? = null)
class GameIconFetcher(
private val game: Game,
@@ -43,15 +31,14 @@ class GameIconFetcher(
) : Fetcher {
override suspend fun fetch(): FetchResult {
return DrawableResult(
drawable = decodeGameIcon(game)!!.toDrawable(options.context.resources),
drawable = decodeGameIcon(game.path)!!.toDrawable(options.context.resources),
isSampled = false,
dataSource = DataSource.DISK
)
}
private fun decodeGameIcon(game: Game): Bitmap? {
val data = GameMetadata.getIcon(game.path)
gameIconHashes[game.iconCacheKey()] = data.contentHashCode()
private fun decodeGameIcon(uri: String): Bitmap? {
val data = GameMetadata.getIcon(uri)
return BitmapFactory.decodeByteArray(
data,
0,
@@ -67,7 +54,7 @@ class GameIconFetcher(
}
class GameIconKeyer : Keyer<Game> {
override fun key(data: Game, options: Options): String = data.iconCacheKey()
override fun key(data: Game, options: Options): String = data.path
}
object GameIconUtils {
@@ -84,58 +71,14 @@ object GameIconUtils {
.build()
fun loadGameIcon(game: Game, imageView: ImageView) {
gameIconTargets[imageView] = GameIconTarget(game)
val request = ImageRequest.Builder(YuzuApplication.appContext)
.data(game)
.target(imageView)
.error(R.drawable.default_icon)
.listener(
onSuccess = { _, _ ->
val target = gameIconTargets[imageView]
if (target?.game?.iconCacheKey() == game.iconCacheKey()) {
gameIconHashes[game.iconCacheKey()]?.let {
target.iconHash = it
}
}
},
onError = { _, _ ->
gameIconTargets[imageView]?.iconHash = null
}
)
.build()
imageLoader.enqueue(request)
}
fun refreshGameIcon(game: Game) {
val targets = synchronized(gameIconTargets) {
gameIconTargets
.filterValues { it.game.path == game.path && it.game.programId == game.programId }
.keys
.toList()
}
if (targets.isEmpty()) {
return
}
val iconHash = GameMetadata.getIcon(game.path).contentHashCode()
val targetsToRefresh = targets.filter { gameIconTargets[it]?.iconHash != iconHash }
if (targetsToRefresh.isEmpty()) {
return
}
imageLoader.memoryCache?.remove(MemoryCache.Key(game.iconCacheKey()))
targetsToRefresh.forEach { imageView ->
imageView.post {
val target = gameIconTargets[imageView] ?: return@post
if (target.game.path == game.path && target.game.programId == game.programId) {
if (target.iconHash != iconHash) {
loadGameIcon(game, imageView)
}
}
}
}
}
suspend fun getGameIcon(lifecycleOwner: LifecycleOwner, game: Game): Bitmap {
val request = ImageRequest.Builder(YuzuApplication.appContext)
.data(game)
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="?attr/colorControlHighlight" />
<item android:state_focused="true" android:color="@android:color/transparent" />
<item android:state_selected="true" android:color="@android:color/transparent" />
<item android:state_hovered="true" android:color="@android:color/transparent" />
<item android:color="@android:color/transparent" />
</selector>
@@ -10,7 +10,6 @@
android:clipChildren="true"
android:layout_margin="0dp"
app:cardBackgroundColor="@color/eden_card_background"
app:rippleColor="@color/game_card_ripple"
app:strokeWidth="1dp"
app:strokeColor="@color/eden_border">
@@ -11,7 +11,6 @@
app:cardCornerRadius="16dp"
app:cardPreventCornerOverlap="true"
android:clipChildren="true"
app:rippleColor="@color/game_card_ripple"
android:layout_margin="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -22,7 +22,6 @@
android:focusable="true"
android:transitionName="card_game"
app:cardCornerRadius="16dp"
app:rippleColor="@color/game_card_ripple"
android:foreground="@color/eden_border_gradient_start">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -22,7 +22,6 @@
android:focusable="true"
android:transitionName="card_game_compact"
app:cardCornerRadius="16dp"
app:rippleColor="@color/game_card_ripple"
android:foreground="@color/eden_border_gradient_start">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -12,7 +12,6 @@
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:cardBackgroundColor="@android:color/transparent"
app:rippleColor="@color/game_card_ripple"
app:strokeWidth="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
-2
View File
@@ -7,6 +7,4 @@
#define STB_IMAGE_IMPLEMENTATION 1
#define STB_IMAGE_RESIZE_IMPLEMENTATION 1
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
#define STBI_ONLY_JPEG 1
#include "common/stb.h"
+1
View File
@@ -7,6 +7,7 @@
#pragma once
#define STBI_ONLY_JPEG 1
#define STBI_WRITE_NO_STDIO 1
#include <stb_image.h>
#include <stb_image_resize.h>
#include <stb_image_write.h>
+6 -108
View File
@@ -116,122 +116,20 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
}
std::string UTF16ToUTF8(std::u16string_view input) {
std::string result;
result.reserve(input.size() * 4);
for (size_t i = 0; i < input.size(); ++i) {
uint32_t code = input[i];
// Handle surrogate pairs
if (code >= 0xD800 && code <= 0xDBFF) {
if (i + 1 < input.size()) {
uint32_t low = input[i + 1];
if (low >= 0xDC00 && low <= 0xDFFF) {
code = ((code - 0xD800) << 10) + (low - 0xDC00) + 0x10000;
++i;
}
}
}
if (code <= 0x7F) {
result.push_back(char(code));
} else if (code <= 0x7FF) {
result.push_back(char(0xC0 | (code >> 6)));
result.push_back(char(0x80 | (code & 0x3F)));
} else if (code <= 0xFFFF) {
result.push_back(char(0xE0 | (code >> 12)));
result.push_back(char(0x80 | ((code >> 6) & 0x3F)));
result.push_back(char(0x80 | (code & 0x3F)));
} else {
result.push_back(char(0xF0 | (code >> 18)));
result.push_back(char(0x80 | ((code >> 12) & 0x3F)));
result.push_back(char(0x80 | ((code >> 6) & 0x3F)));
result.push_back(char(0x80 | (code & 0x3F)));
}
}
return result;
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.to_bytes(input.data(), input.data() + input.size());
}
std::u16string UTF8ToUTF16(std::string_view input) {
std::u16string result;
result.reserve(input.size() * 2);
for (size_t i = 0; i < input.size(); ) {
uint32_t code = 0;
unsigned char c = input[i];
size_t len = 0;
if ((c & 0x80) == 0) {
code = c;
len = 1;
} else if ((c & 0xE0) == 0xC0) {
code = c & 0x1F;
len = 2;
} else if ((c & 0xF0) == 0xE0) {
code = c & 0x0F;
len = 3;
} else if ((c & 0xF8) == 0xF0) {
code = c & 0x07;
len = 4;
} else {
++i;
continue;
}
if (i + len - 1 >= input.size())
break;
for (size_t j = 1; j <= len - 1; ++j) {
if ((input[i + j] & 0xC0) != 0x80) {
code = 0xFFFD;
break;
}
code = (code << 6) | (input[i + j] & 0x3F);
}
if (code <= 0xFFFF) {
result.push_back(char16_t(code));
} else {
code -= 0x10000;
result.push_back(char16_t(0xD800 + (code >> 10)));
result.push_back(char16_t(0xDC00 + (code & 0x3FF)));
}
i += len;
}
return result;
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.from_bytes(input.data(), input.data() + input.size());
}
std::u32string UTF8ToUTF32(std::string_view input) {
std::u32string result;
result.reserve(input.size());
for (size_t i = 0; i < input.size(); ) {
uint32_t code = 0;
unsigned char c = input[i];
size_t len = 0;
if ((c & 0x80) == 0) {
code = c;
len = 1;
} else if ((c & 0xE0) == 0xC0) {
code = c & 0x1F;
len = 2;
} else if ((c & 0xF0) == 0xE0) {
code = c & 0x0F;
len = 3;
} else if ((c & 0xF8) == 0xF0) {
code = c & 0x07;
len = 4;
} else {
++i;
continue;
}
if (i + len - 1 >= input.size())
break;
for (size_t j = 1; j <= len - 1; ++j) {
if ((input[i + j] & 0xC0) != 0x80) {
code = 0xFFFD;
break;
}
code = (code << 6) | (input[i + j] & 0x3F);
}
result.push_back(code);
i += len;
}
return result;
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
return convert.from_bytes(input.data(), input.data() + input.size());
}
#ifdef _WIN32
static std::wstring CPToUTF16(u32 code_page, std::string_view input) {
const auto size =
@@ -9,11 +9,7 @@
#include <optional>
#include <string>
#define STBI_ONLY_JPEG 1
#include <stb_image.h>
#include <stb_image_resize.h>
#include <stb_image_write.h>
#include "common/stb.h"
#include "common/settings.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"