code: Prepare frontend for vulkan support
This commit is contained in:
parent
bbb47cd753
commit
a67bfe544d
31 changed files with 557 additions and 232 deletions
|
@ -359,6 +359,8 @@ public final class SettingsFragmentPresenter {
|
||||||
|
|
||||||
SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER);
|
SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER);
|
||||||
Setting graphicsApi = rendererSection.getSetting(SettingsFile.KEY_GRAPHICS_API);
|
Setting graphicsApi = rendererSection.getSetting(SettingsFile.KEY_GRAPHICS_API);
|
||||||
|
Setting spirvShaderGen = rendererSection.getSetting(SettingsFile.KEY_SPIRV_SHADER_GEN);
|
||||||
|
Setting asyncShaders = rendererSection.getSetting(SettingsFile.KEY_ASYNC_SHADERS);
|
||||||
Setting resolutionFactor = rendererSection.getSetting(SettingsFile.KEY_RESOLUTION_FACTOR);
|
Setting resolutionFactor = rendererSection.getSetting(SettingsFile.KEY_RESOLUTION_FACTOR);
|
||||||
Setting filterMode = rendererSection.getSetting(SettingsFile.KEY_FILTER_MODE);
|
Setting filterMode = rendererSection.getSetting(SettingsFile.KEY_FILTER_MODE);
|
||||||
Setting shadersAccurateMul = rendererSection.getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL);
|
Setting shadersAccurateMul = rendererSection.getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL);
|
||||||
|
@ -377,6 +379,8 @@ public final class SettingsFragmentPresenter {
|
||||||
|
|
||||||
sl.add(new HeaderSetting(null, null, R.string.renderer, 0));
|
sl.add(new HeaderSetting(null, null, R.string.renderer, 0));
|
||||||
sl.add(new SingleChoiceSetting(SettingsFile.KEY_GRAPHICS_API, Settings.SECTION_RENDERER, R.string.graphics_api, 0, R.array.graphicsApiNames, R.array.graphicsApiValues, 0, graphicsApi));
|
sl.add(new SingleChoiceSetting(SettingsFile.KEY_GRAPHICS_API, Settings.SECTION_RENDERER, R.string.graphics_api, 0, R.array.graphicsApiNames, R.array.graphicsApiValues, 0, graphicsApi));
|
||||||
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_SPIRV_SHADER_GEN, Settings.SECTION_RENDERER, R.string.spirv_shader_gen, R.string.spirv_shader_gen_description, true, spirvShaderGen));
|
||||||
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_ASYNC_SHADERS, Settings.SECTION_RENDERER, R.string.async_shaders, R.string.async_shaders_description, false, asyncShaders));
|
||||||
sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, Settings.SECTION_RENDERER, R.string.internal_resolution, R.string.internal_resolution_description, 1, 4, "x", 1, resolutionFactor));
|
sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, Settings.SECTION_RENDERER, R.string.internal_resolution, R.string.internal_resolution_description, 1, 4, "x", 1, resolutionFactor));
|
||||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_FILTER_MODE, Settings.SECTION_RENDERER, R.string.linear_filtering, R.string.linear_filtering_description, true, filterMode));
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_FILTER_MODE, Settings.SECTION_RENDERER, R.string.linear_filtering, R.string.linear_filtering_description, true, filterMode));
|
||||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL, Settings.SECTION_RENDERER, R.string.shaders_accurate_mul, R.string.shaders_accurate_mul_description, false, shadersAccurateMul));
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL, Settings.SECTION_RENDERER, R.string.shaders_accurate_mul, R.string.shaders_accurate_mul_description, false, shadersAccurateMul));
|
||||||
|
@ -424,6 +428,6 @@ public final class SettingsFragmentPresenter {
|
||||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_CPU_JIT, Settings.SECTION_CORE, R.string.cpu_jit, R.string.cpu_jit_description, true, useCpuJit, true, mView));
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_CPU_JIT, Settings.SECTION_CORE, R.string.cpu_jit, R.string.cpu_jit_description, true, useCpuJit, true, mView));
|
||||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_SHADER, Settings.SECTION_RENDERER, R.string.hw_shaders, R.string.hw_shaders_description, true, hardwareShader, true, mView));
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_SHADER, Settings.SECTION_RENDERER, R.string.hw_shaders, R.string.hw_shaders_description, true, hardwareShader, true, mView));
|
||||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_VSYNC, Settings.SECTION_RENDERER, R.string.vsync, R.string.vsync_description, true, vsyncEnable));
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_VSYNC, Settings.SECTION_RENDERER, R.string.vsync, R.string.vsync_description, true, vsyncEnable));
|
||||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_RENDERER_DEBUG, Settings.SECTION_RENDERER, R.string.renderer_debug, R.string.renderer_debug_description, false, rendererDebug));
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_RENDERER_DEBUG, Settings.SECTION_DEBUG, R.string.renderer_debug, R.string.renderer_debug_description, false, rendererDebug));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,8 @@ public final class SettingsFile {
|
||||||
public static final String KEY_PREMIUM = "premium";
|
public static final String KEY_PREMIUM = "premium";
|
||||||
|
|
||||||
public static final String KEY_GRAPHICS_API = "graphics_api";
|
public static final String KEY_GRAPHICS_API = "graphics_api";
|
||||||
|
public static final String KEY_SPIRV_SHADER_GEN = "spirv_shader_gen";
|
||||||
|
public static final String KEY_ASYNC_SHADERS = "async_shader_compilation";
|
||||||
public static final String KEY_RENDERER_DEBUG = "renderer_debug";
|
public static final String KEY_RENDERER_DEBUG = "renderer_debug";
|
||||||
public static final String KEY_HW_SHADER = "use_hw_shader";
|
public static final String KEY_HW_SHADER = "use_hw_shader";
|
||||||
public static final String KEY_SHADERS_ACCURATE_MUL = "shaders_accurate_mul";
|
public static final String KEY_SHADERS_ACCURATE_MUL = "shaders_accurate_mul";
|
||||||
|
|
|
@ -19,6 +19,10 @@ add_library(citra-android SHARED
|
||||||
default_ini.h
|
default_ini.h
|
||||||
emu_window/emu_window.cpp
|
emu_window/emu_window.cpp
|
||||||
emu_window/emu_window.h
|
emu_window/emu_window.h
|
||||||
|
emu_window/emu_window_gl.cpp
|
||||||
|
emu_window/emu_window_gl.h
|
||||||
|
emu_window/emu_window_vk.cpp
|
||||||
|
emu_window/emu_window_vk.h
|
||||||
game_info.cpp
|
game_info.cpp
|
||||||
game_settings.cpp
|
game_settings.cpp
|
||||||
game_settings.h
|
game_settings.h
|
||||||
|
|
|
@ -147,6 +147,8 @@ void Config::ReadValues() {
|
||||||
Settings::values.shaders_accurate_mul =
|
Settings::values.shaders_accurate_mul =
|
||||||
sdl2_config->GetBoolean("Renderer", "shaders_accurate_mul", false);
|
sdl2_config->GetBoolean("Renderer", "shaders_accurate_mul", false);
|
||||||
ReadSetting("Renderer", Settings::values.graphics_api);
|
ReadSetting("Renderer", Settings::values.graphics_api);
|
||||||
|
ReadSetting("Renderer", Settings::values.async_shader_compilation);
|
||||||
|
ReadSetting("Renderer", Settings::values.spirv_shader_gen);
|
||||||
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
||||||
ReadSetting("Renderer", Settings::values.use_shader_jit);
|
ReadSetting("Renderer", Settings::values.use_shader_jit);
|
||||||
ReadSetting("Renderer", Settings::values.resolution_factor);
|
ReadSetting("Renderer", Settings::values.resolution_factor);
|
||||||
|
|
|
@ -99,9 +99,17 @@ cpu_clock_percentage =
|
||||||
|
|
||||||
[Renderer]
|
[Renderer]
|
||||||
# Whether to render using OpenGL
|
# Whether to render using OpenGL
|
||||||
# 1: OpenGLES (default)
|
# 1: OpenGL ES (default), 2: Vulkan
|
||||||
graphics_api =
|
graphics_api =
|
||||||
|
|
||||||
|
# Whether to compile shaders on multiple worker threads (Vulkan only)
|
||||||
|
# 0: Off, 1: On (default)
|
||||||
|
async_shader_compilation =
|
||||||
|
|
||||||
|
# Whether to emit PICA fragment shader using SPIRV or GLSL (Vulkan only)
|
||||||
|
# 0: GLSL, 1: SPIR-V (default)
|
||||||
|
spirv_shader_gen =
|
||||||
|
|
||||||
# Whether to use hardware shaders to emulate 3DS shaders
|
# Whether to use hardware shaders to emulate 3DS shaders
|
||||||
# 0: Software, 1 (default): Hardware
|
# 0: Software, 1 (default): Hardware
|
||||||
use_hw_shader =
|
use_hw_shader =
|
||||||
|
|
|
@ -6,10 +6,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <android/native_window_jni.h>
|
#include <android/native_window_jni.h>
|
||||||
#include <glad/glad.h>
|
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
|
@ -20,52 +17,6 @@
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
static constexpr std::array<EGLint, 15> egl_attribs{EGL_SURFACE_TYPE,
|
|
||||||
EGL_WINDOW_BIT,
|
|
||||||
EGL_RENDERABLE_TYPE,
|
|
||||||
EGL_OPENGL_ES3_BIT_KHR,
|
|
||||||
EGL_BLUE_SIZE,
|
|
||||||
8,
|
|
||||||
EGL_GREEN_SIZE,
|
|
||||||
8,
|
|
||||||
EGL_RED_SIZE,
|
|
||||||
8,
|
|
||||||
EGL_DEPTH_SIZE,
|
|
||||||
0,
|
|
||||||
EGL_STENCIL_SIZE,
|
|
||||||
0,
|
|
||||||
EGL_NONE};
|
|
||||||
static constexpr std::array<EGLint, 5> egl_empty_attribs{EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
|
|
||||||
static constexpr std::array<EGLint, 4> egl_context_attribs{EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
|
|
||||||
|
|
||||||
SharedContext_Android::SharedContext_Android(EGLDisplay egl_display, EGLConfig egl_config,
|
|
||||||
EGLContext egl_share_context)
|
|
||||||
: egl_display{egl_display}, egl_surface{eglCreatePbufferSurface(egl_display, egl_config,
|
|
||||||
egl_empty_attribs.data())},
|
|
||||||
egl_context{eglCreateContext(egl_display, egl_config, egl_share_context,
|
|
||||||
egl_context_attribs.data())} {
|
|
||||||
ASSERT_MSG(egl_surface, "eglCreatePbufferSurface() failed!");
|
|
||||||
ASSERT_MSG(egl_context, "eglCreateContext() failed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedContext_Android::~SharedContext_Android() {
|
|
||||||
if (!eglDestroySurface(egl_display, egl_surface)) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!eglDestroyContext(egl_display, egl_context)) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedContext_Android::MakeCurrent() {
|
|
||||||
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedContext_Android::DoneCurrent() {
|
|
||||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsPortraitMode() {
|
static bool IsPortraitMode() {
|
||||||
return JNI_FALSE != IDCache::GetEnvForThread()->CallStaticBooleanMethod(
|
return JNI_FALSE != IDCache::GetEnvForThread()->CallStaticBooleanMethod(
|
||||||
IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode());
|
IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode());
|
||||||
|
@ -79,6 +30,10 @@ static void UpdateLandscapeScreenLayout() {
|
||||||
|
|
||||||
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
||||||
render_window = surface;
|
render_window = surface;
|
||||||
|
|
||||||
|
window_info.type = Frontend::WindowSystemType::Android;
|
||||||
|
window_info.render_surface = surface;
|
||||||
|
|
||||||
StopPresenting();
|
StopPresenting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +53,7 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) {
|
||||||
void EmuWindow_Android::OnFramebufferSizeChanged() {
|
void EmuWindow_Android::OnFramebufferSizeChanged() {
|
||||||
UpdateLandscapeScreenLayout();
|
UpdateLandscapeScreenLayout();
|
||||||
const bool is_portrait_mode{IsPortraitMode()};
|
const bool is_portrait_mode{IsPortraitMode()};
|
||||||
|
|
||||||
const int bigger{window_width > window_height ? window_width : window_height};
|
const int bigger{window_width > window_height ? window_width : window_height};
|
||||||
const int smaller{window_width < window_height ? window_width : window_height};
|
const int smaller{window_width < window_height ? window_width : window_height};
|
||||||
if (is_portrait_mode) {
|
if (is_portrait_mode) {
|
||||||
|
@ -107,7 +63,7 @@ void EmuWindow_Android::OnFramebufferSizeChanged() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) {
|
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) : host_window{surface} {
|
||||||
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android");
|
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android");
|
||||||
|
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
|
@ -115,108 +71,10 @@ EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window_width = ANativeWindow_getWidth(surface);
|
||||||
|
window_height = ANativeWindow_getHeight(surface);
|
||||||
|
|
||||||
Network::Init();
|
Network::Init();
|
||||||
|
|
||||||
host_window = surface;
|
|
||||||
|
|
||||||
if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglGetDisplay() failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (eglInitialize(egl_display, 0, 0) != EGL_TRUE) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglInitialize() failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (EGLint egl_num_configs{}; eglChooseConfig(egl_display, egl_attribs.data(), &egl_config, 1,
|
|
||||||
&egl_num_configs) != EGL_TRUE) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglChooseConfig() failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateWindowSurface();
|
|
||||||
|
|
||||||
if (eglQuerySurface(egl_display, egl_surface, EGL_WIDTH, &window_width) != EGL_TRUE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (eglQuerySurface(egl_display, egl_surface, EGL_HEIGHT, &window_height) != EGL_TRUE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (egl_context = eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data());
|
|
||||||
egl_context == EGL_NO_CONTEXT) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglCreateContext() failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (eglSurfaceAttrib(egl_display, egl_surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) !=
|
|
||||||
EGL_TRUE) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglSurfaceAttrib() failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (core_context = CreateSharedContext(); !core_context) {
|
|
||||||
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) != EGL_TRUE) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglMakeCurrent() failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!gladLoadGLES2Loader((GLADloadproc)eglGetProcAddress)) {
|
|
||||||
LOG_CRITICAL(Frontend, "gladLoadGLES2Loader() failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0)) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglSwapInterval() failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnFramebufferSizeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmuWindow_Android::CreateWindowSurface() {
|
|
||||||
if (!host_window) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLint format{};
|
|
||||||
eglGetConfigAttrib(egl_display, egl_config, EGL_NATIVE_VISUAL_ID, &format);
|
|
||||||
ANativeWindow_setBuffersGeometry(host_window, 0, 0, format);
|
|
||||||
|
|
||||||
if (egl_surface = eglCreateWindowSurface(egl_display, egl_config, host_window, 0);
|
|
||||||
egl_surface == EGL_NO_SURFACE) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!egl_surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuWindow_Android::DestroyWindowSurface() {
|
|
||||||
if (!egl_surface) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (eglGetCurrentSurface(EGL_DRAW) == egl_surface) {
|
|
||||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
||||||
}
|
|
||||||
if (!eglDestroySurface(egl_display, egl_surface)) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
|
||||||
}
|
|
||||||
egl_surface = EGL_NO_SURFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuWindow_Android::DestroyContext() {
|
|
||||||
if (!egl_context) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (eglGetCurrentContext() == egl_context) {
|
|
||||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
||||||
}
|
|
||||||
if (!eglDestroyContext(egl_display, egl_context)) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
|
||||||
}
|
|
||||||
if (!eglTerminate(egl_display)) {
|
|
||||||
LOG_CRITICAL(Frontend, "eglTerminate() failed");
|
|
||||||
}
|
|
||||||
egl_context = EGL_NO_CONTEXT;
|
|
||||||
egl_display = EGL_NO_DISPLAY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_Android::~EmuWindow_Android() {
|
EmuWindow_Android::~EmuWindow_Android() {
|
||||||
|
@ -224,34 +82,6 @@ EmuWindow_Android::~EmuWindow_Android() {
|
||||||
DestroyContext();
|
DestroyContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android::CreateSharedContext() const {
|
|
||||||
return std::make_unique<SharedContext_Android>(egl_display, egl_config, egl_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuWindow_Android::StopPresenting() {
|
|
||||||
if (presenting_state == PresentingState::Running) {
|
|
||||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
||||||
}
|
|
||||||
presenting_state = PresentingState::Stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuWindow_Android::TryPresenting() {
|
|
||||||
if (presenting_state != PresentingState::Running) {
|
|
||||||
if (presenting_state == PresentingState::Initial) {
|
|
||||||
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
||||||
presenting_state = PresentingState::Running;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
|
|
||||||
if (VideoCore::g_renderer) {
|
|
||||||
VideoCore::g_renderer->TryPresent(0);
|
|
||||||
eglSwapBuffers(egl_display, egl_surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuWindow_Android::PollEvents() {
|
void EmuWindow_Android::PollEvents() {
|
||||||
if (!render_window) {
|
if (!render_window) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -5,38 +5,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
|
||||||
#include <EGL/eglext.h>
|
|
||||||
|
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
|
|
||||||
struct ANativeWindow;
|
|
||||||
|
|
||||||
class SharedContext_Android : public Frontend::GraphicsContext {
|
|
||||||
public:
|
|
||||||
SharedContext_Android(EGLDisplay egl_display, EGLConfig egl_config,
|
|
||||||
EGLContext egl_share_context);
|
|
||||||
|
|
||||||
~SharedContext_Android() override;
|
|
||||||
|
|
||||||
void MakeCurrent() override;
|
|
||||||
|
|
||||||
void DoneCurrent() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
EGLDisplay egl_display{};
|
|
||||||
EGLSurface egl_surface{};
|
|
||||||
EGLContext egl_context{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class EmuWindow_Android : public Frontend::EmuWindow {
|
class EmuWindow_Android : public Frontend::EmuWindow {
|
||||||
public:
|
public:
|
||||||
EmuWindow_Android(ANativeWindow* surface);
|
EmuWindow_Android(ANativeWindow* surface);
|
||||||
~EmuWindow_Android();
|
~EmuWindow_Android();
|
||||||
|
|
||||||
void Present();
|
|
||||||
|
|
||||||
/// Called by the onSurfaceChanges() method to change the surface
|
/// Called by the onSurfaceChanges() method to change the surface
|
||||||
void OnSurfaceChanged(ANativeWindow* surface);
|
void OnSurfaceChanged(ANativeWindow* surface);
|
||||||
|
|
||||||
|
@ -47,31 +22,36 @@ public:
|
||||||
void OnTouchMoved(int x, int y);
|
void OnTouchMoved(int x, int y);
|
||||||
|
|
||||||
void PollEvents() override;
|
void PollEvents() override;
|
||||||
|
|
||||||
void MakeCurrent() override;
|
void MakeCurrent() override;
|
||||||
|
|
||||||
void DoneCurrent() override;
|
void DoneCurrent() override;
|
||||||
|
|
||||||
void TryPresenting();
|
virtual void TryPresenting() = 0;
|
||||||
void StopPresenting();
|
|
||||||
|
|
||||||
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
virtual void StopPresenting() = 0;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void OnFramebufferSizeChanged();
|
void OnFramebufferSizeChanged();
|
||||||
bool CreateWindowSurface();
|
|
||||||
void DestroyWindowSurface();
|
|
||||||
void DestroyContext();
|
|
||||||
|
|
||||||
|
/// Creates the API specific window surface
|
||||||
|
virtual bool CreateWindowSurface() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys the API specific window surface
|
||||||
|
virtual void DestroyWindowSurface() {}
|
||||||
|
|
||||||
|
/// Destroys the graphics context
|
||||||
|
virtual void DestroyContext() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
ANativeWindow* render_window{};
|
ANativeWindow* render_window{};
|
||||||
ANativeWindow* host_window{};
|
ANativeWindow* host_window{};
|
||||||
|
|
||||||
int window_width{};
|
int window_width{};
|
||||||
int window_height{};
|
int window_height{};
|
||||||
|
|
||||||
EGLConfig egl_config;
|
|
||||||
EGLSurface egl_surface{};
|
|
||||||
EGLContext egl_context{};
|
|
||||||
EGLDisplay egl_display{};
|
|
||||||
|
|
||||||
std::unique_ptr<Frontend::GraphicsContext> core_context;
|
std::unique_ptr<Frontend::GraphicsContext> core_context;
|
||||||
|
|
||||||
enum class PresentingState {
|
enum class PresentingState {
|
||||||
|
|
201
src/android/app/src/main/jni/emu_window/emu_window_gl.cpp
Normal file
201
src/android/app/src/main/jni/emu_window/emu_window_gl.cpp
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
// Copyright 2019 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <android/native_window_jni.h>
|
||||||
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/settings.h"
|
||||||
|
#include "input_common/main.h"
|
||||||
|
#include "jni/emu_window/emu_window_gl.h"
|
||||||
|
#include "video_core/renderer_base.h"
|
||||||
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
|
static constexpr std::array<EGLint, 15> egl_attribs{EGL_SURFACE_TYPE,
|
||||||
|
EGL_WINDOW_BIT,
|
||||||
|
EGL_RENDERABLE_TYPE,
|
||||||
|
EGL_OPENGL_ES3_BIT_KHR,
|
||||||
|
EGL_BLUE_SIZE,
|
||||||
|
8,
|
||||||
|
EGL_GREEN_SIZE,
|
||||||
|
8,
|
||||||
|
EGL_RED_SIZE,
|
||||||
|
8,
|
||||||
|
EGL_DEPTH_SIZE,
|
||||||
|
0,
|
||||||
|
EGL_STENCIL_SIZE,
|
||||||
|
0,
|
||||||
|
EGL_NONE};
|
||||||
|
static constexpr std::array<EGLint, 5> egl_empty_attribs{EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
|
||||||
|
static constexpr std::array<EGLint, 4> egl_context_attribs{EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
|
||||||
|
|
||||||
|
class SharedContext_Android : public Frontend::GraphicsContext {
|
||||||
|
public:
|
||||||
|
SharedContext_Android(EGLDisplay egl_display, EGLConfig egl_config,
|
||||||
|
EGLContext egl_share_context)
|
||||||
|
: egl_display{egl_display}, egl_surface{eglCreatePbufferSurface(egl_display, egl_config,
|
||||||
|
egl_empty_attribs.data())},
|
||||||
|
egl_context{eglCreateContext(egl_display, egl_config, egl_share_context,
|
||||||
|
egl_context_attribs.data())} {
|
||||||
|
ASSERT_MSG(egl_surface, "eglCreatePbufferSurface() failed!");
|
||||||
|
ASSERT_MSG(egl_context, "eglCreateContext() failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
~SharedContext_Android() override {
|
||||||
|
if (!eglDestroySurface(egl_display, egl_surface)) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eglDestroyContext(egl_display, egl_context)) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MakeCurrent() override {
|
||||||
|
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoneCurrent() override {
|
||||||
|
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
EGLDisplay egl_display{};
|
||||||
|
EGLSurface egl_surface{};
|
||||||
|
EGLContext egl_context{};
|
||||||
|
};
|
||||||
|
|
||||||
|
EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(ANativeWindow* surface)
|
||||||
|
: EmuWindow_Android{surface} {
|
||||||
|
if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglGetDisplay() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (eglInitialize(egl_display, 0, 0) != EGL_TRUE) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglInitialize() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (EGLint egl_num_configs{}; eglChooseConfig(egl_display, egl_attribs.data(), &egl_config, 1,
|
||||||
|
&egl_num_configs) != EGL_TRUE) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglChooseConfig() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateWindowSurface();
|
||||||
|
|
||||||
|
if (eglQuerySurface(egl_display, egl_surface, EGL_WIDTH, &window_width) != EGL_TRUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (eglQuerySurface(egl_display, egl_surface, EGL_HEIGHT, &window_height) != EGL_TRUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (egl_context = eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data());
|
||||||
|
egl_context == EGL_NO_CONTEXT) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglCreateContext() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (eglSurfaceAttrib(egl_display, egl_surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) !=
|
||||||
|
EGL_TRUE) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglSurfaceAttrib() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (core_context = CreateSharedContext(); !core_context) {
|
||||||
|
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) != EGL_TRUE) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglMakeCurrent() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!gladLoadGLES2Loader((GLADloadproc)eglGetProcAddress)) {
|
||||||
|
LOG_CRITICAL(Frontend, "gladLoadGLES2Loader() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0)) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglSwapInterval() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnFramebufferSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EmuWindow_Android_OpenGL::CreateWindowSurface() {
|
||||||
|
if (!host_window) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLint format{};
|
||||||
|
eglGetConfigAttrib(egl_display, egl_config, EGL_NATIVE_VISUAL_ID, &format);
|
||||||
|
ANativeWindow_setBuffersGeometry(host_window, 0, 0, format);
|
||||||
|
|
||||||
|
if (egl_surface = eglCreateWindowSurface(egl_display, egl_config, host_window, 0);
|
||||||
|
egl_surface == EGL_NO_SURFACE) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return egl_surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuWindow_Android_OpenGL::DestroyWindowSurface() {
|
||||||
|
if (!egl_surface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (eglGetCurrentSurface(EGL_DRAW) == egl_surface) {
|
||||||
|
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||||
|
}
|
||||||
|
if (!eglDestroySurface(egl_display, egl_surface)) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||||
|
}
|
||||||
|
egl_surface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuWindow_Android_OpenGL::DestroyContext() {
|
||||||
|
if (!egl_context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (eglGetCurrentContext() == egl_context) {
|
||||||
|
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||||
|
}
|
||||||
|
if (!eglDestroyContext(egl_display, egl_context)) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||||
|
}
|
||||||
|
if (!eglTerminate(egl_display)) {
|
||||||
|
LOG_CRITICAL(Frontend, "eglTerminate() failed");
|
||||||
|
}
|
||||||
|
egl_context = EGL_NO_CONTEXT;
|
||||||
|
egl_display = EGL_NO_DISPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android_OpenGL::CreateSharedContext() const {
|
||||||
|
return std::make_unique<SharedContext_Android>(egl_display, egl_config, egl_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuWindow_Android_OpenGL::StopPresenting() {
|
||||||
|
if (presenting_state == PresentingState::Running) {
|
||||||
|
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||||
|
}
|
||||||
|
presenting_state = PresentingState::Stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuWindow_Android_OpenGL::TryPresenting() {
|
||||||
|
if (presenting_state == PresentingState::Initial) [[unlikely]] {
|
||||||
|
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
presenting_state = PresentingState::Running;
|
||||||
|
}
|
||||||
|
if (presenting_state != PresentingState::Running) [[unlikely]] {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
|
||||||
|
if (VideoCore::g_renderer) {
|
||||||
|
VideoCore::g_renderer->TryPresent(0);
|
||||||
|
eglSwapBuffers(egl_display, egl_surface);
|
||||||
|
}
|
||||||
|
}
|
36
src/android/app/src/main/jni/emu_window/emu_window_gl.h
Normal file
36
src/android/app/src/main/jni/emu_window/emu_window_gl.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2019 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
|
#include "jni/emu_window/emu_window.h"
|
||||||
|
|
||||||
|
struct ANativeWindow;
|
||||||
|
|
||||||
|
class EmuWindow_Android_OpenGL : public EmuWindow_Android {
|
||||||
|
public:
|
||||||
|
EmuWindow_Android_OpenGL(ANativeWindow* surface);
|
||||||
|
~EmuWindow_Android_OpenGL() override = default;
|
||||||
|
|
||||||
|
void TryPresenting() override;
|
||||||
|
void StopPresenting() override;
|
||||||
|
|
||||||
|
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool CreateWindowSurface() override;
|
||||||
|
void DestroyWindowSurface() override;
|
||||||
|
void DestroyContext() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EGLConfig egl_config;
|
||||||
|
EGLSurface egl_surface{};
|
||||||
|
EGLContext egl_context{};
|
||||||
|
EGLDisplay egl_display{};
|
||||||
|
};
|
49
src/android/app/src/main/jni/emu_window/emu_window_vk.cpp
Normal file
49
src/android/app/src/main/jni/emu_window/emu_window_vk.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright 2019 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <android/native_window_jni.h>
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/settings.h"
|
||||||
|
#include "jni/emu_window/emu_window_vk.h"
|
||||||
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
|
class SharedContext_Android : public Frontend::GraphicsContext {};
|
||||||
|
|
||||||
|
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(ANativeWindow* surface)
|
||||||
|
: EmuWindow_Android{surface} {
|
||||||
|
CreateWindowSurface();
|
||||||
|
|
||||||
|
if (core_context = CreateSharedContext(); !core_context) {
|
||||||
|
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnFramebufferSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EmuWindow_Android_Vulkan::CreateWindowSurface() {
|
||||||
|
if (!host_window) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_info.type = Frontend::WindowSystemType::Android;
|
||||||
|
window_info.render_surface = host_window;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android_Vulkan::CreateSharedContext() const {
|
||||||
|
return std::make_unique<SharedContext_Android>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuWindow_Android_Vulkan::StopPresenting() {
|
||||||
|
presenting_state = PresentingState::Stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuWindow_Android_Vulkan::TryPresenting() {
|
||||||
|
if (presenting_state == PresentingState::Initial) {
|
||||||
|
presenting_state = PresentingState::Running;
|
||||||
|
}
|
||||||
|
}
|
23
src/android/app/src/main/jni/emu_window/emu_window_vk.h
Normal file
23
src/android/app/src/main/jni/emu_window/emu_window_vk.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2022 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "jni/emu_window/emu_window.h"
|
||||||
|
|
||||||
|
struct ANativeWindow;
|
||||||
|
|
||||||
|
class EmuWindow_Android_Vulkan : public EmuWindow_Android {
|
||||||
|
public:
|
||||||
|
EmuWindow_Android_Vulkan(ANativeWindow* surface);
|
||||||
|
~EmuWindow_Android_Vulkan() override = default;
|
||||||
|
|
||||||
|
void TryPresenting() override;
|
||||||
|
void StopPresenting() override;
|
||||||
|
|
||||||
|
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool CreateWindowSurface() override;
|
||||||
|
};
|
|
@ -33,7 +33,8 @@
|
||||||
#include "jni/camera/ndk_camera.h"
|
#include "jni/camera/ndk_camera.h"
|
||||||
#include "jni/camera/still_image_camera.h"
|
#include "jni/camera/still_image_camera.h"
|
||||||
#include "jni/config.h"
|
#include "jni/config.h"
|
||||||
#include "jni/emu_window/emu_window.h"
|
#include "jni/emu_window/emu_window_gl.h"
|
||||||
|
#include "jni/emu_window/emu_window_vk.h"
|
||||||
#include "jni/game_settings.h"
|
#include "jni/game_settings.h"
|
||||||
#include "jni/id_cache.h"
|
#include "jni/id_cache.h"
|
||||||
#include "jni/input_manager.h"
|
#include "jni/input_manager.h"
|
||||||
|
@ -123,11 +124,14 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
||||||
const auto graphics_api = Settings::values.graphics_api.GetValue();
|
const auto graphics_api = Settings::values.graphics_api.GetValue();
|
||||||
switch (graphics_api) {
|
switch (graphics_api) {
|
||||||
case Settings::GraphicsAPI::OpenGL:
|
case Settings::GraphicsAPI::OpenGL:
|
||||||
window = std::make_unique<EmuWindow_Android>(s_surf);
|
window = std::make_unique<EmuWindow_Android_OpenGL>(s_surf);
|
||||||
|
break;
|
||||||
|
case Settings::GraphicsAPI::Vulkan:
|
||||||
|
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(Frontend, "Unknown graphics API {}, using OpenGL", graphics_api);
|
LOG_CRITICAL(Frontend, "Unknown graphics API {}, using Vulkan", graphics_api);
|
||||||
window = std::make_unique<EmuWindow_Android>(s_surf);
|
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::System& system{Core::System::GetInstance()};
|
Core::System& system{Core::System::GetInstance()};
|
||||||
|
|
Binary file not shown.
BIN
src/android/app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Normal file
BIN
src/android/app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Normal file
Binary file not shown.
|
@ -177,11 +177,13 @@
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="graphicsApiNames">
|
<string-array name="graphicsApiNames">
|
||||||
<item>OpenGLES</item>
|
<item>OpenGL ES</item>
|
||||||
|
<item>Vulkan</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<integer-array name="graphicsApiValues">
|
<integer-array name="graphicsApiValues">
|
||||||
<item>1</item>
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="textureFilterNames">
|
<string-array name="textureFilterNames">
|
||||||
|
|
|
@ -74,6 +74,10 @@
|
||||||
<!-- Graphics settings strings -->
|
<!-- Graphics settings strings -->
|
||||||
<string name="renderer">Renderer</string>
|
<string name="renderer">Renderer</string>
|
||||||
<string name="graphics_api">Graphics API</string>
|
<string name="graphics_api">Graphics API</string>
|
||||||
|
<string name="spirv_shader_gen">Enable SPIR-V shader generation</string>
|
||||||
|
<string name="spirv_shader_gen_description">Emits the fragment shader used to emulate PICA using SPIR-V instead of GLSL</string>
|
||||||
|
<string name="async_shaders">Enable asynchronous shader compilation</string>
|
||||||
|
<string name="async_shaders_description">Compiles shaders in the background to reduce stuttering during gameplay. When enabled expect temporary graphical glitches</string>
|
||||||
<string name="renderer_debug">Debug Renderer</string>
|
<string name="renderer_debug">Debug Renderer</string>
|
||||||
<string name="renderer_debug_description">Log additional graphics related debug information. When enabled, game performance will be significantly reduced.</string>
|
<string name="renderer_debug_description">Log additional graphics related debug information. When enabled, game performance will be significantly reduced.</string>
|
||||||
<string name="vsync">Enable V-Sync</string>
|
<string name="vsync">Enable V-Sync</string>
|
||||||
|
|
|
@ -12,6 +12,8 @@ add_executable(citra
|
||||||
emu_window/emu_window_sdl2_gl.h
|
emu_window/emu_window_sdl2_gl.h
|
||||||
emu_window/emu_window_sdl2_sw.cpp
|
emu_window/emu_window_sdl2_sw.cpp
|
||||||
emu_window/emu_window_sdl2_sw.h
|
emu_window/emu_window_sdl2_sw.h
|
||||||
|
emu_window/emu_window_sdl2_vk.cpp
|
||||||
|
emu_window/emu_window_sdl2_vk.h
|
||||||
precompiled_headers.h
|
precompiled_headers.h
|
||||||
resource.h
|
resource.h
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "citra/emu_window/emu_window_sdl2.h"
|
#include "citra/emu_window/emu_window_sdl2.h"
|
||||||
#include "citra/emu_window/emu_window_sdl2_gl.h"
|
#include "citra/emu_window/emu_window_sdl2_gl.h"
|
||||||
#include "citra/emu_window/emu_window_sdl2_sw.h"
|
#include "citra/emu_window/emu_window_sdl2_sw.h"
|
||||||
|
#include "citra/emu_window/emu_window_sdl2_vk.h"
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
#include "common/detached_tasks.h"
|
#include "common/detached_tasks.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
|
@ -351,6 +352,8 @@ int main(int argc, char** argv) {
|
||||||
switch (Settings::values.graphics_api.GetValue()) {
|
switch (Settings::values.graphics_api.GetValue()) {
|
||||||
case Settings::GraphicsAPI::OpenGL:
|
case Settings::GraphicsAPI::OpenGL:
|
||||||
return std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen, is_secondary);
|
return std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen, is_secondary);
|
||||||
|
case Settings::GraphicsAPI::Vulkan:
|
||||||
|
return std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen, is_secondary);
|
||||||
case Settings::GraphicsAPI::Software:
|
case Settings::GraphicsAPI::Software:
|
||||||
return std::make_unique<EmuWindow_SDL2_SW>(system, fullscreen, is_secondary);
|
return std::make_unique<EmuWindow_SDL2_SW>(system, fullscreen, is_secondary);
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,10 @@ void Config::ReadValues() {
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
ReadSetting("Renderer", Settings::values.graphics_api);
|
ReadSetting("Renderer", Settings::values.graphics_api);
|
||||||
|
ReadSetting("Renderer", Settings::values.physical_device);
|
||||||
|
ReadSetting("Renderer", Settings::values.spirv_shader_gen);
|
||||||
|
ReadSetting("Renderer", Settings::values.async_shader_compilation);
|
||||||
|
ReadSetting("Renderer", Settings::values.async_presentation);
|
||||||
ReadSetting("Renderer", Settings::values.use_gles);
|
ReadSetting("Renderer", Settings::values.use_gles);
|
||||||
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
||||||
ReadSetting("Renderer", Settings::values.shaders_accurate_mul);
|
ReadSetting("Renderer", Settings::values.shaders_accurate_mul);
|
||||||
|
|
|
@ -99,7 +99,7 @@ cpu_clock_percentage =
|
||||||
|
|
||||||
[Renderer]
|
[Renderer]
|
||||||
# Whether to render using OpenGL or Software
|
# Whether to render using OpenGL or Software
|
||||||
# 0: Software, 1: OpenGL (default)
|
# 0: Software, 1: OpenGL (default), 2: Vulkan
|
||||||
graphics_api =
|
graphics_api =
|
||||||
|
|
||||||
# Whether to render using GLES or OpenGL
|
# Whether to render using GLES or OpenGL
|
||||||
|
|
88
src/citra/emu_window/emu_window_sdl2_vk.cpp
Normal file
88
src/citra/emu_window/emu_window_sdl2_vk.cpp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// Copyright 2023 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_syswm.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include "citra/emu_window/emu_window_sdl2_vk.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/scm_rev.h"
|
||||||
|
#include "core/frontend/emu_window.h"
|
||||||
|
|
||||||
|
class DummyContext : public Frontend::GraphicsContext {};
|
||||||
|
|
||||||
|
EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen, bool is_secondary)
|
||||||
|
: EmuWindow_SDL2{system, is_secondary} {
|
||||||
|
const std::string window_title = fmt::format("Citra {} | {}-{}", Common::g_build_fullname,
|
||||||
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
|
render_window =
|
||||||
|
SDL_CreateWindow(window_title.c_str(),
|
||||||
|
SDL_WINDOWPOS_UNDEFINED, // x position
|
||||||
|
SDL_WINDOWPOS_UNDEFINED, // y position
|
||||||
|
Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight,
|
||||||
|
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||||
|
SDL_SysWMinfo wm;
|
||||||
|
SDL_VERSION(&wm.version);
|
||||||
|
if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) {
|
||||||
|
LOG_CRITICAL(Frontend, "Failed to get information from the window manager");
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullscreen) {
|
||||||
|
Fullscreen();
|
||||||
|
SDL_ShowCursor(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (wm.subsystem) {
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS:
|
||||||
|
window_info.type = Frontend::WindowSystemType::Windows;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_X11
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
|
||||||
|
window_info.type = Frontend::WindowSystemType::X11;
|
||||||
|
window_info.display_connection = wm.info.x11.display;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
|
||||||
|
window_info.type = Frontend::WindowSystemType::Wayland;
|
||||||
|
window_info.display_connection = wm.info.wl.display;
|
||||||
|
window_info.render_surface = wm.info.wl.surface;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_COCOA
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA:
|
||||||
|
window_info.type = Frontend::WindowSystemType::MacOS;
|
||||||
|
window_info.render_surface = SDL_Metal_CreateView(render_window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID:
|
||||||
|
window_info.type = Frontend::WindowSystemType::Android;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.android.window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem);
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnResize();
|
||||||
|
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||||
|
SDL_PumpEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const {
|
||||||
|
return std::make_unique<DummyContext>();
|
||||||
|
}
|
24
src/citra/emu_window/emu_window_sdl2_vk.h
Normal file
24
src/citra/emu_window/emu_window_sdl2_vk.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2023 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include "citra/emu_window/emu_window_sdl2.h"
|
||||||
|
|
||||||
|
namespace Frontend {
|
||||||
|
class GraphicsContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
|
||||||
|
public:
|
||||||
|
explicit EmuWindow_SDL2_VK(Core::System& system_, bool fullscreen, bool is_secondary);
|
||||||
|
~EmuWindow_SDL2_VK() override;
|
||||||
|
|
||||||
|
std::unique_ptr<Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||||
|
};
|
|
@ -289,6 +289,22 @@ private:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class VulkanRenderWidget : public RenderWidget {
|
||||||
|
public:
|
||||||
|
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
|
||||||
|
setAttribute(Qt::WA_NativeWindow);
|
||||||
|
setAttribute(Qt::WA_PaintOnScreen);
|
||||||
|
if (GetWindowSystemType() == Frontend::WindowSystemType::Wayland) {
|
||||||
|
setAttribute(Qt::WA_DontCreateNativeAncestors);
|
||||||
|
}
|
||||||
|
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPaintEngine* paintEngine() const override {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct SoftwareRenderWidget : public RenderWidget {
|
struct SoftwareRenderWidget : public RenderWidget {
|
||||||
explicit SoftwareRenderWidget(GRenderWindow* parent, Core::System& system_)
|
explicit SoftwareRenderWidget(GRenderWindow* parent, Core::System& system_)
|
||||||
: RenderWidget(parent), system(system_) {}
|
: RenderWidget(parent), system(system_) {}
|
||||||
|
@ -601,6 +617,9 @@ bool GRenderWindow::InitRenderTarget() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Settings::GraphicsAPI::Vulkan:
|
||||||
|
InitializeVulkan();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the Window System information with the new render target
|
// Update the Window System information with the new render target
|
||||||
|
@ -686,6 +705,13 @@ bool GRenderWindow::InitializeOpenGL() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GRenderWindow::InitializeVulkan() {
|
||||||
|
auto child = new VulkanRenderWidget(this);
|
||||||
|
child_widget = child;
|
||||||
|
child_widget->windowHandle()->create();
|
||||||
|
main_context = std::make_unique<DummyContext>();
|
||||||
|
}
|
||||||
|
|
||||||
void GRenderWindow::InitializeSoftware() {
|
void GRenderWindow::InitializeSoftware() {
|
||||||
child_widget = new SoftwareRenderWidget(this, system);
|
child_widget = new SoftwareRenderWidget(this, system);
|
||||||
main_context = std::make_unique<DummyContext>();
|
main_context = std::make_unique<DummyContext>();
|
||||||
|
|
|
@ -187,6 +187,7 @@ private:
|
||||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||||
|
|
||||||
bool InitializeOpenGL();
|
bool InitializeOpenGL();
|
||||||
|
void InitializeVulkan();
|
||||||
void InitializeSoftware();
|
void InitializeSoftware();
|
||||||
bool LoadOpenGL();
|
bool LoadOpenGL();
|
||||||
|
|
||||||
|
|
|
@ -483,6 +483,7 @@ void Config::ReadDebuggingValues() {
|
||||||
ReadBasicSetting(Settings::values.use_gdbstub);
|
ReadBasicSetting(Settings::values.use_gdbstub);
|
||||||
ReadBasicSetting(Settings::values.gdbstub_port);
|
ReadBasicSetting(Settings::values.gdbstub_port);
|
||||||
ReadBasicSetting(Settings::values.renderer_debug);
|
ReadBasicSetting(Settings::values.renderer_debug);
|
||||||
|
ReadBasicSetting(Settings::values.dump_command_buffers);
|
||||||
|
|
||||||
qt_config->beginGroup(QStringLiteral("LLE"));
|
qt_config->beginGroup(QStringLiteral("LLE"));
|
||||||
for (const auto& service_module : Service::service_module_map) {
|
for (const auto& service_module : Service::service_module_map) {
|
||||||
|
@ -627,6 +628,10 @@ void Config::ReadRendererValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||||
|
|
||||||
ReadGlobalSetting(Settings::values.graphics_api);
|
ReadGlobalSetting(Settings::values.graphics_api);
|
||||||
|
ReadGlobalSetting(Settings::values.physical_device);
|
||||||
|
ReadGlobalSetting(Settings::values.spirv_shader_gen);
|
||||||
|
ReadGlobalSetting(Settings::values.async_shader_compilation);
|
||||||
|
ReadGlobalSetting(Settings::values.async_presentation);
|
||||||
ReadGlobalSetting(Settings::values.use_hw_shader);
|
ReadGlobalSetting(Settings::values.use_hw_shader);
|
||||||
ReadGlobalSetting(Settings::values.shaders_accurate_mul);
|
ReadGlobalSetting(Settings::values.shaders_accurate_mul);
|
||||||
ReadGlobalSetting(Settings::values.use_disk_shader_cache);
|
ReadGlobalSetting(Settings::values.use_disk_shader_cache);
|
||||||
|
@ -1107,6 +1112,10 @@ void Config::SaveRendererValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||||
|
|
||||||
WriteGlobalSetting(Settings::values.graphics_api);
|
WriteGlobalSetting(Settings::values.graphics_api);
|
||||||
|
WriteGlobalSetting(Settings::values.physical_device);
|
||||||
|
WriteGlobalSetting(Settings::values.spirv_shader_gen);
|
||||||
|
WriteGlobalSetting(Settings::values.async_shader_compilation);
|
||||||
|
WriteGlobalSetting(Settings::values.async_presentation);
|
||||||
WriteGlobalSetting(Settings::values.use_hw_shader);
|
WriteGlobalSetting(Settings::values.use_hw_shader);
|
||||||
WriteGlobalSetting(Settings::values.shaders_accurate_mul);
|
WriteGlobalSetting(Settings::values.shaders_accurate_mul);
|
||||||
WriteGlobalSetting(Settings::values.use_disk_shader_cache);
|
WriteGlobalSetting(Settings::values.use_disk_shader_cache);
|
||||||
|
|
|
@ -63,6 +63,11 @@
|
||||||
<string>OpenGL</string>
|
<string>OpenGL</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Vulkan</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
|
@ -2470,9 +2470,11 @@ void GMainWindow::ShowMouseCursor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::UpdateAPIIndicator(bool update) {
|
void GMainWindow::UpdateAPIIndicator(bool update) {
|
||||||
static std::array graphics_apis = {QStringLiteral("SOFTWARE"), QStringLiteral("OPENGL")};
|
static std::array graphics_apis = {QStringLiteral("SOFTWARE"), QStringLiteral("OPENGL"),
|
||||||
|
QStringLiteral("VULKAN")};
|
||||||
|
|
||||||
static std::array graphics_api_colors = {QStringLiteral("#3ae400"), QStringLiteral("#00ccdd")};
|
static std::array graphics_api_colors = {QStringLiteral("#3ae400"), QStringLiteral("#00ccdd"),
|
||||||
|
QStringLiteral("#91242a")};
|
||||||
|
|
||||||
u32 api_index = static_cast<u32>(Settings::values.graphics_api.GetValue());
|
u32 api_index = static_cast<u32>(Settings::values.graphics_api.GetValue());
|
||||||
if (update) {
|
if (update) {
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
DynamicLibrary::DynamicLibrary() = default;
|
||||||
|
|
||||||
DynamicLibrary::DynamicLibrary(std::string_view name, int major, int minor) {
|
DynamicLibrary::DynamicLibrary(std::string_view name, int major, int minor) {
|
||||||
auto full_name = GetLibraryName(name, major, minor);
|
auto full_name = GetLibraryName(name, major, minor);
|
||||||
void(Load(full_name));
|
void(Load(full_name));
|
||||||
|
|
|
@ -37,8 +37,8 @@ static inline u64 ComputeStructHash64(const T& data) noexcept {
|
||||||
* Combines the seed parameter with the provided hash, producing a new unique hash
|
* Combines the seed parameter with the provided hash, producing a new unique hash
|
||||||
* Implementation from: http://boost.sourceforge.net/doc/html/boost/hash_combine.html
|
* Implementation from: http://boost.sourceforge.net/doc/html/boost/hash_combine.html
|
||||||
*/
|
*/
|
||||||
inline u64 HashCombine(std::size_t& seed, const u64 hash) {
|
inline u64 HashCombine(std::size_t seed, const u64 hash) {
|
||||||
return seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -72,6 +72,9 @@ void LogSettings() {
|
||||||
log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage.GetValue());
|
log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage.GetValue());
|
||||||
log_setting("Renderer_UseGLES", values.use_gles.GetValue());
|
log_setting("Renderer_UseGLES", values.use_gles.GetValue());
|
||||||
log_setting("Renderer_GraphicsAPI", GetGraphicsAPIName(values.graphics_api.GetValue()));
|
log_setting("Renderer_GraphicsAPI", GetGraphicsAPIName(values.graphics_api.GetValue()));
|
||||||
|
log_setting("Renderer_AsyncShaders", values.async_shader_compilation.GetValue());
|
||||||
|
log_setting("Renderer_AsyncPresentation", values.async_presentation.GetValue());
|
||||||
|
log_setting("Renderer_SpirvShaderGen", values.spirv_shader_gen.GetValue());
|
||||||
log_setting("Renderer_Debug", values.renderer_debug.GetValue());
|
log_setting("Renderer_Debug", values.renderer_debug.GetValue());
|
||||||
log_setting("Renderer_UseHwShader", values.use_hw_shader.GetValue());
|
log_setting("Renderer_UseHwShader", values.use_hw_shader.GetValue());
|
||||||
log_setting("Renderer_ShadersAccurateMul", values.shaders_accurate_mul.GetValue());
|
log_setting("Renderer_ShadersAccurateMul", values.shaders_accurate_mul.GetValue());
|
||||||
|
@ -159,6 +162,10 @@ void RestoreGlobalState(bool is_powered_on) {
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
values.graphics_api.SetGlobal(true);
|
values.graphics_api.SetGlobal(true);
|
||||||
|
values.physical_device.SetGlobal(true);
|
||||||
|
values.spirv_shader_gen.SetGlobal(true);
|
||||||
|
values.async_shader_compilation.SetGlobal(true);
|
||||||
|
values.async_presentation.SetGlobal(true);
|
||||||
values.use_hw_shader.SetGlobal(true);
|
values.use_hw_shader.SetGlobal(true);
|
||||||
values.use_disk_shader_cache.SetGlobal(true);
|
values.use_disk_shader_cache.SetGlobal(true);
|
||||||
values.shaders_accurate_mul.SetGlobal(true);
|
values.shaders_accurate_mul.SetGlobal(true);
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
constexpr u32 GraphicsAPICount = 2;
|
|
||||||
enum class GraphicsAPI {
|
enum class GraphicsAPI {
|
||||||
Software = 0,
|
Software = 0,
|
||||||
OpenGL = 1,
|
OpenGL = 1,
|
||||||
|
Vulkan = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class InitClock : u32 {
|
enum class InitClock : u32 {
|
||||||
|
@ -430,12 +430,15 @@ struct Values {
|
||||||
Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"};
|
Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"};
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
SwitchableSetting<GraphicsAPI, true> graphics_api{
|
SwitchableSetting<GraphicsAPI, true> graphics_api{GraphicsAPI::OpenGL, GraphicsAPI::Software,
|
||||||
GraphicsAPI::OpenGL, GraphicsAPI::Software, static_cast<GraphicsAPI>(GraphicsAPICount - 1),
|
GraphicsAPI::Vulkan, "graphics_api"};
|
||||||
"graphics_api"};
|
SwitchableSetting<u32> physical_device{0, "physical_device"};
|
||||||
Setting<bool> use_gles{false, "use_gles"};
|
Setting<bool> use_gles{false, "use_gles"};
|
||||||
Setting<bool> renderer_debug{false, "renderer_debug"};
|
Setting<bool> renderer_debug{false, "renderer_debug"};
|
||||||
Setting<bool> dump_command_buffers{false, "dump_command_buffers"};
|
Setting<bool> dump_command_buffers{false, "dump_command_buffers"};
|
||||||
|
SwitchableSetting<bool> spirv_shader_gen{true, "spirv_shader_gen"};
|
||||||
|
SwitchableSetting<bool> async_shader_compilation{false, "async_shader_compilation"};
|
||||||
|
SwitchableSetting<bool> async_presentation{true, "async_presentation"};
|
||||||
SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"};
|
SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"};
|
||||||
SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
|
SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
|
||||||
SwitchableSetting<bool> shaders_accurate_mul{true, "shaders_accurate_mul"};
|
SwitchableSetting<bool> shaders_accurate_mul{true, "shaders_accurate_mul"};
|
||||||
|
|
Loading…
Reference in a new issue