Compare commits

...

18 commits

Author SHA1 Message Date
OpenSauce04
54f35a72f9 Updated translations via Transifex 2026-01-29 12:16:18 +00:00
PabloMK7
aafd263e4a frontend: Revert removal of .3ds support (#1701)
* frontend: Revert removal of .3ds support

* Added 3ds extension to Info.plist

* Added .3ds extension to org.azahar_emu.Azahar.xml

* game_list.h: Removed leftover definitions

---------

Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
2026-01-29 12:10:49 +00:00
OpenSauce04
3703dcec3e Updated translations via Transifex 2026-01-25 00:57:26 +00:00
OpenSauce04
64b7f7e5b1 Revert "core: Temporary workaround for MSVC compiler bug (#1505)"
This reverts commit b0fe4d190d.
2026-01-25 00:49:54 +00:00
OpenSauce04
fa3be2d9a5 externals: Updated SDL to 2.32.10 2026-01-25 00:44:51 +00:00
OpenSauce04
b900b635ad ci: Only build appimage-wayland for tagged jobs
This is to reduce stress on the CI/CD build queue and cache
2026-01-25 00:44:51 +00:00
David Griswold
3d954bc74d update language and use UP instead of DOWN on axis mapping 2026-01-25 00:27:39 +00:00
OpenSauce04
e10999fe81 plgldr: Fixed plugins that should load for all titles failing to load due to a missing check 2026-01-25 00:24:40 +00:00
PabloMK7
6020f48e06 Revert: video_core/renderer_vulkan: Add texture filtering (#1678) 2026-01-25 00:24:22 +00:00
Immersion95
c7dda3c444 qt: Mention in the tooltip that async presentation adds 1 frame of input lag (#1669)
Async Presentation (Vulkan) adds 1 frame of input lag - Mention in the tooltip
2026-01-25 00:24:05 +00:00
PabloMK7
e96e84e1b3 video_core: Fix custom textures when loading a savestate 2026-01-25 00:23:46 +00:00
PabloMK7
8c5161e88f core: Fix accurate multiplication loading (home menu and savestate) 2026-01-25 00:23:29 +00:00
David Griswold
15e06bd000 android: prioritize non-built-in displays (#1667) 2026-01-25 00:23:13 +00:00
PabloMK7
656ab12542 log: Fix compilation with gcc backtrace (#1668) 2026-01-25 00:22:57 +00:00
OpenSauce
933a9e5596 qt: Workaround for Qt directoryChanged event spam on macOS (#1665)
* qt: Workaround for Qt directoryChanged event spam on macOS

* Use steady_clock instead of system_clock
2026-01-21 21:35:17 +00:00
OpenSauce04
6fa51c2fe4 qt: Implement Update Channel setting 2026-01-21 21:34:40 +00:00
OpenSauce04
9dd0149ec7 android: Fix desynced default value for use_vsync setting 2026-01-21 21:30:55 +00:00
Marcin Serwin
b038cdaf86 citra_meta: search for Qt6::GuiPrivate before using it
Otherwise, the configuration on darwin fails for me with the following
error:

```
CMake Error at src/citra_meta/CMakeLists.txt:64 (target_link_libraries):
  Target "citra_meta" links to:

    Qt6::GuiPrivate

  but the target was not found.
```

Signed-off-by: Marcin Serwin <marcin@serwin.dev>
2026-01-21 21:29:54 +00:00
78 changed files with 8198 additions and 8411 deletions

View file

@ -38,11 +38,14 @@ jobs:
CCACHE_SLOPPINESS: time_macros
OS: linux
TARGET: ${{ matrix.target }}
SHOULD_RUN: ${{ (matrix.target != 'appimage-wayland' || github.ref_type == 'tag') }}
steps:
- uses: actions/checkout@v4
if: ${{ env.SHOULD_RUN == 'true' }}
with:
submodules: recursive
- name: Set up cache
if: ${{ env.SHOULD_RUN == 'true' }}
uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
@ -50,18 +53,19 @@ jobs:
restore-keys: |
${{ runner.os }}-${{ matrix.target }}-
- name: Build
if: ${{ env.SHOULD_RUN == 'true' }}
run: ./.ci/linux.sh
- name: Move AppImage to artifacts directory
if: ${{ contains(matrix.target, 'appimage') }}
if: ${{ contains(matrix.target, 'appimage') && env.SHOULD_RUN == 'true' }}
run: |
mkdir -p artifacts
mv build/bundle/*.AppImage artifacts/
- name: Rename AppImage
if: ${{ matrix.target == 'appimage-wayland' }}
if: ${{ matrix.target == 'appimage-wayland' && env.SHOULD_RUN == 'true' }}
run: |
mv artifacts/azahar.AppImage artifacts/azahar-wayland.AppImage
- name: Upload
if: ${{ contains(matrix.target, 'appimage') }}
if: ${{ contains(matrix.target, 'appimage') && env.SHOULD_RUN == 'true' }}
uses: actions/upload-artifact@v4
with:
name: ${{ env.OS }}-${{ env.TARGET }}

View file

@ -35,6 +35,7 @@
<string>cci</string>
<string>cxi</string>
<string>cia</string>
<string>3ds</string>
</array>
<key>CFBundleTypeName</key>
<string>Nintendo 3DS File</string>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

642
dist/languages/de.ts vendored

File diff suppressed because it is too large Load diff

640
dist/languages/el.ts vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

640
dist/languages/fi.ts vendored

File diff suppressed because it is too large Load diff

759
dist/languages/fr.ts vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

640
dist/languages/id.ts vendored

File diff suppressed because it is too large Load diff

644
dist/languages/it.ts vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

640
dist/languages/nb.ts vendored

File diff suppressed because it is too large Load diff

640
dist/languages/nl.ts vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

644
dist/languages/sv.ts vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -16,6 +16,7 @@
<expanded-acronym>CTR Cart Image</expanded-acronym>
<icon name="azahar"/>
<glob pattern="*.cci"/>
<glob pattern="*.3ds"/>
<magic><match value="NCSD" type="string" offset="256"/></magic>
</mime-type>

2
externals/sdl2/SDL vendored

@ -1 +1 @@
Subproject commit 2359383fc187386204c3bb22de89655a494cd128
Subproject commit 5d249570393f7a37e037abf22cd6012a4cc56a71

View file

@ -50,7 +50,7 @@ class SecondaryDisplay(val context: Context) : DisplayManager.DisplayListener {
val currentDisplayId = context.display.displayId
val displays = dm.displays
val presDisplays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
return displays.firstOrNull {
val extDisplays = displays.filter {
val isPresentable = presDisplays.any { pd -> pd.displayId == it.displayId }
val isNotDefaultOrPresentable = it.displayId != Display.DEFAULT_DISPLAY || isPresentable
isNotDefaultOrPresentable &&
@ -59,6 +59,10 @@ class SecondaryDisplay(val context: Context) : DisplayManager.DisplayListener {
it.state != Display.STATE_OFF &&
it.isValid
}
// if there is a display called Built-In Display or Built-In Screen, prioritize the OTHER screen
val selected = extDisplays.firstOrNull { ! it.name.contains("Built",true) }
?: extDisplays.firstOrNull()
return selected
}
fun updateDisplay() {

View file

@ -255,7 +255,9 @@ class InputBindingSetting(
} else {
buttonCode
}
writeAxisMapping(motionRange.axis, button, axisDir == '-')
// use UP (-) to map vertical, but use RIGHT (+) to map horizontal
val inverted = if (isHorizontalOrientation()) axisDir == '-' else axisDir == '+'
writeAxisMapping(motionRange.axis, button, inverted)
val uiString = "${device.name}: Axis ${motionRange.axis}" + axisDir
value = uiString
}

View file

@ -7,16 +7,12 @@ package org.citra.citra_emu.fragments
import android.annotation.SuppressLint
import android.net.Uri
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import androidx.core.text.HtmlCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
@ -50,7 +46,6 @@ class GamesFragment : Fragment() {
private val gamesViewModel: GamesViewModel by activityViewModels()
private val homeViewModel: HomeViewModel by activityViewModels()
private var show3DSFileWarning: Boolean = true
private lateinit var gameAdapter: GameAdapter
private val openImageLauncher = registerForActivityResult(
@ -224,34 +219,6 @@ class GamesFragment : Fragment() {
setInsets()
}
override fun onResume() {
super.onResume()
if (show3DSFileWarning &&
!PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
.getBoolean("show_3ds_files_warning", false)) {
val message = HtmlCompat.fromHtml(getString(R.string.warning_3ds_files),
HtmlCompat.FROM_HTML_MODE_LEGACY)
context?.let {
val alert = MaterialAlertDialogBuilder(it)
.setTitle(getString(R.string.important))
.setMessage(message)
.setPositiveButton(R.string.dont_show_again) { _, _ ->
PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
.edit() {
putBoolean("show_3ds_files_warning", true)
}
}
.show()
val alertMessage = alert.findViewById<View>(android.R.id.message) as TextView
alertMessage.movementMethod = LinkMovementMethod.getInstance()
}
}
show3DSFileWarning = false
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

View file

@ -66,7 +66,7 @@ class Game(
val allExtensions: Set<String> get() = extensions + badExtensions
val extensions: Set<String> = HashSet(
listOf("3dsx", "app", "axf", "cci", "cxi", "elf", "z3dsx", "zcci", "zcxi")
listOf("3dsx", "app", "axf", "cci", "cxi", "elf", "z3dsx", "zcci", "zcxi", "3ds")
)
val badExtensions: Set<String> = HashSet(

View file

@ -269,6 +269,8 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
system.GPU().ApplyPerProgramSettings(program_id);
std::unique_ptr<Frontend::GraphicsContext> cpu_context;
system.GPU().Renderer().Rasterizer()->LoadDefaultDiskResources(stop_run,
&LoadDiskCacheProgress);

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">Canvia els fitxers que Azahar utilitza per a carregar aplicacions</string>
<string name="theme_and_color_description">Modifica l\'aspecte de l\'app</string>
<string name="install_cia_title">Instal·lar CIA</string>
<string name="warning_3ds_files"><![CDATA[Els fitxers encriptats .3ds ja no són compatibles. Pot ser que siga necessari desencriptar-los o canviar-los de nom a .cci. <a href=\"https://azahar-emu.org/blog/game-loading-changes/\">Més Informació.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Seleccionar driver de GPU</string>
@ -112,8 +111,6 @@
<string name="controller_dpad_axis_description">És possible que alguns controladors no puguen assignar el D-pad com un eix. Si aquest és el cas, utilitza la secció D-Pad (botons).</string>
<string name="controller_dpad_button">D-Pad (Botó)</string>
<string name="controller_dpad_button_description">Assigna només el D-pad a aquests si tens problemes amb les assignacions de botons del D-Pad (Eix).</string>
<string name="controller_axis_vertical">Eix Vertical</string>
<string name="controller_axis_horizontal">Eix Horitzontal</string>
<string name="direction_up">Amunt</string>
<string name="direction_down">Avall</string>
<string name="direction_left">Esquerra</string>
@ -350,8 +347,6 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="auto_select">Auto-elegir</string>
<string name="start">Iniciar</string>
<string name="cancelling">Cancel·lant</string>
<string name="important">Important</string>
<string name="dont_show_again">No tornar a mostrar</string>
<string name="visibility">Visibilitat</string>
<string name="information">Informació</string>

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">Ændrer de filer, som Azahar bruger til at indlæse applikationer</string>
<string name="theme_and_color_description">Rediger appens udseende</string>
<string name="install_cia_title">Installer CIA</string>
<string name="warning_3ds_files"><![CDATA[Krypterede filer og .3ds filer understøttes ikke længere. Det kan være nødvendigt at dekryptere og/eller omdøbe til .cci.<a href=\"https://azahar-emu.org/blog/game-loading-changes/\">Lær mere.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Vælg GPU-driver</string>
@ -119,8 +118,6 @@
<string name="controller_dpad_axis_description">Nogle kontrollere er muligvis ikke i stand til at tilknytte deres D-Pad som en akse. Hvis det er tilfældet, skal du bruge afsnittet D-Pad (knapper).</string>
<string name="controller_dpad_button">D-Pad (knapper)</string>
<string name="controller_dpad_button_description">Udfyld kun disse D-Pad, hvis du har problemer med opsætningen af D-Pad (akser).</string>
<string name="controller_axis_vertical">Op/ned akse</string>
<string name="controller_axis_horizontal">Venstre/højre akse</string>
<string name="direction_up">Op</string>
<string name="direction_down">Ned</string>
<string name="direction_left">Venstre</string>
@ -129,8 +126,6 @@
<string name="input_dialog_description">Tryk på eller flyt et input.</string>
<string name="input_binding">Inputbinding</string>
<string name="input_binding_description">Tryk på eller flyt et input for at binde det til %1$s.</string>
<string name="input_binding_description_vertical_axis">Bevæg joysticket ned</string>
<string name="input_binding_description_horizontal_axis">Bevæg joysticket til højre</string>
<string name="button_home">HOME</string>
<string name="button_swap">Byt skærme</string>
<string name="button_turbo">Turbo</string>
@ -377,8 +372,6 @@
<string name="auto_select">Automatisk valg</string>
<string name="start">Start</string>
<string name="cancelling">Annullerer...</string>
<string name="important">Vigtig</string>
<string name="dont_show_again">Vis ikke igen</string>
<string name="visibility">Sigtbarhed</string>
<string name="information">Information</string>

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">Cambia los archivos que Azahar usa para cargar aplicaciones</string>
<string name="theme_and_color_description">Modifica el aspecto de la app</string>
<string name="install_cia_title">Instalar CIA</string>
<string name="warning_3ds_files"><![CDATA[Los archivos cifrados y .3ds ya no son compatibles. Puede que sea necesario descifrarlos o renombrarlos a .cci. <a href=\"https://azahar-emu.org/blog/game-loading-changes/\">Más Información.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Seleccionar driver de GPU</string>
@ -116,8 +115,6 @@
<string name="controller_dpad_axis_description">Es posible que algunos controladores no puedan asignar su D-pad como un eje. Si ese es el caso, utilice la sección D-Pad (botones).</string>
<string name="controller_dpad_button">D-Pad (Botón)</string>
<string name="controller_dpad_button_description">Asigne solo el D-pad a éstos si tiene problemas con las asignaciones de botones del D-Pad (Eje).</string>
<string name="controller_axis_vertical">Eje Vertical</string>
<string name="controller_axis_horizontal">Eje Horizontal</string>
<string name="direction_up">Arriba</string>
<string name="direction_down">Abajo</string>
<string name="direction_left">Izquierda</string>
@ -126,8 +123,6 @@
<string name="input_dialog_description">Pulsa o mueve un botón/palanca.</string>
<string name="input_binding">Asignación de botones</string>
<string name="input_binding_description">Pulsa o mueve un botón para asignarlo a %1$s.</string>
<string name="input_binding_description_vertical_axis">Mueve el joystick abajo</string>
<string name="input_binding_description_horizontal_axis">Mueve el joystick a la derecha</string>
<string name="button_home">HOME</string>
<string name="button_swap">Intercambiar Pantallas</string>
<string name="button_turbo">Turbo</string>
@ -368,8 +363,6 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="auto_select">Auto-elegir</string>
<string name="start">Iniciar</string>
<string name="cancelling">Cancelando...</string>
<string name="important">Importante</string>
<string name="dont_show_again">No volver a mostrar</string>
<string name="visibility">Visibilidad</string>
<string name="information">Información</string>

View file

@ -67,8 +67,6 @@
<string name="reset_all_settings">Atstatyti visus nustatymus?</string>
<string name="start">Pradėti</string>
<string name="cancelling">Atšaukiama...</string>
<string name="important">Svarbu</string>
<string name="dont_show_again">Daugiau niekada nerodyti</string>
<!-- Preferences Screen -->
<string name="preferences_settings">Nustatymai</string>
<string name="preferences_system">Sistema</string>

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">Zmienia pliki, których Azahar używa do ładowania aplikacji</string>
<string name="theme_and_color_description">Zmodyfikuj wygląd aplikacji</string>
<string name="install_cia_title">Instaluj CIA</string>
<string name="warning_3ds_files"><![CDATA[Zaszyfrowane pliki i pliki .3ds nie są już obsługiwane. Konieczne może być odszyfrowanie i/lub zmiana nazwy pliku na .cci. <a href=\"https://azahar-emu.org/blog/game-loading-changes/\">Więcej informacji.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Wybierz sterownik GPU</string>
@ -119,8 +118,8 @@
<string name="controller_dpad_axis_description">Niektóre kontrolery mogą nie być w stanie zmapować swojego D-pada jako osi. W takim przypadku należy użyć sekcji D-Pad (przyciski).</string>
<string name="controller_dpad_button">Krzyżak (Przycisk)</string>
<string name="controller_dpad_button_description">Zmapuj D-pad na te ustawienia tylko wtedy, gdy masz problemy z mapowaniem przycisków D-Pada (Oś).</string>
<string name="controller_axis_vertical">góra/dół</string>
<string name="controller_axis_horizontal">lewa/prawa</string>
<string name="controller_axis_vertical">pionowa</string>
<string name="controller_axis_horizontal">pozioma</string>
<string name="direction_up">Góra</string>
<string name="direction_down">Dół</string>
<string name="direction_left">Lewo</string>
@ -129,8 +128,8 @@
<string name="input_dialog_description">Naciśnij lub przenieś wejście.</string>
<string name="input_binding">Powiązanie wejścia</string>
<string name="input_binding_description">Naciśnij lub przesuń wejście, aby powiązać je z %1$s.</string>
<string name="input_binding_description_vertical_axis">Przesuń analog w dół.</string>
<string name="input_binding_description_horizontal_axis">Przesuń analog w prawo.</string>
<string name="input_binding_description_vertical_axis">Naciśnij joystick w górę.</string>
<string name="input_binding_description_horizontal_axis">Naciśnij joystick w prawo.</string>
<string name="button_home">HOME</string>
<string name="button_swap">Zamień ekrany</string>
<string name="button_turbo">Turbo</string>
@ -377,8 +376,6 @@
<string name="auto_select">Wybór automatyczny</string>
<string name="start">Rozpocznij</string>
<string name="cancelling">Anulowanie...</string>
<string name="important">Ważne</string>
<string name="dont_show_again">Nie pokazuj tego ponownie</string>
<string name="visibility">Widoczność</string>
<string name="information">Informacje</string>

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">Altera os arquivos que o Azahar usa para carregar aplicativos</string>
<string name="theme_and_color_description">Modificar a aparência do aplicativo</string>
<string name="install_cia_title">Instalar arquivo CIA</string>
<string name="warning_3ds_files"><![CDATA[Arquivos criptografados e arquivos .3ds não são mais suportados. Talvez seja necessário descriptografá-los e/ou renomeá-los para .cci. <a href=\"https://azahar-emu.org/blog/game-loading-changes/\">Saiba mais.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Selecionar driver da GPU</string>
@ -119,8 +118,6 @@
<string name="controller_dpad_axis_description">Alguns controles podem não ser capazes de mapear os D-pads para um eixo. Se esse for o caso, use a seção de D-Pad (Botões).</string>
<string name="controller_dpad_button">D-Pad (Botão)</string>
<string name="controller_dpad_button_description">Só mapeie o D-pad para isso se você se você estiver encontrando problemas com o mapeamento de botão do D-Pad (Eixo).</string>
<string name="controller_axis_vertical">Eixo vertical</string>
<string name="controller_axis_horizontal">Eixo horizontal</string>
<string name="direction_up">Cima</string>
<string name="direction_down">Baixo</string>
<string name="direction_left">Esquerda</string>
@ -129,8 +126,6 @@
<string name="input_dialog_description">Pressione ou mova uma entrada.</string>
<string name="input_binding">Mapeamento de controles</string>
<string name="input_binding_description">Pressione ou mova um botão/alavanca para mapear para %1$s.</string>
<string name="input_binding_description_vertical_axis">Mova o seu joystick para baixo</string>
<string name="input_binding_description_horizontal_axis">Mova o seu joystick para a direita</string>
<string name="button_home">Menu Principal</string>
<string name="button_swap">Trocar telas</string>
<string name="button_turbo">Turbo</string>
@ -377,8 +372,6 @@
<string name="auto_select">Seleção Automática</string>
<string name="start">Iniciar</string>
<string name="cancelling">Cancelando...</string>
<string name="important">Importante</string>
<string name="dont_show_again">Não mostrar novamente</string>
<string name="visibility">Visibilidade</string>
<string name="information">Informação</string>

View file

@ -19,6 +19,7 @@
<string name="about_description">Версия сборки, разработчики и другое</string>
<string name="theme_and_color_description">Настройка внешнего вида приложения</string>
<string name="install_cia_title">Установить CIA</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Выбрать драйвер GPU</string>
<string name="select_gpu_driver_title">Заменить текущий драйвер GPU устройства?</string>
@ -64,8 +65,6 @@
<string name="controller_triggers">Триггеры</string>
<string name="controller_trigger">Триггер</string>
<string name="controller_dpad">Крестовина</string>
<string name="controller_axis_vertical">Ось вверх/вниз</string>
<string name="controller_axis_horizontal">Ось влево/вправо</string>
<string name="input_dialog_title">Привязка %1$s %2$s</string>
<string name="input_dialog_description">Нажмите или отклоните элемент управления.</string>
<string name="input_binding">Привязки ввода</string>

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">Azahar\'ın uygulama yüklemek için kullandığı dosyaları değiştirir</string>
<string name="theme_and_color_description">Uygulamanın görünüşünü değiştir</string>
<string name="install_cia_title">CIA Yükle</string>
<string name="warning_3ds_files"><![CDATA[Şifrelenmiş dosyalar ve .3ds dosyaları artık desteklenmemektedir. Dosyanın şifresinin çözülmesi ve/veya .cci olarak yeniden adlandırması gerekli olabilir.<a href=\"https://azahar-emu.org/blog/game-loading-changes/\">Daha fazla öğren.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">GPU Sürücüsü seç</string>
@ -111,8 +110,6 @@
<string name="controller_dpad_axis_description">Bazı oyun kolları D-pad\'lerini bir eksen olarak atayamayabilir. Durum buysa D-Pad (butonlar) bölümünü kullanın.</string>
<string name="controller_dpad_button">D-pad (Buton)</string>
<string name="controller_dpad_button_description">Sadece D-Pad (Eksen) atamasında sorun yaşıyorsanız D-Pad\'inizi bunlara atayın.</string>
<string name="controller_axis_vertical">Yukarı/Aşağı Eksen</string>
<string name="controller_axis_horizontal">Sol/Sağ Eksen</string>
<string name="direction_up">Yukarı</string>
<string name="direction_down">Aşağı</string>
<string name="direction_left">Sol</string>
@ -329,8 +326,6 @@
<string name="auto_select">Otomatik Seç</string>
<string name="start">Başlat</string>
<string name="cancelling">İptal ediliyor...</string>
<string name="important">Önemli</string>
<string name="dont_show_again">Tekrar gösterme</string>
<string name="visibility">Görünürlük</string>
<string name="information">Bilgi</string>

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">更改 Azahar 用于加载应用的相关文件</string>
<string name="theme_and_color_description">更改应用程序的外观</string>
<string name="install_cia_title">安装 CIA</string>
<string name="warning_3ds_files"><![CDATA[加密文件和 3ds 后缀名文件不再受支持。可能需要解密和/或重命名为 cci 后缀名。<a href=\"https://azahar-emu.org/blog/game-loading-changes/\">了解详情。</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">选择 GPU 驱动</string>
@ -112,8 +111,6 @@
<string name="controller_dpad_axis_description">有些控制器可能无法将其方向键映射为轴。如果是这种情况,只能使用方向键(按键)部分。</string>
<string name="controller_dpad_button">十字键(按键)</string>
<string name="controller_dpad_button_description">仅当您在方向键 (轴) 映射遇到问题时,才将方向键映射到这些按键。</string>
<string name="controller_axis_vertical">上/下轴</string>
<string name="controller_axis_horizontal">左/右轴</string>
<string name="direction_up"></string>
<string name="direction_down"></string>
<string name="direction_left"></string>
@ -358,8 +355,6 @@
<string name="auto_select">自动选择</string>
<string name="start">开始</string>
<string name="cancelling">取消中…</string>
<string name="important">重要提示</string>
<string name="dont_show_again">不再显示</string>
<string name="visibility">可见度</string>
<string name="information">信息</string>

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">Ändere die Dateien, die Azahar nutzt, um Anwendungen zu laden</string>
<string name="theme_and_color_description">Ändere das Aussehen der App</string>
<string name="install_cia_title">CIA Installieren</string>
<string name="warning_3ds_files"><![CDATA[Verschlüsselte Dateien und .3ds-Dateien werden nicht mehr unterstützt. Eine Entschlüsselung und/oder Umbenennung in .cci kann erforderlich sein. <a href=\"https://azahar-emu.org/blog/game-loading-changes/\">Erfahre mehr.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">GPU-Treiber auswählen</string>
@ -112,8 +111,6 @@
<string name="controller_dpad_axis_description">Einige Controller sind nicht in der Lage, das Steuerkreuz als Achse zuzuordnen. Wenn das der Fall ist, dann nutze den Abschnitt: „Steuerkreuz (Knöpfe)“.</string>
<string name="controller_dpad_button">Steuerkreuz (Knöpfe)</string>
<string name="controller_dpad_button_description">Nutze diese Funktion nur, wenn du Probleme mit der Funktion „Steuerkreuz (Achse) hast“.</string>
<string name="controller_axis_vertical">Achse (Oben/Unten)</string>
<string name="controller_axis_horizontal">Achse (Links/Rechts)</string>
<string name="direction_up">Hoch</string>
<string name="direction_down">Runter</string>
<string name="direction_left">Links</string>
@ -349,8 +346,6 @@
<string name="auto_select">Automatisch auswählen</string>
<string name="start">Start</string>
<string name="cancelling">Wird abgebrochen...</string>
<string name="important">Wichtig</string>
<string name="dont_show_again">Nicht noch einmal anzeigen</string>
<string name="visibility">Sichtbarkeit</string>
<string name="information">Information</string>

View file

@ -4,6 +4,7 @@
<string name="install_game_content">Εγκατάσταση αρχείου CIA</string>
<string name="about">Σχετικά</string>
<string name="install_cia_title">Εγκατάσταση CIA</string>
<string name="select_gpu_driver_install">Εγκατάσταση</string>
<string name="select_gpu_driver_install_success">Εγκαταστάθηκε %s</string>
</resources>

View file

@ -6,8 +6,6 @@
<string name="controller_c">C-Tikku</string>
<string name="controller_triggers">Liipaisimet</string>
<string name="controller_dpad">D-Pad</string>
<string name="controller_axis_vertical">Ylä/ala-akseli</string>
<string name="controller_axis_horizontal">Vasen/oikea akseli</string>
<!-- Generic buttons (Shared with lots of stuff) -->
<string name="generic_buttons">Nappulat</string>
<string name="init_clock">Järjestelmän kellotyyppi</string>

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">Modifie les fichiers utilisés par Azahar pour charger les applications</string>
<string name="theme_and_color_description">Modifier l\'apparence de l\'application</string>
<string name="install_cia_title">Installer un CIA</string>
<string name="warning_3ds_files"><![CDATA[Les fichiers cryptés et les fichiers .3ds ne sont plus pris en charge. Il peut être nécessaire de les décrypter et/ou de les renommer en .cci. <a href=\"https://azahar-emu.org/blog/game-loading-changes/\">En savoir plus.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Sélectionner le pilote du GPU</string>
@ -67,10 +66,14 @@
<string name="give_permission">Accorder l\'autorisation</string>
<string name="notification_warning">Ne pas autoriser les notifications ?</string>
<string name="notification_warning_description">Azahar ne pourra pas vous avertir des informations importantes.</string>
<string name="filesystem_permission_warning">Autorisations manquantes</string>
<string name="filesystem_permission_warning_description">Azahar a besoin de l\'autorisation de gérer les fichiers de cet appareil afin de stocker et gérer ses données.\n\nVeuillez accorder l\'autorisation \"Accès à tous les fichiers\" avant de continuer.</string>
<string name="camera_permission">Caméra</string>
<string name="camera_permission_description">Accorder l\'autorisation de la caméra ci-dessous pour émuler la caméra 3DS.</string>
<string name="microphone_permission">Microphone</string>
<string name="microphone_permission_description">Accorder l\'autorisation du microphone ci-dessous pour émuler le microphone 3DS.</string>
<string name="filesystem_permission">Accès à tous les fichiers</string>
<string name="filesystem_permission_description">Accordez l\'autorisation de l\'accès à tous les fichiers ci-dessous pour autoriser Azahar à stocker des fichiers.</string>
<string name="permission_denied">Autorisation refusée</string>
<string name="add_games_warning">Passer la sélection du dossier des applications ?</string>
<string name="add_games_warning_description">Les logiciels ne seront pas affichés dans la liste des applications si un dossier n\'est pas sélectionné.</string>
@ -90,6 +93,9 @@
<string name="cannot_skip">Vous ne pouvez pas ignorer la configuration du dossier utilisateur</string>
<string name="cannot_skip_directory_description">Cette étape est requise pour permettre à Azahar de fonctionner. Sélectionnez un répertoire et ensuite vous pourrez continuer.</string>
<string name="selecting_user_directory_without_write_permissions">Vous avez perdu les droits d\'écriture sur votre répertoire de <a href="https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage">données utilisateur</a>, où sont stockées les sauvegardes et autres informations. Cela peut se produire après certaines mises à jour d\'applications ou d\'Android. Veuillez resélectionner le répertoire pour récupérer les droits d\'accès afin de pouvoir continuer.</string>
<string name="invalid_selection">Sélection Invalide</string>
<string name="invalid_user_directory">La sélection du répertoire utilisateur était invalide.\nVeuillez re-sélectionner le répertoire utilisateur, en s\'assurant de le sélectionner depuis la racine du stockage de votre appareil.</string>
<string name="filesystem_permission_lost">Azahar a perdu l\'autorisation de gérer les fichiers de cet appareil. Cela peut arriver suite à des mises à jour d\'applis ou d\'Android. Veuillez ré-accorder cette autorisation sur l\'écran suivant pour continuer d\'utiliser l\'appli.</string>
<string name="set_up_theme_settings">Paramètres du thème</string>
<string name="setup_theme_settings_description">Configurez les préférences de votre thème pour Azahar.</string>
<string name="setup_set_theme">Mettre le thème</string>
@ -112,8 +118,8 @@
<string name="controller_dpad_axis_description">Certaines manettes ne sont pas en mesure d\'affecter leur manette + à un axe. Dans ce cas, utilisez la section manette + (boutons).</string>
<string name="controller_dpad_button">Manette + (bouton)</string>
<string name="controller_dpad_button_description">N\'affectez la manette + à ces boutons que si vous rencontrez des problèmes avec l\'affectation des boutons de la manette + (axes).</string>
<string name="controller_axis_vertical">Axe Haut/Bas</string>
<string name="controller_axis_horizontal">Axe Gauche/Droite</string>
<string name="controller_axis_vertical">Axe Vertical</string>
<string name="controller_axis_horizontal">Axe Horizontal</string>
<string name="direction_up">Haut</string>
<string name="direction_down">Bas</string>
<string name="direction_left">Gauche</string>
@ -122,6 +128,8 @@
<string name="input_dialog_description">Appuyez ou faites bouger une touche.</string>
<string name="input_binding">Liaison de boutons</string>
<string name="input_binding_description">Appuyez ou déplacez pour la rattacher à %1$s.</string>
<string name="input_binding_description_vertical_axis">Déplacez votre joystick vers le HAUT.</string>
<string name="input_binding_description_horizontal_axis">Déplacez votre joystick vers la DROITE.</string>
<string name="button_home">HOME</string>
<string name="button_swap">Permuter les écrans</string>
<string name="button_turbo">Turbo</string>
@ -160,6 +168,8 @@
<string name="username">Nom d\'utilisateur</string>
<string name="new_3ds">Mode New 3DS</string>
<string name="lle_applets">Utilise les applets LLE (si installés)</string>
<string name="apply_region_free_patch">Appliquer des correctifs pour désactiver les restrictions régionales des applications installées</string>
<string name="apply_region_free_patch_desc">Corrige la région des applications installées pour qu\'elles soient sans région, afin qu\'elles apparaissent toujours dans le menu home.</string>
<string name="enable_required_online_lle_modules">Activer les modules LLE requis pour les fonctionnalités en ligne (si installés)</string>
<string name="enable_required_online_lle_modules_desc">Active les modules LLE nécessaires pour le multijoueur en ligne, l\'accès à l\'eShop, etc.</string>
<string name="clock">Horloge</string>
@ -215,22 +225,27 @@
<string name="spirv_shader_gen_description">Émet le shader de fragment utilisé pour émuler PICA en utilisant SPIR-V plutôt que GLSL</string>
<string name="disable_spirv_optimizer">Désactiver l\'optimiseur SPIR-V</string>
<string name="disable_spirv_optimizer_description">Désactive le passage d\'optimisation SPIR-V, ce qui réduit considérablement les ralentissements sans affecter les performances.</string>
<string name="async_shaders">Activer la compilation asynchrone des shaders</string>
<string name="async_shaders_description">Compile les shaders en arrière-plan pour réduire les saccades pendant le jeu. Lorsqu\'il est activé, prévoyez des problèmes graphiques temporaires.</string>
<string name="linear_filtering">Filtrage linéaire</string>
<string name="linear_filtering_description">Active le filtrage linéaire, qui améliorera le lissage graphique du jeu.</string>
<string name="texture_filter_name">Filtrage des textures</string>
<string name="texture_filter_description">Améliore l\'aspect visuel des applications en appliquant un filtre aux textures. Les filtres pris en charge sont Anime4K Ultrafast, Bicubique, ScaleForce, xBRZ freescale et MMPX.</string>
<string name="delay_render_thread">Retarder le thread de rendu du jeu</string>
<string name="delay_render_thread_description">Délai le thread de rendu du jeu lorsqu\'il soumet des données au GPU. Cela permet de résoudre les problèmes de performance dans les (très rares) applications avec des fréquences d\'images dynamiques.</string>
<string name="advanced">Avancé</string>
<string name="texture_sampling_name">Échantillonnage de texture</string>
<string name="texture_sampling_description">Remplace le filtre d\'échantillonnage utilisé par les jeux. Cela peut être utile dans certains cas où les jeux se comportent mal lors de la conversion ascendante. En cas de doute, réglez ce paramètre sur « Contrôlé par le jeu ».</string>
<string name="shaders_accurate_mul">Multiplication précise</string>
<string name="shaders_accurate_mul_description">Utilise une multiplication plus précise dans les shaders hardware, ce qui peut corriger certains bugs graphiques. Lorsqu\'elle est activée, la performance sera réduite.</string>
<string name="asynchronous_gpu">Activer l\'émulation asynchrone du GPU</string>
<string name="asynchronous_gpu_description">Utilise une unité dexécution séparée pour émuler le GPU de manière asynchrone. La performance sera améliorée.</string>
<string name="frame_limit_enable">Limite de vitesse</string>
<string name="frame_limit_enable_description">Une fois activée, la vitesse d\'émulation sera limitée à un pourcentage spécifié de la vitesse normale. Si elle est désactivée, la vitesse d\'émulation ne sera pas limitée et le raccourci clavier turbo ne fonctionnera pas.</string>
<string name="frame_limit_slider">Limiter le pourcentage de vitesse</string>
<string name="frame_limit_slider_description">Définit le taux de limitation de la vitesse d\'émulation. À 100%, par défaut, l\'émulation sera limitée à la vitesse normale. Des valeurs supérieures ou inférieures augmenteront ou diminueront la limite de la vitesse.</string>
<string name="android_hide_images">Cacher à Android les images 3DS</string>
<string name="android_hide_images_description">Empêche les photos, captures d\'écran et textures personnalisées 3DS d\'être indexées par Android et affichées dans la galerie. Votre appareil pourrait nécessiter un redémarrage pour que ce paramètre prenne effet après son changement.</string>
<string name="turbo_limit">Turbo Speed Limite</string>
<string name="turbo_limit_description">Limite de vitesse d\'émulation utilisée lorsque la touche de raccourci turbo est active.</string>
<string name="expand_to_cutout_area">Étendre à la zone de découpe</string>
@ -252,10 +267,18 @@
<string name="debug_warning">Attention : Modifier ces paramètres ralentira l\'émulation</string>
<string name="stereoscopy">Stéréoscopie</string>
<string name="render3d">Mode 3D stéréoscopique</string>
<string name="render3d_description">Choisissez le mode de 3D stéréoscopique pour l\'affichage 3D. Les modes Côte à Côte sont les plus courants en utilisation moderne. Les modes Anaglyphe et Entrelacé seront toujours appliqués à tout les écrans connectés.</string>
<string name="factor3d">Profondeur</string>
<string name="factor3d_description">Spécifie la valeur du curseur 3D. Cette valeur doit être supérieure à 0 % lorsque la 3D stéréoscopique est activée. Remarque : les valeurs de profondeur supérieures à 100 % ne sont pas possibles sur du matériel réel et peuvent entraîner des problèmes graphiques.</string>
<string name="disable_right_eye_render">Désactiver le rendu de l\'œil droit</string>
<string name="disable_right_eye_render_description">Améliore considérablement les performances dans certaines applications, mais peut provoquer des scintillements dans d\'autres.</string>
<string name="swap_eyes_3d">Intervertir les yeux</string>
<string name="swap_eyes_3d_description">Intervertis quel œil est affiché de quel côté. Combiné avec le mode Côte à Côte il est possible de voir en 3D en croisant vos yeux !</string>
<string name="render_3d_which_display">Afficher la 3D stéréoscopique</string>
<string name="render_3d_which_display_description">Choisir s\'il faut activer la 3D stéréoscopique, et sur quel(s) écran(s). Les options d\'écran unique ne sont utiles que lorsque plusieurs écrans sont connectés.</string>
<string name="render_3d_which_display_both">Activé (Tous les écrans)</string>
<string name="render_3d_which_display_primary">Activé (Écran principal uniquement)</string>
<string name="render_3d_which_display_secondary">Activé (Écran secondaire uniquement)</string>
<string name="cardboard_vr">Réalité virtuelle Cardboard</string>
<string name="cardboard_screen_size">Taille de l\'écran Cardboard</string>
<string name="cardboard_screen_size_description">Redimensionne l\'écran à un pourcentage de sa taille d\'origine.</string>
@ -280,6 +303,7 @@
<string name="audio_volume">Volume</string>
<string name="audio_stretch">Étirement audio</string>
<string name="audio_stretch_description">Étire le son pour réduire les saccades. Lorsqu\'il est activé, la latence est augmentée et les performances sont légèrement réduites.</string>
<string name="realtime_audio">Activer l\'audio en temps réel</string>
<string name="realtime_audio_description">Adapte la vitesse de lecture de l\'audio afin de ne pas être perturbé par les pertes de framerate. Ceci veut dire que l\'audio sera joué correctement même si le jeu n\'est pas aussi rapide. Peut provoquer des problèmes de synchronisation audio.</string>
<string name="audio_input_type">Périphérique d\'entrée audio</string>
<string name="sound_output_mode">Mode de sortie audio</string>
@ -291,9 +315,12 @@
<string name="hw_shaders_description">Utilise le hardware pour émuler les shaders de la 3DS. Lorsqu\'il est activé, la performance des jeux sera améliorée de manière significative.</string>
<string name="cpu_clock_speed">Fréquence d\'horloge du CPU</string>
<string name="vsync">Activer la synchronisation verticale (VSync)</string>
<string name="vsync_description">Synchronise la fréquence d\'images du jeu avec la fréquence de rafraîchissement de votre appareil. Peut rajouter de la latence d\'entrée mais peut réduire le tearing dans certains cas.</string>
<string name="renderer_debug">Rendu de débogage</string>
<string name="renderer_debug_description">Enregistre des informations de débogage supplémentaires liées aux graphiques. Lorsqu\'il est activé, les performances du jeu seront significativement réduites.</string>
<string name="instant_debug_log">Vider la sortie des logs sur chaque message</string>
<string name="instant_debug_log_description">Enregistre immédiatement le log de débogage dans un fichier. A utiliser si Azahar se plante et que la sortie du journal est coupée.</string>
<string name="delay_start_lle_modules">Démarrage différé avec les modules LLE</string>
<string name="delay_start_lle_modules_description">Retarde le démarrage de l\'application lorsque les modules LLE sont activés.</string>
<string name="deterministic_async_operations">Opérations asynchrones déterministes</string>
<string name="deterministic_async_operations_description">Rend les opérations asynchrones déterministes pour le débogage. L\'activation de cette fonction peut entraîner des blocages.</string>
@ -349,8 +376,6 @@
<string name="auto_select">Sélection Automatique</string>
<string name="start">Démarrer</string>
<string name="cancelling">Annulation...</string>
<string name="important">Important</string>
<string name="dont_show_again">Ne pas montrer à nouveau</string>
<string name="visibility">Visibilité</string>
<string name="information">Information</string>
@ -407,6 +432,8 @@
<string name="emulation_aspect_ratio">Rapport d\'aspect</string>
<string name="emulation_switch_screen_layout">Disposition en mode paysage</string>
<string name="emulation_switch_portrait_layout">Disposition en mode portait</string>
<string name="emulation_switch_secondary_layout">Disposition de l\'écran secondaire</string>
<string name="emulation_switch_secondary_layout_description">La disposition utilisée par un écran secondaire connecté par câble ou sans fil (Chromecast, Miracast)</string>
<string name="emulation_screen_layout_largescreen">Écran large</string>
<string name="emulation_screen_layout_portrait">Mode portrait</string>
<string name="emulation_screen_layout_single">Un seul écran</string>
@ -414,7 +441,15 @@
<string name="emulation_screen_layout_hybrid">Écrans hybrides</string>
<string name="emulation_screen_layout_original">Original</string>
<string name="emulation_portrait_layout_top_full">Défaut</string>
<string name="emulation_secondary_display_default">Par défaut (dupliquer)</string>
<string name="emulation_screen_layout_custom">Disposition personnalisée</string>
<string name="bg_color">Couleur de fond</string>
<string name="bg_color_description">La couleur qui apparaît derrière les écrans pendant l\'émulation, représentée par une valeur RGB.</string>
<string name="bg_red">Rouge</string>
<string name="bg_green">Vert</string>
<string name="bg_blue">Bleu</string>
<string name="second_screen_opacity">Opacité du deuxième écran dans la disposition personnalisée</string>
<string name="second_screen_opacity_description">L\'opacité du deuxième écran 3DS lors de l\'utilisation d\'une disposition personnalisée. Utile si le deuxième écran est au-dessus du premier.</string>
<string name="emulation_small_screen_position">Position petit écran</string>
<string name="small_screen_position_description">Où le petit écran doit-il apparaître par rapport au grand écran dans la disposition Écran large ?</string>
<string name="small_screen_position_top_right">En haut à droite</string>
@ -510,6 +545,9 @@
<string name="fatal_error">Erreur fatale</string>
<string name="fatal_error_message">Une erreur fatale s\'est produite. Veuillez consulter les logs pour plus de détails.\nPoursuivre l\'émulation peut entraîner des plantages et des bugs.</string>
<string name="unsupported_encrypted">Application encryptée non supportée</string>
<string name="invalid_system_mode">Mode système invalide</string>
<string name="invalid_system_mode_message">Les applications exclusives à la New 3DS ne peuvent pas être chargées sans activer le mode New 3DS.</string>
<!-- Disk Shader Cache -->
<string name="preparing_shaders">Préparation des shaders</string>
<string name="building_shaders">Construction des shaders</string>
@ -536,11 +574,37 @@
<string name="game_context_id">ID :</string>
<string name="game_context_file">Fichier :</string>
<string name="game_context_type">Type :</string>
<string name="game_context_insert">Insérer Cartouche</string>
<string name="game_context_eject">Éjecter Cartouche</string>
<!-- Performance Overlay settings -->
<string name="performance_overlay_show">Afficher l\'overlay des performances</string>
<string name="performance_overlay_options">Overlay des performances</string>
<string name="performance_overlay_enable">Activer l\'overlay des performances</string>
<string name="performance_overlay_options_description">Configurez si l\'overlay des performances doit être affichée et quelles informations doivent être affichées.</string>
<string name="performance_overlay_show_fps">Afficher IPS</string>
<string name="performance_overlay_show_fps_description">Afficher le nombre actuel d\'images par seconde.</string>
<string name="performance_overlay_show_frametime">Afficher le temps d\'affichage d\'une image</string>
<string name="performance_overlay_show_frametime_description">Afficher le temps d\'affichage actuel d\'une image.</string>
<string name="performance_overlay_show_speed">Afficher la vitesse</string>
<string name="performance_overlay_show_speed_description">Afficher le pourcentage actuel de la vitesse d\'émulation.</string>
<string name="performance_overlay_show_app_ram_usage">Afficher l\'utilisation de la mémoire par l\'application</string>
<string name="performance_overlay_show_app_ram_usage_description">Affichez la quantité de RAM utilisée par l\'émulateur.</string>
<string name="performance_overlay_show_available_ram">Afficher la mémoire disponible</string>
<string name="performance_overlay_show_available_ram_description">Afficher la quantité de RAM disponible.</string>
<string name="performance_overlay_show_battery_temp">Afficher la température de la batterie</string>
<string name="performance_overlay_show_battery_temp_description">Afficher la température actuelle de la batterie en degrés Celsius et Fahrenheit.</string>
<string name="performance_overlay_position">Position de l\'overlay</string>
<string name="performance_overlay_position_description">Choisissez l\'emplacement d\'affichage de l\'overlay des performances à l\'écran.</string>
<string name="performance_overlay_position_top_left">En haut à gauche</string>
<string name="performance_overlay_position_top_right">En haut à droite</string>
<string name="performance_overlay_position_bottom_left">En bas à gauche</string>
<string name="performance_overlay_position_bottom_right">En bas à droite</string>
<string name="performance_overlay_position_center_top">Au centre en haut</string>
<string name="performance_overlay_position_center_bottom">Au centre en bas</string>
<string name="performance_overlay_background">Arrière-plan de l\'overlay</string>
<string name="performance_overlay_background_description">Ajoute un arrière-plan derrière l\'overlay pour faciliter la lecture.</string>
<!-- Cheats -->
<string name="cheats">Codes de triche</string>
<string name="cheats_add">Ajouter un code de triche</string>
@ -644,6 +708,7 @@
<!-- Render 3D modes -->
<string name="side_by_side">Côte à côte</string>
<string name="side_by_side_full">Côte à côte largeur maximale</string>
<string name="anaglyph">Anaglyphe</string>
<string name="interlaced">Entrelacé</string>
<string name="reverse_interlaced">Entrelacement inversé</string>
@ -832,4 +897,19 @@
<string name="emulation_occupied_quicksave_slot">Sauvegarde rapide - %1$tF %1$tR</string>
<string name="quickload_not_found">Aucune sauvegarde rapide disponible.</string>
</resources>
<!-- File Compression -->
<string name="compress">Compresser</string>
<string name="compressing">Compression ...</string>
<string name="decompress">Décompresser</string>
<string name="decompressing">Décompression ...</string>
<string name="compress_success">La compression a été réalisée avec succès.</string>
<string name="compress_unsupported">La compression n\'est pas supportée pour ce fichier.</string>
<string name="compress_already">Le fichier est déjà compressé.</string>
<string name="compress_failed">Échec de la compression.</string>
<string name="decompress_success">La décompression a été réalisée avec succès.</string>
<string name="decompress_unsupported">La décompression n\'est pas supportée pour ce fichier.</string>
<string name="decompress_not_compressed">Le fichier n\'est pas compressé.</string>
<string name="decompress_failed">Échec de la décompression.</string>
<string name="compress_decompress_installed_app">Les applications déjà installées ne peuvent pas être compressées ou décompressées.</string>
</resources>

View file

@ -19,6 +19,7 @@
<string name="about_description">Versi build, Kredit, dan lainnya</string>
<string name="theme_and_color_description">Ubah tampilan aplikasi</string>
<string name="install_cia_title">Install CIA</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Pilih driver GPU</string>
<string name="select_gpu_driver_title">Apakah anda ingin untuk mengganti driver GPU mu saat ini?</string>

View file

@ -36,7 +36,6 @@ Controlla ancora questa opzione in futuro per controllare se il supporto è stat
<string name="select_citra_user_folder_home_description">Cambia i file che Azahar usa per caricare le applicazioni</string>
<string name="theme_and_color_description">Modifica l\'aspetto dell\'app</string>
<string name="install_cia_title">Installa CIA</string>
<string name="warning_3ds_files"><![CDATA[File criptati e file .3ds non sono più supportati. Decriptare o rinominare i file in .cci potrebbe essere necessario <a href=\"https://azahar-emu.org/blog/game-loading-changes/\">Scopri di più.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Seleziona il driver GPU</string>
@ -134,8 +133,6 @@ Divertiti usando l\'emulatore!</string>
<string name="input_dialog_description">Premi o sposta un comando</string>
<string name="input_binding">Assegnazione Input</string>
<string name="input_binding_description">Premi o muovi un comando per assegnarlo a %1$s.</string>
<string name="input_binding_description_vertical_axis">Sposta il joystick verso il basso</string>
<string name="input_binding_description_horizontal_axis">Sposta il joystick verso destra</string>
<string name="button_home">Home</string>
<string name="button_swap">Inverti schermi</string>
<string name="button_turbo">Turbo</string>
@ -382,8 +379,6 @@ Divertiti usando l\'emulatore!</string>
<string name="auto_select">Seleziona automaticamente</string>
<string name="start">Avvia</string>
<string name="cancelling">Annullamento in corso...</string>
<string name="important">Importante</string>
<string name="dont_show_again">Non mostrare più</string>
<string name="visibility">Visibilità</string>
<string name="information">Informazione</string>

View file

@ -8,8 +8,6 @@
<string name="controller_c">C-Spak</string>
<string name="controller_triggers">Utløser</string>
<string name="controller_dpad">Kontrollpluss</string>
<string name="controller_axis_vertical">Opp/Ned Akse</string>
<string name="controller_axis_horizontal">Venstre/Høyre Akse</string>
<string name="input_binding">Inngangsinnbinding</string>
<string name="input_binding_description">Trykk eller flytt en inngang for å binde den til %1$s.</string>
<string name="input_message_analog_only">Denne kontrollen må være bundet til en håndkontroller\'s analog spak eller kontrollpluss akse!</string>

View file

@ -24,6 +24,7 @@ Vink deze optie in de toekomst nogmaals aan om te zien of er ondersteuning is to
<string name="about_description">Bouwversie, credits en meer</string>
<string name="theme_and_color_description">Wijzig het uiterlijk van de app</string>
<string name="install_cia_title">Installeer CIA</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Selecteer GPU-stuurprogramma</string>
<string name="select_gpu_driver_title">Wilt u uw huidige GPU-driver vervangen?</string>
@ -83,8 +84,6 @@ Vink deze optie in de toekomst nogmaals aan om te zien of er ondersteuning is to
<string name="controller_dpad_axis_description">Sommige controllers kunnen hun D-pad mogelijk niet als as in kaart brengen. Als dat het geval is, gebruik dan de D-Pad (knoppen) sectie.</string>
<string name="controller_dpad_button">D-Pad (Knop)</string>
<string name="controller_dpad_button_description">Wijs het D-pad hier alleen aan toe als je problemen ondervindt met de toewijzing van de D-Pad (as)-knoppen.</string>
<string name="controller_axis_vertical">Op/neer-as</string>
<string name="controller_axis_horizontal">Links/rechts as</string>
<string name="direction_up">Op</string>
<string name="direction_down">Neer</string>
<string name="direction_left">Links</string>

View file

@ -32,7 +32,6 @@
<string name="select_citra_user_folder_home_description">Ändrar de filer som Azahar använder för att ladda applikationer</string>
<string name="theme_and_color_description">Modifiera utseendet på appen</string>
<string name="install_cia_title">Installera CIA</string>
<string name="warning_3ds_files"><![CDATA[Krypterade filer och .3ds-filer stöds inte längre. Det kan vara nödvändigt att dekryptera och/eller byta namn till .cci. <a href=\"https://azahar-emu.org/blog/game-loading-changes/\">Läs mer.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Välj GPU-drivrutin</string>
@ -119,8 +118,8 @@
<string name="controller_dpad_axis_description">Vissa styrenheter kanske inte kan mappa sina riktningsknappar som en axel. Om så är fallet, använd avsnittet Riktningsknappar (knappar).</string>
<string name="controller_dpad_button">Riktningsknappar (knapp)</string>
<string name="controller_dpad_button_description">Mappa endast D-pad till dessa om du har problem med knappmappningarna för D-pad (axel).</string>
<string name="controller_axis_vertical">Axel upp/ner</string>
<string name="controller_axis_horizontal">Vänster/höger-axel</string>
<string name="controller_axis_vertical">Vertikal axel</string>
<string name="controller_axis_horizontal">Horisontell axel</string>
<string name="direction_up">Upp</string>
<string name="direction_down">Ner</string>
<string name="direction_left">Vänster</string>
@ -129,8 +128,8 @@
<string name="input_dialog_description">Tryck på eller flytta en inmatning.</string>
<string name="input_binding">Inmatningsbindning</string>
<string name="input_binding_description">Tryck eller flytta en inmatning för att binda den till %1$s.</string>
<string name="input_binding_description_vertical_axis">Rör din joystick neråt</string>
<string name="input_binding_description_horizontal_axis">Rör din joystick åt höger</string>
<string name="input_binding_description_vertical_axis">Tryck UPP på din styrspak.</string>
<string name="input_binding_description_horizontal_axis">Tryck HÖGER på din styrspak.</string>
<string name="button_home">HOME</string>
<string name="button_swap">Byt skärm</string>
<string name="button_turbo">Turbo</string>
@ -377,8 +376,6 @@
<string name="auto_select">Autovälj</string>
<string name="start">Starta</string>
<string name="cancelling">Avbryter...</string>
<string name="important">Viktigt</string>
<string name="dont_show_again">Visa inte igen</string>
<string name="visibility">Synlighet</string>
<string name="information">Information</string>

View file

@ -36,7 +36,6 @@
<string name="select_citra_user_folder_home_description">Changes the files that Azahar uses to load applications</string>
<string name="theme_and_color_description">Modify the look of the app</string>
<string name="install_cia_title">Install CIA</string>
<string name="warning_3ds_files"><![CDATA[Encrypted files and .3ds files are no longer supported. Decrypting and/or renaming to .cci may be necessary. <a href="https://azahar-emu.org/blog/game-loading-changes/">Learn more.</a>]]></string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Select GPU driver</string>
@ -130,8 +129,8 @@
<string name="controller_dpad_axis_description">Some controllers may not be able to map their D-pad as an axis. If that\'s the case, use the D-Pad (buttons) section.</string>
<string name="controller_dpad_button">D-Pad (Button)</string>
<string name="controller_dpad_button_description">Only map the D-pad to these if you\'re facing issues with the D-Pad (Axis) button mappings.</string>
<string name="controller_axis_vertical">Up/Down Axis</string>
<string name="controller_axis_horizontal">Left/Right Axis</string>
<string name="controller_axis_vertical">Vertical Axis</string>
<string name="controller_axis_horizontal">Horizontal Axis</string>
<string name="direction_up">Up</string>
<string name="direction_down">Down</string>
<string name="direction_left">Left</string>
@ -140,8 +139,8 @@
<string name="input_dialog_description">Press or move an input.</string>
<string name="input_binding">Input Binding</string>
<string name="input_binding_description">Press or move an input to bind it to %1$s.</string>
<string name="input_binding_description_vertical_axis">Move your joystick down</string>
<string name="input_binding_description_horizontal_axis">Move your joystick right</string>
<string name="input_binding_description_vertical_axis">Press UP on your joystick.</string>
<string name="input_binding_description_horizontal_axis">Press RIGHT on your joystick.</string>
<string name="button_a" translatable="false">A</string>
<string name="button_b" translatable="false">B</string>
<string name="button_select" translatable="false">SELECT</string>
@ -398,8 +397,6 @@
<string name="auto_select">Auto-Select</string>
<string name="start">Start</string>
<string name="cancelling">Cancelling…</string>
<string name="important">Important</string>
<string name="dont_show_again">Don\'t show again</string>
<string name="visibility">Visibility</string>
<string name="information">Information</string>

View file

@ -63,6 +63,7 @@ if (ENABLE_QT AND UNIX AND NOT APPLE)
endif()
if (ENABLE_QT AND APPLE)
find_package(Qt6 REQUIRED COMPONENTS GuiPrivate)
target_link_libraries(citra_meta PRIVATE Qt6::GuiPrivate)
endif()

View file

@ -18,6 +18,7 @@
#include "core/3ds.h"
#include "core/core.h"
#include "core/frontend/framebuffer_layout.h"
#include "core/loader/loader.h"
#include "core/perf_stats.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
@ -78,6 +79,10 @@ void EmuThread::run() {
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
u64 program_id{};
system.GetAppLoader().ReadProgramId(program_id);
system.GPU().ApplyPerProgramSettings(program_id);
system.GPU().Renderer().Rasterizer()->LoadDefaultDiskResources(
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total);

View file

@ -171,12 +171,21 @@ void GMainWindow::ShowCommandOutput(std::string title, std::string message) {
#endif
}
bool IsPrerelease() {
bool IsPrereleaseBuild() {
return ((strstr(Common::g_build_fullname, "alpha") != NULL) ||
(strstr(Common::g_build_fullname, "beta") != NULL) ||
(strstr(Common::g_build_fullname, "rc") != NULL));
}
#ifdef ENABLE_QT_UPDATE_CHECKER
bool ShouldCheckForPrereleaseUpdates() {
const bool update_channel = UISettings::values.update_check_channel.GetValue();
const bool using_prerelease_channel =
(update_channel == UISettings::UpdateCheckChannels::PRERELEASE);
return (IsPrereleaseBuild() || using_prerelease_channel);
}
#endif
GMainWindow::GMainWindow(Core::System& system_)
: ui{std::make_unique<Ui::MainWindow>()}, system{system_}, movie{system.Movie()},
user_data_migrator{this}, config{std::make_unique<QtConfig>()}, emu_thread{nullptr} {
@ -406,7 +415,8 @@ GMainWindow::GMainWindow(Core::System& system_)
if (UISettings::values.check_for_update_on_start) {
update_future = QtConcurrent::run([]() -> QString {
const std::optional<std::string> latest_release_tag =
UpdateChecker::GetLatestRelease(IsPrerelease());
UpdateChecker::GetLatestRelease(ShouldCheckForPrereleaseUpdates());
if (latest_release_tag && latest_release_tag.value() != Common::g_build_fullname) {
return QString::fromStdString(latest_release_tag.value());
}
@ -3158,7 +3168,7 @@ void GMainWindow::OnCompressFile() {
QStringList filepaths =
QFileDialog::getOpenFileNames(this, tr("Load 3DS ROM Files"), UISettings::values.roms_path,
tr("3DS ROM Files (*.cia *.cci *.3dsx *.cxi)") +
tr("3DS ROM Files (*.cia *.cci *.3dsx *.cxi *.3ds)") +
QStringLiteral(";;") + tr("All Files (*.*)"));
QString out_path;
@ -3838,8 +3848,8 @@ static bool IsSingleFileDropEvent(const QMimeData* mime) {
return mime->hasUrls() && mime->urls().length() == 1;
}
static const std::array<std::string, 10> AcceptedExtensions = {
"cci", "cxi", "bin", "3dsx", "app", "elf", "axf", "zcci", "zcxi", "z3dsx"};
static const std::array<std::string, 11> AcceptedExtensions = {
"cci", "cxi", "bin", "3dsx", "app", "elf", "axf", "zcci", "zcxi", "z3dsx", "3ds"};
static bool IsCorrectFileExtension(const QMimeData* mime) {
const QString& filename = mime->urls().at(0).toLocalFile();
@ -4057,7 +4067,7 @@ void GMainWindow::OnEmulatorUpdateAvailable() {
update_prompt.exec();
if (update_prompt.button(QMessageBox::Yes) == update_prompt.clickedButton()) {
std::string update_page_url;
if (IsPrerelease()) {
if (ShouldCheckForPrereleaseUpdates()) {
update_page_url = "https://github.com/azahar-emu/azahar/releases";
} else {
update_page_url = "https://azahar-emu.org/pages/download/";

View file

@ -568,6 +568,7 @@ void QtConfig::ReadMiscellaneousValues() {
ReadBasicSetting(Settings::values.log_regex_filter);
ReadBasicSetting(Settings::values.enable_gamemode);
ReadBasicSetting(UISettings::values.check_for_update_on_start);
ReadBasicSetting(UISettings::values.update_check_channel);
qt_config->endGroup();
}
@ -845,7 +846,6 @@ void QtConfig::ReadUIGameListValues() {
ReadBasicSetting(UISettings::values.game_list_row_2);
ReadBasicSetting(UISettings::values.game_list_hide_no_icon);
ReadBasicSetting(UISettings::values.game_list_single_line_mode);
ReadBasicSetting(UISettings::values.show_3ds_files_warning);
ReadBasicSetting(UISettings::values.show_compat_column);
ReadBasicSetting(UISettings::values.show_region_column);
@ -1139,7 +1139,7 @@ void QtConfig::SaveMiscellaneousValues() {
WriteBasicSetting(Settings::values.log_regex_filter);
WriteBasicSetting(Settings::values.enable_gamemode);
WriteBasicSetting(UISettings::values.check_for_update_on_start);
WriteBasicSetting(UISettings::values.update_check_channel);
qt_config->endGroup();
}
@ -1363,7 +1363,6 @@ void QtConfig::SaveUIGameListValues() {
WriteBasicSetting(UISettings::values.game_list_row_2);
WriteBasicSetting(UISettings::values.game_list_hide_no_icon);
WriteBasicSetting(UISettings::values.game_list_single_line_mode);
WriteBasicSetting(UISettings::values.show_3ds_files_warning);
WriteBasicSetting(UISettings::values.show_compat_column);
WriteBasicSetting(UISettings::values.show_region_column);

View file

@ -44,7 +44,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ui->toggle_gamemode->setVisible(false);
#endif
#ifndef ENABLE_QT_UPDATE_CHECKER
ui->toggle_update_checker->setVisible(false);
ui->updates_group->setVisible(false);
#endif
SetupPerGameUI();
@ -92,6 +92,8 @@ void ConfigureGeneral::SetConfiguration() {
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
ui->toggle_update_checker->setChecked(
UISettings::values.check_for_update_on_start.GetValue());
ui->update_channel_combobox->setCurrentIndex(
UISettings::values.update_check_channel.GetValue());
#ifdef __unix__
ui->toggle_gamemode->setChecked(Settings::values.enable_gamemode.GetValue());
#endif
@ -179,6 +181,7 @@ void ConfigureGeneral::ApplyConfiguration() {
UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked();
UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
UISettings::values.check_for_update_on_start = ui->toggle_update_checker->isChecked();
UISettings::values.update_check_channel = ui->update_channel_combobox->currentIndex();
#ifdef __unix__
Settings::values.enable_gamemode = ui->toggle_gamemode->isChecked();
#endif
@ -211,5 +214,5 @@ void ConfigureGeneral::SetupPerGameUI() {
ui->general_group->setVisible(false);
ui->button_reset_defaults->setVisible(false);
ui->toggle_gamemode->setVisible(false);
ui->toggle_update_checker->setVisible(false);
ui->updates_group->setVisible(false);
}

View file

@ -16,6 +16,43 @@
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="updates_group">
<property name="title">
<string>Updates</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="toggle_update_checker">
<property name="text">
<string>Check for updates</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="update_channel_label">
<property name="text">
<string>Update Channel</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="update_channel_combobox">
<item>
<property name="text">
<string>Stable</string>
</property>
</item>
<item>
<property name="text">
<string>Prerelease</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="general_group">
<property name="title">
@ -57,13 +94,6 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_update_checker">
<property name="text">
<string>Check for updates</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -315,7 +345,6 @@
<tabstop>toggle_check_exit</tabstop>
<tabstop>toggle_background_pause</tabstop>
<tabstop>toggle_hide_mouse</tabstop>
<tabstop>toggle_update_checker</tabstop>
<tabstop>button_reset_defaults</tabstop>
</tabstops>
<resources/>

View file

@ -234,7 +234,7 @@
<item>
<widget class="QCheckBox" name="toggle_async_present">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Perform presentation on separate threads. Improves performance when using Vulkan in most applications.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Perform presentation on separate threads. Improves performance when using Vulkan in most applications. Adds ~1 frame of input lag.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable async presentation</string>

View file

@ -391,40 +391,6 @@ GameList::GameList(PlayTime::PlayTimeManager& play_time_manager_, GMainWindow* p
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
if (UISettings::values.show_3ds_files_warning.GetValue()) {
warning_layout = new QHBoxLayout;
deprecated_3ds_warning = new QLabel;
deprecated_3ds_warning->setText(
tr("IMPORTANT: Encrypted files and .3ds files are no longer supported. Decrypting "
"and/or renaming to .cci may be necessary. <a "
"href='https://azahar-emu.org/blog/game-loading-changes/'>Learn more.</a>"));
deprecated_3ds_warning->setOpenExternalLinks(true);
deprecated_3ds_warning->setStyleSheet(
QString::fromStdString("color: black; font-weight: bold;"));
warning_hide = new QPushButton(tr("Don't show again"));
warning_hide->setStyleSheet(
QString::fromStdString("color: blue; text-decoration: underline;"));
warning_hide->setFlat(true);
warning_hide->setCursor(Qt::PointingHandCursor);
connect(warning_hide, &QPushButton::clicked, [this]() {
warning_widget->setVisible(false);
UISettings::values.show_3ds_files_warning.SetValue(false);
});
warning_layout->addWidget(deprecated_3ds_warning);
warning_layout->addStretch();
warning_layout->addWidget(warning_hide);
warning_layout->setContentsMargins(3, 3, 3, 3);
warning_widget = new QWidget;
warning_widget->setStyleSheet(QString::fromStdString("background-color: khaki;"));
warning_widget->setLayout(warning_layout);
layout->addWidget(warning_widget);
}
layout->addWidget(tree_view);
layout->addWidget(search_field);
setLayout(layout);
@ -1107,19 +1073,27 @@ void GameList::LoadInterfaceLayout() {
}
const QStringList GameList::supported_file_extensions = {
QStringLiteral("3dsx"), QStringLiteral("elf"), QStringLiteral("axf"),
QStringLiteral("cci"), QStringLiteral("cxi"), QStringLiteral("app"),
QStringLiteral("z3dsx"), QStringLiteral("zcci"), QStringLiteral("zcxi"),
QStringLiteral("3dsx"), QStringLiteral("elf"), QStringLiteral("axf"), QStringLiteral("cci"),
QStringLiteral("cxi"), QStringLiteral("app"), QStringLiteral("z3dsx"), QStringLiteral("zcci"),
QStringLiteral("zcxi"), QStringLiteral("3ds"),
};
void GameList::RefreshGameDirectory() {
// Do not scan directories when the system is powered on, it will be
// repopulated on shutdown anyways.
if (Core::System::GetInstance().IsPoweredOn()) {
return;
}
const auto time_now = std::chrono::steady_clock::now();
// Max of 1 refresh every 1 second.
if (time_last_refresh + std::chrono::seconds(1) > time_now) {
return;
}
time_last_refresh = time_now;
if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) {
LOG_INFO(Frontend, "Change detected in the applications directory. Reloading game list.");
PopulateAsync(UISettings::values.game_dirs);

View file

@ -135,10 +135,6 @@ private:
void changeEvent(QEvent*) override;
void RetranslateUI();
QHBoxLayout* warning_layout = nullptr;
QWidget* warning_widget = nullptr;
QLabel* deprecated_3ds_warning = nullptr;
QPushButton* warning_hide = nullptr;
GameListSearchField* search_field;
GMainWindow* main_window = nullptr;
QVBoxLayout* layout = nullptr;
@ -151,6 +147,8 @@ private:
friend class GameListSearchField;
const PlayTime::PlayTimeManager& play_time_manager;
std::chrono::time_point<std::chrono::steady_clock> time_last_refresh;
};
class GameListPlaceholder : public QWidget {

View file

@ -59,6 +59,12 @@ enum class GameListText : s32 {
ListEnd, ///< Keep this at the end of the enum.
};
class UpdateCheckChannels {
public:
static constexpr int STABLE = 0;
static constexpr int PRERELEASE = 1;
};
struct Values {
QByteArray geometry;
QByteArray state;
@ -84,6 +90,8 @@ struct Values {
Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
Settings::Setting<bool> hide_mouse{false, "hideInactiveMouse"};
Settings::Setting<bool> check_for_update_on_start{true, "check_for_update_on_start"};
Settings::Setting<int> update_check_channel{UpdateCheckChannels::STABLE,
"update_check_channel"};
Settings::Setting<std::string> inserted_cartridge{"", "inserted_cartridge"};
@ -97,7 +105,6 @@ struct Values {
Settings::Setting<GameListText> game_list_row_2{GameListText::FileName, "row2"};
Settings::Setting<bool> game_list_hide_no_icon{false, "hideNoIcon"};
Settings::Setting<bool> game_list_single_line_mode{false, "singleLineMode"};
Settings::Setting<bool> show_3ds_files_warning{true, "show_3ds_files_warning"};
// Compatibility List
Settings::Setting<bool> show_compat_column{true, "show_compat_column"};

View file

@ -474,6 +474,10 @@ int LaunchSdlFrontend(int argc, char** argv) {
}
});
u64 program_id{};
system.GetAppLoader().ReadProgramId(program_id);
system.GPU().ApplyPerProgramSettings(program_id);
std::atomic_bool stop_run;
system.GPU().Renderer().Rasterizer()->LoadDefaultDiskResources(
stop_run, [](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {

View file

@ -330,9 +330,9 @@ private:
}
backend_thread.request_stop();
backend_thread.join();
const auto signal_entry =
CreateEntry(Class::Log, Level::Critical, "?", 0, "?",
fmt::vformat("Received signal {}", fmt::make_format_args(sig)));
const auto signal_entry = CreateEntry(
Class::Log, Level::Critical, "?", 0, "?",
fmt::vformat("Received signal {}", fmt::make_format_args(sig)), time_origin);
ForEachBackend([&signal_entry](Backend& backend) {
backend.EnableForStacktrace();
backend.Write(signal_entry);
@ -345,12 +345,13 @@ private:
abort();
}
line.pop_back(); // Remove newline
const auto frame_entry =
CreateEntry(Class::Log, Level::Critical, "?", 0, "?", std::move(line));
const auto frame_entry = CreateEntry(Class::Log, Level::Critical, "?", 0, "?",
std::move(line), time_origin);
ForEachBackend([&frame_entry](Backend& backend) { backend.Write(frame_entry); });
}
using namespace std::literals;
const auto rip_entry = CreateEntry(Class::Log, Level::Critical, "?", 0, "?", "RIP"s);
const auto rip_entry =
CreateEntry(Class::Log, Level::Critical, "?", 0, "?", "RIP"s, time_origin);
ForEachBackend([&rip_entry](Backend& backend) {
backend.Write(rip_entry);
backend.Flush();

View file

@ -515,7 +515,11 @@ struct Values {
SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"};
SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
SwitchableSetting<bool> shaders_accurate_mul{true, "shaders_accurate_mul"};
#ifdef ANDROID // TODO: Fuck this -OS
SwitchableSetting<bool> use_vsync{false, "use_vsync"};
#else
SwitchableSetting<bool> use_vsync{true, "use_vsync"};
#endif
Setting<bool> use_shader_jit{true, "use_shader_jit"};
SwitchableSetting<u32, true> resolution_factor{1, 0, 10, "resolution_factor"};
SwitchableSetting<double, true> frame_limit{100, 0, 1000, "frame_limit"};

View file

@ -403,8 +403,6 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
kernel->UpdateCPUAndMemoryState(program_id, app_mem_mode, app_n3ds_hw_capabilities);
gpu->ReportLoadingProgramID(program_id);
// Restore any parameters that should be carried through a reset.
if (auto apt = Service::APT::GetModule(*this)) {
if (restore_deliver_arg.has_value()) {
@ -896,19 +894,26 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
timing->UnlockEventQueue();
cheat_engine.Connect(cheats_pid);
if (Settings::values.custom_textures) {
custom_tex_manager->FindCustomTextures();
}
// Re-register gpu callback, because gsp service changed after service_manager got
// serialized
auto gsp = service_manager->GetService<Service::GSP::GSP_GPU>("gsp::Gpu");
gpu->SetInterruptHandler(
[gsp](Service::GSP::InterruptId interrupt_id) { gsp->SignalInterrupt(interrupt_id); });
// Switch the shader cache to the title running when the savestate was created
// Apply per program settings and switch the shader cache to the title running when the
// savestate was created.
// TODO(PabloMK7): Find better way to obtain the program ID.
const u32 thread_id = gsp->GetActiveClientThreadId();
if (thread_id != std::numeric_limits<u32>::max()) {
const auto thread = kernel->GetThreadByID(thread_id);
if (thread) {
const std::shared_ptr<Kernel::Process> process = thread->owner_process.lock();
if (process) {
gpu->ApplyPerProgramSettings(process->codeset->program_id);
gpu->Renderer().Rasterizer()->SwitchDiskResources(process->codeset->program_id);
}
}

View file

@ -693,6 +693,7 @@ Result GSP_GPU::AcquireGpuRight(const Kernel::HLERequestContext& ctx,
Common::Hacks::HackAllowMode::DISALLOW) != Common::Hacks::HackAllowMode::DISALLOW;
auto& gpu = system.GPU();
gpu.ApplyPerProgramSettings(process->codeset->program_id);
gpu.GetRightEyeDisabler().SetEnabled(right_eye_disable_allow);
gpu.PicaCore().vs_setup.requires_fixup = requires_shader_fixup;
gpu.PicaCore().gs_setup.requires_fixup = requires_shader_fixup;

View file

@ -115,9 +115,10 @@ void PLG_LDR::OnProcessRun(Kernel::Process& process, Kernel::KernelSystem& kerne
}
}
FileSys::Plugin3GXLoader plugin_loader;
const auto low_title_Id = plgldr_context.user_load_parameters.low_title_Id;
if (plgldr_context.use_user_load_parameters &&
plgldr_context.user_load_parameters.low_title_Id ==
static_cast<u32>(process.codeset->program_id) &&
(low_title_Id == static_cast<u32>(process.codeset->program_id) ||
low_title_Id == 0 /* Should load for any title */) &&
plgldr_context.user_load_parameters.path[0]) {
std::string plugin_file = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) +
std::string(plgldr_context.user_load_parameters.path + 1);

View file

@ -178,7 +178,7 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(u32* cmd_buf, const Funct
void ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
auto itr = handlers.find(context.CommandHeader().command_id.Value());
const FunctionInfoBase* info = itr == handlers.end() ? nullptr : &itr->second;
if (info == nullptr || !info->implemented) {
if (info == nullptr || info->handler_callback == nullptr) {
context.ReportUnimplemented();
return ReportUnimplementedFunction(context.CommandBuffer(), info);
}

View file

@ -82,7 +82,6 @@ private:
struct FunctionInfoBase {
u32 command_id;
bool implemented;
HandlerFnP<ServiceFrameworkBase> handler_callback;
const char* name;
};
@ -97,8 +96,6 @@ private:
void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
void ReportUnimplementedFunction(u32* cmd_buf, const FunctionInfoBase* info);
void Empty(Kernel::HLERequestContext& ctx) {}
/// Identifier string used to connect to the service.
std::string service_name;
/// Maximum number of concurrent sessions that this service can handle.
@ -137,11 +134,9 @@ protected:
*/
constexpr FunctionInfo(u32 command_id, HandlerFnP<Self> handler_callback, const char* name)
: FunctionInfoBase{
command_id, handler_callback != nullptr,
command_id,
// Type-erase member function pointer by casting it down to the base class.
handler_callback ? static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback)
: &ServiceFrameworkBase::Empty,
name} {}
static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback), name} {}
};
/**

View file

@ -48,7 +48,7 @@ FileType GuessFromExtension(const std::string& extension_) {
if (extension == ".elf" || extension == ".axf")
return FileType::ELF;
if (extension == ".cci" || extension == ".zcci")
if (extension == ".cci" || extension == ".zcci" || extension == ".3ds")
return FileType::CCI;
if (extension == ".cxi" || extension == ".app" || extension == ".zcxi")

View file

@ -311,7 +311,7 @@ GraphicsDebugger& GPU::Debugger() {
return impl->gpu_debugger;
}
void GPU::ReportLoadingProgramID(u64 program_ID) {
void GPU::ApplyPerProgramSettings(u64 program_ID) {
auto hack = Common::Hacks::hack_manager.GetHack(
Common::Hacks::HackType::ACCURATE_MULTIPLICATION, program_ID);
bool use_accurate_mul = Settings::values.shaders_accurate_mul.GetValue();

View file

@ -94,7 +94,7 @@ public:
return *right_eye_disabler;
}
void ReportLoadingProgramID(u64 program_ID);
void ApplyPerProgramSettings(u64 program_ID);
private:
void SubmitCmdList(u32 index);

View file

@ -1,8 +1,7 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/settings.h"
#include "common/vector_math.h"
#include "video_core/renderer_vulkan/vk_blit_helper.h"
#include "video_core/renderer_vulkan/vk_descriptor_update_queue.h"
@ -17,19 +16,8 @@
#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag.h"
#include "video_core/host_shaders/vulkan_depth_to_buffer_comp.h"
// Texture filtering shader includes
#include "video_core/host_shaders/texture_filtering/bicubic_frag.h"
#include "video_core/host_shaders/texture_filtering/mmpx_frag.h"
#include "video_core/host_shaders/texture_filtering/refine_frag.h"
#include "video_core/host_shaders/texture_filtering/scale_force_frag.h"
#include "video_core/host_shaders/texture_filtering/x_gradient_frag.h"
#include "video_core/host_shaders/texture_filtering/xbrz_freescale_frag.h"
#include "video_core/host_shaders/texture_filtering/y_gradient_frag.h"
#include "vk_blit_helper.h"
namespace Vulkan {
using Settings::TextureFilter;
using VideoCore::PixelFormat;
namespace {
@ -67,33 +55,8 @@ constexpr std::array<vk::DescriptorSetLayoutBinding, 2> TWO_TEXTURES_BINDINGS =
{1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment},
}};
// Texture filtering descriptor set bindings
constexpr std::array<vk::DescriptorSetLayoutBinding, 1> SINGLE_TEXTURE_BINDINGS = {{
{0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment},
}};
constexpr std::array<vk::DescriptorSetLayoutBinding, 3> THREE_TEXTURES_BINDINGS = {{
{0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment},
{1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment},
{2, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment},
}};
// Note: Removed FILTER_UTILITY_BINDINGS as texture filtering doesn't need shadow buffers
// Push constant structure for texture filtering
struct FilterPushConstants {
std::array<float, 2> tex_scale;
std::array<float, 2> tex_offset;
float res_scale; // For xBRZ filter
};
inline constexpr vk::PushConstantRange FILTER_PUSH_CONSTANT_RANGE{
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
.offset = 0,
.size = sizeof(FilterPushConstants),
};
inline constexpr vk::PushConstantRange PUSH_CONSTANT_RANGE{
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
.stageFlags = vk::ShaderStageFlagBits::eVertex,
.offset = 0,
.size = sizeof(PushConstants),
};
@ -141,17 +104,12 @@ constexpr vk::PipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
.dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()),
.pDynamicStates = DYNAMIC_STATES.data(),
};
constexpr vk::PipelineColorBlendAttachmentState COLOR_BLEND_ATTACHMENT{
.blendEnable = VK_FALSE,
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
};
constexpr vk::PipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_CREATE_INFO{
constexpr vk::PipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{
.logicOpEnable = VK_FALSE,
.attachmentCount = 1,
.pAttachments = &COLOR_BLEND_ATTACHMENT,
.logicOp = vk::LogicOp::eClear,
.attachmentCount = 0,
.pAttachments = nullptr,
.blendConstants = std::array{0.0f, 0.0f, 0.0f, 0.0f},
};
constexpr vk::PipelineDepthStencilStateCreateInfo PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO{
.depthTestEnable = VK_TRUE,
@ -170,9 +128,9 @@ inline constexpr vk::SamplerCreateInfo SAMPLER_CREATE_INFO{
.magFilter = filter,
.minFilter = filter,
.mipmapMode = vk::SamplerMipmapMode::eNearest,
.addressModeU = vk::SamplerAddressMode::eClampToEdge,
.addressModeV = vk::SamplerAddressMode::eClampToEdge,
.addressModeW = vk::SamplerAddressMode::eClampToEdge,
.addressModeU = vk::SamplerAddressMode::eClampToBorder,
.addressModeV = vk::SamplerAddressMode::eClampToBorder,
.addressModeW = vk::SamplerAddressMode::eClampToBorder,
.mipLodBias = 0.0f,
.anisotropyEnable = VK_FALSE,
.maxAnisotropy = 0.0f,
@ -185,14 +143,12 @@ inline constexpr vk::SamplerCreateInfo SAMPLER_CREATE_INFO{
};
constexpr vk::PipelineLayoutCreateInfo PipelineLayoutCreateInfo(
const vk::DescriptorSetLayout* set_layout, bool compute = false, bool filter = false) {
const vk::DescriptorSetLayout* set_layout, bool compute = false) {
return vk::PipelineLayoutCreateInfo{
.setLayoutCount = 1,
.pSetLayouts = set_layout,
.pushConstantRangeCount = 1,
.pPushConstantRanges =
(compute ? &COMPUTE_PUSH_CONSTANT_RANGE
: (filter ? &FILTER_PUSH_CONSTANT_RANGE : &PUSH_CONSTANT_RANGE)),
.pPushConstantRanges = (compute ? &COMPUTE_PUSH_CONSTANT_RANGE : &PUSH_CONSTANT_RANGE),
};
}
@ -229,20 +185,12 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_,
compute_provider{instance, scheduler.GetMasterSemaphore(), COMPUTE_BINDINGS},
compute_buffer_provider{instance, scheduler.GetMasterSemaphore(), COMPUTE_BUFFER_BINDINGS},
two_textures_provider{instance, scheduler.GetMasterSemaphore(), TWO_TEXTURES_BINDINGS, 16},
single_texture_provider{instance, scheduler.GetMasterSemaphore(), SINGLE_TEXTURE_BINDINGS,
16},
three_textures_provider{instance, scheduler.GetMasterSemaphore(), THREE_TEXTURES_BINDINGS,
16},
compute_pipeline_layout{
device.createPipelineLayout(PipelineLayoutCreateInfo(&compute_provider.Layout(), true))},
compute_buffer_pipeline_layout{device.createPipelineLayout(
PipelineLayoutCreateInfo(&compute_buffer_provider.Layout(), true))},
two_textures_pipeline_layout{
device.createPipelineLayout(PipelineLayoutCreateInfo(&two_textures_provider.Layout()))},
single_texture_pipeline_layout{device.createPipelineLayout(
PipelineLayoutCreateInfo(&single_texture_provider.Layout(), false, true))},
three_textures_pipeline_layout{device.createPipelineLayout(
PipelineLayoutCreateInfo(&three_textures_provider.Layout(), false, true))},
full_screen_vert{Compile(HostShaders::FULL_SCREEN_TRIANGLE_VERT,
vk::ShaderStageFlagBits::eVertex, device)},
d24s8_to_rgba8_comp{Compile(HostShaders::VULKAN_D24S8_TO_RGBA8_COMP,
@ -251,14 +199,6 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_,
vk::ShaderStageFlagBits::eCompute, device)},
blit_depth_stencil_frag{Compile(HostShaders::VULKAN_BLIT_DEPTH_STENCIL_FRAG,
vk::ShaderStageFlagBits::eFragment, device)},
// Texture filtering shader modules
bicubic_frag{Compile(HostShaders::BICUBIC_FRAG, vk::ShaderStageFlagBits::eFragment, device)},
scale_force_frag{
Compile(HostShaders::SCALE_FORCE_FRAG, vk::ShaderStageFlagBits::eFragment, device)},
xbrz_frag{
Compile(HostShaders::XBRZ_FREESCALE_FRAG, vk::ShaderStageFlagBits::eFragment, device)},
mmpx_frag{Compile(HostShaders::MMPX_FRAG, vk::ShaderStageFlagBits::eFragment, device)},
refine_frag{Compile(HostShaders::REFINE_FRAG, vk::ShaderStageFlagBits::eFragment, device)},
d24s8_to_rgba8_pipeline{MakeComputePipeline(d24s8_to_rgba8_comp, compute_pipeline_layout)},
depth_to_buffer_pipeline{
MakeComputePipeline(depth_to_buffer_comp, compute_buffer_pipeline_layout)},
@ -290,18 +230,10 @@ BlitHelper::~BlitHelper() {
device.destroyPipelineLayout(compute_pipeline_layout);
device.destroyPipelineLayout(compute_buffer_pipeline_layout);
device.destroyPipelineLayout(two_textures_pipeline_layout);
device.destroyPipelineLayout(single_texture_pipeline_layout);
device.destroyPipelineLayout(three_textures_pipeline_layout);
device.destroyShaderModule(full_screen_vert);
device.destroyShaderModule(d24s8_to_rgba8_comp);
device.destroyShaderModule(depth_to_buffer_comp);
device.destroyShaderModule(blit_depth_stencil_frag);
// Destroy texture filtering shader modules
device.destroyShaderModule(bicubic_frag);
device.destroyShaderModule(scale_force_frag);
device.destroyShaderModule(xbrz_frag);
device.destroyShaderModule(mmpx_frag);
device.destroyShaderModule(refine_frag);
device.destroyPipeline(depth_to_buffer_pipeline);
device.destroyPipeline(d24s8_to_rgba8_pipeline);
device.destroyPipeline(depth_blit_pipeline);
@ -310,7 +242,7 @@ BlitHelper::~BlitHelper() {
}
void BindBlitState(vk::CommandBuffer cmdbuf, vk::PipelineLayout layout,
const VideoCore::TextureBlit& blit, const Surface& dest) {
const VideoCore::TextureBlit& blit) {
const vk::Offset2D offset{
.x = std::min<s32>(blit.dst_rect.left, blit.dst_rect.right),
.y = std::min<s32>(blit.dst_rect.bottom, blit.dst_rect.top),
@ -340,9 +272,8 @@ void BindBlitState(vk::CommandBuffer cmdbuf, vk::PipelineLayout layout,
};
cmdbuf.setViewport(0, viewport);
cmdbuf.setScissor(0, scissor);
cmdbuf.pushConstants(layout,
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0,
sizeof(push_constants), &push_constants);
cmdbuf.pushConstants(layout, vk::ShaderStageFlagBits::eVertex, 0, sizeof(push_constants),
&push_constants);
}
bool BlitHelper::BlitDepthStencil(Surface& source, Surface& dest,
@ -369,12 +300,12 @@ bool BlitHelper::BlitDepthStencil(Surface& source, Surface& dest,
};
renderpass_cache.BeginRendering(depth_pass);
scheduler.Record([blit, descriptor_set, &dest, this](vk::CommandBuffer cmdbuf) {
scheduler.Record([blit, descriptor_set, this](vk::CommandBuffer cmdbuf) {
const vk::PipelineLayout layout = two_textures_pipeline_layout;
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, depth_blit_pipeline);
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, descriptor_set, {});
BindBlitState(cmdbuf, layout, blit, dest);
BindBlitState(cmdbuf, layout, blit);
cmdbuf.draw(3, 1, 0, 0);
});
scheduler.MakeDirty(StateFlags::Pipeline);
@ -600,7 +531,7 @@ vk::Pipeline BlitHelper::MakeDepthStencilBlitPipeline() {
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.layout = two_textures_pipeline_layout,
.renderPass = renderpass,
@ -616,280 +547,4 @@ vk::Pipeline BlitHelper::MakeDepthStencilBlitPipeline() {
return VK_NULL_HANDLE;
}
bool BlitHelper::Filter(Surface& surface, const VideoCore::TextureBlit& blit) {
const auto filter = Settings::values.texture_filter.GetValue();
const bool is_depth =
surface.type == VideoCore::SurfaceType::Depth ||
surface.type == VideoCore::SurfaceType::DepthStencil; // Skip filtering for depth textures
// and when no filter is selected
if (filter == Settings::TextureFilter::NoFilter || is_depth) {
return false;
} // Only filter base mipmap level
if (blit.src_level != 0) {
return true;
}
switch (filter) {
case TextureFilter::Anime4K:
FilterAnime4K(surface, blit);
break;
case TextureFilter::Bicubic:
FilterBicubic(surface, blit);
break;
case TextureFilter::ScaleForce:
FilterScaleForce(surface, blit);
break;
case TextureFilter::xBRZ:
FilterXbrz(surface, blit);
break;
case TextureFilter::MMPX:
FilterMMPX(surface, blit);
break;
default:
LOG_ERROR(Render_Vulkan, "Unknown texture filter {}", filter);
return false;
}
return true;
}
void BlitHelper::FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& blit) {
const bool is_depth = surface.type == VideoCore::SurfaceType::Depth ||
surface.type == VideoCore::SurfaceType::DepthStencil;
const auto color_format = is_depth ? VideoCore::PixelFormat::Invalid : surface.pixel_format;
auto pipeline = MakeFilterPipeline(refine_frag, three_textures_pipeline_layout, color_format);
FilterPassThreeTextures(surface, surface, surface, surface, pipeline,
three_textures_pipeline_layout, blit);
}
void BlitHelper::FilterBicubic(Surface& surface, const VideoCore::TextureBlit& blit) {
const bool is_depth = surface.type == VideoCore::SurfaceType::Depth ||
surface.type == VideoCore::SurfaceType::DepthStencil;
const auto color_format = is_depth ? VideoCore::PixelFormat::Invalid : surface.pixel_format;
auto pipeline = MakeFilterPipeline(bicubic_frag, single_texture_pipeline_layout, color_format);
FilterPass(surface, surface, pipeline, single_texture_pipeline_layout, blit);
}
void BlitHelper::FilterScaleForce(Surface& surface, const VideoCore::TextureBlit& blit) {
const bool is_depth = surface.type == VideoCore::SurfaceType::Depth ||
surface.type == VideoCore::SurfaceType::DepthStencil;
const auto color_format = is_depth ? VideoCore::PixelFormat::Invalid : surface.pixel_format;
auto pipeline =
MakeFilterPipeline(scale_force_frag, single_texture_pipeline_layout, color_format);
FilterPass(surface, surface, pipeline, single_texture_pipeline_layout, blit);
}
void BlitHelper::FilterXbrz(Surface& surface, const VideoCore::TextureBlit& blit) {
const bool is_depth = surface.type == VideoCore::SurfaceType::Depth ||
surface.type == VideoCore::SurfaceType::DepthStencil;
const auto color_format = is_depth ? VideoCore::PixelFormat::Invalid : surface.pixel_format;
auto pipeline = MakeFilterPipeline(xbrz_frag, single_texture_pipeline_layout, color_format);
FilterPass(surface, surface, pipeline, single_texture_pipeline_layout, blit);
}
void BlitHelper::FilterMMPX(Surface& surface, const VideoCore::TextureBlit& blit) {
const bool is_depth = surface.type == VideoCore::SurfaceType::Depth ||
surface.type == VideoCore::SurfaceType::DepthStencil;
const auto color_format = is_depth ? VideoCore::PixelFormat::Invalid : surface.pixel_format;
auto pipeline = MakeFilterPipeline(mmpx_frag, single_texture_pipeline_layout, color_format);
FilterPass(surface, surface, pipeline, single_texture_pipeline_layout, blit);
}
vk::Pipeline BlitHelper::MakeFilterPipeline(vk::ShaderModule fragment_shader,
vk::PipelineLayout layout,
VideoCore::PixelFormat color_format) {
const std::array stages = MakeStages(full_screen_vert, fragment_shader);
// Use the provided color format for render pass compatibility
const auto renderpass =
renderpass_cache.GetRenderpass(color_format, VideoCore::PixelFormat::Invalid, false);
vk::GraphicsPipelineCreateInfo pipeline_info = {
.stageCount = static_cast<u32>(stages.size()),
.pStages = stages.data(),
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.pTessellationState = nullptr,
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.pDepthStencilState = nullptr,
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.layout = layout,
.renderPass = renderpass,
};
if (const auto result = device.createGraphicsPipeline({}, pipeline_info);
result.result == vk::Result::eSuccess) {
return result.value;
} else {
LOG_CRITICAL(Render_Vulkan, "Filter pipeline creation failed!");
UNREACHABLE();
}
}
void BlitHelper::FilterPass(Surface& source, Surface& dest, vk::Pipeline pipeline,
vk::PipelineLayout layout, const VideoCore::TextureBlit& blit) {
const auto texture_descriptor_set = single_texture_provider.Commit();
update_queue.AddImageSampler(texture_descriptor_set, 0, 0, source.ImageView(0), linear_sampler,
vk::ImageLayout::eGeneral);
const bool is_depth = dest.type == VideoCore::SurfaceType::Depth ||
dest.type == VideoCore::SurfaceType::DepthStencil;
const auto color_format = is_depth ? VideoCore::PixelFormat::Invalid : dest.pixel_format;
const auto depth_format = is_depth ? dest.pixel_format : VideoCore::PixelFormat::Invalid;
const auto renderpass = renderpass_cache.GetRenderpass(color_format, depth_format, false);
const RenderPass render_pass = {
.framebuffer = dest.Framebuffer(),
.render_pass = renderpass,
.render_area =
{
.offset = {0, 0},
.extent = {dest.GetScaledWidth(), dest.GetScaledHeight()},
},
};
renderpass_cache.BeginRendering(render_pass);
const float src_scale = static_cast<float>(source.GetResScale());
// Calculate normalized texture coordinates like OpenGL does
const auto src_extent = source.RealExtent(false); // Get unscaled texture extent
const float tex_scale_x =
static_cast<float>(blit.src_rect.GetWidth()) / static_cast<float>(src_extent.width);
const float tex_scale_y =
static_cast<float>(blit.src_rect.GetHeight()) / static_cast<float>(src_extent.height);
const float tex_offset_x =
static_cast<float>(blit.src_rect.left) / static_cast<float>(src_extent.width);
const float tex_offset_y =
static_cast<float>(blit.src_rect.bottom) / static_cast<float>(src_extent.height);
scheduler.Record([pipeline, layout, texture_descriptor_set, blit, tex_scale_x, tex_scale_y,
tex_offset_x, tex_offset_y, src_scale](vk::CommandBuffer cmdbuf) {
const FilterPushConstants push_constants{.tex_scale = {tex_scale_x, tex_scale_y},
.tex_offset = {tex_offset_x, tex_offset_y},
.res_scale = src_scale};
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
// Bind single texture descriptor set
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0,
texture_descriptor_set, {});
cmdbuf.pushConstants(layout, FILTER_PUSH_CONSTANT_RANGE.stageFlags,
FILTER_PUSH_CONSTANT_RANGE.offset, FILTER_PUSH_CONSTANT_RANGE.size,
&push_constants);
// Set up viewport and scissor for filtering (don't use BindBlitState as it overwrites push
// constants)
const vk::Offset2D offset{
.x = std::min<s32>(blit.dst_rect.left, blit.dst_rect.right),
.y = std::min<s32>(blit.dst_rect.bottom, blit.dst_rect.top),
};
const vk::Extent2D extent{
.width = blit.dst_rect.GetWidth(),
.height = blit.dst_rect.GetHeight(),
};
const vk::Viewport viewport{
.x = static_cast<float>(offset.x),
.y = static_cast<float>(offset.y),
.width = static_cast<float>(extent.width),
.height = static_cast<float>(extent.height),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
const vk::Rect2D scissor{
.offset = offset,
.extent = extent,
};
cmdbuf.setViewport(0, viewport);
cmdbuf.setScissor(0, scissor);
cmdbuf.draw(3, 1, 0, 0);
});
scheduler.MakeDirty(StateFlags::Pipeline);
}
void BlitHelper::FilterPassThreeTextures(Surface& source1, Surface& source2, Surface& source3,
Surface& dest, vk::Pipeline pipeline,
vk::PipelineLayout layout,
const VideoCore::TextureBlit& blit) {
const auto texture_descriptor_set = three_textures_provider.Commit();
update_queue.AddImageSampler(texture_descriptor_set, 0, 0, source1.ImageView(0), linear_sampler,
vk::ImageLayout::eGeneral);
update_queue.AddImageSampler(texture_descriptor_set, 1, 0, source2.ImageView(0), linear_sampler,
vk::ImageLayout::eGeneral);
update_queue.AddImageSampler(texture_descriptor_set, 2, 0, source3.ImageView(0), linear_sampler,
vk::ImageLayout::eGeneral);
const bool is_depth = dest.type == VideoCore::SurfaceType::Depth ||
dest.type == VideoCore::SurfaceType::DepthStencil;
const auto color_format = is_depth ? VideoCore::PixelFormat::Invalid : dest.pixel_format;
const auto depth_format = is_depth ? dest.pixel_format : VideoCore::PixelFormat::Invalid;
const auto renderpass = renderpass_cache.GetRenderpass(color_format, depth_format, false);
const RenderPass render_pass = {
.framebuffer = dest.Framebuffer(),
.render_pass = renderpass,
.render_area =
{
.offset = {0, 0},
.extent = {dest.GetScaledWidth(), dest.GetScaledHeight()},
},
};
renderpass_cache.BeginRendering(render_pass);
const float src_scale = static_cast<float>(source1.GetResScale());
// Calculate normalized texture coordinates like OpenGL does
const auto src_extent = source1.RealExtent(false); // Get unscaled texture extent
const float tex_scale_x =
static_cast<float>(blit.src_rect.GetWidth()) / static_cast<float>(src_extent.width);
const float tex_scale_y =
static_cast<float>(blit.src_rect.GetHeight()) / static_cast<float>(src_extent.height);
const float tex_offset_x =
static_cast<float>(blit.src_rect.left) / static_cast<float>(src_extent.width);
const float tex_offset_y =
static_cast<float>(blit.src_rect.bottom) / static_cast<float>(src_extent.height);
scheduler.Record([pipeline, layout, texture_descriptor_set, blit, tex_scale_x, tex_scale_y,
tex_offset_x, tex_offset_y, src_scale](vk::CommandBuffer cmdbuf) {
const FilterPushConstants push_constants{.tex_scale = {tex_scale_x, tex_scale_y},
.tex_offset = {tex_offset_x, tex_offset_y},
.res_scale = src_scale};
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
// Bind single texture descriptor set
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0,
texture_descriptor_set, {});
cmdbuf.pushConstants(layout, FILTER_PUSH_CONSTANT_RANGE.stageFlags,
FILTER_PUSH_CONSTANT_RANGE.offset, FILTER_PUSH_CONSTANT_RANGE.size,
&push_constants);
// Set up viewport and scissor using safe viewport like working filters
const vk::Offset2D offset{
.x = std::min<s32>(blit.dst_rect.left, blit.dst_rect.right),
.y = std::min<s32>(blit.dst_rect.bottom, blit.dst_rect.top),
};
const vk::Extent2D extent{
.width = blit.dst_rect.GetWidth(),
.height = blit.dst_rect.GetHeight(),
};
const vk::Viewport viewport{
.x = static_cast<float>(offset.x),
.y = static_cast<float>(offset.y),
.width = static_cast<float>(extent.width),
.height = static_cast<float>(extent.height),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
const vk::Rect2D scissor{
.offset = offset,
.extent = extent,
};
cmdbuf.setViewport(0, viewport);
cmdbuf.setScissor(0, scissor);
cmdbuf.draw(3, 1, 0, 0);
});
scheduler.MakeDirty(StateFlags::Pipeline);
}
} // namespace Vulkan

View file

@ -1,10 +1,9 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "video_core/rasterizer_cache/pixel_format.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h"
namespace VideoCore {
@ -28,7 +27,6 @@ public:
explicit BlitHelper(const Instance& instance, Scheduler& scheduler,
RenderManager& renderpass_cache, DescriptorUpdateQueue& update_queue);
~BlitHelper();
bool Filter(Surface& surface, const VideoCore::TextureBlit& blit);
bool BlitDepthStencil(Surface& source, Surface& dest, const VideoCore::TextureBlit& blit);
@ -40,25 +38,6 @@ public:
private:
vk::Pipeline MakeComputePipeline(vk::ShaderModule shader, vk::PipelineLayout layout);
vk::Pipeline MakeDepthStencilBlitPipeline();
vk::Pipeline MakeFilterPipeline(
vk::ShaderModule fragment_shader, vk::PipelineLayout layout,
VideoCore::PixelFormat color_format = VideoCore::PixelFormat::RGBA8);
void FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& blit);
void FilterBicubic(Surface& surface, const VideoCore::TextureBlit& blit);
void FilterScaleForce(Surface& surface, const VideoCore::TextureBlit& blit);
void FilterXbrz(Surface& surface, const VideoCore::TextureBlit& blit);
void FilterMMPX(Surface& surface, const VideoCore::TextureBlit& blit);
void FilterPass(Surface& source, Surface& dest, vk::Pipeline pipeline,
vk::PipelineLayout layout, const VideoCore::TextureBlit& blit);
void FilterPassThreeTextures(Surface& source1, Surface& source2, Surface& source3,
Surface& dest, vk::Pipeline pipeline, vk::PipelineLayout layout,
const VideoCore::TextureBlit& blit);
void FilterPassYGradient(Surface& source, Surface& dest, vk::Pipeline pipeline,
vk::PipelineLayout layout, const VideoCore::TextureBlit& blit);
private:
const Instance& instance;
@ -72,23 +51,14 @@ private:
DescriptorHeap compute_provider;
DescriptorHeap compute_buffer_provider;
DescriptorHeap two_textures_provider;
DescriptorHeap single_texture_provider;
DescriptorHeap three_textures_provider;
vk::PipelineLayout compute_pipeline_layout;
vk::PipelineLayout compute_buffer_pipeline_layout;
vk::PipelineLayout two_textures_pipeline_layout;
vk::PipelineLayout single_texture_pipeline_layout;
vk::PipelineLayout three_textures_pipeline_layout;
vk::ShaderModule full_screen_vert;
vk::ShaderModule d24s8_to_rgba8_comp;
vk::ShaderModule depth_to_buffer_comp;
vk::ShaderModule blit_depth_stencil_frag;
vk::ShaderModule bicubic_frag;
vk::ShaderModule scale_force_frag;
vk::ShaderModule xbrz_frag;
vk::ShaderModule mmpx_frag;
vk::ShaderModule refine_frag;
vk::Pipeline d24s8_to_rgba8_pipeline;
vk::Pipeline depth_to_buffer_pipeline;

View file

@ -1,4 +1,4 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -103,14 +103,13 @@ vk::CommandBuffer CommandPool::Commit() {
return cmd_buffers[index];
}
constexpr u32 DESCRIPTOR_SET_BATCH = 64;
constexpr u32 DESCRIPTOR_MULTIPLIER = 4; // Increase capacity of each pool
constexpr u32 DESCRIPTOR_SET_BATCH = 32;
DescriptorHeap::DescriptorHeap(const Instance& instance, MasterSemaphore* master_semaphore,
std::span<const vk::DescriptorSetLayoutBinding> bindings,
u32 descriptor_heap_count_)
: ResourcePool{master_semaphore, DESCRIPTOR_SET_BATCH}, device{instance.GetDevice()},
descriptor_heap_count{descriptor_heap_count_ * DESCRIPTOR_MULTIPLIER} { // Increase pool size
descriptor_heap_count{descriptor_heap_count_} {
// Create descriptor set layout.
const vk::DescriptorSetLayoutCreateInfo layout_ci = {
.bindingCount = static_cast<u32>(bindings.size()),

View file

@ -1,23 +1,9 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "video_core/renderer_vulkan/vk_texture_runtime.h"
#include <cmath>
#include <limits>
#include <span>
#include <string>
#include <boost/container/small_vector.hpp>
#include <boost/container/static_vector.hpp>
#include <vulkan/vulkan.hpp>
#include "video_core/custom_textures/custom_tex_manager.h"
#include "video_core/rasterizer_cache/pixel_format.h"
#include "video_core/rasterizer_cache/surface_params.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/vk_blit_helper.h"
#include "video_core/renderer_vulkan/vk_descriptor_update_queue.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "common/literals.h"
#include "common/microprofile.h"
@ -714,7 +700,7 @@ Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceParams& param
: SurfaceBase{params}, runtime{&runtime_}, instance{&runtime_.GetInstance()},
scheduler{&runtime_.GetScheduler()}, traits{instance->GetTraits(pixel_format)} {
if (pixel_format == VideoCore::PixelFormat::Invalid || !traits.transfer_support) {
if (pixel_format == VideoCore::PixelFormat::Invalid) {
return;
}
@ -734,25 +720,18 @@ Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceParams& param
flags |= vk::ImageCreateFlagBits::eMutableFormat;
}
// Ensure color formats have the color attachment bit set for framebuffers
auto usage = traits.usage;
const bool is_color =
(traits.aspect & vk::ImageAspectFlagBits::eColor) != vk::ImageAspectFlags{};
if (is_color) {
usage |= vk::ImageUsageFlagBits::eColorAttachment;
}
const bool need_format_list = is_mutable && instance->IsImageFormatListSupported();
handles[0] = MakeHandle(instance, width, height, levels, texture_type, format, usage, flags,
traits.aspect, need_format_list, DebugName(false));
handles[0] = MakeHandle(instance, width, height, levels, texture_type, format, traits.usage,
flags, traits.aspect, need_format_list, DebugName(false));
raw_images.emplace_back(handles[0].image);
if (res_scale != 1) {
handles[1] =
MakeHandle(instance, GetScaledWidth(), GetScaledHeight(), levels, texture_type, format,
usage, flags, traits.aspect, need_format_list, DebugName(true));
traits.usage, flags, traits.aspect, need_format_list, DebugName(true));
raw_images.emplace_back(handles[1].image);
}
runtime->renderpass_cache.EndRendering();
scheduler->Record([raw_images, aspect = traits.aspect](vk::CommandBuffer cmdbuf) {
const auto barriers = MakeInitBarriers(aspect, raw_images);
@ -809,49 +788,6 @@ Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceBase& surface
material = mat;
}
Surface::Surface(TextureRuntime& runtime_, u32 width_, u32 height_, VideoCore::PixelFormat format_)
: SurfaceBase{{
.width = width_,
.height = height_,
.pixel_format = format_,
.type = VideoCore::SurfaceType::Texture,
}},
runtime{&runtime_}, instance{&runtime_.GetInstance()}, scheduler{&runtime_.GetScheduler()},
traits{instance->GetTraits(format_)} {
// Create texture with requested size and format
const vk::ImageUsageFlags usage =
vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled;
handles[0] = MakeHandle(instance, width_, height_, 1, VideoCore::TextureType::Texture2D,
traits.native, usage, {}, traits.aspect, false, "Temporary Surface");
// Create image view
const vk::ImageViewCreateInfo view_info = {
.image = handles[0].image,
.viewType = vk::ImageViewType::e2D,
.format = traits.native,
.subresourceRange{
.aspectMask = traits.aspect,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
handles[0].image_view = instance->GetDevice().createImageViewUnique(view_info);
runtime->renderpass_cache.EndRendering();
scheduler->Record(
[raw_images = std::array{Image()}, aspect = traits.aspect](vk::CommandBuffer cmdbuf) {
const auto barriers = MakeInitBarriers(aspect, raw_images);
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe,
vk::PipelineStageFlagBits::eTopOfPipe,
vk::DependencyFlagBits::eByRegion, {}, {}, barriers);
});
}
Surface::~Surface() {
if (!handles[0].image_view) {
return;
@ -940,23 +876,14 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload,
runtime->upload_buffer.Commit(staging.size);
if (res_scale != 1) {
// Always ensure the scaled image exists
if (!handles[1].image) {
// This will create handles[1] and perform the initial scaling
ScaleUp(res_scale);
} else {
// Update the scaled version of the uploaded area
const VideoCore::TextureBlit blit = {
.src_level = upload.texture_level,
.dst_level = upload.texture_level,
.src_rect = upload.texture_rect,
.dst_rect = upload.texture_rect * res_scale,
};
// Only apply texture filtering when upscaling, matching OpenGL behavior
if (res_scale != 1 && !runtime->blit_helper.Filter(*this, blit)) {
BlitScale(blit, true);
}
}
const VideoCore::TextureBlit blit = {
.src_level = upload.texture_level,
.dst_level = upload.texture_level,
.src_rect = upload.texture_rect,
.dst_rect = upload.texture_rect * res_scale,
};
BlitScale(blit, true);
}
}
@ -1322,6 +1249,11 @@ vk::ImageView Surface::ImageView(u32 index) const noexcept {
return image_view;
}
vk::ImageView Surface::FramebufferView() noexcept {
is_framebuffer = true;
return ImageView();
}
vk::ImageView Surface::DepthView() noexcept {
if (depth_view) {
return depth_view.get();
@ -1397,8 +1329,6 @@ vk::ImageView Surface::StorageView() noexcept {
}
vk::Framebuffer Surface::Framebuffer() noexcept {
is_framebuffer = true;
const u32 index = res_scale == 1 ? 0u : 1u;
if (framebuffers[index]) {
return framebuffers[index].get();
@ -1409,29 +1339,12 @@ vk::Framebuffer Surface::Framebuffer() noexcept {
const auto depth_format = is_depth ? pixel_format : PixelFormat::Invalid;
const auto render_pass =
runtime->renderpass_cache.GetRenderpass(color_format, depth_format, false);
// Use AttachmentView() to get single mip level view for framebuffer
const auto attachments = std::array{AttachmentView()};
const auto attachments = std::array{ImageView()};
framebuffers[index] = MakeFramebuffer(instance->GetDevice(), render_pass, GetScaledWidth(),
GetScaledHeight(), attachments);
return framebuffers[index].get();
}
vk::ImageView Surface::AttachmentView() noexcept {
const vk::ImageViewCreateInfo view_info = {
.image = Image(),
.viewType = vk::ImageViewType::e2D,
.format = traits.native,
.subresourceRange{
.aspectMask = traits.aspect,
.baseMipLevel = 0,
.levelCount = 1, // Single mip level for framebuffer
.baseArrayLayer = 0,
.layerCount = 1,
},
};
return instance->GetDevice().createImageViewUnique(view_info).release();
}
void Surface::BlitScale(const VideoCore::TextureBlit& blit, bool up_scale) {
const FormatTraits& depth_traits = instance->GetTraits(pixel_format);
const bool is_depth_stencil = pixel_format == PixelFormat::D24S8;
@ -1440,16 +1353,9 @@ void Surface::BlitScale(const VideoCore::TextureBlit& blit, bool up_scale) {
return;
}
// Always use consistent source and destination images for proper scaling
// When upscaling: source = unscaled (0), destination = scaled (1)
// When downscaling: source = scaled (1), destination = unscaled (0)
const vk::Image src_image = up_scale ? Image(0) : Image(1);
const vk::Image dst_image = up_scale ? Image(1) : Image(0);
scheduler->Record([src_image, aspect = Aspect(), filter = MakeFilter(pixel_format), dst_image,
src_access = AccessFlags(), dst_access = AccessFlags(),
scheduler->Record([src_image = Image(!up_scale), aspect = Aspect(),
filter = MakeFilter(pixel_format), dst_image = Image(up_scale),
blit](vk::CommandBuffer render_cmdbuf) {
// Adjust blitting parameters for filtered upscaling
const std::array source_offsets = {
vk::Offset3D{static_cast<s32>(blit.src_rect.left),
static_cast<s32>(blit.src_rect.bottom), 0},
@ -1483,7 +1389,7 @@ void Surface::BlitScale(const VideoCore::TextureBlit& blit, bool up_scale) {
const std::array read_barriers = {
vk::ImageMemoryBarrier{
.srcAccessMask = src_access,
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferRead,
.oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
@ -1493,7 +1399,10 @@ void Surface::BlitScale(const VideoCore::TextureBlit& blit, bool up_scale) {
.subresourceRange = MakeSubresourceRange(aspect, blit.src_level),
},
vk::ImageMemoryBarrier{
.srcAccessMask = dst_access,
.srcAccessMask = vk::AccessFlagBits::eShaderRead |
vk::AccessFlagBits::eDepthStencilAttachmentRead |
vk::AccessFlagBits::eColorAttachmentRead |
vk::AccessFlagBits::eTransferRead,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferDstOptimal,
@ -1540,9 +1449,9 @@ void Surface::BlitScale(const VideoCore::TextureBlit& blit, bool up_scale) {
}
Framebuffer::Framebuffer(TextureRuntime& runtime, const VideoCore::FramebufferParams& params,
Surface* color, Surface* depth_stencil)
Surface* color, Surface* depth)
: VideoCore::FramebufferParams{params},
res_scale{color ? color->res_scale : (depth_stencil ? depth_stencil->res_scale : 1u)} {
res_scale{color ? color->res_scale : (depth ? depth->res_scale : 1u)} {
auto& renderpass_cache = runtime.GetRenderpassCache();
if (shadow_rendering && !color) {
return;
@ -1559,41 +1468,27 @@ Framebuffer::Framebuffer(TextureRuntime& runtime, const VideoCore::FramebufferPa
}
images[index] = surface->Image();
aspects[index] = surface->Aspect();
// Use AttachmentView() for single-mip-level framebuffer attachment
image_views[index] = surface->AttachmentView();
image_views[index] = shadow_rendering ? surface->StorageView() : surface->FramebufferView();
};
boost::container::static_vector<vk::ImageView, 2> attachments;
if (!shadow_rendering) {
// Prepare the surfaces for use in framebuffer
if (color) {
prepare(0, color);
attachments.emplace_back(image_views[0]);
}
if (color) {
prepare(0, color);
attachments.emplace_back(image_views[0]);
}
if (depth_stencil) {
prepare(1, depth_stencil);
attachments.emplace_back(image_views[1]);
}
} else {
// For shadow rendering, just collect surface info without adding attachments
if (color) {
prepare(0, color);
}
if (depth_stencil) {
prepare(1, depth_stencil);
}
if (depth) {
prepare(1, depth);
attachments.emplace_back(image_views[1]);
}
const vk::Device device = runtime.GetInstance().GetDevice();
if (shadow_rendering) {
// For shadow rendering, we don't need a framebuffer with attachments
// Just create a dummy render pass for the rendering pipeline
render_pass =
renderpass_cache.GetRenderpass(PixelFormat::Invalid, PixelFormat::Invalid, false);
// Don't create a framebuffer for shadow rendering
framebuffer.reset();
framebuffer = MakeFramebuffer(device, render_pass, color->GetScaledWidth(),
color->GetScaledHeight(), {});
} else {
render_pass = renderpass_cache.GetRenderpass(formats[0], formats[1], false);
framebuffer = MakeFramebuffer(device, render_pass, width, height, attachments);

View file

@ -1,4 +1,4 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -110,8 +110,6 @@ public:
explicit Surface(TextureRuntime& runtime, const VideoCore::SurfaceParams& params);
explicit Surface(TextureRuntime& runtime, const VideoCore::SurfaceBase& surface,
const VideoCore::Material* materal);
explicit Surface(TextureRuntime& runtime, u32 width_, u32 height_,
VideoCore::PixelFormat format_);
~Surface();
Surface(const Surface&) = delete;
@ -130,24 +128,12 @@ public:
/// Returns the image view at index, otherwise the base view
vk::ImageView ImageView(u32 index = 1) const noexcept;
/// Returns width of the surface
u32 GetWidth() const noexcept {
return width;
}
/// Returns height of the surface
u32 GetHeight() const noexcept {
return height;
}
/// Returns resolution scale of the surface
u32 GetResScale() const noexcept {
return res_scale;
}
/// Returns a copy of the upscaled image handle, used for feedback loops.
vk::ImageView CopyImageView() noexcept;
/// Returns the framebuffer view of the surface image
vk::ImageView FramebufferView() noexcept;
/// Returns the depth view of the surface image
vk::ImageView DepthView() noexcept;
@ -160,9 +146,6 @@ public:
/// Returns a framebuffer handle for rendering to this surface
vk::Framebuffer Framebuffer() noexcept;
/// Returns a single-mip-level view suitable for framebuffer attachments
vk::ImageView AttachmentView() noexcept;
/// Uploads pixel data in staging to a rectangle region of the surface texture
void Upload(const VideoCore::BufferTextureCopy& upload, const VideoCore::StagingData& staging);
@ -248,12 +231,19 @@ public:
return res_scale;
}
u32 Width() const noexcept {
return width;
}
u32 Height() const noexcept {
return height;
}
private:
std::array<vk::Image, 2> images{};
std::array<vk::ImageView, 2> image_views{};
vk::UniqueFramebuffer framebuffer;
vk::RenderPass render_pass;
std::vector<vk::UniqueImageView> framebuffer_views;
std::array<vk::ImageAspectFlags, 2> aspects{};
std::array<VideoCore::PixelFormat, 2> formats{VideoCore::PixelFormat::Invalid,
VideoCore::PixelFormat::Invalid};