summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rwxr-xr-x.travis/clang-format/build.sh2
-rwxr-xr-x.travis/clang-format/deps.sh2
-rwxr-xr-x.travis/clang-format/docker.sh3
-rwxr-xr-x.travis/linux-mingw/docker.sh1
-rw-r--r--CMakeLists.txt2
-rw-r--r--appveyor.yml19
-rw-r--r--externals/CMakeLists.txt9
-rw-r--r--externals/cmake-modules/GetGitRevisionDescription.cmake.in8
-rw-r--r--externals/glad/include/glad/glad.h2390
-rw-r--r--externals/glad/src/glad.c2467
m---------externals/xbyak0
-rw-r--r--src/audio_core/audio_renderer.cpp4
-rw-r--r--src/audio_core/audio_renderer.h9
-rw-r--r--src/common/CMakeLists.txt6
-rw-r--r--src/common/assert.h5
-rw-r--r--src/common/bit_field.h19
-rw-r--r--src/common/bit_set.h244
-rw-r--r--src/common/math_util.h16
-rw-r--r--src/common/string_util.cpp66
-rw-r--r--src/common/string_util.h41
-rw-r--r--src/common/thread.cpp35
-rw-r--r--src/common/thread.h20
-rw-r--r--src/common/x64/xbyak_abi.h222
-rw-r--r--src/common/x64/xbyak_util.h47
-rw-r--r--src/core/CMakeLists.txt16
-rw-r--r--src/core/core.cpp136
-rw-r--r--src/core/core.h5
-rw-r--r--src/core/cpu_core_manager.cpp142
-rw-r--r--src/core/cpu_core_manager.h59
-rw-r--r--src/core/crypto/key_manager.cpp3
-rw-r--r--src/core/file_sys/bis_factory.cpp9
-rw-r--r--src/core/file_sys/bis_factory.h4
-rw-r--r--src/core/file_sys/card_image.cpp2
-rw-r--r--src/core/file_sys/card_image.h16
-rw-r--r--src/core/file_sys/content_archive.cpp5
-rw-r--r--src/core/file_sys/content_archive.h3
-rw-r--r--src/core/file_sys/control_metadata.cpp30
-rw-r--r--src/core/file_sys/control_metadata.h1
-rw-r--r--src/core/file_sys/errors.h25
-rw-r--r--src/core/file_sys/patch_manager.cpp81
-rw-r--r--src/core/file_sys/registered_cache.cpp108
-rw-r--r--src/core/file_sys/registered_cache.h13
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/savedata_factory.cpp32
-rw-r--r--src/core/file_sys/savedata_factory.h3
-rw-r--r--src/core/file_sys/submission_package.cpp2
-rw-r--r--src/core/file_sys/submission_package.h2
-rw-r--r--src/core/file_sys/vfs.cpp46
-rw-r--r--src/core/file_sys/vfs.h20
-rw-r--r--src/core/frontend/applets/software_keyboard.cpp29
-rw-r--r--src/core/frontend/applets/software_keyboard.h54
-rw-r--r--src/core/frontend/input.h7
-rw-r--r--src/core/gdbstub/gdbstub.cpp123
-rw-r--r--src/core/hle/kernel/errors.h74
-rw-r--r--src/core/hle/kernel/handle_table.cpp16
-rw-r--r--src/core/hle/kernel/handle_table.h16
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp29
-rw-r--r--src/core/hle/kernel/hle_ipc.h12
-rw-r--r--src/core/hle/kernel/kernel.cpp79
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/kernel/object.cpp3
-rw-r--r--src/core/hle/kernel/object.h9
-rw-r--r--src/core/hle/kernel/process.cpp91
-rw-r--r--src/core/hle/kernel/process.h33
-rw-r--r--src/core/hle/kernel/readable_event.cpp (renamed from src/core/hle/kernel/event.cpp)27
-rw-r--r--src/core/hle/kernel/readable_event.h55
-rw-r--r--src/core/hle/kernel/resource_limit.cpp75
-rw-r--r--src/core/hle/kernel/resource_limit.h102
-rw-r--r--src/core/hle/kernel/shared_memory.cpp22
-rw-r--r--src/core/hle/kernel/shared_memory.h48
-rw-r--r--src/core/hle/kernel/svc.cpp718
-rw-r--r--src/core/hle/kernel/svc_wrap.h26
-rw-r--r--src/core/hle/kernel/thread.cpp48
-rw-r--r--src/core/hle/kernel/thread.h2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp82
-rw-r--r--src/core/hle/kernel/vm_manager.h16
-rw-r--r--src/core/hle/kernel/writable_event.cpp52
-rw-r--r--src/core/hle/kernel/writable_event.h (renamed from src/core/hle/kernel/event.h)35
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/acc/acc.cpp28
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp28
-rw-r--r--src/core/hle/service/acc/profile_manager.h27
-rw-r--r--src/core/hle/service/am/am.cpp567
-rw-r--r--src/core/hle/service/am/am.h46
-rw-r--r--src/core/hle/service/am/applet_ae.cpp66
-rw-r--r--src/core/hle/service/am/applet_oe.cpp27
-rw-r--r--src/core/hle/service/am/applets/applets.cpp114
-rw-r--r--src/core/hle/service/am/applets/applets.h109
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp161
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h74
-rw-r--r--src/core/hle/service/am/applets/stub_applet.cpp70
-rw-r--r--src/core/hle/service/am/applets/stub_applet.h24
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp20
-rw-r--r--src/core/hle/service/aoc/aoc_u.h6
-rw-r--r--src/core/hle/service/apm/interface.cpp16
-rw-r--r--src/core/hle/service/arp/arp.cpp4
-rw-r--r--src/core/hle/service/audio/audout_u.cpp48
-rw-r--r--src/core/hle/service/audio/audout_u.h3
-rw-r--r--src/core/hle/service/audio/audren_u.cpp102
-rw-r--r--src/core/hle/service/audio/hwopus.cpp48
-rw-r--r--src/core/hle/service/bcat/module.cpp3
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp43
-rw-r--r--src/core/hle/service/btm/btm.cpp121
-rw-r--r--src/core/hle/service/erpt/erpt.cpp12
-rw-r--r--src/core/hle/service/fgm/fgm.cpp4
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp57
-rw-r--r--src/core/hle/service/filesystem/filesystem.h16
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp196
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h1
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp43
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h41
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp20
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h7
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp25
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h9
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp529
-rw-r--r--src/core/hle/service/hid/controllers/npad.h56
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp13
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h12
-rw-r--r--src/core/hle/service/hid/hid.cpp133
-rw-r--r--src/core/hle/service/hid/irs.cpp54
-rw-r--r--src/core/hle/service/lbl/lbl.cpp12
-rw-r--r--src/core/hle/service/ldn/ldn.cpp12
-rw-r--r--src/core/hle/service/ldr/ldr.cpp392
-rw-r--r--src/core/hle/service/lm/lm.cpp17
-rw-r--r--src/core/hle/service/mm/mm_u.cpp14
-rw-r--r--src/core/hle/service/nfc/nfc.cpp24
-rw-r--r--src/core/hle/service/nfp/nfp.cpp52
-rw-r--r--src/core/hle/service/nfp/nfp.h7
-rw-r--r--src/core/hle/service/nifm/nifm.cpp43
-rw-r--r--src/core/hle/service/nim/nim.cpp43
-rw-r--r--src/core/hle/service/ns/ns.cpp72
-rw-r--r--src/core/hle/service/ns/pl_u.cpp18
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp25
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp16
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp33
-rw-r--r--src/core/hle/service/nvdrv/interface.h9
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp24
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h11
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp13
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h11
-rw-r--r--src/core/hle/service/pctl/module.cpp8
-rw-r--r--src/core/hle/service/pm/pm.cpp4
-rw-r--r--src/core/hle/service/psc/psc.cpp4
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/hle/service/set/set.cpp52
-rw-r--r--src/core/hle/service/set/set.h1
-rw-r--r--src/core/hle/service/set/set_sys.cpp8
-rw-r--r--src/core/hle/service/sm/controller.cpp11
-rw-r--r--src/core/hle/service/sm/sm.cpp58
-rw-r--r--src/core/hle/service/sm/sm.h3
-rw-r--r--src/core/hle/service/spl/module.cpp13
-rw-r--r--src/core/hle/service/spl/module.h4
-rw-r--r--src/core/hle/service/ssl/ssl.cpp2
-rw-r--r--src/core/hle/service/time/interface.cpp5
-rw-r--r--src/core/hle/service/time/time.cpp170
-rw-r--r--src/core/hle/service/time/time.h20
-rw-r--r--src/core/hle/service/usb/usb.cpp6
-rw-r--r--src/core/hle/service/vi/vi.cpp99
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp3
-rw-r--r--src/core/loader/nro.cpp27
-rw-r--r--src/core/loader/nro.h8
-rw-r--r--src/core/loader/nso.cpp10
-rw-r--r--src/core/loader/nso.h8
-rw-r--r--src/core/settings.cpp50
-rw-r--r--src/core/settings.h322
-rw-r--r--src/video_core/CMakeLists.txt7
-rw-r--r--src/video_core/command_processor.cpp139
-rw-r--r--src/video_core/command_processor.h53
-rw-r--r--src/video_core/dma_pusher.cpp123
-rw-r--r--src/video_core/dma_pusher.h99
-rw-r--r--src/video_core/engines/fermi_2d.cpp17
-rw-r--r--src/video_core/engines/fermi_2d.h2
-rw-r--r--src/video_core/engines/kepler_memory.cpp13
-rw-r--r--src/video_core/engines/kepler_memory.h3
-rw-r--r--src/video_core/engines/maxwell_3d.cpp69
-rw-r--r--src/video_core/engines/maxwell_3d.h234
-rw-r--r--src/video_core/engines/maxwell_compute.cpp8
-rw-r--r--src/video_core/engines/maxwell_compute.h3
-rw-r--r--src/video_core/engines/maxwell_dma.cpp13
-rw-r--r--src/video_core/engines/maxwell_dma.h2
-rw-r--r--src/video_core/engines/shader_bytecode.h27
-rw-r--r--src/video_core/engines/shader_header.h11
-rw-r--r--src/video_core/gpu.cpp59
-rw-r--r--src/video_core/gpu.h27
-rw-r--r--src/video_core/macro_interpreter.cpp31
-rw-r--r--src/video_core/macro_interpreter.h4
-rw-r--r--src/video_core/memory_manager.cpp7
-rw-r--r--src/video_core/memory_manager.h3
-rw-r--r--src/video_core/morton.cpp355
-rw-r--r--src/video_core/morton.h21
-rw-r--r--src/video_core/rasterizer_cache.h35
-rw-r--r--src/video_core/renderer_base.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp310
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h60
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp432
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp1487
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h29
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp247
-rw-r--r--src/video_core/renderer_opengl/gl_state.h61
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h11
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp10
-rw-r--r--src/video_core/surface.cpp4
-rw-r--r--src/video_core/surface.h148
-rw-r--r--src/video_core/textures/decoders.cpp115
-rw-r--r--src/video_core/textures/decoders.h12
-rw-r--r--src/video_core/textures/texture.h17
-rw-r--r--src/video_core/utils.h164
-rw-r--r--src/yuzu/CMakeLists.txt11
-rw-r--r--src/yuzu/applets/software_keyboard.cpp152
-rw-r--r--src/yuzu/applets/software_keyboard.h79
-rw-r--r--src/yuzu/bootmanager.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp403
-rw-r--r--src/yuzu/configuration/config.h14
-rw-r--r--src/yuzu/configuration/configure_audio.h5
-rw-r--r--src/yuzu/configuration/configure_debug.cpp4
-rw-r--r--src/yuzu/configuration/configure_debug.h3
-rw-r--r--src/yuzu/configuration/configure_debug.ui31
-rw-r--r--src/yuzu/configuration/configure_dialog.h3
-rw-r--r--src/yuzu/configuration/configure_gamelist.cpp16
-rw-r--r--src/yuzu/configuration/configure_gamelist.h4
-rw-r--r--src/yuzu/configuration/configure_gamelist.ui223
-rw-r--r--src/yuzu/configuration/configure_general.cpp36
-rw-r--r--src/yuzu/configuration/configure_general.h3
-rw-r--r--src/yuzu/configuration/configure_general.ui9
-rw-r--r--src/yuzu/configuration/configure_graphics.h3
-rw-r--r--src/yuzu/configuration/configure_graphics.ui94
-rw-r--r--src/yuzu/configuration/configure_input.cpp446
-rw-r--r--src/yuzu/configuration/configure_input.h58
-rw-r--r--src/yuzu/configuration/configure_input.ui1064
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp500
-rw-r--r--src/yuzu/configuration/configure_input_player.h104
-rw-r--r--src/yuzu/configuration/configure_input_player.ui1164
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp213
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.h68
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.ui261
-rw-r--r--src/yuzu/configuration/configure_system.cpp19
-rw-r--r--src/yuzu/configuration/configure_system.ui228
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.cpp42
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.h32
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.ui199
-rw-r--r--src/yuzu/configuration/configure_web.h5
-rw-r--r--src/yuzu/debugger/wait_tree.cpp11
-rw-r--r--src/yuzu/debugger/wait_tree.h4
-rw-r--r--src/yuzu/game_list.cpp34
-rw-r--r--src/yuzu/game_list_worker.cpp109
-rw-r--r--src/yuzu/main.cpp88
-rw-r--r--src/yuzu/main.h11
-rw-r--r--src/yuzu/main.ui3
-rw-r--r--src/yuzu/ui_settings.h3
-rw-r--r--src/yuzu_cmd/config.cpp285
-rw-r--r--src/yuzu_cmd/default_ini.h9
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp18
268 files changed, 15545 insertions, 8108 deletions
diff --git a/.gitmodules b/.gitmodules
index 2c044ed7d..a33a04167 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,9 +13,6 @@
13[submodule "dynarmic"] 13[submodule "dynarmic"]
14 path = externals/dynarmic 14 path = externals/dynarmic
15 url = https://github.com/MerryMage/dynarmic.git 15 url = https://github.com/MerryMage/dynarmic.git
16[submodule "xbyak"]
17 path = externals/xbyak
18 url = https://github.com/herumi/xbyak.git
19[submodule "fmt"] 16[submodule "fmt"]
20 path = externals/fmt 17 path = externals/fmt
21 url = https://github.com/fmtlib/fmt.git 18 url = https://github.com/fmtlib/fmt.git
diff --git a/.travis/clang-format/build.sh b/.travis/clang-format/build.sh
index 3707be3c9..36c276c43 100755
--- a/.travis/clang-format/build.sh
+++ b/.travis/clang-format/build.sh
@@ -1,3 +1,3 @@
1#!/bin/bash -ex 1#!/bin/bash -ex
2 2
3docker run -v $(pwd):/yuzu ubuntu:18.04 /bin/bash -ex /yuzu/.travis/clang-format/docker.sh 3docker run --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/root/.ccache citraemu/build-environments:linux-clang-format /bin/bash -ex /yuzu/.travis/clang-format/docker.sh
diff --git a/.travis/clang-format/deps.sh b/.travis/clang-format/deps.sh
index 540bb934a..a15d164c7 100755
--- a/.travis/clang-format/deps.sh
+++ b/.travis/clang-format/deps.sh
@@ -1,3 +1,3 @@
1#!/bin/sh -ex 1#!/bin/sh -ex
2 2
3docker pull ubuntu:18.04 3docker pull citraemu/build-environments:linux-clang-format
diff --git a/.travis/clang-format/docker.sh b/.travis/clang-format/docker.sh
index 05047e9b8..b519ab40e 100755
--- a/.travis/clang-format/docker.sh
+++ b/.travis/clang-format/docker.sh
@@ -1,8 +1,5 @@
1#!/bin/bash -ex 1#!/bin/bash -ex
2 2
3apt-get update
4apt-get install -y clang-format-6.0
5
6# Run clang-format 3# Run clang-format
7cd /yuzu 4cd /yuzu
8./.travis/clang-format/script.sh 5./.travis/clang-format/script.sh
diff --git a/.travis/linux-mingw/docker.sh b/.travis/linux-mingw/docker.sh
index d15c3f6e8..6cf43a006 100755
--- a/.travis/linux-mingw/docker.sh
+++ b/.travis/linux-mingw/docker.sh
@@ -57,3 +57,4 @@ done
57 57
58pip3 install pefile 58pip3 install pefile
59python3 .travis/linux-mingw/scan_dll.py package/*.exe "package/" 59python3 .travis/linux-mingw/scan_dll.py package/*.exe "package/"
60python3 .travis/linux-mingw/scan_dll.py package/imageformats/*.dll "package/"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 918cf5372..1f71f9fd9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -377,7 +377,7 @@ if (CLANG_FORMAT)
377 set(CCOMMENT "Running clang format against all the .h and .cpp files in src/") 377 set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
378 if (WIN32) 378 if (WIN32)
379 add_custom_target(clang-format 379 add_custom_target(clang-format
380 COMMAND powershell.exe -Command "${CLANG_FORMAT} -i @(Get-ChildItem -Recurse ${SRCS}/* -Include \'*.h\', \'*.cpp\')" 380 COMMAND powershell.exe -Command "Get-ChildItem ${SRCS}/* -Include *.cpp,*.h -Recurse | Foreach {${CLANG_FORMAT} -i $_.fullname}"
381 COMMENT ${CCOMMENT}) 381 COMMENT ${CCOMMENT})
382 elseif(MINGW) 382 elseif(MINGW)
383 add_custom_target(clang-format 383 add_custom_target(clang-format
diff --git a/appveyor.yml b/appveyor.yml
index 6d0e6522a..d6a69fbc2 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -125,26 +125,27 @@ after_build:
125 Copy-Item -path "$CMAKE_SOURCE_DIR/license.txt" -destination $RELEASE_DIST 125 Copy-Item -path "$CMAKE_SOURCE_DIR/license.txt" -destination $RELEASE_DIST
126 Copy-Item -path "$CMAKE_SOURCE_DIR/README.md" -destination $RELEASE_DIST 126 Copy-Item -path "$CMAKE_SOURCE_DIR/README.md" -destination $RELEASE_DIST
127 127
128 # copy the qt windows plugin dll to platforms
129 Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/platforms/qwindows.dll" -force -destination "$RELEASE_DIST/platforms"
130
131 # copy the qt windows vista style dll to platforms
132 Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/styles/qwindowsvistastyle.dll" -force -destination "$RELEASE_DIST/styles"
133
134 # copy the qt jpeg imageformat dll to platforms
135 Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/imageformats/qjpeg.dll" -force -destination "$RELEASE_DIST/imageformats"
136
128 # copy all the dll dependencies to the release folder 137 # copy all the dll dependencies to the release folder
129 . "./.appveyor/UtilityFunctions.ps1" 138 . "./.appveyor/UtilityFunctions.ps1"
130 $DLLSearchPath = "C:\msys64\mingw64\bin;$env:PATH" 139 $DLLSearchPath = "C:\msys64\mingw64\bin;$env:PATH"
131 $MingwDLLs = RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu.exe" 140 $MingwDLLs = RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu.exe"
132 $MingwDLLs += RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu_cmd.exe" 141 $MingwDLLs += RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu_cmd.exe"
142 $MingwDLLs += RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\imageformats\qjpeg.dll"
133 Write-Host "Detected the following dependencies:" 143 Write-Host "Detected the following dependencies:"
134 Write-Host $MingwDLLs 144 Write-Host $MingwDLLs
135 foreach ($file in $MingwDLLs) { 145 foreach ($file in $MingwDLLs) {
136 Copy-Item -path "$file" -force -destination "$RELEASE_DIST" 146 Copy-Item -path "$file" -force -destination "$RELEASE_DIST"
137 } 147 }
138 148
139 # copy the qt windows plugin dll to platforms
140 Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/platforms/qwindows.dll" -force -destination "$RELEASE_DIST/platforms"
141
142 # copy the qt windows vista style dll to platforms
143 Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/styles/qwindowsvistastyle.dll" -force -destination "$RELEASE_DIST/styles"
144
145 # copy the qt jpeg imageformat dll to platforms
146 Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/imageformats/qjpeg.dll" -force -destination "$RELEASE_DIST/imageformats"
147
148 7z a -tzip $MINGW_BUILD_ZIP $RELEASE_DIST\* 149 7z a -tzip $MINGW_BUILD_ZIP $RELEASE_DIST\*
149 7z a $MINGW_SEVENZIP $RELEASE_DIST 150 7z a $MINGW_SEVENZIP $RELEASE_DIST
150 } 151 }
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 1261062e8..e156bbece 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -9,7 +9,6 @@ target_include_directories(catch-single-include INTERFACE catch/single_include)
9 9
10# Dynarmic 10# Dynarmic
11if (ARCHITECTURE_x86_64) 11if (ARCHITECTURE_x86_64)
12 add_library(xbyak INTERFACE)
13 set(DYNARMIC_TESTS OFF) 12 set(DYNARMIC_TESTS OFF)
14 set(DYNARMIC_NO_BUNDLED_FMT ON) 13 set(DYNARMIC_NO_BUNDLED_FMT ON)
15 add_subdirectory(dynarmic) 14 add_subdirectory(dynarmic)
@@ -53,14 +52,6 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
53# SoundTouch 52# SoundTouch
54add_subdirectory(soundtouch) 53add_subdirectory(soundtouch)
55 54
56# Xbyak
57if (ARCHITECTURE_x86_64)
58 # Defined before "dynarmic" above
59 # add_library(xbyak INTERFACE)
60 target_include_directories(xbyak INTERFACE ./xbyak/xbyak)
61 target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
62endif()
63
64# Opus 55# Opus
65add_subdirectory(opus) 56add_subdirectory(opus)
66target_include_directories(opus INTERFACE ./opus/include) 57target_include_directories(opus INTERFACE ./opus/include)
diff --git a/externals/cmake-modules/GetGitRevisionDescription.cmake.in b/externals/cmake-modules/GetGitRevisionDescription.cmake.in
index 888ce13aa..0d7eb3c26 100644
--- a/externals/cmake-modules/GetGitRevisionDescription.cmake.in
+++ b/externals/cmake-modules/GetGitRevisionDescription.cmake.in
@@ -33,6 +33,10 @@ else()
33endif() 33endif()
34 34
35if(NOT HEAD_HASH) 35if(NOT HEAD_HASH)
36 file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 36 if(EXISTS "@GIT_DATA@/head-ref")
37 string(STRIP "${HEAD_HASH}" HEAD_HASH) 37 file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
38 string(STRIP "${HEAD_HASH}" HEAD_HASH)
39 else()
40 set(HEAD_HASH "Unknown")
41 endif()
38endif() 42endif()
diff --git a/externals/glad/include/glad/glad.h b/externals/glad/include/glad/glad.h
index fd41dc702..d638600ff 100644
--- a/externals/glad/include/glad/glad.h
+++ b/externals/glad/include/glad/glad.h
@@ -1,10 +1,10 @@
1/* 1/*
2 2
3 OpenGL loader generated by glad 0.1.26 on Tue Aug 7 08:21:50 2018. 3 OpenGL loader generated by glad 0.1.28 on Sat Nov 17 22:59:18 2018.
4 4
5 Language/Generator: C/C++ 5 Language/Generator: C/C++
6 Specification: gl 6 Specification: gl
7 APIs: gl=3.3 7 APIs: gl=4.3
8 Profile: core 8 Profile: core
9 Extensions: 9 Extensions:
10 GL_3DFX_multisample, 10 GL_3DFX_multisample,
@@ -418,6 +418,7 @@
418 GL_NV_clip_space_w_scaling, 418 GL_NV_clip_space_w_scaling,
419 GL_NV_command_list, 419 GL_NV_command_list,
420 GL_NV_compute_program5, 420 GL_NV_compute_program5,
421 GL_NV_compute_shader_derivatives,
421 GL_NV_conditional_render, 422 GL_NV_conditional_render,
422 GL_NV_conservative_raster, 423 GL_NV_conservative_raster,
423 GL_NV_conservative_raster_dilate, 424 GL_NV_conservative_raster_dilate,
@@ -442,6 +443,7 @@
442 GL_NV_fragment_program2, 443 GL_NV_fragment_program2,
443 GL_NV_fragment_program4, 444 GL_NV_fragment_program4,
444 GL_NV_fragment_program_option, 445 GL_NV_fragment_program_option,
446 GL_NV_fragment_shader_barycentric,
445 GL_NV_fragment_shader_interlock, 447 GL_NV_fragment_shader_interlock,
446 GL_NV_framebuffer_mixed_samples, 448 GL_NV_framebuffer_mixed_samples,
447 GL_NV_framebuffer_multisample_coverage, 449 GL_NV_framebuffer_multisample_coverage,
@@ -456,6 +458,8 @@
456 GL_NV_half_float, 458 GL_NV_half_float,
457 GL_NV_internalformat_sample_query, 459 GL_NV_internalformat_sample_query,
458 GL_NV_light_max_exponent, 460 GL_NV_light_max_exponent,
461 GL_NV_memory_attachment,
462 GL_NV_mesh_shader,
459 GL_NV_multisample_coverage, 463 GL_NV_multisample_coverage,
460 GL_NV_multisample_filter_hint, 464 GL_NV_multisample_filter_hint,
461 GL_NV_occlusion_query, 465 GL_NV_occlusion_query,
@@ -472,9 +476,11 @@
472 GL_NV_query_resource_tag, 476 GL_NV_query_resource_tag,
473 GL_NV_register_combiners, 477 GL_NV_register_combiners,
474 GL_NV_register_combiners2, 478 GL_NV_register_combiners2,
479 GL_NV_representative_fragment_test,
475 GL_NV_robustness_video_memory_purge, 480 GL_NV_robustness_video_memory_purge,
476 GL_NV_sample_locations, 481 GL_NV_sample_locations,
477 GL_NV_sample_mask_override_coverage, 482 GL_NV_sample_mask_override_coverage,
483 GL_NV_scissor_exclusive,
478 GL_NV_shader_atomic_counters, 484 GL_NV_shader_atomic_counters,
479 GL_NV_shader_atomic_float, 485 GL_NV_shader_atomic_float,
480 GL_NV_shader_atomic_float64, 486 GL_NV_shader_atomic_float64,
@@ -483,8 +489,10 @@
483 GL_NV_shader_buffer_load, 489 GL_NV_shader_buffer_load,
484 GL_NV_shader_buffer_store, 490 GL_NV_shader_buffer_store,
485 GL_NV_shader_storage_buffer_object, 491 GL_NV_shader_storage_buffer_object,
492 GL_NV_shader_texture_footprint,
486 GL_NV_shader_thread_group, 493 GL_NV_shader_thread_group,
487 GL_NV_shader_thread_shuffle, 494 GL_NV_shader_thread_shuffle,
495 GL_NV_shading_rate_image,
488 GL_NV_stereo_view_rendering, 496 GL_NV_stereo_view_rendering,
489 GL_NV_tessellation_program5, 497 GL_NV_tessellation_program5,
490 GL_NV_texgen_emboss, 498 GL_NV_texgen_emboss,
@@ -503,6 +511,7 @@
503 GL_NV_transform_feedback2, 511 GL_NV_transform_feedback2,
504 GL_NV_uniform_buffer_unified_memory, 512 GL_NV_uniform_buffer_unified_memory,
505 GL_NV_vdpau_interop, 513 GL_NV_vdpau_interop,
514 GL_NV_vdpau_interop2,
506 GL_NV_vertex_array_range, 515 GL_NV_vertex_array_range,
507 GL_NV_vertex_array_range2, 516 GL_NV_vertex_array_range2,
508 GL_NV_vertex_attrib_integer_64bit, 517 GL_NV_vertex_attrib_integer_64bit,
@@ -599,9 +608,10 @@
599 Loader: True 608 Loader: True
600 Local files: False 609 Local files: False
601 Omit khrplatform: False 610 Omit khrplatform: False
611 Reproducible: False
602 612
603 Commandline: 613 Commandline:
604 --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_3DFX_multisample,GL_3DFX_tbuffer,GL_3DFX_texture_compression_FXT1,GL_AMD_blend_minmax_factor,GL_AMD_conservative_depth,GL_AMD_debug_output,GL_AMD_depth_clamp_separate,GL_AMD_draw_buffers_blend,GL_AMD_framebuffer_multisample_advanced,GL_AMD_framebuffer_sample_positions,GL_AMD_gcn_shader,GL_AMD_gpu_shader_half_float,GL_AMD_gpu_shader_int16,GL_AMD_gpu_shader_int64,GL_AMD_interleaved_elements,GL_AMD_multi_draw_indirect,GL_AMD_name_gen_delete,GL_AMD_occlusion_query_event,GL_AMD_performance_monitor,GL_AMD_pinned_memory,GL_AMD_query_buffer_object,GL_AMD_sample_positions,GL_AMD_seamless_cubemap_per_texture,GL_AMD_shader_atomic_counter_ops,GL_AMD_shader_ballot,GL_AMD_shader_explicit_vertex_parameter,GL_AMD_shader_gpu_shader_half_float_fetch,GL_AMD_shader_image_load_store_lod,GL_AMD_shader_stencil_export,GL_AMD_shader_trinary_minmax,GL_AMD_sparse_texture,GL_AMD_stencil_operation_extended,GL_AMD_texture_gather_bias_lod,GL_AMD_texture_texture4,GL_AMD_transform_feedback3_lines_triangles,GL_AMD_transform_feedback4,GL_AMD_vertex_shader_layer,GL_AMD_vertex_shader_tessellator,GL_AMD_vertex_shader_viewport_index,GL_APPLE_aux_depth_stencil,GL_APPLE_client_storage,GL_APPLE_element_array,GL_APPLE_fence,GL_APPLE_float_pixels,GL_APPLE_flush_buffer_range,GL_APPLE_object_purgeable,GL_APPLE_rgb_422,GL_APPLE_row_bytes,GL_APPLE_specular_vector,GL_APPLE_texture_range,GL_APPLE_transform_hint,GL_APPLE_vertex_array_object,GL_APPLE_vertex_array_range,GL_APPLE_vertex_program_evaluators,GL_APPLE_ycbcr_422,GL_ARB_ES2_compatibility,GL_ARB_ES3_1_compatibility,GL_ARB_ES3_2_compatibility,GL_ARB_ES3_compatibility,GL_ARB_arrays_of_arrays,GL_ARB_base_instance,GL_ARB_bindless_texture,GL_ARB_blend_func_extended,GL_ARB_buffer_storage,GL_ARB_cl_event,GL_ARB_clear_buffer_object,GL_ARB_clear_texture,GL_ARB_clip_control,GL_ARB_color_buffer_float,GL_ARB_compatibility,GL_ARB_compressed_texture_pixel_storage,GL_ARB_compute_shader,GL_ARB_compute_variable_group_size,GL_ARB_conditional_render_inverted,GL_ARB_conservative_depth,GL_ARB_copy_buffer,GL_ARB_copy_image,GL_ARB_cull_distance,GL_ARB_debug_output,GL_ARB_depth_buffer_float,GL_ARB_depth_clamp,GL_ARB_depth_texture,GL_ARB_derivative_control,GL_ARB_direct_state_access,GL_ARB_draw_buffers,GL_ARB_draw_buffers_blend,GL_ARB_draw_elements_base_vertex,GL_ARB_draw_indirect,GL_ARB_draw_instanced,GL_ARB_enhanced_layouts,GL_ARB_explicit_attrib_location,GL_ARB_explicit_uniform_location,GL_ARB_fragment_coord_conventions,GL_ARB_fragment_layer_viewport,GL_ARB_fragment_program,GL_ARB_fragment_program_shadow,GL_ARB_fragment_shader,GL_ARB_fragment_shader_interlock,GL_ARB_framebuffer_no_attachments,GL_ARB_framebuffer_object,GL_ARB_framebuffer_sRGB,GL_ARB_geometry_shader4,GL_ARB_get_program_binary,GL_ARB_get_texture_sub_image,GL_ARB_gl_spirv,GL_ARB_gpu_shader5,GL_ARB_gpu_shader_fp64,GL_ARB_gpu_shader_int64,GL_ARB_half_float_pixel,GL_ARB_half_float_vertex,GL_ARB_imaging,GL_ARB_indirect_parameters,GL_ARB_instanced_arrays,GL_ARB_internalformat_query,GL_ARB_internalformat_query2,GL_ARB_invalidate_subdata,GL_ARB_map_buffer_alignment,GL_ARB_map_buffer_range,GL_ARB_matrix_palette,GL_ARB_multi_bind,GL_ARB_multi_draw_indirect,GL_ARB_multisample,GL_ARB_multitexture,GL_ARB_occlusion_query,GL_ARB_occlusion_query2,GL_ARB_parallel_shader_compile,GL_ARB_pipeline_statistics_query,GL_ARB_pixel_buffer_object,GL_ARB_point_parameters,GL_ARB_point_sprite,GL_ARB_polygon_offset_clamp,GL_ARB_post_depth_coverage,GL_ARB_program_interface_query,GL_ARB_provoking_vertex,GL_ARB_query_buffer_object,GL_ARB_robust_buffer_access_behavior,GL_ARB_robustness,GL_ARB_robustness_isolation,GL_ARB_sample_locations,GL_ARB_sample_shading,GL_ARB_sampler_objects,GL_ARB_seamless_cube_map,GL_ARB_seamless_cubemap_per_texture,GL_ARB_separate_shader_objects,GL_ARB_shader_atomic_counter_ops,GL_ARB_shader_atomic_counters,GL_ARB_shader_ballot,GL_ARB_shader_bit_encoding,GL_ARB_shader_clock,GL_ARB_shader_draw_parameters,GL_ARB_shader_group_vote,GL_ARB_shader_image_load_store,GL_ARB_shader_image_size,GL_ARB_shader_objects,GL_ARB_shader_precision,GL_ARB_shader_stencil_export,GL_ARB_shader_storage_buffer_object,GL_ARB_shader_subroutine,GL_ARB_shader_texture_image_samples,GL_ARB_shader_texture_lod,GL_ARB_shader_viewport_layer_array,GL_ARB_shading_language_100,GL_ARB_shading_language_420pack,GL_ARB_shading_language_include,GL_ARB_shading_language_packing,GL_ARB_shadow,GL_ARB_shadow_ambient,GL_ARB_sparse_buffer,GL_ARB_sparse_texture,GL_ARB_sparse_texture2,GL_ARB_sparse_texture_clamp,GL_ARB_spirv_extensions,GL_ARB_stencil_texturing,GL_ARB_sync,GL_ARB_tessellation_shader,GL_ARB_texture_barrier,GL_ARB_texture_border_clamp,GL_ARB_texture_buffer_object,GL_ARB_texture_buffer_object_rgb32,GL_ARB_texture_buffer_range,GL_ARB_texture_compression,GL_ARB_texture_compression_bptc,GL_ARB_texture_compression_rgtc,GL_ARB_texture_cube_map,GL_ARB_texture_cube_map_array,GL_ARB_texture_env_add,GL_ARB_texture_env_combine,GL_ARB_texture_env_crossbar,GL_ARB_texture_env_dot3,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_filter_minmax,GL_ARB_texture_float,GL_ARB_texture_gather,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_texture_mirrored_repeat,GL_ARB_texture_multisample,GL_ARB_texture_non_power_of_two,GL_ARB_texture_query_levels,GL_ARB_texture_query_lod,GL_ARB_texture_rectangle,GL_ARB_texture_rg,GL_ARB_texture_rgb10_a2ui,GL_ARB_texture_stencil8,GL_ARB_texture_storage,GL_ARB_texture_storage_multisample,GL_ARB_texture_swizzle,GL_ARB_texture_view,GL_ARB_timer_query,GL_ARB_transform_feedback2,GL_ARB_transform_feedback3,GL_ARB_transform_feedback_instanced,GL_ARB_transform_feedback_overflow_query,GL_ARB_transpose_matrix,GL_ARB_uniform_buffer_object,GL_ARB_vertex_array_bgra,GL_ARB_vertex_array_object,GL_ARB_vertex_attrib_64bit,GL_ARB_vertex_attrib_binding,GL_ARB_vertex_blend,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_ARB_vertex_type_10f_11f_11f_rev,GL_ARB_vertex_type_2_10_10_10_rev,GL_ARB_viewport_array,GL_ARB_window_pos,GL_ATI_draw_buffers,GL_ATI_element_array,GL_ATI_envmap_bumpmap,GL_ATI_fragment_shader,GL_ATI_map_object_buffer,GL_ATI_meminfo,GL_ATI_pixel_format_float,GL_ATI_pn_triangles,GL_ATI_separate_stencil,GL_ATI_text_fragment_shader,GL_ATI_texture_env_combine3,GL_ATI_texture_float,GL_ATI_texture_mirror_once,GL_ATI_vertex_array_object,GL_ATI_vertex_attrib_array_object,GL_ATI_vertex_streams,GL_EXT_422_pixels,GL_EXT_EGL_image_storage,GL_EXT_abgr,GL_EXT_bgra,GL_EXT_bindable_uniform,GL_EXT_blend_color,GL_EXT_blend_equation_separate,GL_EXT_blend_func_separate,GL_EXT_blend_logic_op,GL_EXT_blend_minmax,GL_EXT_blend_subtract,GL_EXT_clip_volume_hint,GL_EXT_cmyka,GL_EXT_color_subtable,GL_EXT_compiled_vertex_array,GL_EXT_convolution,GL_EXT_coordinate_frame,GL_EXT_copy_texture,GL_EXT_cull_vertex,GL_EXT_debug_label,GL_EXT_debug_marker,GL_EXT_depth_bounds_test,GL_EXT_direct_state_access,GL_EXT_draw_buffers2,GL_EXT_draw_instanced,GL_EXT_draw_range_elements,GL_EXT_external_buffer,GL_EXT_fog_coord,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_multisample_blit_scaled,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_geometry_shader4,GL_EXT_gpu_program_parameters,GL_EXT_gpu_shader4,GL_EXT_histogram,GL_EXT_index_array_formats,GL_EXT_index_func,GL_EXT_index_material,GL_EXT_index_texture,GL_EXT_light_texture,GL_EXT_memory_object,GL_EXT_memory_object_fd,GL_EXT_memory_object_win32,GL_EXT_misc_attribute,GL_EXT_multi_draw_arrays,GL_EXT_multisample,GL_EXT_packed_depth_stencil,GL_EXT_packed_float,GL_EXT_packed_pixels,GL_EXT_paletted_texture,GL_EXT_pixel_buffer_object,GL_EXT_pixel_transform,GL_EXT_pixel_transform_color_table,GL_EXT_point_parameters,GL_EXT_polygon_offset,GL_EXT_polygon_offset_clamp,GL_EXT_post_depth_coverage,GL_EXT_provoking_vertex,GL_EXT_raster_multisample,GL_EXT_rescale_normal,GL_EXT_secondary_color,GL_EXT_semaphore,GL_EXT_semaphore_fd,GL_EXT_semaphore_win32,GL_EXT_separate_shader_objects,GL_EXT_separate_specular_color,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_framebuffer_fetch_non_coherent,GL_EXT_shader_image_load_formatted,GL_EXT_shader_image_load_store,GL_EXT_shader_integer_mix,GL_EXT_shadow_funcs,GL_EXT_shared_texture_palette,GL_EXT_sparse_texture2,GL_EXT_stencil_clear_tag,GL_EXT_stencil_two_side,GL_EXT_stencil_wrap,GL_EXT_subtexture,GL_EXT_texture,GL_EXT_texture3D,GL_EXT_texture_array,GL_EXT_texture_buffer_object,GL_EXT_texture_compression_latc,GL_EXT_texture_compression_rgtc,GL_EXT_texture_compression_s3tc,GL_EXT_texture_cube_map,GL_EXT_texture_env_add,GL_EXT_texture_env_combine,GL_EXT_texture_env_dot3,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_filter_minmax,GL_EXT_texture_integer,GL_EXT_texture_lod_bias,GL_EXT_texture_mirror_clamp,GL_EXT_texture_object,GL_EXT_texture_perturb_normal,GL_EXT_texture_sRGB,GL_EXT_texture_sRGB_decode,GL_EXT_texture_shared_exponent,GL_EXT_texture_snorm,GL_EXT_texture_swizzle,GL_EXT_timer_query,GL_EXT_transform_feedback,GL_EXT_vertex_array,GL_EXT_vertex_array_bgra,GL_EXT_vertex_attrib_64bit,GL_EXT_vertex_shader,GL_EXT_vertex_weighting,GL_EXT_win32_keyed_mutex,GL_EXT_window_rectangles,GL_EXT_x11_sync_object,GL_GREMEDY_frame_terminator,GL_GREMEDY_string_marker,GL_HP_convolution_border_modes,GL_HP_image_transform,GL_HP_occlusion_test,GL_HP_texture_lighting,GL_IBM_cull_vertex,GL_IBM_multimode_draw_arrays,GL_IBM_rasterpos_clip,GL_IBM_static_data,GL_IBM_texture_mirrored_repeat,GL_IBM_vertex_array_lists,GL_INGR_blend_func_separate,GL_INGR_color_clamp,GL_INGR_interlace_read,GL_INTEL_blackhole_render,GL_INTEL_conservative_rasterization,GL_INTEL_fragment_shader_ordering,GL_INTEL_framebuffer_CMAA,GL_INTEL_map_texture,GL_INTEL_parallel_arrays,GL_INTEL_performance_query,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_context_flush_control,GL_KHR_debug,GL_KHR_no_error,GL_KHR_parallel_shader_compile,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_MESAX_texture_stack,GL_MESA_pack_invert,GL_MESA_program_binary_formats,GL_MESA_resize_buffers,GL_MESA_shader_integer_functions,GL_MESA_tile_raster_order,GL_MESA_window_pos,GL_MESA_ycbcr_texture,GL_NVX_blend_equation_advanced_multi_draw_buffers,GL_NVX_conditional_render,GL_NVX_gpu_memory_info,GL_NVX_linked_gpu_multicast,GL_NV_alpha_to_coverage_dither_control,GL_NV_bindless_multi_draw_indirect,GL_NV_bindless_multi_draw_indirect_count,GL_NV_bindless_texture,GL_NV_blend_equation_advanced,GL_NV_blend_equation_advanced_coherent,GL_NV_blend_minmax_factor,GL_NV_blend_square,GL_NV_clip_space_w_scaling,GL_NV_command_list,GL_NV_compute_program5,GL_NV_conditional_render,GL_NV_conservative_raster,GL_NV_conservative_raster_dilate,GL_NV_conservative_raster_pre_snap,GL_NV_conservative_raster_pre_snap_triangles,GL_NV_conservative_raster_underestimation,GL_NV_copy_depth_to_color,GL_NV_copy_image,GL_NV_deep_texture3D,GL_NV_depth_buffer_float,GL_NV_depth_clamp,GL_NV_draw_texture,GL_NV_draw_vulkan_image,GL_NV_evaluators,GL_NV_explicit_multisample,GL_NV_fence,GL_NV_fill_rectangle,GL_NV_float_buffer,GL_NV_fog_distance,GL_NV_fragment_coverage_to_color,GL_NV_fragment_program,GL_NV_fragment_program2,GL_NV_fragment_program4,GL_NV_fragment_program_option,GL_NV_fragment_shader_interlock,GL_NV_framebuffer_mixed_samples,GL_NV_framebuffer_multisample_coverage,GL_NV_geometry_program4,GL_NV_geometry_shader4,GL_NV_geometry_shader_passthrough,GL_NV_gpu_multicast,GL_NV_gpu_program4,GL_NV_gpu_program5,GL_NV_gpu_program5_mem_extended,GL_NV_gpu_shader5,GL_NV_half_float,GL_NV_internalformat_sample_query,GL_NV_light_max_exponent,GL_NV_multisample_coverage,GL_NV_multisample_filter_hint,GL_NV_occlusion_query,GL_NV_packed_depth_stencil,GL_NV_parameter_buffer_object,GL_NV_parameter_buffer_object2,GL_NV_path_rendering,GL_NV_path_rendering_shared_edge,GL_NV_pixel_data_range,GL_NV_point_sprite,GL_NV_present_video,GL_NV_primitive_restart,GL_NV_query_resource,GL_NV_query_resource_tag,GL_NV_register_combiners,GL_NV_register_combiners2,GL_NV_robustness_video_memory_purge,GL_NV_sample_locations,GL_NV_sample_mask_override_coverage,GL_NV_shader_atomic_counters,GL_NV_shader_atomic_float,GL_NV_shader_atomic_float64,GL_NV_shader_atomic_fp16_vector,GL_NV_shader_atomic_int64,GL_NV_shader_buffer_load,GL_NV_shader_buffer_store,GL_NV_shader_storage_buffer_object,GL_NV_shader_thread_group,GL_NV_shader_thread_shuffle,GL_NV_stereo_view_rendering,GL_NV_tessellation_program5,GL_NV_texgen_emboss,GL_NV_texgen_reflection,GL_NV_texture_barrier,GL_NV_texture_compression_vtc,GL_NV_texture_env_combine4,GL_NV_texture_expand_normal,GL_NV_texture_multisample,GL_NV_texture_rectangle,GL_NV_texture_rectangle_compressed,GL_NV_texture_shader,GL_NV_texture_shader2,GL_NV_texture_shader3,GL_NV_transform_feedback,GL_NV_transform_feedback2,GL_NV_uniform_buffer_unified_memory,GL_NV_vdpau_interop,GL_NV_vertex_array_range,GL_NV_vertex_array_range2,GL_NV_vertex_attrib_integer_64bit,GL_NV_vertex_buffer_unified_memory,GL_NV_vertex_program,GL_NV_vertex_program1_1,GL_NV_vertex_program2,GL_NV_vertex_program2_option,GL_NV_vertex_program3,GL_NV_vertex_program4,GL_NV_video_capture,GL_NV_viewport_array2,GL_NV_viewport_swizzle,GL_OES_byte_coordinates,GL_OES_compressed_paletted_texture,GL_OES_fixed_point,GL_OES_query_matrix,GL_OES_read_format,GL_OES_single_precision,GL_OML_interlace,GL_OML_resample,GL_OML_subsample,GL_OVR_multiview,GL_OVR_multiview2,GL_PGI_misc_hints,GL_PGI_vertex_hints,GL_REND_screen_coordinates,GL_S3_s3tc,GL_SGIS_detail_texture,GL_SGIS_fog_function,GL_SGIS_generate_mipmap,GL_SGIS_multisample,GL_SGIS_pixel_texture,GL_SGIS_point_line_texgen,GL_SGIS_point_parameters,GL_SGIS_sharpen_texture,GL_SGIS_texture4D,GL_SGIS_texture_border_clamp,GL_SGIS_texture_color_mask,GL_SGIS_texture_edge_clamp,GL_SGIS_texture_filter4,GL_SGIS_texture_lod,GL_SGIS_texture_select,GL_SGIX_async,GL_SGIX_async_histogram,GL_SGIX_async_pixel,GL_SGIX_blend_alpha_minmax,GL_SGIX_calligraphic_fragment,GL_SGIX_clipmap,GL_SGIX_convolution_accuracy,GL_SGIX_depth_pass_instrument,GL_SGIX_depth_texture,GL_SGIX_flush_raster,GL_SGIX_fog_offset,GL_SGIX_fragment_lighting,GL_SGIX_framezoom,GL_SGIX_igloo_interface,GL_SGIX_instruments,GL_SGIX_interlace,GL_SGIX_ir_instrument1,GL_SGIX_list_priority,GL_SGIX_pixel_texture,GL_SGIX_pixel_tiles,GL_SGIX_polynomial_ffd,GL_SGIX_reference_plane,GL_SGIX_resample,GL_SGIX_scalebias_hint,GL_SGIX_shadow,GL_SGIX_shadow_ambient,GL_SGIX_sprite,GL_SGIX_subsample,GL_SGIX_tag_sample_buffer,GL_SGIX_texture_add_env,GL_SGIX_texture_coordinate_clamp,GL_SGIX_texture_lod_bias,GL_SGIX_texture_multi_buffer,GL_SGIX_texture_scale_bias,GL_SGIX_vertex_preclip,GL_SGIX_ycrcb,GL_SGIX_ycrcb_subsample,GL_SGIX_ycrcba,GL_SGI_color_matrix,GL_SGI_color_table,GL_SGI_texture_color_table,GL_SUNX_constant_data,GL_SUN_convolution_border_modes,GL_SUN_global_alpha,GL_SUN_mesh_array,GL_SUN_slice_accum,GL_SUN_triangle_list,GL_SUN_vertex,GL_WIN_phong_shading,GL_WIN_specular_fog" 614 --profile="core" --api="gl=4.3" --generator="c" --spec="gl" --extensions="GL_3DFX_multisample,GL_3DFX_tbuffer,GL_3DFX_texture_compression_FXT1,GL_AMD_blend_minmax_factor,GL_AMD_conservative_depth,GL_AMD_debug_output,GL_AMD_depth_clamp_separate,GL_AMD_draw_buffers_blend,GL_AMD_framebuffer_multisample_advanced,GL_AMD_framebuffer_sample_positions,GL_AMD_gcn_shader,GL_AMD_gpu_shader_half_float,GL_AMD_gpu_shader_int16,GL_AMD_gpu_shader_int64,GL_AMD_interleaved_elements,GL_AMD_multi_draw_indirect,GL_AMD_name_gen_delete,GL_AMD_occlusion_query_event,GL_AMD_performance_monitor,GL_AMD_pinned_memory,GL_AMD_query_buffer_object,GL_AMD_sample_positions,GL_AMD_seamless_cubemap_per_texture,GL_AMD_shader_atomic_counter_ops,GL_AMD_shader_ballot,GL_AMD_shader_explicit_vertex_parameter,GL_AMD_shader_gpu_shader_half_float_fetch,GL_AMD_shader_image_load_store_lod,GL_AMD_shader_stencil_export,GL_AMD_shader_trinary_minmax,GL_AMD_sparse_texture,GL_AMD_stencil_operation_extended,GL_AMD_texture_gather_bias_lod,GL_AMD_texture_texture4,GL_AMD_transform_feedback3_lines_triangles,GL_AMD_transform_feedback4,GL_AMD_vertex_shader_layer,GL_AMD_vertex_shader_tessellator,GL_AMD_vertex_shader_viewport_index,GL_APPLE_aux_depth_stencil,GL_APPLE_client_storage,GL_APPLE_element_array,GL_APPLE_fence,GL_APPLE_float_pixels,GL_APPLE_flush_buffer_range,GL_APPLE_object_purgeable,GL_APPLE_rgb_422,GL_APPLE_row_bytes,GL_APPLE_specular_vector,GL_APPLE_texture_range,GL_APPLE_transform_hint,GL_APPLE_vertex_array_object,GL_APPLE_vertex_array_range,GL_APPLE_vertex_program_evaluators,GL_APPLE_ycbcr_422,GL_ARB_ES2_compatibility,GL_ARB_ES3_1_compatibility,GL_ARB_ES3_2_compatibility,GL_ARB_ES3_compatibility,GL_ARB_arrays_of_arrays,GL_ARB_base_instance,GL_ARB_bindless_texture,GL_ARB_blend_func_extended,GL_ARB_buffer_storage,GL_ARB_cl_event,GL_ARB_clear_buffer_object,GL_ARB_clear_texture,GL_ARB_clip_control,GL_ARB_color_buffer_float,GL_ARB_compatibility,GL_ARB_compressed_texture_pixel_storage,GL_ARB_compute_shader,GL_ARB_compute_variable_group_size,GL_ARB_conditional_render_inverted,GL_ARB_conservative_depth,GL_ARB_copy_buffer,GL_ARB_copy_image,GL_ARB_cull_distance,GL_ARB_debug_output,GL_ARB_depth_buffer_float,GL_ARB_depth_clamp,GL_ARB_depth_texture,GL_ARB_derivative_control,GL_ARB_direct_state_access,GL_ARB_draw_buffers,GL_ARB_draw_buffers_blend,GL_ARB_draw_elements_base_vertex,GL_ARB_draw_indirect,GL_ARB_draw_instanced,GL_ARB_enhanced_layouts,GL_ARB_explicit_attrib_location,GL_ARB_explicit_uniform_location,GL_ARB_fragment_coord_conventions,GL_ARB_fragment_layer_viewport,GL_ARB_fragment_program,GL_ARB_fragment_program_shadow,GL_ARB_fragment_shader,GL_ARB_fragment_shader_interlock,GL_ARB_framebuffer_no_attachments,GL_ARB_framebuffer_object,GL_ARB_framebuffer_sRGB,GL_ARB_geometry_shader4,GL_ARB_get_program_binary,GL_ARB_get_texture_sub_image,GL_ARB_gl_spirv,GL_ARB_gpu_shader5,GL_ARB_gpu_shader_fp64,GL_ARB_gpu_shader_int64,GL_ARB_half_float_pixel,GL_ARB_half_float_vertex,GL_ARB_imaging,GL_ARB_indirect_parameters,GL_ARB_instanced_arrays,GL_ARB_internalformat_query,GL_ARB_internalformat_query2,GL_ARB_invalidate_subdata,GL_ARB_map_buffer_alignment,GL_ARB_map_buffer_range,GL_ARB_matrix_palette,GL_ARB_multi_bind,GL_ARB_multi_draw_indirect,GL_ARB_multisample,GL_ARB_multitexture,GL_ARB_occlusion_query,GL_ARB_occlusion_query2,GL_ARB_parallel_shader_compile,GL_ARB_pipeline_statistics_query,GL_ARB_pixel_buffer_object,GL_ARB_point_parameters,GL_ARB_point_sprite,GL_ARB_polygon_offset_clamp,GL_ARB_post_depth_coverage,GL_ARB_program_interface_query,GL_ARB_provoking_vertex,GL_ARB_query_buffer_object,GL_ARB_robust_buffer_access_behavior,GL_ARB_robustness,GL_ARB_robustness_isolation,GL_ARB_sample_locations,GL_ARB_sample_shading,GL_ARB_sampler_objects,GL_ARB_seamless_cube_map,GL_ARB_seamless_cubemap_per_texture,GL_ARB_separate_shader_objects,GL_ARB_shader_atomic_counter_ops,GL_ARB_shader_atomic_counters,GL_ARB_shader_ballot,GL_ARB_shader_bit_encoding,GL_ARB_shader_clock,GL_ARB_shader_draw_parameters,GL_ARB_shader_group_vote,GL_ARB_shader_image_load_store,GL_ARB_shader_image_size,GL_ARB_shader_objects,GL_ARB_shader_precision,GL_ARB_shader_stencil_export,GL_ARB_shader_storage_buffer_object,GL_ARB_shader_subroutine,GL_ARB_shader_texture_image_samples,GL_ARB_shader_texture_lod,GL_ARB_shader_viewport_layer_array,GL_ARB_shading_language_100,GL_ARB_shading_language_420pack,GL_ARB_shading_language_include,GL_ARB_shading_language_packing,GL_ARB_shadow,GL_ARB_shadow_ambient,GL_ARB_sparse_buffer,GL_ARB_sparse_texture,GL_ARB_sparse_texture2,GL_ARB_sparse_texture_clamp,GL_ARB_spirv_extensions,GL_ARB_stencil_texturing,GL_ARB_sync,GL_ARB_tessellation_shader,GL_ARB_texture_barrier,GL_ARB_texture_border_clamp,GL_ARB_texture_buffer_object,GL_ARB_texture_buffer_object_rgb32,GL_ARB_texture_buffer_range,GL_ARB_texture_compression,GL_ARB_texture_compression_bptc,GL_ARB_texture_compression_rgtc,GL_ARB_texture_cube_map,GL_ARB_texture_cube_map_array,GL_ARB_texture_env_add,GL_ARB_texture_env_combine,GL_ARB_texture_env_crossbar,GL_ARB_texture_env_dot3,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_filter_minmax,GL_ARB_texture_float,GL_ARB_texture_gather,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_texture_mirrored_repeat,GL_ARB_texture_multisample,GL_ARB_texture_non_power_of_two,GL_ARB_texture_query_levels,GL_ARB_texture_query_lod,GL_ARB_texture_rectangle,GL_ARB_texture_rg,GL_ARB_texture_rgb10_a2ui,GL_ARB_texture_stencil8,GL_ARB_texture_storage,GL_ARB_texture_storage_multisample,GL_ARB_texture_swizzle,GL_ARB_texture_view,GL_ARB_timer_query,GL_ARB_transform_feedback2,GL_ARB_transform_feedback3,GL_ARB_transform_feedback_instanced,GL_ARB_transform_feedback_overflow_query,GL_ARB_transpose_matrix,GL_ARB_uniform_buffer_object,GL_ARB_vertex_array_bgra,GL_ARB_vertex_array_object,GL_ARB_vertex_attrib_64bit,GL_ARB_vertex_attrib_binding,GL_ARB_vertex_blend,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_ARB_vertex_type_10f_11f_11f_rev,GL_ARB_vertex_type_2_10_10_10_rev,GL_ARB_viewport_array,GL_ARB_window_pos,GL_ATI_draw_buffers,GL_ATI_element_array,GL_ATI_envmap_bumpmap,GL_ATI_fragment_shader,GL_ATI_map_object_buffer,GL_ATI_meminfo,GL_ATI_pixel_format_float,GL_ATI_pn_triangles,GL_ATI_separate_stencil,GL_ATI_text_fragment_shader,GL_ATI_texture_env_combine3,GL_ATI_texture_float,GL_ATI_texture_mirror_once,GL_ATI_vertex_array_object,GL_ATI_vertex_attrib_array_object,GL_ATI_vertex_streams,GL_EXT_422_pixels,GL_EXT_EGL_image_storage,GL_EXT_abgr,GL_EXT_bgra,GL_EXT_bindable_uniform,GL_EXT_blend_color,GL_EXT_blend_equation_separate,GL_EXT_blend_func_separate,GL_EXT_blend_logic_op,GL_EXT_blend_minmax,GL_EXT_blend_subtract,GL_EXT_clip_volume_hint,GL_EXT_cmyka,GL_EXT_color_subtable,GL_EXT_compiled_vertex_array,GL_EXT_convolution,GL_EXT_coordinate_frame,GL_EXT_copy_texture,GL_EXT_cull_vertex,GL_EXT_debug_label,GL_EXT_debug_marker,GL_EXT_depth_bounds_test,GL_EXT_direct_state_access,GL_EXT_draw_buffers2,GL_EXT_draw_instanced,GL_EXT_draw_range_elements,GL_EXT_external_buffer,GL_EXT_fog_coord,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_multisample_blit_scaled,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_geometry_shader4,GL_EXT_gpu_program_parameters,GL_EXT_gpu_shader4,GL_EXT_histogram,GL_EXT_index_array_formats,GL_EXT_index_func,GL_EXT_index_material,GL_EXT_index_texture,GL_EXT_light_texture,GL_EXT_memory_object,GL_EXT_memory_object_fd,GL_EXT_memory_object_win32,GL_EXT_misc_attribute,GL_EXT_multi_draw_arrays,GL_EXT_multisample,GL_EXT_packed_depth_stencil,GL_EXT_packed_float,GL_EXT_packed_pixels,GL_EXT_paletted_texture,GL_EXT_pixel_buffer_object,GL_EXT_pixel_transform,GL_EXT_pixel_transform_color_table,GL_EXT_point_parameters,GL_EXT_polygon_offset,GL_EXT_polygon_offset_clamp,GL_EXT_post_depth_coverage,GL_EXT_provoking_vertex,GL_EXT_raster_multisample,GL_EXT_rescale_normal,GL_EXT_secondary_color,GL_EXT_semaphore,GL_EXT_semaphore_fd,GL_EXT_semaphore_win32,GL_EXT_separate_shader_objects,GL_EXT_separate_specular_color,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_framebuffer_fetch_non_coherent,GL_EXT_shader_image_load_formatted,GL_EXT_shader_image_load_store,GL_EXT_shader_integer_mix,GL_EXT_shadow_funcs,GL_EXT_shared_texture_palette,GL_EXT_sparse_texture2,GL_EXT_stencil_clear_tag,GL_EXT_stencil_two_side,GL_EXT_stencil_wrap,GL_EXT_subtexture,GL_EXT_texture,GL_EXT_texture3D,GL_EXT_texture_array,GL_EXT_texture_buffer_object,GL_EXT_texture_compression_latc,GL_EXT_texture_compression_rgtc,GL_EXT_texture_compression_s3tc,GL_EXT_texture_cube_map,GL_EXT_texture_env_add,GL_EXT_texture_env_combine,GL_EXT_texture_env_dot3,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_filter_minmax,GL_EXT_texture_integer,GL_EXT_texture_lod_bias,GL_EXT_texture_mirror_clamp,GL_EXT_texture_object,GL_EXT_texture_perturb_normal,GL_EXT_texture_sRGB,GL_EXT_texture_sRGB_decode,GL_EXT_texture_shared_exponent,GL_EXT_texture_snorm,GL_EXT_texture_swizzle,GL_EXT_timer_query,GL_EXT_transform_feedback,GL_EXT_vertex_array,GL_EXT_vertex_array_bgra,GL_EXT_vertex_attrib_64bit,GL_EXT_vertex_shader,GL_EXT_vertex_weighting,GL_EXT_win32_keyed_mutex,GL_EXT_window_rectangles,GL_EXT_x11_sync_object,GL_GREMEDY_frame_terminator,GL_GREMEDY_string_marker,GL_HP_convolution_border_modes,GL_HP_image_transform,GL_HP_occlusion_test,GL_HP_texture_lighting,GL_IBM_cull_vertex,GL_IBM_multimode_draw_arrays,GL_IBM_rasterpos_clip,GL_IBM_static_data,GL_IBM_texture_mirrored_repeat,GL_IBM_vertex_array_lists,GL_INGR_blend_func_separate,GL_INGR_color_clamp,GL_INGR_interlace_read,GL_INTEL_blackhole_render,GL_INTEL_conservative_rasterization,GL_INTEL_fragment_shader_ordering,GL_INTEL_framebuffer_CMAA,GL_INTEL_map_texture,GL_INTEL_parallel_arrays,GL_INTEL_performance_query,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_context_flush_control,GL_KHR_debug,GL_KHR_no_error,GL_KHR_parallel_shader_compile,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_MESAX_texture_stack,GL_MESA_pack_invert,GL_MESA_program_binary_formats,GL_MESA_resize_buffers,GL_MESA_shader_integer_functions,GL_MESA_tile_raster_order,GL_MESA_window_pos,GL_MESA_ycbcr_texture,GL_NVX_blend_equation_advanced_multi_draw_buffers,GL_NVX_conditional_render,GL_NVX_gpu_memory_info,GL_NVX_linked_gpu_multicast,GL_NV_alpha_to_coverage_dither_control,GL_NV_bindless_multi_draw_indirect,GL_NV_bindless_multi_draw_indirect_count,GL_NV_bindless_texture,GL_NV_blend_equation_advanced,GL_NV_blend_equation_advanced_coherent,GL_NV_blend_minmax_factor,GL_NV_blend_square,GL_NV_clip_space_w_scaling,GL_NV_command_list,GL_NV_compute_program5,GL_NV_compute_shader_derivatives,GL_NV_conditional_render,GL_NV_conservative_raster,GL_NV_conservative_raster_dilate,GL_NV_conservative_raster_pre_snap,GL_NV_conservative_raster_pre_snap_triangles,GL_NV_conservative_raster_underestimation,GL_NV_copy_depth_to_color,GL_NV_copy_image,GL_NV_deep_texture3D,GL_NV_depth_buffer_float,GL_NV_depth_clamp,GL_NV_draw_texture,GL_NV_draw_vulkan_image,GL_NV_evaluators,GL_NV_explicit_multisample,GL_NV_fence,GL_NV_fill_rectangle,GL_NV_float_buffer,GL_NV_fog_distance,GL_NV_fragment_coverage_to_color,GL_NV_fragment_program,GL_NV_fragment_program2,GL_NV_fragment_program4,GL_NV_fragment_program_option,GL_NV_fragment_shader_barycentric,GL_NV_fragment_shader_interlock,GL_NV_framebuffer_mixed_samples,GL_NV_framebuffer_multisample_coverage,GL_NV_geometry_program4,GL_NV_geometry_shader4,GL_NV_geometry_shader_passthrough,GL_NV_gpu_multicast,GL_NV_gpu_program4,GL_NV_gpu_program5,GL_NV_gpu_program5_mem_extended,GL_NV_gpu_shader5,GL_NV_half_float,GL_NV_internalformat_sample_query,GL_NV_light_max_exponent,GL_NV_memory_attachment,GL_NV_mesh_shader,GL_NV_multisample_coverage,GL_NV_multisample_filter_hint,GL_NV_occlusion_query,GL_NV_packed_depth_stencil,GL_NV_parameter_buffer_object,GL_NV_parameter_buffer_object2,GL_NV_path_rendering,GL_NV_path_rendering_shared_edge,GL_NV_pixel_data_range,GL_NV_point_sprite,GL_NV_present_video,GL_NV_primitive_restart,GL_NV_query_resource,GL_NV_query_resource_tag,GL_NV_register_combiners,GL_NV_register_combiners2,GL_NV_representative_fragment_test,GL_NV_robustness_video_memory_purge,GL_NV_sample_locations,GL_NV_sample_mask_override_coverage,GL_NV_scissor_exclusive,GL_NV_shader_atomic_counters,GL_NV_shader_atomic_float,GL_NV_shader_atomic_float64,GL_NV_shader_atomic_fp16_vector,GL_NV_shader_atomic_int64,GL_NV_shader_buffer_load,GL_NV_shader_buffer_store,GL_NV_shader_storage_buffer_object,GL_NV_shader_texture_footprint,GL_NV_shader_thread_group,GL_NV_shader_thread_shuffle,GL_NV_shading_rate_image,GL_NV_stereo_view_rendering,GL_NV_tessellation_program5,GL_NV_texgen_emboss,GL_NV_texgen_reflection,GL_NV_texture_barrier,GL_NV_texture_compression_vtc,GL_NV_texture_env_combine4,GL_NV_texture_expand_normal,GL_NV_texture_multisample,GL_NV_texture_rectangle,GL_NV_texture_rectangle_compressed,GL_NV_texture_shader,GL_NV_texture_shader2,GL_NV_texture_shader3,GL_NV_transform_feedback,GL_NV_transform_feedback2,GL_NV_uniform_buffer_unified_memory,GL_NV_vdpau_interop,GL_NV_vdpau_interop2,GL_NV_vertex_array_range,GL_NV_vertex_array_range2,GL_NV_vertex_attrib_integer_64bit,GL_NV_vertex_buffer_unified_memory,GL_NV_vertex_program,GL_NV_vertex_program1_1,GL_NV_vertex_program2,GL_NV_vertex_program2_option,GL_NV_vertex_program3,GL_NV_vertex_program4,GL_NV_video_capture,GL_NV_viewport_array2,GL_NV_viewport_swizzle,GL_OES_byte_coordinates,GL_OES_compressed_paletted_texture,GL_OES_fixed_point,GL_OES_query_matrix,GL_OES_read_format,GL_OES_single_precision,GL_OML_interlace,GL_OML_resample,GL_OML_subsample,GL_OVR_multiview,GL_OVR_multiview2,GL_PGI_misc_hints,GL_PGI_vertex_hints,GL_REND_screen_coordinates,GL_S3_s3tc,GL_SGIS_detail_texture,GL_SGIS_fog_function,GL_SGIS_generate_mipmap,GL_SGIS_multisample,GL_SGIS_pixel_texture,GL_SGIS_point_line_texgen,GL_SGIS_point_parameters,GL_SGIS_sharpen_texture,GL_SGIS_texture4D,GL_SGIS_texture_border_clamp,GL_SGIS_texture_color_mask,GL_SGIS_texture_edge_clamp,GL_SGIS_texture_filter4,GL_SGIS_texture_lod,GL_SGIS_texture_select,GL_SGIX_async,GL_SGIX_async_histogram,GL_SGIX_async_pixel,GL_SGIX_blend_alpha_minmax,GL_SGIX_calligraphic_fragment,GL_SGIX_clipmap,GL_SGIX_convolution_accuracy,GL_SGIX_depth_pass_instrument,GL_SGIX_depth_texture,GL_SGIX_flush_raster,GL_SGIX_fog_offset,GL_SGIX_fragment_lighting,GL_SGIX_framezoom,GL_SGIX_igloo_interface,GL_SGIX_instruments,GL_SGIX_interlace,GL_SGIX_ir_instrument1,GL_SGIX_list_priority,GL_SGIX_pixel_texture,GL_SGIX_pixel_tiles,GL_SGIX_polynomial_ffd,GL_SGIX_reference_plane,GL_SGIX_resample,GL_SGIX_scalebias_hint,GL_SGIX_shadow,GL_SGIX_shadow_ambient,GL_SGIX_sprite,GL_SGIX_subsample,GL_SGIX_tag_sample_buffer,GL_SGIX_texture_add_env,GL_SGIX_texture_coordinate_clamp,GL_SGIX_texture_lod_bias,GL_SGIX_texture_multi_buffer,GL_SGIX_texture_scale_bias,GL_SGIX_vertex_preclip,GL_SGIX_ycrcb,GL_SGIX_ycrcb_subsample,GL_SGIX_ycrcba,GL_SGI_color_matrix,GL_SGI_color_table,GL_SGI_texture_color_table,GL_SUNX_constant_data,GL_SUN_convolution_border_modes,GL_SUN_global_alpha,GL_SUN_mesh_array,GL_SUN_slice_accum,GL_SUN_triangle_list,GL_SUN_vertex,GL_WIN_phong_shading,GL_WIN_specular_fog"
605 Online: 615 Online:
606 Too many extensions 616 Too many extensions
607*/ 617*/
@@ -632,6 +642,10 @@
632#define APIENTRYP APIENTRY * 642#define APIENTRYP APIENTRY *
633#endif 643#endif
634 644
645#ifndef GLAPIENTRY
646#define GLAPIENTRY APIENTRY
647#endif
648
635#ifdef __cplusplus 649#ifdef __cplusplus
636extern "C" { 650extern "C" {
637#endif 651#endif
@@ -675,59 +689,21 @@ GLAPI int gladLoadGL(void);
675 689
676GLAPI int gladLoadGLLoader(GLADloadproc); 690GLAPI int gladLoadGLLoader(GLADloadproc);
677 691
678#include <stddef.h>
679#include <KHR/khrplatform.h> 692#include <KHR/khrplatform.h>
680#ifndef GLEXT_64_TYPES_DEFINED
681/* This code block is duplicated in glxext.h, so must be protected */
682#define GLEXT_64_TYPES_DEFINED
683/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
684/* (as used in the GL_EXT_timer_query extension). */
685#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
686#include <inttypes.h>
687#elif defined(__sun__) || defined(__digital__)
688#include <inttypes.h>
689#if defined(__STDC__)
690#if defined(__arch64__) || defined(_LP64)
691typedef long int int64_t;
692typedef unsigned long int uint64_t;
693#else
694typedef long long int int64_t;
695typedef unsigned long long int uint64_t;
696#endif /* __arch64__ */
697#endif /* __STDC__ */
698#elif defined( __VMS ) || defined(__sgi)
699#include <inttypes.h>
700#elif defined(__SCO__) || defined(__USLC__)
701#include <stdint.h>
702#elif defined(__UNIXOS2__) || defined(__SOL64__)
703typedef long int int32_t;
704typedef long long int int64_t;
705typedef unsigned long long int uint64_t;
706#elif defined(_WIN32) && defined(__GNUC__)
707#include <stdint.h>
708#elif defined(_WIN32)
709typedef __int32 int32_t;
710typedef __int64 int64_t;
711typedef unsigned __int64 uint64_t;
712#else
713/* Fallback if nothing above works */
714#include <inttypes.h>
715#endif
716#endif
717typedef unsigned int GLenum; 693typedef unsigned int GLenum;
718typedef unsigned char GLboolean; 694typedef unsigned char GLboolean;
719typedef unsigned int GLbitfield; 695typedef unsigned int GLbitfield;
720typedef void GLvoid; 696typedef void GLvoid;
721typedef signed char GLbyte; 697typedef khronos_int8_t GLbyte;
722typedef short GLshort; 698typedef khronos_uint8_t GLubyte;
699typedef khronos_int16_t GLshort;
700typedef khronos_uint16_t GLushort;
723typedef int GLint; 701typedef int GLint;
724typedef int GLclampx;
725typedef unsigned char GLubyte;
726typedef unsigned short GLushort;
727typedef unsigned int GLuint; 702typedef unsigned int GLuint;
703typedef khronos_int32_t GLclampx;
728typedef int GLsizei; 704typedef int GLsizei;
729typedef float GLfloat; 705typedef khronos_float_t GLfloat;
730typedef float GLclampf; 706typedef khronos_float_t GLclampf;
731typedef double GLdouble; 707typedef double GLdouble;
732typedef double GLclampd; 708typedef double GLclampd;
733typedef void *GLeglClientBufferEXT; 709typedef void *GLeglClientBufferEXT;
@@ -739,25 +715,17 @@ typedef void *GLhandleARB;
739#else 715#else
740typedef unsigned int GLhandleARB; 716typedef unsigned int GLhandleARB;
741#endif 717#endif
742typedef unsigned short GLhalfARB; 718typedef khronos_uint16_t GLhalf;
743typedef unsigned short GLhalf; 719typedef khronos_uint16_t GLhalfARB;
744typedef GLint GLfixed; 720typedef khronos_int32_t GLfixed;
745typedef khronos_intptr_t GLintptr; 721typedef khronos_intptr_t GLintptr;
722typedef khronos_intptr_t GLintptrARB;
746typedef khronos_ssize_t GLsizeiptr; 723typedef khronos_ssize_t GLsizeiptr;
747typedef int64_t GLint64; 724typedef khronos_ssize_t GLsizeiptrARB;
748typedef uint64_t GLuint64; 725typedef khronos_int64_t GLint64;
749#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) 726typedef khronos_int64_t GLint64EXT;
750typedef long GLintptrARB; 727typedef khronos_uint64_t GLuint64;
751#else 728typedef khronos_uint64_t GLuint64EXT;
752typedef ptrdiff_t GLintptrARB;
753#endif
754#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
755typedef long GLsizeiptrARB;
756#else
757typedef ptrdiff_t GLsizeiptrARB;
758#endif
759typedef int64_t GLint64EXT;
760typedef uint64_t GLuint64EXT;
761typedef struct __GLsync *GLsync; 729typedef struct __GLsync *GLsync;
762struct _cl_context; 730struct _cl_context;
763struct _cl_event; 731struct _cl_event;
@@ -1586,6 +1554,493 @@ typedef void (APIENTRY *GLVULKANPROCNV)(void);
1586#define GL_TIME_ELAPSED 0x88BF 1554#define GL_TIME_ELAPSED 0x88BF
1587#define GL_TIMESTAMP 0x8E28 1555#define GL_TIMESTAMP 0x8E28
1588#define GL_INT_2_10_10_10_REV 0x8D9F 1556#define GL_INT_2_10_10_10_REV 0x8D9F
1557#define GL_SAMPLE_SHADING 0x8C36
1558#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37
1559#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E
1560#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F
1561#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
1562#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A
1563#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B
1564#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C
1565#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D
1566#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E
1567#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
1568#define GL_DRAW_INDIRECT_BUFFER 0x8F3F
1569#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43
1570#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F
1571#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A
1572#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B
1573#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C
1574#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D
1575#define GL_MAX_VERTEX_STREAMS 0x8E71
1576#define GL_DOUBLE_VEC2 0x8FFC
1577#define GL_DOUBLE_VEC3 0x8FFD
1578#define GL_DOUBLE_VEC4 0x8FFE
1579#define GL_DOUBLE_MAT2 0x8F46
1580#define GL_DOUBLE_MAT3 0x8F47
1581#define GL_DOUBLE_MAT4 0x8F48
1582#define GL_DOUBLE_MAT2x3 0x8F49
1583#define GL_DOUBLE_MAT2x4 0x8F4A
1584#define GL_DOUBLE_MAT3x2 0x8F4B
1585#define GL_DOUBLE_MAT3x4 0x8F4C
1586#define GL_DOUBLE_MAT4x2 0x8F4D
1587#define GL_DOUBLE_MAT4x3 0x8F4E
1588#define GL_ACTIVE_SUBROUTINES 0x8DE5
1589#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6
1590#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47
1591#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48
1592#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49
1593#define GL_MAX_SUBROUTINES 0x8DE7
1594#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8
1595#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A
1596#define GL_COMPATIBLE_SUBROUTINES 0x8E4B
1597#define GL_PATCHES 0x000E
1598#define GL_PATCH_VERTICES 0x8E72
1599#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
1600#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74
1601#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75
1602#define GL_TESS_GEN_MODE 0x8E76
1603#define GL_TESS_GEN_SPACING 0x8E77
1604#define GL_TESS_GEN_VERTEX_ORDER 0x8E78
1605#define GL_TESS_GEN_POINT_MODE 0x8E79
1606#define GL_ISOLINES 0x8E7A
1607#define GL_QUADS 0x0007
1608#define GL_FRACTIONAL_ODD 0x8E7B
1609#define GL_FRACTIONAL_EVEN 0x8E7C
1610#define GL_MAX_PATCH_VERTICES 0x8E7D
1611#define GL_MAX_TESS_GEN_LEVEL 0x8E7E
1612#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
1613#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
1614#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
1615#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
1616#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
1617#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84
1618#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
1619#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
1620#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
1621#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
1622#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
1623#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
1624#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
1625#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
1626#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0
1627#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1
1628#define GL_TESS_EVALUATION_SHADER 0x8E87
1629#define GL_TESS_CONTROL_SHADER 0x8E88
1630#define GL_TRANSFORM_FEEDBACK 0x8E22
1631#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23
1632#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24
1633#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
1634#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70
1635#define GL_FIXED 0x140C
1636#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
1637#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
1638#define GL_LOW_FLOAT 0x8DF0
1639#define GL_MEDIUM_FLOAT 0x8DF1
1640#define GL_HIGH_FLOAT 0x8DF2
1641#define GL_LOW_INT 0x8DF3
1642#define GL_MEDIUM_INT 0x8DF4
1643#define GL_HIGH_INT 0x8DF5
1644#define GL_SHADER_COMPILER 0x8DFA
1645#define GL_SHADER_BINARY_FORMATS 0x8DF8
1646#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
1647#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
1648#define GL_MAX_VARYING_VECTORS 0x8DFC
1649#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
1650#define GL_RGB565 0x8D62
1651#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
1652#define GL_PROGRAM_BINARY_LENGTH 0x8741
1653#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
1654#define GL_PROGRAM_BINARY_FORMATS 0x87FF
1655#define GL_VERTEX_SHADER_BIT 0x00000001
1656#define GL_FRAGMENT_SHADER_BIT 0x00000002
1657#define GL_GEOMETRY_SHADER_BIT 0x00000004
1658#define GL_TESS_CONTROL_SHADER_BIT 0x00000008
1659#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010
1660#define GL_ALL_SHADER_BITS 0xFFFFFFFF
1661#define GL_PROGRAM_SEPARABLE 0x8258
1662#define GL_ACTIVE_PROGRAM 0x8259
1663#define GL_PROGRAM_PIPELINE_BINDING 0x825A
1664#define GL_MAX_VIEWPORTS 0x825B
1665#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C
1666#define GL_VIEWPORT_BOUNDS_RANGE 0x825D
1667#define GL_LAYER_PROVOKING_VERTEX 0x825E
1668#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F
1669#define GL_UNDEFINED_VERTEX 0x8260
1670#define GL_COPY_READ_BUFFER_BINDING 0x8F36
1671#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37
1672#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
1673#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
1674#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127
1675#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
1676#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129
1677#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A
1678#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B
1679#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C
1680#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D
1681#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E
1682#define GL_NUM_SAMPLE_COUNTS 0x9380
1683#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC
1684#define GL_ATOMIC_COUNTER_BUFFER 0x92C0
1685#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1
1686#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2
1687#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3
1688#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
1689#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
1690#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
1691#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
1692#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
1693#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
1694#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
1695#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
1696#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
1697#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
1698#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
1699#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
1700#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
1701#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
1702#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2
1703#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
1704#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
1705#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5
1706#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6
1707#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7
1708#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
1709#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
1710#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9
1711#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
1712#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
1713#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
1714#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
1715#define GL_UNIFORM_BARRIER_BIT 0x00000004
1716#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
1717#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
1718#define GL_COMMAND_BARRIER_BIT 0x00000040
1719#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
1720#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
1721#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
1722#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
1723#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
1724#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
1725#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
1726#define GL_MAX_IMAGE_UNITS 0x8F38
1727#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
1728#define GL_IMAGE_BINDING_NAME 0x8F3A
1729#define GL_IMAGE_BINDING_LEVEL 0x8F3B
1730#define GL_IMAGE_BINDING_LAYERED 0x8F3C
1731#define GL_IMAGE_BINDING_LAYER 0x8F3D
1732#define GL_IMAGE_BINDING_ACCESS 0x8F3E
1733#define GL_IMAGE_1D 0x904C
1734#define GL_IMAGE_2D 0x904D
1735#define GL_IMAGE_3D 0x904E
1736#define GL_IMAGE_2D_RECT 0x904F
1737#define GL_IMAGE_CUBE 0x9050
1738#define GL_IMAGE_BUFFER 0x9051
1739#define GL_IMAGE_1D_ARRAY 0x9052
1740#define GL_IMAGE_2D_ARRAY 0x9053
1741#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
1742#define GL_IMAGE_2D_MULTISAMPLE 0x9055
1743#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
1744#define GL_INT_IMAGE_1D 0x9057
1745#define GL_INT_IMAGE_2D 0x9058
1746#define GL_INT_IMAGE_3D 0x9059
1747#define GL_INT_IMAGE_2D_RECT 0x905A
1748#define GL_INT_IMAGE_CUBE 0x905B
1749#define GL_INT_IMAGE_BUFFER 0x905C
1750#define GL_INT_IMAGE_1D_ARRAY 0x905D
1751#define GL_INT_IMAGE_2D_ARRAY 0x905E
1752#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
1753#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
1754#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
1755#define GL_UNSIGNED_INT_IMAGE_1D 0x9062
1756#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
1757#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
1758#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
1759#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
1760#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
1761#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
1762#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
1763#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
1764#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
1765#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
1766#define GL_MAX_IMAGE_SAMPLES 0x906D
1767#define GL_IMAGE_BINDING_FORMAT 0x906E
1768#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
1769#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
1770#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
1771#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA
1772#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
1773#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
1774#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD
1775#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE
1776#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF
1777#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
1778#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
1779#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
1780#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
1781#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
1782#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9
1783#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E
1784#define GL_COMPRESSED_RGB8_ETC2 0x9274
1785#define GL_COMPRESSED_SRGB8_ETC2 0x9275
1786#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
1787#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
1788#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
1789#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
1790#define GL_COMPRESSED_R11_EAC 0x9270
1791#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
1792#define GL_COMPRESSED_RG11_EAC 0x9272
1793#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
1794#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
1795#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
1796#define GL_MAX_ELEMENT_INDEX 0x8D6B
1797#define GL_COMPUTE_SHADER 0x91B9
1798#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB
1799#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC
1800#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD
1801#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262
1802#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263
1803#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264
1804#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265
1805#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266
1806#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB
1807#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE
1808#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF
1809#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267
1810#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC
1811#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED
1812#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE
1813#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF
1814#define GL_COMPUTE_SHADER_BIT 0x00000020
1815#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
1816#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
1817#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
1818#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
1819#define GL_DEBUG_SOURCE_API 0x8246
1820#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
1821#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
1822#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
1823#define GL_DEBUG_SOURCE_APPLICATION 0x824A
1824#define GL_DEBUG_SOURCE_OTHER 0x824B
1825#define GL_DEBUG_TYPE_ERROR 0x824C
1826#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
1827#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
1828#define GL_DEBUG_TYPE_PORTABILITY 0x824F
1829#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
1830#define GL_DEBUG_TYPE_OTHER 0x8251
1831#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
1832#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
1833#define GL_DEBUG_LOGGED_MESSAGES 0x9145
1834#define GL_DEBUG_SEVERITY_HIGH 0x9146
1835#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
1836#define GL_DEBUG_SEVERITY_LOW 0x9148
1837#define GL_DEBUG_TYPE_MARKER 0x8268
1838#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
1839#define GL_DEBUG_TYPE_POP_GROUP 0x826A
1840#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
1841#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
1842#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
1843#define GL_BUFFER 0x82E0
1844#define GL_SHADER 0x82E1
1845#define GL_PROGRAM 0x82E2
1846#define GL_VERTEX_ARRAY 0x8074
1847#define GL_QUERY 0x82E3
1848#define GL_PROGRAM_PIPELINE 0x82E4
1849#define GL_SAMPLER 0x82E6
1850#define GL_MAX_LABEL_LENGTH 0x82E8
1851#define GL_DEBUG_OUTPUT 0x92E0
1852#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
1853#define GL_MAX_UNIFORM_LOCATIONS 0x826E
1854#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310
1855#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311
1856#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312
1857#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313
1858#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314
1859#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315
1860#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316
1861#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317
1862#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318
1863#define GL_INTERNALFORMAT_SUPPORTED 0x826F
1864#define GL_INTERNALFORMAT_PREFERRED 0x8270
1865#define GL_INTERNALFORMAT_RED_SIZE 0x8271
1866#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272
1867#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273
1868#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274
1869#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275
1870#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276
1871#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277
1872#define GL_INTERNALFORMAT_RED_TYPE 0x8278
1873#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279
1874#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A
1875#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B
1876#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C
1877#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D
1878#define GL_MAX_WIDTH 0x827E
1879#define GL_MAX_HEIGHT 0x827F
1880#define GL_MAX_DEPTH 0x8280
1881#define GL_MAX_LAYERS 0x8281
1882#define GL_MAX_COMBINED_DIMENSIONS 0x8282
1883#define GL_COLOR_COMPONENTS 0x8283
1884#define GL_DEPTH_COMPONENTS 0x8284
1885#define GL_STENCIL_COMPONENTS 0x8285
1886#define GL_COLOR_RENDERABLE 0x8286
1887#define GL_DEPTH_RENDERABLE 0x8287
1888#define GL_STENCIL_RENDERABLE 0x8288
1889#define GL_FRAMEBUFFER_RENDERABLE 0x8289
1890#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A
1891#define GL_FRAMEBUFFER_BLEND 0x828B
1892#define GL_READ_PIXELS 0x828C
1893#define GL_READ_PIXELS_FORMAT 0x828D
1894#define GL_READ_PIXELS_TYPE 0x828E
1895#define GL_TEXTURE_IMAGE_FORMAT 0x828F
1896#define GL_TEXTURE_IMAGE_TYPE 0x8290
1897#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291
1898#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292
1899#define GL_MIPMAP 0x8293
1900#define GL_MANUAL_GENERATE_MIPMAP 0x8294
1901#define GL_AUTO_GENERATE_MIPMAP 0x8295
1902#define GL_COLOR_ENCODING 0x8296
1903#define GL_SRGB_READ 0x8297
1904#define GL_SRGB_WRITE 0x8298
1905#define GL_FILTER 0x829A
1906#define GL_VERTEX_TEXTURE 0x829B
1907#define GL_TESS_CONTROL_TEXTURE 0x829C
1908#define GL_TESS_EVALUATION_TEXTURE 0x829D
1909#define GL_GEOMETRY_TEXTURE 0x829E
1910#define GL_FRAGMENT_TEXTURE 0x829F
1911#define GL_COMPUTE_TEXTURE 0x82A0
1912#define GL_TEXTURE_SHADOW 0x82A1
1913#define GL_TEXTURE_GATHER 0x82A2
1914#define GL_TEXTURE_GATHER_SHADOW 0x82A3
1915#define GL_SHADER_IMAGE_LOAD 0x82A4
1916#define GL_SHADER_IMAGE_STORE 0x82A5
1917#define GL_SHADER_IMAGE_ATOMIC 0x82A6
1918#define GL_IMAGE_TEXEL_SIZE 0x82A7
1919#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8
1920#define GL_IMAGE_PIXEL_FORMAT 0x82A9
1921#define GL_IMAGE_PIXEL_TYPE 0x82AA
1922#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC
1923#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD
1924#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE
1925#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF
1926#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1
1927#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2
1928#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3
1929#define GL_CLEAR_BUFFER 0x82B4
1930#define GL_TEXTURE_VIEW 0x82B5
1931#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6
1932#define GL_FULL_SUPPORT 0x82B7
1933#define GL_CAVEAT_SUPPORT 0x82B8
1934#define GL_IMAGE_CLASS_4_X_32 0x82B9
1935#define GL_IMAGE_CLASS_2_X_32 0x82BA
1936#define GL_IMAGE_CLASS_1_X_32 0x82BB
1937#define GL_IMAGE_CLASS_4_X_16 0x82BC
1938#define GL_IMAGE_CLASS_2_X_16 0x82BD
1939#define GL_IMAGE_CLASS_1_X_16 0x82BE
1940#define GL_IMAGE_CLASS_4_X_8 0x82BF
1941#define GL_IMAGE_CLASS_2_X_8 0x82C0
1942#define GL_IMAGE_CLASS_1_X_8 0x82C1
1943#define GL_IMAGE_CLASS_11_11_10 0x82C2
1944#define GL_IMAGE_CLASS_10_10_10_2 0x82C3
1945#define GL_VIEW_CLASS_128_BITS 0x82C4
1946#define GL_VIEW_CLASS_96_BITS 0x82C5
1947#define GL_VIEW_CLASS_64_BITS 0x82C6
1948#define GL_VIEW_CLASS_48_BITS 0x82C7
1949#define GL_VIEW_CLASS_32_BITS 0x82C8
1950#define GL_VIEW_CLASS_24_BITS 0x82C9
1951#define GL_VIEW_CLASS_16_BITS 0x82CA
1952#define GL_VIEW_CLASS_8_BITS 0x82CB
1953#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC
1954#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD
1955#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE
1956#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF
1957#define GL_VIEW_CLASS_RGTC1_RED 0x82D0
1958#define GL_VIEW_CLASS_RGTC2_RG 0x82D1
1959#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2
1960#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3
1961#define GL_UNIFORM 0x92E1
1962#define GL_UNIFORM_BLOCK 0x92E2
1963#define GL_PROGRAM_INPUT 0x92E3
1964#define GL_PROGRAM_OUTPUT 0x92E4
1965#define GL_BUFFER_VARIABLE 0x92E5
1966#define GL_SHADER_STORAGE_BLOCK 0x92E6
1967#define GL_VERTEX_SUBROUTINE 0x92E8
1968#define GL_TESS_CONTROL_SUBROUTINE 0x92E9
1969#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA
1970#define GL_GEOMETRY_SUBROUTINE 0x92EB
1971#define GL_FRAGMENT_SUBROUTINE 0x92EC
1972#define GL_COMPUTE_SUBROUTINE 0x92ED
1973#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE
1974#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF
1975#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0
1976#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1
1977#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2
1978#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3
1979#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4
1980#define GL_ACTIVE_RESOURCES 0x92F5
1981#define GL_MAX_NAME_LENGTH 0x92F6
1982#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7
1983#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8
1984#define GL_NAME_LENGTH 0x92F9
1985#define GL_TYPE 0x92FA
1986#define GL_ARRAY_SIZE 0x92FB
1987#define GL_OFFSET 0x92FC
1988#define GL_BLOCK_INDEX 0x92FD
1989#define GL_ARRAY_STRIDE 0x92FE
1990#define GL_MATRIX_STRIDE 0x92FF
1991#define GL_IS_ROW_MAJOR 0x9300
1992#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301
1993#define GL_BUFFER_BINDING 0x9302
1994#define GL_BUFFER_DATA_SIZE 0x9303
1995#define GL_NUM_ACTIVE_VARIABLES 0x9304
1996#define GL_ACTIVE_VARIABLES 0x9305
1997#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306
1998#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307
1999#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308
2000#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309
2001#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A
2002#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B
2003#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C
2004#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D
2005#define GL_LOCATION 0x930E
2006#define GL_LOCATION_INDEX 0x930F
2007#define GL_IS_PER_PATCH 0x92E7
2008#define GL_SHADER_STORAGE_BUFFER 0x90D2
2009#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3
2010#define GL_SHADER_STORAGE_BUFFER_START 0x90D4
2011#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5
2012#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6
2013#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7
2014#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8
2015#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9
2016#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA
2017#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB
2018#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC
2019#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
2020#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE
2021#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF
2022#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
2023#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39
2024#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA
2025#define GL_TEXTURE_BUFFER_OFFSET 0x919D
2026#define GL_TEXTURE_BUFFER_SIZE 0x919E
2027#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F
2028#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB
2029#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC
2030#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD
2031#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE
2032#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
2033#define GL_VERTEX_ATTRIB_BINDING 0x82D4
2034#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5
2035#define GL_VERTEX_BINDING_DIVISOR 0x82D6
2036#define GL_VERTEX_BINDING_OFFSET 0x82D7
2037#define GL_VERTEX_BINDING_STRIDE 0x82D8
2038#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
2039#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA
2040#define GL_VERTEX_BINDING_BUFFER 0x8F4F
2041#define GL_DISPLAY_LIST 0x82E7
2042#define GL_STACK_UNDERFLOW 0x0504
2043#define GL_STACK_OVERFLOW 0x0503
1589#ifndef GL_VERSION_1_0 2044#ifndef GL_VERSION_1_0
1590#define GL_VERSION_1_0 1 2045#define GL_VERSION_1_0 1
1591GLAPI int GLAD_GL_VERSION_1_0; 2046GLAPI int GLAD_GL_VERSION_1_0;
@@ -2756,6 +3211,592 @@ typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint
2756GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; 3211GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
2757#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv 3212#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv
2758#endif 3213#endif
3214#ifndef GL_VERSION_4_0
3215#define GL_VERSION_4_0 1
3216GLAPI int GLAD_GL_VERSION_4_0;
3217typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC)(GLfloat value);
3218GLAPI PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading;
3219#define glMinSampleShading glad_glMinSampleShading
3220typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode);
3221GLAPI PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi;
3222#define glBlendEquationi glad_glBlendEquationi
3223typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha);
3224GLAPI PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei;
3225#define glBlendEquationSeparatei glad_glBlendEquationSeparatei
3226typedef void (APIENTRYP PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst);
3227GLAPI PFNGLBLENDFUNCIPROC glad_glBlendFunci;
3228#define glBlendFunci glad_glBlendFunci
3229typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
3230GLAPI PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei;
3231#define glBlendFuncSeparatei glad_glBlendFuncSeparatei
3232typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect);
3233GLAPI PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect;
3234#define glDrawArraysIndirect glad_glDrawArraysIndirect
3235typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect);
3236GLAPI PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect;
3237#define glDrawElementsIndirect glad_glDrawElementsIndirect
3238typedef void (APIENTRYP PFNGLUNIFORM1DPROC)(GLint location, GLdouble x);
3239GLAPI PFNGLUNIFORM1DPROC glad_glUniform1d;
3240#define glUniform1d glad_glUniform1d
3241typedef void (APIENTRYP PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y);
3242GLAPI PFNGLUNIFORM2DPROC glad_glUniform2d;
3243#define glUniform2d glad_glUniform2d
3244typedef void (APIENTRYP PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z);
3245GLAPI PFNGLUNIFORM3DPROC glad_glUniform3d;
3246#define glUniform3d glad_glUniform3d
3247typedef void (APIENTRYP PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
3248GLAPI PFNGLUNIFORM4DPROC glad_glUniform4d;
3249#define glUniform4d glad_glUniform4d
3250typedef void (APIENTRYP PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble *value);
3251GLAPI PFNGLUNIFORM1DVPROC glad_glUniform1dv;
3252#define glUniform1dv glad_glUniform1dv
3253typedef void (APIENTRYP PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble *value);
3254GLAPI PFNGLUNIFORM2DVPROC glad_glUniform2dv;
3255#define glUniform2dv glad_glUniform2dv
3256typedef void (APIENTRYP PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble *value);
3257GLAPI PFNGLUNIFORM3DVPROC glad_glUniform3dv;
3258#define glUniform3dv glad_glUniform3dv
3259typedef void (APIENTRYP PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble *value);
3260GLAPI PFNGLUNIFORM4DVPROC glad_glUniform4dv;
3261#define glUniform4dv glad_glUniform4dv
3262typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3263GLAPI PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv;
3264#define glUniformMatrix2dv glad_glUniformMatrix2dv
3265typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3266GLAPI PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv;
3267#define glUniformMatrix3dv glad_glUniformMatrix3dv
3268typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3269GLAPI PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv;
3270#define glUniformMatrix4dv glad_glUniformMatrix4dv
3271typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3272GLAPI PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv;
3273#define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv
3274typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3275GLAPI PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv;
3276#define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv
3277typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3278GLAPI PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv;
3279#define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv
3280typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3281GLAPI PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv;
3282#define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv
3283typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3284GLAPI PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv;
3285#define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv
3286typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3287GLAPI PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv;
3288#define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv
3289typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble *params);
3290GLAPI PFNGLGETUNIFORMDVPROC glad_glGetUniformdv;
3291#define glGetUniformdv glad_glGetUniformdv
3292typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar *name);
3293GLAPI PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation;
3294#define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation
3295typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar *name);
3296GLAPI PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex;
3297#define glGetSubroutineIndex glad_glGetSubroutineIndex
3298typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
3299GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv;
3300#define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv
3301typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
3302GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName;
3303#define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName
3304typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
3305GLAPI PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName;
3306#define glGetActiveSubroutineName glad_glGetActiveSubroutineName
3307typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint *indices);
3308GLAPI PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv;
3309#define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv
3310typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint *params);
3311GLAPI PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv;
3312#define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv
3313typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint *values);
3314GLAPI PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv;
3315#define glGetProgramStageiv glad_glGetProgramStageiv
3316typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value);
3317GLAPI PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri;
3318#define glPatchParameteri glad_glPatchParameteri
3319typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat *values);
3320GLAPI PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv;
3321#define glPatchParameterfv glad_glPatchParameterfv
3322typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id);
3323GLAPI PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback;
3324#define glBindTransformFeedback glad_glBindTransformFeedback
3325typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint *ids);
3326GLAPI PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks;
3327#define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks
3328typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint *ids);
3329GLAPI PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks;
3330#define glGenTransformFeedbacks glad_glGenTransformFeedbacks
3331typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id);
3332GLAPI PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback;
3333#define glIsTransformFeedback glad_glIsTransformFeedback
3334typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC)(void);
3335GLAPI PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback;
3336#define glPauseTransformFeedback glad_glPauseTransformFeedback
3337typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC)(void);
3338GLAPI PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback;
3339#define glResumeTransformFeedback glad_glResumeTransformFeedback
3340typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id);
3341GLAPI PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback;
3342#define glDrawTransformFeedback glad_glDrawTransformFeedback
3343typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream);
3344GLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream;
3345#define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream
3346typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id);
3347GLAPI PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed;
3348#define glBeginQueryIndexed glad_glBeginQueryIndexed
3349typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index);
3350GLAPI PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed;
3351#define glEndQueryIndexed glad_glEndQueryIndexed
3352typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint *params);
3353GLAPI PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv;
3354#define glGetQueryIndexediv glad_glGetQueryIndexediv
3355#endif
3356#ifndef GL_VERSION_4_1
3357#define GL_VERSION_4_1 1
3358GLAPI int GLAD_GL_VERSION_4_1;
3359typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(void);
3360GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;
3361#define glReleaseShaderCompiler glad_glReleaseShaderCompiler
3362typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
3363GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary;
3364#define glShaderBinary glad_glShaderBinary
3365typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
3366GLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;
3367#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat
3368typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f);
3369GLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef;
3370#define glDepthRangef glad_glDepthRangef
3371typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d);
3372GLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf;
3373#define glClearDepthf glad_glClearDepthf
3374typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
3375GLAPI PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary;
3376#define glGetProgramBinary glad_glGetProgramBinary
3377typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
3378GLAPI PFNGLPROGRAMBINARYPROC glad_glProgramBinary;
3379#define glProgramBinary glad_glProgramBinary
3380typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value);
3381GLAPI PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri;
3382#define glProgramParameteri glad_glProgramParameteri
3383typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program);
3384GLAPI PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages;
3385#define glUseProgramStages glad_glUseProgramStages
3386typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program);
3387GLAPI PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram;
3388#define glActiveShaderProgram glad_glActiveShaderProgram
3389typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const*strings);
3390GLAPI PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv;
3391#define glCreateShaderProgramv glad_glCreateShaderProgramv
3392typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline);
3393GLAPI PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline;
3394#define glBindProgramPipeline glad_glBindProgramPipeline
3395typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint *pipelines);
3396GLAPI PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines;
3397#define glDeleteProgramPipelines glad_glDeleteProgramPipelines
3398typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint *pipelines);
3399GLAPI PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines;
3400#define glGenProgramPipelines glad_glGenProgramPipelines
3401typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline);
3402GLAPI PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline;
3403#define glIsProgramPipeline glad_glIsProgramPipeline
3404typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint *params);
3405GLAPI PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv;
3406#define glGetProgramPipelineiv glad_glGetProgramPipelineiv
3407typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0);
3408GLAPI PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i;
3409#define glProgramUniform1i glad_glProgramUniform1i
3410typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
3411GLAPI PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv;
3412#define glProgramUniform1iv glad_glProgramUniform1iv
3413typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0);
3414GLAPI PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f;
3415#define glProgramUniform1f glad_glProgramUniform1f
3416typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
3417GLAPI PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv;
3418#define glProgramUniform1fv glad_glProgramUniform1fv
3419typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0);
3420GLAPI PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d;
3421#define glProgramUniform1d glad_glProgramUniform1d
3422typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
3423GLAPI PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv;
3424#define glProgramUniform1dv glad_glProgramUniform1dv
3425typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0);
3426GLAPI PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui;
3427#define glProgramUniform1ui glad_glProgramUniform1ui
3428typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
3429GLAPI PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv;
3430#define glProgramUniform1uiv glad_glProgramUniform1uiv
3431typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1);
3432GLAPI PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i;
3433#define glProgramUniform2i glad_glProgramUniform2i
3434typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
3435GLAPI PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv;
3436#define glProgramUniform2iv glad_glProgramUniform2iv
3437typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1);
3438GLAPI PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f;
3439#define glProgramUniform2f glad_glProgramUniform2f
3440typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
3441GLAPI PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv;
3442#define glProgramUniform2fv glad_glProgramUniform2fv
3443typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1);
3444GLAPI PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d;
3445#define glProgramUniform2d glad_glProgramUniform2d
3446typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
3447GLAPI PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv;
3448#define glProgramUniform2dv glad_glProgramUniform2dv
3449typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1);
3450GLAPI PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui;
3451#define glProgramUniform2ui glad_glProgramUniform2ui
3452typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
3453GLAPI PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv;
3454#define glProgramUniform2uiv glad_glProgramUniform2uiv
3455typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
3456GLAPI PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i;
3457#define glProgramUniform3i glad_glProgramUniform3i
3458typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
3459GLAPI PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv;
3460#define glProgramUniform3iv glad_glProgramUniform3iv
3461typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
3462GLAPI PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f;
3463#define glProgramUniform3f glad_glProgramUniform3f
3464typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
3465GLAPI PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv;
3466#define glProgramUniform3fv glad_glProgramUniform3fv
3467typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
3468GLAPI PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d;
3469#define glProgramUniform3d glad_glProgramUniform3d
3470typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
3471GLAPI PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv;
3472#define glProgramUniform3dv glad_glProgramUniform3dv
3473typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
3474GLAPI PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui;
3475#define glProgramUniform3ui glad_glProgramUniform3ui
3476typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
3477GLAPI PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv;
3478#define glProgramUniform3uiv glad_glProgramUniform3uiv
3479typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
3480GLAPI PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i;
3481#define glProgramUniform4i glad_glProgramUniform4i
3482typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
3483GLAPI PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv;
3484#define glProgramUniform4iv glad_glProgramUniform4iv
3485typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
3486GLAPI PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f;
3487#define glProgramUniform4f glad_glProgramUniform4f
3488typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
3489GLAPI PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv;
3490#define glProgramUniform4fv glad_glProgramUniform4fv
3491typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
3492GLAPI PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d;
3493#define glProgramUniform4d glad_glProgramUniform4d
3494typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
3495GLAPI PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv;
3496#define glProgramUniform4dv glad_glProgramUniform4dv
3497typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
3498GLAPI PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui;
3499#define glProgramUniform4ui glad_glProgramUniform4ui
3500typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
3501GLAPI PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv;
3502#define glProgramUniform4uiv glad_glProgramUniform4uiv
3503typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
3504GLAPI PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv;
3505#define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv
3506typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
3507GLAPI PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv;
3508#define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv
3509typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
3510GLAPI PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv;
3511#define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv
3512typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3513GLAPI PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv;
3514#define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv
3515typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3516GLAPI PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv;
3517#define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv
3518typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3519GLAPI PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv;
3520#define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv
3521typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
3522GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv;
3523#define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv
3524typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
3525GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv;
3526#define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv
3527typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
3528GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv;
3529#define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv
3530typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
3531GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv;
3532#define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv
3533typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
3534GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv;
3535#define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv
3536typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
3537GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv;
3538#define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv
3539typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3540GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv;
3541#define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv
3542typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3543GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv;
3544#define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv
3545typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3546GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv;
3547#define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv
3548typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3549GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv;
3550#define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv
3551typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3552GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv;
3553#define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv
3554typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
3555GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv;
3556#define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv
3557typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline);
3558GLAPI PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline;
3559#define glValidateProgramPipeline glad_glValidateProgramPipeline
3560typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
3561GLAPI PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog;
3562#define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog
3563typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x);
3564GLAPI PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d;
3565#define glVertexAttribL1d glad_glVertexAttribL1d
3566typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y);
3567GLAPI PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d;
3568#define glVertexAttribL2d glad_glVertexAttribL2d
3569typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);
3570GLAPI PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d;
3571#define glVertexAttribL3d glad_glVertexAttribL3d
3572typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
3573GLAPI PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d;
3574#define glVertexAttribL4d glad_glVertexAttribL4d
3575typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble *v);
3576GLAPI PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv;
3577#define glVertexAttribL1dv glad_glVertexAttribL1dv
3578typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble *v);
3579GLAPI PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv;
3580#define glVertexAttribL2dv glad_glVertexAttribL2dv
3581typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble *v);
3582GLAPI PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv;
3583#define glVertexAttribL3dv glad_glVertexAttribL3dv
3584typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble *v);
3585GLAPI PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv;
3586#define glVertexAttribL4dv glad_glVertexAttribL4dv
3587typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
3588GLAPI PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer;
3589#define glVertexAttribLPointer glad_glVertexAttribLPointer
3590typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble *params);
3591GLAPI PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv;
3592#define glGetVertexAttribLdv glad_glGetVertexAttribLdv
3593typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat *v);
3594GLAPI PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv;
3595#define glViewportArrayv glad_glViewportArrayv
3596typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
3597GLAPI PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf;
3598#define glViewportIndexedf glad_glViewportIndexedf
3599typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat *v);
3600GLAPI PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv;
3601#define glViewportIndexedfv glad_glViewportIndexedfv
3602typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint *v);
3603GLAPI PFNGLSCISSORARRAYVPROC glad_glScissorArrayv;
3604#define glScissorArrayv glad_glScissorArrayv
3605typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
3606GLAPI PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed;
3607#define glScissorIndexed glad_glScissorIndexed
3608typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint *v);
3609GLAPI PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv;
3610#define glScissorIndexedv glad_glScissorIndexedv
3611typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble *v);
3612GLAPI PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv;
3613#define glDepthRangeArrayv glad_glDepthRangeArrayv
3614typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f);
3615GLAPI PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed;
3616#define glDepthRangeIndexed glad_glDepthRangeIndexed
3617typedef void (APIENTRYP PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat *data);
3618GLAPI PFNGLGETFLOATI_VPROC glad_glGetFloati_v;
3619#define glGetFloati_v glad_glGetFloati_v
3620typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble *data);
3621GLAPI PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v;
3622#define glGetDoublei_v glad_glGetDoublei_v
3623#endif
3624#ifndef GL_VERSION_4_2
3625#define GL_VERSION_4_2 1
3626GLAPI int GLAD_GL_VERSION_4_2;
3627typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
3628GLAPI PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance;
3629#define glDrawArraysInstancedBaseInstance glad_glDrawArraysInstancedBaseInstance
3630typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
3631GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance;
3632#define glDrawElementsInstancedBaseInstance glad_glDrawElementsInstancedBaseInstance
3633typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
3634GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance;
3635#define glDrawElementsInstancedBaseVertexBaseInstance glad_glDrawElementsInstancedBaseVertexBaseInstance
3636typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
3637GLAPI PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ;
3638#define glGetInternalformativ glad_glGetInternalformativ
3639typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)(GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
3640GLAPI PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv;
3641#define glGetActiveAtomicCounterBufferiv glad_glGetActiveAtomicCounterBufferiv
3642typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
3643GLAPI PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture;
3644#define glBindImageTexture glad_glBindImageTexture
3645typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC)(GLbitfield barriers);
3646GLAPI PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier;
3647#define glMemoryBarrier glad_glMemoryBarrier
3648typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
3649GLAPI PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D;
3650#define glTexStorage1D glad_glTexStorage1D
3651typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
3652GLAPI PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D;
3653#define glTexStorage2D glad_glTexStorage2D
3654typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
3655GLAPI PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D;
3656#define glTexStorage3D glad_glTexStorage3D
3657typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)(GLenum mode, GLuint id, GLsizei instancecount);
3658GLAPI PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced;
3659#define glDrawTransformFeedbackInstanced glad_glDrawTransformFeedbackInstanced
3660typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)(GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
3661GLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced;
3662#define glDrawTransformFeedbackStreamInstanced glad_glDrawTransformFeedbackStreamInstanced
3663#endif
3664#ifndef GL_VERSION_4_3
3665#define GL_VERSION_4_3 1
3666GLAPI int GLAD_GL_VERSION_4_3;
3667typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC)(GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
3668GLAPI PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData;
3669#define glClearBufferData glad_glClearBufferData
3670typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC)(GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
3671GLAPI PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData;
3672#define glClearBufferSubData glad_glClearBufferSubData
3673typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
3674GLAPI PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute;
3675#define glDispatchCompute glad_glDispatchCompute
3676typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect);
3677GLAPI PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect;
3678#define glDispatchComputeIndirect glad_glDispatchComputeIndirect
3679typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
3680GLAPI PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData;
3681#define glCopyImageSubData glad_glCopyImageSubData
3682typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
3683GLAPI PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri;
3684#define glFramebufferParameteri glad_glFramebufferParameteri
3685typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);
3686GLAPI PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv;
3687#define glGetFramebufferParameteriv glad_glGetFramebufferParameteriv
3688typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);
3689GLAPI PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v;
3690#define glGetInternalformati64v glad_glGetInternalformati64v
3691typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
3692GLAPI PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage;
3693#define glInvalidateTexSubImage glad_glInvalidateTexSubImage
3694typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC)(GLuint texture, GLint level);
3695GLAPI PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage;
3696#define glInvalidateTexImage glad_glInvalidateTexImage
3697typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length);
3698GLAPI PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData;
3699#define glInvalidateBufferSubData glad_glInvalidateBufferSubData
3700typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer);
3701GLAPI PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData;
3702#define glInvalidateBufferData glad_glInvalidateBufferData
3703typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments);
3704GLAPI PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer;
3705#define glInvalidateFramebuffer glad_glInvalidateFramebuffer
3706typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
3707GLAPI PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer;
3708#define glInvalidateSubFramebuffer glad_glInvalidateSubFramebuffer
3709typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
3710GLAPI PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect;
3711#define glMultiDrawArraysIndirect glad_glMultiDrawArraysIndirect
3712typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
3713GLAPI PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect;
3714#define glMultiDrawElementsIndirect glad_glMultiDrawElementsIndirect
3715typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC)(GLuint program, GLenum programInterface, GLenum pname, GLint *params);
3716GLAPI PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv;
3717#define glGetProgramInterfaceiv glad_glGetProgramInterfaceiv
3718typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name);
3719GLAPI PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex;
3720#define glGetProgramResourceIndex glad_glGetProgramResourceIndex
3721typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
3722GLAPI PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName;
3723#define glGetProgramResourceName glad_glGetProgramResourceName
3724typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
3725GLAPI PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv;
3726#define glGetProgramResourceiv glad_glGetProgramResourceiv
3727typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC)(GLuint program, GLenum programInterface, const GLchar *name);
3728GLAPI PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation;
3729#define glGetProgramResourceLocation glad_glGetProgramResourceLocation
3730typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name);
3731GLAPI PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex;
3732#define glGetProgramResourceLocationIndex glad_glGetProgramResourceLocationIndex
3733typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC)(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
3734GLAPI PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding;
3735#define glShaderStorageBlockBinding glad_glShaderStorageBlockBinding
3736typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
3737GLAPI PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange;
3738#define glTexBufferRange glad_glTexBufferRange
3739typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
3740GLAPI PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample;
3741#define glTexStorage2DMultisample glad_glTexStorage2DMultisample
3742typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
3743GLAPI PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample;
3744#define glTexStorage3DMultisample glad_glTexStorage3DMultisample
3745typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
3746GLAPI PFNGLTEXTUREVIEWPROC glad_glTextureView;
3747#define glTextureView glad_glTextureView
3748typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
3749GLAPI PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer;
3750#define glBindVertexBuffer glad_glBindVertexBuffer
3751typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
3752GLAPI PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat;
3753#define glVertexAttribFormat glad_glVertexAttribFormat
3754typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
3755GLAPI PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat;
3756#define glVertexAttribIFormat glad_glVertexAttribIFormat
3757typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
3758GLAPI PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat;
3759#define glVertexAttribLFormat glad_glVertexAttribLFormat
3760typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex);
3761GLAPI PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding;
3762#define glVertexAttribBinding glad_glVertexAttribBinding
3763typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor);
3764GLAPI PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor;
3765#define glVertexBindingDivisor glad_glVertexBindingDivisor
3766typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
3767GLAPI PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl;
3768#define glDebugMessageControl glad_glDebugMessageControl
3769typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
3770GLAPI PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert;
3771#define glDebugMessageInsert glad_glDebugMessageInsert
3772typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam);
3773GLAPI PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback;
3774#define glDebugMessageCallback glad_glDebugMessageCallback
3775typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
3776GLAPI PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog;
3777#define glGetDebugMessageLog glad_glGetDebugMessageLog
3778typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message);
3779GLAPI PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup;
3780#define glPushDebugGroup glad_glPushDebugGroup
3781typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC)(void);
3782GLAPI PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup;
3783#define glPopDebugGroup glad_glPopDebugGroup
3784typedef void (APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
3785GLAPI PFNGLOBJECTLABELPROC glad_glObjectLabel;
3786#define glObjectLabel glad_glObjectLabel
3787typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
3788GLAPI PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel;
3789#define glGetObjectLabel glad_glGetObjectLabel
3790typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void *ptr, GLsizei length, const GLchar *label);
3791GLAPI PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel;
3792#define glObjectPtrLabel glad_glObjectPtrLabel
3793typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
3794GLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel;
3795#define glGetObjectPtrLabel glad_glGetObjectPtrLabel
3796typedef void (APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void **params);
3797GLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv;
3798#define glGetPointerv glad_glGetPointerv
3799#endif
2759#define GL_MULTISAMPLE_3DFX 0x86B2 3800#define GL_MULTISAMPLE_3DFX 0x86B2
2760#define GL_SAMPLE_BUFFERS_3DFX 0x86B3 3801#define GL_SAMPLE_BUFFERS_3DFX 0x86B3
2761#define GL_SAMPLES_3DFX 0x86B4 3802#define GL_SAMPLES_3DFX 0x86B4
@@ -2932,38 +3973,9 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
2932#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 3973#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08
2933#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 3974#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09
2934#define GL_YCBCR_422_APPLE 0x85B9 3975#define GL_YCBCR_422_APPLE 0x85B9
2935#define GL_FIXED 0x140C
2936#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
2937#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
2938#define GL_LOW_FLOAT 0x8DF0
2939#define GL_MEDIUM_FLOAT 0x8DF1
2940#define GL_HIGH_FLOAT 0x8DF2
2941#define GL_LOW_INT 0x8DF3
2942#define GL_MEDIUM_INT 0x8DF4
2943#define GL_HIGH_INT 0x8DF5
2944#define GL_SHADER_COMPILER 0x8DFA
2945#define GL_SHADER_BINARY_FORMATS 0x8DF8
2946#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
2947#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
2948#define GL_MAX_VARYING_VECTORS 0x8DFC
2949#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
2950#define GL_RGB565 0x8D62
2951#define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE 3976#define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE
2952#define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381 3977#define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381
2953#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382 3978#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382
2954#define GL_COMPRESSED_RGB8_ETC2 0x9274
2955#define GL_COMPRESSED_SRGB8_ETC2 0x9275
2956#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
2957#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
2958#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
2959#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
2960#define GL_COMPRESSED_R11_EAC 0x9270
2961#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
2962#define GL_COMPRESSED_RG11_EAC 0x9272
2963#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
2964#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
2965#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
2966#define GL_MAX_ELEMENT_INDEX 0x8D6B
2967#define GL_UNSIGNED_INT64_ARB 0x140F 3979#define GL_UNSIGNED_INT64_ARB 0x140F
2968#define GL_MAP_PERSISTENT_BIT 0x0040 3980#define GL_MAP_PERSISTENT_BIT 0x0040
2969#define GL_MAP_COHERENT_BIT 0x0080 3981#define GL_MAP_COHERENT_BIT 0x0080
@@ -2984,32 +3996,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
2984#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B 3996#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B
2985#define GL_CLAMP_READ_COLOR_ARB 0x891C 3997#define GL_CLAMP_READ_COLOR_ARB 0x891C
2986#define GL_FIXED_ONLY_ARB 0x891D 3998#define GL_FIXED_ONLY_ARB 0x891D
2987#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127
2988#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
2989#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129
2990#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A
2991#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B
2992#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C
2993#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D
2994#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E
2995#define GL_COMPUTE_SHADER 0x91B9
2996#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB
2997#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC
2998#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD
2999#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262
3000#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263
3001#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264
3002#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265
3003#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266
3004#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB
3005#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE
3006#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF
3007#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267
3008#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC
3009#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED
3010#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE
3011#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF
3012#define GL_COMPUTE_SHADER_BIT 0x00000020
3013#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 3999#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344
3014#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB 4000#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB
3015#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 4001#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345
@@ -3049,7 +4035,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3049#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B 4035#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B
3050#define GL_TEXTURE_TARGET 0x1006 4036#define GL_TEXTURE_TARGET 0x1006
3051#define GL_QUERY_TARGET 0x82EA 4037#define GL_QUERY_TARGET 0x82EA
3052#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A
3053#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 4038#define GL_MAX_DRAW_BUFFERS_ARB 0x8824
3054#define GL_DRAW_BUFFER0_ARB 0x8825 4039#define GL_DRAW_BUFFER0_ARB 0x8825
3055#define GL_DRAW_BUFFER1_ARB 0x8826 4040#define GL_DRAW_BUFFER1_ARB 0x8826
@@ -3067,12 +4052,9 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3067#define GL_DRAW_BUFFER13_ARB 0x8832 4052#define GL_DRAW_BUFFER13_ARB 0x8832
3068#define GL_DRAW_BUFFER14_ARB 0x8833 4053#define GL_DRAW_BUFFER14_ARB 0x8833
3069#define GL_DRAW_BUFFER15_ARB 0x8834 4054#define GL_DRAW_BUFFER15_ARB 0x8834
3070#define GL_DRAW_INDIRECT_BUFFER 0x8F3F
3071#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43
3072#define GL_LOCATION_COMPONENT 0x934A 4055#define GL_LOCATION_COMPONENT 0x934A
3073#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B 4056#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B
3074#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C 4057#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C
3075#define GL_MAX_UNIFORM_LOCATIONS 0x826E
3076#define GL_FRAGMENT_PROGRAM_ARB 0x8804 4058#define GL_FRAGMENT_PROGRAM_ARB 0x8804
3077#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 4059#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875
3078#define GL_PROGRAM_LENGTH_ARB 0x8627 4060#define GL_PROGRAM_LENGTH_ARB 0x8627
@@ -3154,15 +4136,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3154#define GL_FRAGMENT_SHADER_ARB 0x8B30 4136#define GL_FRAGMENT_SHADER_ARB 0x8B30
3155#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 4137#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
3156#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B 4138#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
3157#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310
3158#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311
3159#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312
3160#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313
3161#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314
3162#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315
3163#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316
3164#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317
3165#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318
3166#define GL_INDEX 0x8222 4139#define GL_INDEX 0x8222
3167#define GL_LINES_ADJACENCY_ARB 0x000A 4140#define GL_LINES_ADJACENCY_ARB 0x000A
3168#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B 4141#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B
@@ -3182,30 +4155,8 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3182#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF 4155#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF
3183#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 4156#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0
3184#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 4157#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1
3185#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
3186#define GL_PROGRAM_BINARY_LENGTH 0x8741
3187#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
3188#define GL_PROGRAM_BINARY_FORMATS 0x87FF
3189#define GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551 4158#define GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551
3190#define GL_SPIR_V_BINARY_ARB 0x9552 4159#define GL_SPIR_V_BINARY_ARB 0x9552
3191#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F
3192#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A
3193#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B
3194#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C
3195#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D
3196#define GL_MAX_VERTEX_STREAMS 0x8E71
3197#define GL_DOUBLE_VEC2 0x8FFC
3198#define GL_DOUBLE_VEC3 0x8FFD
3199#define GL_DOUBLE_VEC4 0x8FFE
3200#define GL_DOUBLE_MAT2 0x8F46
3201#define GL_DOUBLE_MAT3 0x8F47
3202#define GL_DOUBLE_MAT4 0x8F48
3203#define GL_DOUBLE_MAT2x3 0x8F49
3204#define GL_DOUBLE_MAT2x4 0x8F4A
3205#define GL_DOUBLE_MAT3x2 0x8F4B
3206#define GL_DOUBLE_MAT3x4 0x8F4C
3207#define GL_DOUBLE_MAT4x2 0x8F4D
3208#define GL_DOUBLE_MAT4x3 0x8F4E
3209#define GL_INT64_ARB 0x140E 4160#define GL_INT64_ARB 0x140E
3210#define GL_INT64_VEC2_ARB 0x8FE9 4161#define GL_INT64_VEC2_ARB 0x8FE9
3211#define GL_INT64_VEC3_ARB 0x8FEA 4162#define GL_INT64_VEC3_ARB 0x8FEA
@@ -3281,109 +4232,26 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3281#define GL_PARAMETER_BUFFER_ARB 0x80EE 4232#define GL_PARAMETER_BUFFER_ARB 0x80EE
3282#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF 4233#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF
3283#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE 4234#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE
3284#define GL_NUM_SAMPLE_COUNTS 0x9380
3285#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
3286#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
3287#define GL_INTERNALFORMAT_SUPPORTED 0x826F
3288#define GL_INTERNALFORMAT_PREFERRED 0x8270
3289#define GL_INTERNALFORMAT_RED_SIZE 0x8271
3290#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272
3291#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273
3292#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274
3293#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275
3294#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276
3295#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277
3296#define GL_INTERNALFORMAT_RED_TYPE 0x8278
3297#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279
3298#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A
3299#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B
3300#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C
3301#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D
3302#define GL_MAX_WIDTH 0x827E
3303#define GL_MAX_HEIGHT 0x827F
3304#define GL_MAX_DEPTH 0x8280
3305#define GL_MAX_LAYERS 0x8281
3306#define GL_MAX_COMBINED_DIMENSIONS 0x8282
3307#define GL_COLOR_COMPONENTS 0x8283
3308#define GL_DEPTH_COMPONENTS 0x8284
3309#define GL_STENCIL_COMPONENTS 0x8285
3310#define GL_COLOR_RENDERABLE 0x8286
3311#define GL_DEPTH_RENDERABLE 0x8287
3312#define GL_STENCIL_RENDERABLE 0x8288
3313#define GL_FRAMEBUFFER_RENDERABLE 0x8289
3314#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A
3315#define GL_FRAMEBUFFER_BLEND 0x828B
3316#define GL_READ_PIXELS 0x828C
3317#define GL_READ_PIXELS_FORMAT 0x828D
3318#define GL_READ_PIXELS_TYPE 0x828E
3319#define GL_TEXTURE_IMAGE_FORMAT 0x828F
3320#define GL_TEXTURE_IMAGE_TYPE 0x8290
3321#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291
3322#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292
3323#define GL_MIPMAP 0x8293
3324#define GL_MANUAL_GENERATE_MIPMAP 0x8294
3325#define GL_AUTO_GENERATE_MIPMAP 0x8295
3326#define GL_COLOR_ENCODING 0x8296
3327#define GL_SRGB_READ 0x8297
3328#define GL_SRGB_WRITE 0x8298
3329#define GL_SRGB_DECODE_ARB 0x8299 4235#define GL_SRGB_DECODE_ARB 0x8299
3330#define GL_FILTER 0x829A 4236#define GL_VIEW_CLASS_EAC_R11 0x9383
3331#define GL_VERTEX_TEXTURE 0x829B 4237#define GL_VIEW_CLASS_EAC_RG11 0x9384
3332#define GL_TESS_CONTROL_TEXTURE 0x829C 4238#define GL_VIEW_CLASS_ETC2_RGB 0x9385
3333#define GL_TESS_EVALUATION_TEXTURE 0x829D 4239#define GL_VIEW_CLASS_ETC2_RGBA 0x9386
3334#define GL_GEOMETRY_TEXTURE 0x829E 4240#define GL_VIEW_CLASS_ETC2_EAC_RGBA 0x9387
3335#define GL_FRAGMENT_TEXTURE 0x829F 4241#define GL_VIEW_CLASS_ASTC_4x4_RGBA 0x9388
3336#define GL_COMPUTE_TEXTURE 0x82A0 4242#define GL_VIEW_CLASS_ASTC_5x4_RGBA 0x9389
3337#define GL_TEXTURE_SHADOW 0x82A1 4243#define GL_VIEW_CLASS_ASTC_5x5_RGBA 0x938A
3338#define GL_TEXTURE_GATHER 0x82A2 4244#define GL_VIEW_CLASS_ASTC_6x5_RGBA 0x938B
3339#define GL_TEXTURE_GATHER_SHADOW 0x82A3 4245#define GL_VIEW_CLASS_ASTC_6x6_RGBA 0x938C
3340#define GL_SHADER_IMAGE_LOAD 0x82A4 4246#define GL_VIEW_CLASS_ASTC_8x5_RGBA 0x938D
3341#define GL_SHADER_IMAGE_STORE 0x82A5 4247#define GL_VIEW_CLASS_ASTC_8x6_RGBA 0x938E
3342#define GL_SHADER_IMAGE_ATOMIC 0x82A6 4248#define GL_VIEW_CLASS_ASTC_8x8_RGBA 0x938F
3343#define GL_IMAGE_TEXEL_SIZE 0x82A7 4249#define GL_VIEW_CLASS_ASTC_10x5_RGBA 0x9390
3344#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 4250#define GL_VIEW_CLASS_ASTC_10x6_RGBA 0x9391
3345#define GL_IMAGE_PIXEL_FORMAT 0x82A9 4251#define GL_VIEW_CLASS_ASTC_10x8_RGBA 0x9392
3346#define GL_IMAGE_PIXEL_TYPE 0x82AA 4252#define GL_VIEW_CLASS_ASTC_10x10_RGBA 0x9393
3347#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC 4253#define GL_VIEW_CLASS_ASTC_12x10_RGBA 0x9394
3348#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD 4254#define GL_VIEW_CLASS_ASTC_12x12_RGBA 0x9395
3349#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE
3350#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF
3351#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1
3352#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2
3353#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3
3354#define GL_CLEAR_BUFFER 0x82B4
3355#define GL_TEXTURE_VIEW 0x82B5
3356#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6
3357#define GL_FULL_SUPPORT 0x82B7
3358#define GL_CAVEAT_SUPPORT 0x82B8
3359#define GL_IMAGE_CLASS_4_X_32 0x82B9
3360#define GL_IMAGE_CLASS_2_X_32 0x82BA
3361#define GL_IMAGE_CLASS_1_X_32 0x82BB
3362#define GL_IMAGE_CLASS_4_X_16 0x82BC
3363#define GL_IMAGE_CLASS_2_X_16 0x82BD
3364#define GL_IMAGE_CLASS_1_X_16 0x82BE
3365#define GL_IMAGE_CLASS_4_X_8 0x82BF
3366#define GL_IMAGE_CLASS_2_X_8 0x82C0
3367#define GL_IMAGE_CLASS_1_X_8 0x82C1
3368#define GL_IMAGE_CLASS_11_11_10 0x82C2
3369#define GL_IMAGE_CLASS_10_10_10_2 0x82C3
3370#define GL_VIEW_CLASS_128_BITS 0x82C4
3371#define GL_VIEW_CLASS_96_BITS 0x82C5
3372#define GL_VIEW_CLASS_64_BITS 0x82C6
3373#define GL_VIEW_CLASS_48_BITS 0x82C7
3374#define GL_VIEW_CLASS_32_BITS 0x82C8
3375#define GL_VIEW_CLASS_24_BITS 0x82C9
3376#define GL_VIEW_CLASS_16_BITS 0x82CA
3377#define GL_VIEW_CLASS_8_BITS 0x82CB
3378#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC
3379#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD
3380#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE
3381#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF
3382#define GL_VIEW_CLASS_RGTC1_RED 0x82D0
3383#define GL_VIEW_CLASS_RGTC2_RG 0x82D1
3384#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2
3385#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3
3386#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC
3387#define GL_MATRIX_PALETTE_ARB 0x8840 4255#define GL_MATRIX_PALETTE_ARB 0x8840
3388#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 4256#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841
3389#define GL_MAX_PALETTE_MATRICES_ARB 0x8842 4257#define GL_MAX_PALETTE_MATRICES_ARB 0x8842
@@ -3466,56 +4334,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3466#define GL_POINT_SPRITE_ARB 0x8861 4334#define GL_POINT_SPRITE_ARB 0x8861
3467#define GL_COORD_REPLACE_ARB 0x8862 4335#define GL_COORD_REPLACE_ARB 0x8862
3468#define GL_POLYGON_OFFSET_CLAMP 0x8E1B 4336#define GL_POLYGON_OFFSET_CLAMP 0x8E1B
3469#define GL_UNIFORM 0x92E1
3470#define GL_UNIFORM_BLOCK 0x92E2
3471#define GL_PROGRAM_INPUT 0x92E3
3472#define GL_PROGRAM_OUTPUT 0x92E4
3473#define GL_BUFFER_VARIABLE 0x92E5
3474#define GL_SHADER_STORAGE_BLOCK 0x92E6
3475#define GL_ATOMIC_COUNTER_BUFFER 0x92C0
3476#define GL_VERTEX_SUBROUTINE 0x92E8
3477#define GL_TESS_CONTROL_SUBROUTINE 0x92E9
3478#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA
3479#define GL_GEOMETRY_SUBROUTINE 0x92EB
3480#define GL_FRAGMENT_SUBROUTINE 0x92EC
3481#define GL_COMPUTE_SUBROUTINE 0x92ED
3482#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE
3483#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF
3484#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0
3485#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1
3486#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2
3487#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3
3488#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4
3489#define GL_ACTIVE_RESOURCES 0x92F5
3490#define GL_MAX_NAME_LENGTH 0x92F6
3491#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7
3492#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8
3493#define GL_NAME_LENGTH 0x92F9
3494#define GL_TYPE 0x92FA
3495#define GL_ARRAY_SIZE 0x92FB
3496#define GL_OFFSET 0x92FC
3497#define GL_BLOCK_INDEX 0x92FD
3498#define GL_ARRAY_STRIDE 0x92FE
3499#define GL_MATRIX_STRIDE 0x92FF
3500#define GL_IS_ROW_MAJOR 0x9300
3501#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301
3502#define GL_BUFFER_BINDING 0x9302
3503#define GL_BUFFER_DATA_SIZE 0x9303
3504#define GL_NUM_ACTIVE_VARIABLES 0x9304
3505#define GL_ACTIVE_VARIABLES 0x9305
3506#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306
3507#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307
3508#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308
3509#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309
3510#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A
3511#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B
3512#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C
3513#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D
3514#define GL_LOCATION 0x930E
3515#define GL_LOCATION_INDEX 0x930F
3516#define GL_IS_PER_PATCH 0x92E7
3517#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A
3518#define GL_COMPATIBLE_SUBROUTINES 0x8E4B
3519#define GL_QUERY_BUFFER 0x9192 4337#define GL_QUERY_BUFFER 0x9192
3520#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 4338#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000
3521#define GL_QUERY_BUFFER_BINDING 0x9193 4339#define GL_QUERY_BUFFER_BINDING 0x9193
@@ -3537,106 +4355,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3537#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343 4355#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343
3538#define GL_SAMPLE_SHADING_ARB 0x8C36 4356#define GL_SAMPLE_SHADING_ARB 0x8C36
3539#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 4357#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37
3540#define GL_VERTEX_SHADER_BIT 0x00000001
3541#define GL_FRAGMENT_SHADER_BIT 0x00000002
3542#define GL_GEOMETRY_SHADER_BIT 0x00000004
3543#define GL_TESS_CONTROL_SHADER_BIT 0x00000008
3544#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010
3545#define GL_ALL_SHADER_BITS 0xFFFFFFFF
3546#define GL_PROGRAM_SEPARABLE 0x8258
3547#define GL_ACTIVE_PROGRAM 0x8259
3548#define GL_PROGRAM_PIPELINE_BINDING 0x825A
3549#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1
3550#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2
3551#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3
3552#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
3553#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
3554#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
3555#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
3556#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
3557#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
3558#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
3559#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
3560#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
3561#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
3562#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
3563#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
3564#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
3565#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
3566#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2
3567#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
3568#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
3569#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5
3570#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6
3571#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7
3572#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
3573#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
3574#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9
3575#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
3576#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
3577#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
3578#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
3579#define GL_UNIFORM_BARRIER_BIT 0x00000004
3580#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
3581#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
3582#define GL_COMMAND_BARRIER_BIT 0x00000040
3583#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
3584#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
3585#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
3586#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
3587#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
3588#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
3589#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
3590#define GL_MAX_IMAGE_UNITS 0x8F38
3591#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
3592#define GL_IMAGE_BINDING_NAME 0x8F3A
3593#define GL_IMAGE_BINDING_LEVEL 0x8F3B
3594#define GL_IMAGE_BINDING_LAYERED 0x8F3C
3595#define GL_IMAGE_BINDING_LAYER 0x8F3D
3596#define GL_IMAGE_BINDING_ACCESS 0x8F3E
3597#define GL_IMAGE_1D 0x904C
3598#define GL_IMAGE_2D 0x904D
3599#define GL_IMAGE_3D 0x904E
3600#define GL_IMAGE_2D_RECT 0x904F
3601#define GL_IMAGE_CUBE 0x9050
3602#define GL_IMAGE_BUFFER 0x9051
3603#define GL_IMAGE_1D_ARRAY 0x9052
3604#define GL_IMAGE_2D_ARRAY 0x9053
3605#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
3606#define GL_IMAGE_2D_MULTISAMPLE 0x9055
3607#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
3608#define GL_INT_IMAGE_1D 0x9057
3609#define GL_INT_IMAGE_2D 0x9058
3610#define GL_INT_IMAGE_3D 0x9059
3611#define GL_INT_IMAGE_2D_RECT 0x905A
3612#define GL_INT_IMAGE_CUBE 0x905B
3613#define GL_INT_IMAGE_BUFFER 0x905C
3614#define GL_INT_IMAGE_1D_ARRAY 0x905D
3615#define GL_INT_IMAGE_2D_ARRAY 0x905E
3616#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
3617#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
3618#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
3619#define GL_UNSIGNED_INT_IMAGE_1D 0x9062
3620#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
3621#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
3622#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
3623#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
3624#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
3625#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
3626#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
3627#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
3628#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
3629#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
3630#define GL_MAX_IMAGE_SAMPLES 0x906D
3631#define GL_IMAGE_BINDING_FORMAT 0x906E
3632#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
3633#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
3634#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA
3635#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
3636#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
3637#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD
3638#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE
3639#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF
3640#define GL_PROGRAM_OBJECT_ARB 0x8B40 4358#define GL_PROGRAM_OBJECT_ARB 0x8B40
3641#define GL_SHADER_OBJECT_ARB 0x8B48 4359#define GL_SHADER_OBJECT_ARB 0x8B48
3642#define GL_OBJECT_TYPE_ARB 0x8B4E 4360#define GL_OBJECT_TYPE_ARB 0x8B4E
@@ -3671,29 +4389,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3671#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 4389#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86
3672#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 4390#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
3673#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 4391#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
3674#define GL_SHADER_STORAGE_BUFFER 0x90D2
3675#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3
3676#define GL_SHADER_STORAGE_BUFFER_START 0x90D4
3677#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5
3678#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6
3679#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7
3680#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8
3681#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9
3682#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA
3683#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB
3684#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC
3685#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
3686#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE
3687#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF
3688#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
3689#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39
3690#define GL_ACTIVE_SUBROUTINES 0x8DE5
3691#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6
3692#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47
3693#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48
3694#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49
3695#define GL_MAX_SUBROUTINES 0x8DE7
3696#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8
3697#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C 4392#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C
3698#define GL_SHADER_INCLUDE_ARB 0x8DAE 4393#define GL_SHADER_INCLUDE_ARB 0x8DAE
3699#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 4394#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9
@@ -3717,49 +4412,12 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3717#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 4412#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9
3718#define GL_SPIR_V_EXTENSIONS 0x9553 4413#define GL_SPIR_V_EXTENSIONS 0x9553
3719#define GL_NUM_SPIR_V_EXTENSIONS 0x9554 4414#define GL_NUM_SPIR_V_EXTENSIONS 0x9554
3720#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA
3721#define GL_PATCHES 0x000E
3722#define GL_PATCH_VERTICES 0x8E72
3723#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
3724#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74
3725#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75
3726#define GL_TESS_GEN_MODE 0x8E76
3727#define GL_TESS_GEN_SPACING 0x8E77
3728#define GL_TESS_GEN_VERTEX_ORDER 0x8E78
3729#define GL_TESS_GEN_POINT_MODE 0x8E79
3730#define GL_ISOLINES 0x8E7A
3731#define GL_QUADS 0x0007
3732#define GL_FRACTIONAL_ODD 0x8E7B
3733#define GL_FRACTIONAL_EVEN 0x8E7C
3734#define GL_MAX_PATCH_VERTICES 0x8E7D
3735#define GL_MAX_TESS_GEN_LEVEL 0x8E7E
3736#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
3737#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
3738#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
3739#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
3740#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
3741#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84
3742#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
3743#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
3744#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
3745#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
3746#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
3747#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
3748#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
3749#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
3750#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0
3751#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1
3752#define GL_TESS_EVALUATION_SHADER 0x8E87
3753#define GL_TESS_CONTROL_SHADER 0x8E88
3754#define GL_CLAMP_TO_BORDER_ARB 0x812D 4415#define GL_CLAMP_TO_BORDER_ARB 0x812D
3755#define GL_TEXTURE_BUFFER_ARB 0x8C2A 4416#define GL_TEXTURE_BUFFER_ARB 0x8C2A
3756#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B 4417#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B
3757#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C 4418#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C
3758#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D 4419#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D
3759#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E 4420#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E
3760#define GL_TEXTURE_BUFFER_OFFSET 0x919D
3761#define GL_TEXTURE_BUFFER_SIZE 0x919E
3762#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F
3763#define GL_COMPRESSED_ALPHA_ARB 0x84E9 4421#define GL_COMPRESSED_ALPHA_ARB 0x84E9
3764#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA 4422#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA
3765#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB 4423#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
@@ -3851,30 +4509,12 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3851#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 4509#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6
3852#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 4510#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7
3853#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 4511#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
3854#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
3855#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB
3856#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC
3857#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD
3858#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE
3859#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
3860#define GL_TRANSFORM_FEEDBACK 0x8E22
3861#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23
3862#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24
3863#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
3864#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70
3865#define GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB 0x82EC 4512#define GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB 0x82EC
3866#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB 0x82ED 4513#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB 0x82ED
3867#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 4514#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3
3868#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 4515#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4
3869#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 4516#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5
3870#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 4517#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6
3871#define GL_VERTEX_ATTRIB_BINDING 0x82D4
3872#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5
3873#define GL_VERTEX_BINDING_DIVISOR 0x82D6
3874#define GL_VERTEX_BINDING_OFFSET 0x82D7
3875#define GL_VERTEX_BINDING_STRIDE 0x82D8
3876#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
3877#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA
3878#define GL_MAX_VERTEX_UNITS_ARB 0x86A4 4518#define GL_MAX_VERTEX_UNITS_ARB 0x86A4
3879#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 4519#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5
3880#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 4520#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6
@@ -3971,12 +4611,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
3971#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D 4611#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
3972#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 4612#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89
3973#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A 4613#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
3974#define GL_MAX_VIEWPORTS 0x825B
3975#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C
3976#define GL_VIEWPORT_BOUNDS_RANGE 0x825D
3977#define GL_LAYER_PROVOKING_VERTEX 0x825E
3978#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F
3979#define GL_UNDEFINED_VERTEX 0x8260
3980#define GL_MAX_DRAW_BUFFERS_ATI 0x8824 4614#define GL_MAX_DRAW_BUFFERS_ATI 0x8824
3981#define GL_DRAW_BUFFER0_ATI 0x8825 4615#define GL_DRAW_BUFFER0_ATI 0x8825
3982#define GL_DRAW_BUFFER1_ATI 0x8826 4616#define GL_DRAW_BUFFER1_ATI 0x8826
@@ -4243,7 +4877,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
4243#define GL_BUFFER_OBJECT_EXT 0x9151 4877#define GL_BUFFER_OBJECT_EXT 0x9151
4244#define GL_QUERY_OBJECT_EXT 0x9153 4878#define GL_QUERY_OBJECT_EXT 0x9153
4245#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 4879#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154
4246#define GL_SAMPLER 0x82E6
4247#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 4880#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890
4248#define GL_DEPTH_BOUNDS_EXT 0x8891 4881#define GL_DEPTH_BOUNDS_EXT 0x8891
4249#define GL_PROGRAM_MATRIX_EXT 0x8E2D 4882#define GL_PROGRAM_MATRIX_EXT 0x8E2D
@@ -5099,45 +5732,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
5099#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC 5732#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC
5100#define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB 5733#define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB
5101#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x82FC 5734#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x82FC
5102#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
5103#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
5104#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
5105#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
5106#define GL_DEBUG_SOURCE_API 0x8246
5107#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
5108#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
5109#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
5110#define GL_DEBUG_SOURCE_APPLICATION 0x824A
5111#define GL_DEBUG_SOURCE_OTHER 0x824B
5112#define GL_DEBUG_TYPE_ERROR 0x824C
5113#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
5114#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
5115#define GL_DEBUG_TYPE_PORTABILITY 0x824F
5116#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
5117#define GL_DEBUG_TYPE_OTHER 0x8251
5118#define GL_DEBUG_TYPE_MARKER 0x8268
5119#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
5120#define GL_DEBUG_TYPE_POP_GROUP 0x826A
5121#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
5122#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
5123#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
5124#define GL_BUFFER 0x82E0
5125#define GL_SHADER 0x82E1
5126#define GL_PROGRAM 0x82E2
5127#define GL_VERTEX_ARRAY 0x8074
5128#define GL_QUERY 0x82E3
5129#define GL_PROGRAM_PIPELINE 0x82E4
5130#define GL_MAX_LABEL_LENGTH 0x82E8
5131#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
5132#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
5133#define GL_DEBUG_LOGGED_MESSAGES 0x9145
5134#define GL_DEBUG_SEVERITY_HIGH 0x9146
5135#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
5136#define GL_DEBUG_SEVERITY_LOW 0x9148
5137#define GL_DEBUG_OUTPUT 0x92E0
5138#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
5139#define GL_STACK_OVERFLOW 0x0503
5140#define GL_STACK_UNDERFLOW 0x0504
5141#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 5735#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242
5142#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 5736#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243
5143#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 5737#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244
@@ -5178,7 +5772,6 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
5178#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 5772#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002
5179#define GL_STACK_OVERFLOW_KHR 0x0503 5773#define GL_STACK_OVERFLOW_KHR 0x0503
5180#define GL_STACK_UNDERFLOW_KHR 0x0504 5774#define GL_STACK_UNDERFLOW_KHR 0x0504
5181#define GL_DISPLAY_LIST 0x82E7
5182#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 5775#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008
5183#define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0 5776#define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0
5184#define GL_COMPLETION_STATUS_KHR 0x91B1 5777#define GL_COMPLETION_STATUS_KHR 0x91B1
@@ -5462,6 +6055,64 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
5462#define GL_CONFORMANT_NV 0x9374 6055#define GL_CONFORMANT_NV 0x9374
5463#define GL_MAX_SHININESS_NV 0x8504 6056#define GL_MAX_SHININESS_NV 0x8504
5464#define GL_MAX_SPOT_EXPONENT_NV 0x8505 6057#define GL_MAX_SPOT_EXPONENT_NV 0x8505
6058#define GL_ATTACHED_MEMORY_OBJECT_NV 0x95A4
6059#define GL_ATTACHED_MEMORY_OFFSET_NV 0x95A5
6060#define GL_MEMORY_ATTACHABLE_ALIGNMENT_NV 0x95A6
6061#define GL_MEMORY_ATTACHABLE_SIZE_NV 0x95A7
6062#define GL_MEMORY_ATTACHABLE_NV 0x95A8
6063#define GL_DETACHED_MEMORY_INCARNATION_NV 0x95A9
6064#define GL_DETACHED_TEXTURES_NV 0x95AA
6065#define GL_DETACHED_BUFFERS_NV 0x95AB
6066#define GL_MAX_DETACHED_TEXTURES_NV 0x95AC
6067#define GL_MAX_DETACHED_BUFFERS_NV 0x95AD
6068#define GL_MESH_SHADER_NV 0x9559
6069#define GL_TASK_SHADER_NV 0x955A
6070#define GL_MAX_MESH_UNIFORM_BLOCKS_NV 0x8E60
6071#define GL_MAX_MESH_TEXTURE_IMAGE_UNITS_NV 0x8E61
6072#define GL_MAX_MESH_IMAGE_UNIFORMS_NV 0x8E62
6073#define GL_MAX_MESH_UNIFORM_COMPONENTS_NV 0x8E63
6074#define GL_MAX_MESH_ATOMIC_COUNTER_BUFFERS_NV 0x8E64
6075#define GL_MAX_MESH_ATOMIC_COUNTERS_NV 0x8E65
6076#define GL_MAX_MESH_SHADER_STORAGE_BLOCKS_NV 0x8E66
6077#define GL_MAX_COMBINED_MESH_UNIFORM_COMPONENTS_NV 0x8E67
6078#define GL_MAX_TASK_UNIFORM_BLOCKS_NV 0x8E68
6079#define GL_MAX_TASK_TEXTURE_IMAGE_UNITS_NV 0x8E69
6080#define GL_MAX_TASK_IMAGE_UNIFORMS_NV 0x8E6A
6081#define GL_MAX_TASK_UNIFORM_COMPONENTS_NV 0x8E6B
6082#define GL_MAX_TASK_ATOMIC_COUNTER_BUFFERS_NV 0x8E6C
6083#define GL_MAX_TASK_ATOMIC_COUNTERS_NV 0x8E6D
6084#define GL_MAX_TASK_SHADER_STORAGE_BLOCKS_NV 0x8E6E
6085#define GL_MAX_COMBINED_TASK_UNIFORM_COMPONENTS_NV 0x8E6F
6086#define GL_MAX_MESH_WORK_GROUP_INVOCATIONS_NV 0x95A2
6087#define GL_MAX_TASK_WORK_GROUP_INVOCATIONS_NV 0x95A3
6088#define GL_MAX_MESH_TOTAL_MEMORY_SIZE_NV 0x9536
6089#define GL_MAX_TASK_TOTAL_MEMORY_SIZE_NV 0x9537
6090#define GL_MAX_MESH_OUTPUT_VERTICES_NV 0x9538
6091#define GL_MAX_MESH_OUTPUT_PRIMITIVES_NV 0x9539
6092#define GL_MAX_TASK_OUTPUT_COUNT_NV 0x953A
6093#define GL_MAX_DRAW_MESH_TASKS_COUNT_NV 0x953D
6094#define GL_MAX_MESH_VIEWS_NV 0x9557
6095#define GL_MESH_OUTPUT_PER_VERTEX_GRANULARITY_NV 0x92DF
6096#define GL_MESH_OUTPUT_PER_PRIMITIVE_GRANULARITY_NV 0x9543
6097#define GL_MAX_MESH_WORK_GROUP_SIZE_NV 0x953B
6098#define GL_MAX_TASK_WORK_GROUP_SIZE_NV 0x953C
6099#define GL_MESH_WORK_GROUP_SIZE_NV 0x953E
6100#define GL_TASK_WORK_GROUP_SIZE_NV 0x953F
6101#define GL_MESH_VERTICES_OUT_NV 0x9579
6102#define GL_MESH_PRIMITIVES_OUT_NV 0x957A
6103#define GL_MESH_OUTPUT_TYPE_NV 0x957B
6104#define GL_UNIFORM_BLOCK_REFERENCED_BY_MESH_SHADER_NV 0x959C
6105#define GL_UNIFORM_BLOCK_REFERENCED_BY_TASK_SHADER_NV 0x959D
6106#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_MESH_SHADER_NV 0x959E
6107#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TASK_SHADER_NV 0x959F
6108#define GL_REFERENCED_BY_MESH_SHADER_NV 0x95A0
6109#define GL_REFERENCED_BY_TASK_SHADER_NV 0x95A1
6110#define GL_MESH_SUBROUTINE_NV 0x957C
6111#define GL_TASK_SUBROUTINE_NV 0x957D
6112#define GL_MESH_SUBROUTINE_UNIFORM_NV 0x957E
6113#define GL_TASK_SUBROUTINE_UNIFORM_NV 0x957F
6114#define GL_MESH_SHADER_BIT_NV 0x00000040
6115#define GL_TASK_SHADER_BIT_NV 0x00000080
5465#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 6116#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534
5466#define GL_PIXEL_COUNTER_BITS_NV 0x8864 6117#define GL_PIXEL_COUNTER_BITS_NV 0x8864
5467#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 6118#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865
@@ -5713,6 +6364,7 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
5713#define GL_COMBINER7_NV 0x8557 6364#define GL_COMBINER7_NV 0x8557
5714#define GL_FOG 0x0B60 6365#define GL_FOG 0x0B60
5715#define GL_PER_STAGE_CONSTANTS_NV 0x8535 6366#define GL_PER_STAGE_CONSTANTS_NV 0x8535
6367#define GL_REPRESENTATIVE_FRAGMENT_TEST_NV 0x937F
5716#define GL_PURGED_CONTEXT_RESET_NV 0x92BB 6368#define GL_PURGED_CONTEXT_RESET_NV 0x92BB
5717#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D 6369#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D
5718#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E 6370#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E
@@ -5722,6 +6374,8 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
5722#define GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341 6374#define GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341
5723#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342 6375#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342
5724#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343 6376#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343
6377#define GL_SCISSOR_TEST_EXCLUSIVE_NV 0x9555
6378#define GL_SCISSOR_BOX_EXCLUSIVE_NV 0x9556
5725#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D 6379#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D
5726#define GL_GPU_ADDRESS_NV 0x8F34 6380#define GL_GPU_ADDRESS_NV 0x8F34
5727#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 6381#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35
@@ -5729,6 +6383,27 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
5729#define GL_WARP_SIZE_NV 0x9339 6383#define GL_WARP_SIZE_NV 0x9339
5730#define GL_WARPS_PER_SM_NV 0x933A 6384#define GL_WARPS_PER_SM_NV 0x933A
5731#define GL_SM_COUNT_NV 0x933B 6385#define GL_SM_COUNT_NV 0x933B
6386#define GL_SHADING_RATE_IMAGE_NV 0x9563
6387#define GL_SHADING_RATE_NO_INVOCATIONS_NV 0x9564
6388#define GL_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV 0x9565
6389#define GL_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV 0x9566
6390#define GL_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV 0x9567
6391#define GL_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV 0x9568
6392#define GL_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV 0x9569
6393#define GL_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV 0x956A
6394#define GL_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV 0x956B
6395#define GL_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV 0x956C
6396#define GL_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV 0x956D
6397#define GL_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV 0x956E
6398#define GL_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV 0x956F
6399#define GL_SHADING_RATE_IMAGE_BINDING_NV 0x955B
6400#define GL_SHADING_RATE_IMAGE_TEXEL_WIDTH_NV 0x955C
6401#define GL_SHADING_RATE_IMAGE_TEXEL_HEIGHT_NV 0x955D
6402#define GL_SHADING_RATE_IMAGE_PALETTE_SIZE_NV 0x955E
6403#define GL_MAX_COARSE_FRAGMENT_SAMPLES_NV 0x955F
6404#define GL_SHADING_RATE_SAMPLE_ORDER_DEFAULT_NV 0x95AE
6405#define GL_SHADING_RATE_SAMPLE_ORDER_PIXEL_MAJOR_NV 0x95AF
6406#define GL_SHADING_RATE_SAMPLE_ORDER_SAMPLE_MAJOR_NV 0x95B0
5732#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 6407#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8
5733#define GL_TESS_CONTROL_PROGRAM_NV 0x891E 6408#define GL_TESS_CONTROL_PROGRAM_NV 0x891E
5734#define GL_TESS_EVALUATION_PROGRAM_NV 0x891F 6409#define GL_TESS_EVALUATION_PROGRAM_NV 0x891F
@@ -6925,21 +7600,6 @@ GLAPI int GLAD_GL_APPLE_ycbcr_422;
6925#ifndef GL_ARB_ES2_compatibility 7600#ifndef GL_ARB_ES2_compatibility
6926#define GL_ARB_ES2_compatibility 1 7601#define GL_ARB_ES2_compatibility 1
6927GLAPI int GLAD_GL_ARB_ES2_compatibility; 7602GLAPI int GLAD_GL_ARB_ES2_compatibility;
6928typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(void);
6929GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;
6930#define glReleaseShaderCompiler glad_glReleaseShaderCompiler
6931typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
6932GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary;
6933#define glShaderBinary glad_glShaderBinary
6934typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
6935GLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;
6936#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat
6937typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f);
6938GLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef;
6939#define glDepthRangef glad_glDepthRangef
6940typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d);
6941GLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf;
6942#define glClearDepthf glad_glClearDepthf
6943#endif 7603#endif
6944#ifndef GL_ARB_ES3_1_compatibility 7604#ifndef GL_ARB_ES3_1_compatibility
6945#define GL_ARB_ES3_1_compatibility 1 7605#define GL_ARB_ES3_1_compatibility 1
@@ -6966,15 +7626,6 @@ GLAPI int GLAD_GL_ARB_arrays_of_arrays;
6966#ifndef GL_ARB_base_instance 7626#ifndef GL_ARB_base_instance
6967#define GL_ARB_base_instance 1 7627#define GL_ARB_base_instance 1
6968GLAPI int GLAD_GL_ARB_base_instance; 7628GLAPI int GLAD_GL_ARB_base_instance;
6969typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
6970GLAPI PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance;
6971#define glDrawArraysInstancedBaseInstance glad_glDrawArraysInstancedBaseInstance
6972typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
6973GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance;
6974#define glDrawElementsInstancedBaseInstance glad_glDrawElementsInstancedBaseInstance
6975typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
6976GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance;
6977#define glDrawElementsInstancedBaseVertexBaseInstance glad_glDrawElementsInstancedBaseVertexBaseInstance
6978#endif 7629#endif
6979#ifndef GL_ARB_bindless_texture 7630#ifndef GL_ARB_bindless_texture
6980#define GL_ARB_bindless_texture 1 7631#define GL_ARB_bindless_texture 1
@@ -7049,12 +7700,6 @@ GLAPI PFNGLCREATESYNCFROMCLEVENTARBPROC glad_glCreateSyncFromCLeventARB;
7049#ifndef GL_ARB_clear_buffer_object 7700#ifndef GL_ARB_clear_buffer_object
7050#define GL_ARB_clear_buffer_object 1 7701#define GL_ARB_clear_buffer_object 1
7051GLAPI int GLAD_GL_ARB_clear_buffer_object; 7702GLAPI int GLAD_GL_ARB_clear_buffer_object;
7052typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC)(GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
7053GLAPI PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData;
7054#define glClearBufferData glad_glClearBufferData
7055typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC)(GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
7056GLAPI PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData;
7057#define glClearBufferSubData glad_glClearBufferSubData
7058#endif 7703#endif
7059#ifndef GL_ARB_clear_texture 7704#ifndef GL_ARB_clear_texture
7060#define GL_ARB_clear_texture 1 7705#define GL_ARB_clear_texture 1
@@ -7091,12 +7736,6 @@ GLAPI int GLAD_GL_ARB_compressed_texture_pixel_storage;
7091#ifndef GL_ARB_compute_shader 7736#ifndef GL_ARB_compute_shader
7092#define GL_ARB_compute_shader 1 7737#define GL_ARB_compute_shader 1
7093GLAPI int GLAD_GL_ARB_compute_shader; 7738GLAPI int GLAD_GL_ARB_compute_shader;
7094typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
7095GLAPI PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute;
7096#define glDispatchCompute glad_glDispatchCompute
7097typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect);
7098GLAPI PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect;
7099#define glDispatchComputeIndirect glad_glDispatchComputeIndirect
7100#endif 7739#endif
7101#ifndef GL_ARB_compute_variable_group_size 7740#ifndef GL_ARB_compute_variable_group_size
7102#define GL_ARB_compute_variable_group_size 1 7741#define GL_ARB_compute_variable_group_size 1
@@ -7120,9 +7759,6 @@ GLAPI int GLAD_GL_ARB_copy_buffer;
7120#ifndef GL_ARB_copy_image 7759#ifndef GL_ARB_copy_image
7121#define GL_ARB_copy_image 1 7760#define GL_ARB_copy_image 1
7122GLAPI int GLAD_GL_ARB_copy_image; 7761GLAPI int GLAD_GL_ARB_copy_image;
7123typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
7124GLAPI PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData;
7125#define glCopyImageSubData glad_glCopyImageSubData
7126#endif 7762#endif
7127#ifndef GL_ARB_cull_distance 7763#ifndef GL_ARB_cull_distance
7128#define GL_ARB_cull_distance 1 7764#define GL_ARB_cull_distance 1
@@ -7485,12 +8121,6 @@ GLAPI int GLAD_GL_ARB_draw_elements_base_vertex;
7485#ifndef GL_ARB_draw_indirect 8121#ifndef GL_ARB_draw_indirect
7486#define GL_ARB_draw_indirect 1 8122#define GL_ARB_draw_indirect 1
7487GLAPI int GLAD_GL_ARB_draw_indirect; 8123GLAPI int GLAD_GL_ARB_draw_indirect;
7488typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect);
7489GLAPI PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect;
7490#define glDrawArraysIndirect glad_glDrawArraysIndirect
7491typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect);
7492GLAPI PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect;
7493#define glDrawElementsIndirect glad_glDrawElementsIndirect
7494#endif 8124#endif
7495#ifndef GL_ARB_draw_instanced 8125#ifndef GL_ARB_draw_instanced
7496#define GL_ARB_draw_instanced 1 8126#define GL_ARB_draw_instanced 1
@@ -7598,12 +8228,6 @@ GLAPI int GLAD_GL_ARB_fragment_shader_interlock;
7598#ifndef GL_ARB_framebuffer_no_attachments 8228#ifndef GL_ARB_framebuffer_no_attachments
7599#define GL_ARB_framebuffer_no_attachments 1 8229#define GL_ARB_framebuffer_no_attachments 1
7600GLAPI int GLAD_GL_ARB_framebuffer_no_attachments; 8230GLAPI int GLAD_GL_ARB_framebuffer_no_attachments;
7601typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
7602GLAPI PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri;
7603#define glFramebufferParameteri glad_glFramebufferParameteri
7604typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);
7605GLAPI PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv;
7606#define glGetFramebufferParameteriv glad_glGetFramebufferParameteriv
7607#endif 8231#endif
7608#ifndef GL_ARB_framebuffer_object 8232#ifndef GL_ARB_framebuffer_object
7609#define GL_ARB_framebuffer_object 1 8233#define GL_ARB_framebuffer_object 1
@@ -7632,15 +8256,6 @@ GLAPI PFNGLFRAMEBUFFERTEXTUREFACEARBPROC glad_glFramebufferTextureFaceARB;
7632#ifndef GL_ARB_get_program_binary 8256#ifndef GL_ARB_get_program_binary
7633#define GL_ARB_get_program_binary 1 8257#define GL_ARB_get_program_binary 1
7634GLAPI int GLAD_GL_ARB_get_program_binary; 8258GLAPI int GLAD_GL_ARB_get_program_binary;
7635typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
7636GLAPI PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary;
7637#define glGetProgramBinary glad_glGetProgramBinary
7638typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
7639GLAPI PFNGLPROGRAMBINARYPROC glad_glProgramBinary;
7640#define glProgramBinary glad_glProgramBinary
7641typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value);
7642GLAPI PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri;
7643#define glProgramParameteri glad_glProgramParameteri
7644#endif 8259#endif
7645#ifndef GL_ARB_get_texture_sub_image 8260#ifndef GL_ARB_get_texture_sub_image
7646#define GL_ARB_get_texture_sub_image 1 8261#define GL_ARB_get_texture_sub_image 1
@@ -7666,60 +8281,6 @@ GLAPI int GLAD_GL_ARB_gpu_shader5;
7666#ifndef GL_ARB_gpu_shader_fp64 8281#ifndef GL_ARB_gpu_shader_fp64
7667#define GL_ARB_gpu_shader_fp64 1 8282#define GL_ARB_gpu_shader_fp64 1
7668GLAPI int GLAD_GL_ARB_gpu_shader_fp64; 8283GLAPI int GLAD_GL_ARB_gpu_shader_fp64;
7669typedef void (APIENTRYP PFNGLUNIFORM1DPROC)(GLint location, GLdouble x);
7670GLAPI PFNGLUNIFORM1DPROC glad_glUniform1d;
7671#define glUniform1d glad_glUniform1d
7672typedef void (APIENTRYP PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y);
7673GLAPI PFNGLUNIFORM2DPROC glad_glUniform2d;
7674#define glUniform2d glad_glUniform2d
7675typedef void (APIENTRYP PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z);
7676GLAPI PFNGLUNIFORM3DPROC glad_glUniform3d;
7677#define glUniform3d glad_glUniform3d
7678typedef void (APIENTRYP PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
7679GLAPI PFNGLUNIFORM4DPROC glad_glUniform4d;
7680#define glUniform4d glad_glUniform4d
7681typedef void (APIENTRYP PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble *value);
7682GLAPI PFNGLUNIFORM1DVPROC glad_glUniform1dv;
7683#define glUniform1dv glad_glUniform1dv
7684typedef void (APIENTRYP PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble *value);
7685GLAPI PFNGLUNIFORM2DVPROC glad_glUniform2dv;
7686#define glUniform2dv glad_glUniform2dv
7687typedef void (APIENTRYP PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble *value);
7688GLAPI PFNGLUNIFORM3DVPROC glad_glUniform3dv;
7689#define glUniform3dv glad_glUniform3dv
7690typedef void (APIENTRYP PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble *value);
7691GLAPI PFNGLUNIFORM4DVPROC glad_glUniform4dv;
7692#define glUniform4dv glad_glUniform4dv
7693typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
7694GLAPI PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv;
7695#define glUniformMatrix2dv glad_glUniformMatrix2dv
7696typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
7697GLAPI PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv;
7698#define glUniformMatrix3dv glad_glUniformMatrix3dv
7699typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
7700GLAPI PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv;
7701#define glUniformMatrix4dv glad_glUniformMatrix4dv
7702typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
7703GLAPI PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv;
7704#define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv
7705typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
7706GLAPI PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv;
7707#define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv
7708typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
7709GLAPI PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv;
7710#define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv
7711typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
7712GLAPI PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv;
7713#define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv
7714typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
7715GLAPI PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv;
7716#define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv
7717typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
7718GLAPI PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv;
7719#define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv
7720typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble *params);
7721GLAPI PFNGLGETUNIFORMDVPROC glad_glGetUniformdv;
7722#define glGetUniformdv glad_glGetUniformdv
7723#endif 8284#endif
7724#ifndef GL_ARB_gpu_shader_int64 8285#ifndef GL_ARB_gpu_shader_int64
7725#define GL_ARB_gpu_shader_int64 1 8286#define GL_ARB_gpu_shader_int64 1
@@ -7961,38 +8522,14 @@ GLAPI PFNGLVERTEXATTRIBDIVISORARBPROC glad_glVertexAttribDivisorARB;
7961#ifndef GL_ARB_internalformat_query 8522#ifndef GL_ARB_internalformat_query
7962#define GL_ARB_internalformat_query 1 8523#define GL_ARB_internalformat_query 1
7963GLAPI int GLAD_GL_ARB_internalformat_query; 8524GLAPI int GLAD_GL_ARB_internalformat_query;
7964typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
7965GLAPI PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ;
7966#define glGetInternalformativ glad_glGetInternalformativ
7967#endif 8525#endif
7968#ifndef GL_ARB_internalformat_query2 8526#ifndef GL_ARB_internalformat_query2
7969#define GL_ARB_internalformat_query2 1 8527#define GL_ARB_internalformat_query2 1
7970GLAPI int GLAD_GL_ARB_internalformat_query2; 8528GLAPI int GLAD_GL_ARB_internalformat_query2;
7971typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);
7972GLAPI PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v;
7973#define glGetInternalformati64v glad_glGetInternalformati64v
7974#endif 8529#endif
7975#ifndef GL_ARB_invalidate_subdata 8530#ifndef GL_ARB_invalidate_subdata
7976#define GL_ARB_invalidate_subdata 1 8531#define GL_ARB_invalidate_subdata 1
7977GLAPI int GLAD_GL_ARB_invalidate_subdata; 8532GLAPI int GLAD_GL_ARB_invalidate_subdata;
7978typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
7979GLAPI PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage;
7980#define glInvalidateTexSubImage glad_glInvalidateTexSubImage
7981typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC)(GLuint texture, GLint level);
7982GLAPI PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage;
7983#define glInvalidateTexImage glad_glInvalidateTexImage
7984typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length);
7985GLAPI PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData;
7986#define glInvalidateBufferSubData glad_glInvalidateBufferSubData
7987typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer);
7988GLAPI PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData;
7989#define glInvalidateBufferData glad_glInvalidateBufferData
7990typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments);
7991GLAPI PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer;
7992#define glInvalidateFramebuffer glad_glInvalidateFramebuffer
7993typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
7994GLAPI PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer;
7995#define glInvalidateSubFramebuffer glad_glInvalidateSubFramebuffer
7996#endif 8533#endif
7997#ifndef GL_ARB_map_buffer_alignment 8534#ifndef GL_ARB_map_buffer_alignment
7998#define GL_ARB_map_buffer_alignment 1 8535#define GL_ARB_map_buffer_alignment 1
@@ -8046,12 +8583,6 @@ GLAPI PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers;
8046#ifndef GL_ARB_multi_draw_indirect 8583#ifndef GL_ARB_multi_draw_indirect
8047#define GL_ARB_multi_draw_indirect 1 8584#define GL_ARB_multi_draw_indirect 1
8048GLAPI int GLAD_GL_ARB_multi_draw_indirect; 8585GLAPI int GLAD_GL_ARB_multi_draw_indirect;
8049typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
8050GLAPI PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect;
8051#define glMultiDrawArraysIndirect glad_glMultiDrawArraysIndirect
8052typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
8053GLAPI PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect;
8054#define glMultiDrawElementsIndirect glad_glMultiDrawElementsIndirect
8055#endif 8586#endif
8056#ifndef GL_ARB_multisample 8587#ifndef GL_ARB_multisample
8057#define GL_ARB_multisample 1 8588#define GL_ARB_multisample 1
@@ -8241,24 +8772,6 @@ GLAPI int GLAD_GL_ARB_post_depth_coverage;
8241#ifndef GL_ARB_program_interface_query 8772#ifndef GL_ARB_program_interface_query
8242#define GL_ARB_program_interface_query 1 8773#define GL_ARB_program_interface_query 1
8243GLAPI int GLAD_GL_ARB_program_interface_query; 8774GLAPI int GLAD_GL_ARB_program_interface_query;
8244typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC)(GLuint program, GLenum programInterface, GLenum pname, GLint *params);
8245GLAPI PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv;
8246#define glGetProgramInterfaceiv glad_glGetProgramInterfaceiv
8247typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name);
8248GLAPI PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex;
8249#define glGetProgramResourceIndex glad_glGetProgramResourceIndex
8250typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
8251GLAPI PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName;
8252#define glGetProgramResourceName glad_glGetProgramResourceName
8253typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
8254GLAPI PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv;
8255#define glGetProgramResourceiv glad_glGetProgramResourceiv
8256typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC)(GLuint program, GLenum programInterface, const GLchar *name);
8257GLAPI PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation;
8258#define glGetProgramResourceLocation glad_glGetProgramResourceLocation
8259typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name);
8260GLAPI PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex;
8261#define glGetProgramResourceLocationIndex glad_glGetProgramResourceLocationIndex
8262#endif 8775#endif
8263#ifndef GL_ARB_provoking_vertex 8776#ifndef GL_ARB_provoking_vertex
8264#define GL_ARB_provoking_vertex 1 8777#define GL_ARB_provoking_vertex 1
@@ -8375,186 +8888,6 @@ GLAPI int GLAD_GL_ARB_seamless_cubemap_per_texture;
8375#ifndef GL_ARB_separate_shader_objects 8888#ifndef GL_ARB_separate_shader_objects
8376#define GL_ARB_separate_shader_objects 1 8889#define GL_ARB_separate_shader_objects 1
8377GLAPI int GLAD_GL_ARB_separate_shader_objects; 8890GLAPI int GLAD_GL_ARB_separate_shader_objects;
8378typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program);
8379GLAPI PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages;
8380#define glUseProgramStages glad_glUseProgramStages
8381typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program);
8382GLAPI PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram;
8383#define glActiveShaderProgram glad_glActiveShaderProgram
8384typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const*strings);
8385GLAPI PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv;
8386#define glCreateShaderProgramv glad_glCreateShaderProgramv
8387typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline);
8388GLAPI PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline;
8389#define glBindProgramPipeline glad_glBindProgramPipeline
8390typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint *pipelines);
8391GLAPI PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines;
8392#define glDeleteProgramPipelines glad_glDeleteProgramPipelines
8393typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint *pipelines);
8394GLAPI PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines;
8395#define glGenProgramPipelines glad_glGenProgramPipelines
8396typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline);
8397GLAPI PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline;
8398#define glIsProgramPipeline glad_glIsProgramPipeline
8399typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint *params);
8400GLAPI PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv;
8401#define glGetProgramPipelineiv glad_glGetProgramPipelineiv
8402typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0);
8403GLAPI PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i;
8404#define glProgramUniform1i glad_glProgramUniform1i
8405typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
8406GLAPI PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv;
8407#define glProgramUniform1iv glad_glProgramUniform1iv
8408typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0);
8409GLAPI PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f;
8410#define glProgramUniform1f glad_glProgramUniform1f
8411typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
8412GLAPI PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv;
8413#define glProgramUniform1fv glad_glProgramUniform1fv
8414typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0);
8415GLAPI PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d;
8416#define glProgramUniform1d glad_glProgramUniform1d
8417typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
8418GLAPI PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv;
8419#define glProgramUniform1dv glad_glProgramUniform1dv
8420typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0);
8421GLAPI PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui;
8422#define glProgramUniform1ui glad_glProgramUniform1ui
8423typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
8424GLAPI PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv;
8425#define glProgramUniform1uiv glad_glProgramUniform1uiv
8426typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1);
8427GLAPI PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i;
8428#define glProgramUniform2i glad_glProgramUniform2i
8429typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
8430GLAPI PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv;
8431#define glProgramUniform2iv glad_glProgramUniform2iv
8432typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1);
8433GLAPI PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f;
8434#define glProgramUniform2f glad_glProgramUniform2f
8435typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
8436GLAPI PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv;
8437#define glProgramUniform2fv glad_glProgramUniform2fv
8438typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1);
8439GLAPI PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d;
8440#define glProgramUniform2d glad_glProgramUniform2d
8441typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
8442GLAPI PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv;
8443#define glProgramUniform2dv glad_glProgramUniform2dv
8444typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1);
8445GLAPI PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui;
8446#define glProgramUniform2ui glad_glProgramUniform2ui
8447typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
8448GLAPI PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv;
8449#define glProgramUniform2uiv glad_glProgramUniform2uiv
8450typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
8451GLAPI PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i;
8452#define glProgramUniform3i glad_glProgramUniform3i
8453typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
8454GLAPI PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv;
8455#define glProgramUniform3iv glad_glProgramUniform3iv
8456typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
8457GLAPI PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f;
8458#define glProgramUniform3f glad_glProgramUniform3f
8459typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
8460GLAPI PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv;
8461#define glProgramUniform3fv glad_glProgramUniform3fv
8462typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
8463GLAPI PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d;
8464#define glProgramUniform3d glad_glProgramUniform3d
8465typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
8466GLAPI PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv;
8467#define glProgramUniform3dv glad_glProgramUniform3dv
8468typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
8469GLAPI PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui;
8470#define glProgramUniform3ui glad_glProgramUniform3ui
8471typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
8472GLAPI PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv;
8473#define glProgramUniform3uiv glad_glProgramUniform3uiv
8474typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
8475GLAPI PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i;
8476#define glProgramUniform4i glad_glProgramUniform4i
8477typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
8478GLAPI PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv;
8479#define glProgramUniform4iv glad_glProgramUniform4iv
8480typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
8481GLAPI PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f;
8482#define glProgramUniform4f glad_glProgramUniform4f
8483typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
8484GLAPI PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv;
8485#define glProgramUniform4fv glad_glProgramUniform4fv
8486typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
8487GLAPI PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d;
8488#define glProgramUniform4d glad_glProgramUniform4d
8489typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
8490GLAPI PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv;
8491#define glProgramUniform4dv glad_glProgramUniform4dv
8492typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
8493GLAPI PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui;
8494#define glProgramUniform4ui glad_glProgramUniform4ui
8495typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
8496GLAPI PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv;
8497#define glProgramUniform4uiv glad_glProgramUniform4uiv
8498typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
8499GLAPI PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv;
8500#define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv
8501typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
8502GLAPI PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv;
8503#define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv
8504typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
8505GLAPI PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv;
8506#define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv
8507typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
8508GLAPI PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv;
8509#define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv
8510typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
8511GLAPI PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv;
8512#define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv
8513typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
8514GLAPI PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv;
8515#define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv
8516typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
8517GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv;
8518#define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv
8519typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
8520GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv;
8521#define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv
8522typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
8523GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv;
8524#define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv
8525typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
8526GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv;
8527#define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv
8528typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
8529GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv;
8530#define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv
8531typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
8532GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv;
8533#define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv
8534typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
8535GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv;
8536#define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv
8537typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
8538GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv;
8539#define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv
8540typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
8541GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv;
8542#define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv
8543typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
8544GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv;
8545#define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv
8546typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
8547GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv;
8548#define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv
8549typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
8550GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv;
8551#define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv
8552typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline);
8553GLAPI PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline;
8554#define glValidateProgramPipeline glad_glValidateProgramPipeline
8555typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
8556GLAPI PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog;
8557#define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog
8558#endif 8891#endif
8559#ifndef GL_ARB_shader_atomic_counter_ops 8892#ifndef GL_ARB_shader_atomic_counter_ops
8560#define GL_ARB_shader_atomic_counter_ops 1 8893#define GL_ARB_shader_atomic_counter_ops 1
@@ -8563,9 +8896,6 @@ GLAPI int GLAD_GL_ARB_shader_atomic_counter_ops;
8563#ifndef GL_ARB_shader_atomic_counters 8896#ifndef GL_ARB_shader_atomic_counters
8564#define GL_ARB_shader_atomic_counters 1 8897#define GL_ARB_shader_atomic_counters 1
8565GLAPI int GLAD_GL_ARB_shader_atomic_counters; 8898GLAPI int GLAD_GL_ARB_shader_atomic_counters;
8566typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)(GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
8567GLAPI PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv;
8568#define glGetActiveAtomicCounterBufferiv glad_glGetActiveAtomicCounterBufferiv
8569#endif 8899#endif
8570#ifndef GL_ARB_shader_ballot 8900#ifndef GL_ARB_shader_ballot
8571#define GL_ARB_shader_ballot 1 8901#define GL_ARB_shader_ballot 1
@@ -8590,12 +8920,6 @@ GLAPI int GLAD_GL_ARB_shader_group_vote;
8590#ifndef GL_ARB_shader_image_load_store 8920#ifndef GL_ARB_shader_image_load_store
8591#define GL_ARB_shader_image_load_store 1 8921#define GL_ARB_shader_image_load_store 1
8592GLAPI int GLAD_GL_ARB_shader_image_load_store; 8922GLAPI int GLAD_GL_ARB_shader_image_load_store;
8593typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
8594GLAPI PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture;
8595#define glBindImageTexture glad_glBindImageTexture
8596typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC)(GLbitfield barriers);
8597GLAPI PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier;
8598#define glMemoryBarrier glad_glMemoryBarrier
8599#endif 8923#endif
8600#ifndef GL_ARB_shader_image_size 8924#ifndef GL_ARB_shader_image_size
8601#define GL_ARB_shader_image_size 1 8925#define GL_ARB_shader_image_size 1
@@ -8733,37 +9057,10 @@ GLAPI int GLAD_GL_ARB_shader_stencil_export;
8733#ifndef GL_ARB_shader_storage_buffer_object 9057#ifndef GL_ARB_shader_storage_buffer_object
8734#define GL_ARB_shader_storage_buffer_object 1 9058#define GL_ARB_shader_storage_buffer_object 1
8735GLAPI int GLAD_GL_ARB_shader_storage_buffer_object; 9059GLAPI int GLAD_GL_ARB_shader_storage_buffer_object;
8736typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC)(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
8737GLAPI PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding;
8738#define glShaderStorageBlockBinding glad_glShaderStorageBlockBinding
8739#endif 9060#endif
8740#ifndef GL_ARB_shader_subroutine 9061#ifndef GL_ARB_shader_subroutine
8741#define GL_ARB_shader_subroutine 1 9062#define GL_ARB_shader_subroutine 1
8742GLAPI int GLAD_GL_ARB_shader_subroutine; 9063GLAPI int GLAD_GL_ARB_shader_subroutine;
8743typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar *name);
8744GLAPI PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation;
8745#define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation
8746typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar *name);
8747GLAPI PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex;
8748#define glGetSubroutineIndex glad_glGetSubroutineIndex
8749typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
8750GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv;
8751#define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv
8752typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
8753GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName;
8754#define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName
8755typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
8756GLAPI PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName;
8757#define glGetActiveSubroutineName glad_glGetActiveSubroutineName
8758typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint *indices);
8759GLAPI PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv;
8760#define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv
8761typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint *params);
8762GLAPI PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv;
8763#define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv
8764typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint *values);
8765GLAPI PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv;
8766#define glGetProgramStageiv glad_glGetProgramStageiv
8767#endif 9064#endif
8768#ifndef GL_ARB_shader_texture_image_samples 9065#ifndef GL_ARB_shader_texture_image_samples
8769#define GL_ARB_shader_texture_image_samples 1 9066#define GL_ARB_shader_texture_image_samples 1
@@ -8862,12 +9159,6 @@ GLAPI int GLAD_GL_ARB_sync;
8862#ifndef GL_ARB_tessellation_shader 9159#ifndef GL_ARB_tessellation_shader
8863#define GL_ARB_tessellation_shader 1 9160#define GL_ARB_tessellation_shader 1
8864GLAPI int GLAD_GL_ARB_tessellation_shader; 9161GLAPI int GLAD_GL_ARB_tessellation_shader;
8865typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value);
8866GLAPI PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri;
8867#define glPatchParameteri glad_glPatchParameteri
8868typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat *values);
8869GLAPI PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv;
8870#define glPatchParameterfv glad_glPatchParameterfv
8871#endif 9162#endif
8872#ifndef GL_ARB_texture_barrier 9163#ifndef GL_ARB_texture_barrier
8873#define GL_ARB_texture_barrier 1 9164#define GL_ARB_texture_barrier 1
@@ -8894,9 +9185,6 @@ GLAPI int GLAD_GL_ARB_texture_buffer_object_rgb32;
8894#ifndef GL_ARB_texture_buffer_range 9185#ifndef GL_ARB_texture_buffer_range
8895#define GL_ARB_texture_buffer_range 1 9186#define GL_ARB_texture_buffer_range 1
8896GLAPI int GLAD_GL_ARB_texture_buffer_range; 9187GLAPI int GLAD_GL_ARB_texture_buffer_range;
8897typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
8898GLAPI PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange;
8899#define glTexBufferRange glad_glTexBufferRange
8900#endif 9188#endif
8901#ifndef GL_ARB_texture_compression 9189#ifndef GL_ARB_texture_compression
8902#define GL_ARB_texture_compression 1 9190#define GL_ARB_texture_compression 1
@@ -9014,25 +9302,10 @@ GLAPI int GLAD_GL_ARB_texture_stencil8;
9014#ifndef GL_ARB_texture_storage 9302#ifndef GL_ARB_texture_storage
9015#define GL_ARB_texture_storage 1 9303#define GL_ARB_texture_storage 1
9016GLAPI int GLAD_GL_ARB_texture_storage; 9304GLAPI int GLAD_GL_ARB_texture_storage;
9017typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
9018GLAPI PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D;
9019#define glTexStorage1D glad_glTexStorage1D
9020typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
9021GLAPI PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D;
9022#define glTexStorage2D glad_glTexStorage2D
9023typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
9024GLAPI PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D;
9025#define glTexStorage3D glad_glTexStorage3D
9026#endif 9305#endif
9027#ifndef GL_ARB_texture_storage_multisample 9306#ifndef GL_ARB_texture_storage_multisample
9028#define GL_ARB_texture_storage_multisample 1 9307#define GL_ARB_texture_storage_multisample 1
9029GLAPI int GLAD_GL_ARB_texture_storage_multisample; 9308GLAPI int GLAD_GL_ARB_texture_storage_multisample;
9030typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
9031GLAPI PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample;
9032#define glTexStorage2DMultisample glad_glTexStorage2DMultisample
9033typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
9034GLAPI PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample;
9035#define glTexStorage3DMultisample glad_glTexStorage3DMultisample
9036#endif 9309#endif
9037#ifndef GL_ARB_texture_swizzle 9310#ifndef GL_ARB_texture_swizzle
9038#define GL_ARB_texture_swizzle 1 9311#define GL_ARB_texture_swizzle 1
@@ -9041,9 +9314,6 @@ GLAPI int GLAD_GL_ARB_texture_swizzle;
9041#ifndef GL_ARB_texture_view 9314#ifndef GL_ARB_texture_view
9042#define GL_ARB_texture_view 1 9315#define GL_ARB_texture_view 1
9043GLAPI int GLAD_GL_ARB_texture_view; 9316GLAPI int GLAD_GL_ARB_texture_view;
9044typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
9045GLAPI PFNGLTEXTUREVIEWPROC glad_glTextureView;
9046#define glTextureView glad_glTextureView
9047#endif 9317#endif
9048#ifndef GL_ARB_timer_query 9318#ifndef GL_ARB_timer_query
9049#define GL_ARB_timer_query 1 9319#define GL_ARB_timer_query 1
@@ -9052,53 +9322,14 @@ GLAPI int GLAD_GL_ARB_timer_query;
9052#ifndef GL_ARB_transform_feedback2 9322#ifndef GL_ARB_transform_feedback2
9053#define GL_ARB_transform_feedback2 1 9323#define GL_ARB_transform_feedback2 1
9054GLAPI int GLAD_GL_ARB_transform_feedback2; 9324GLAPI int GLAD_GL_ARB_transform_feedback2;
9055typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id);
9056GLAPI PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback;
9057#define glBindTransformFeedback glad_glBindTransformFeedback
9058typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint *ids);
9059GLAPI PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks;
9060#define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks
9061typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint *ids);
9062GLAPI PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks;
9063#define glGenTransformFeedbacks glad_glGenTransformFeedbacks
9064typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id);
9065GLAPI PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback;
9066#define glIsTransformFeedback glad_glIsTransformFeedback
9067typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC)(void);
9068GLAPI PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback;
9069#define glPauseTransformFeedback glad_glPauseTransformFeedback
9070typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC)(void);
9071GLAPI PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback;
9072#define glResumeTransformFeedback glad_glResumeTransformFeedback
9073typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id);
9074GLAPI PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback;
9075#define glDrawTransformFeedback glad_glDrawTransformFeedback
9076#endif 9325#endif
9077#ifndef GL_ARB_transform_feedback3 9326#ifndef GL_ARB_transform_feedback3
9078#define GL_ARB_transform_feedback3 1 9327#define GL_ARB_transform_feedback3 1
9079GLAPI int GLAD_GL_ARB_transform_feedback3; 9328GLAPI int GLAD_GL_ARB_transform_feedback3;
9080typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream);
9081GLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream;
9082#define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream
9083typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id);
9084GLAPI PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed;
9085#define glBeginQueryIndexed glad_glBeginQueryIndexed
9086typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index);
9087GLAPI PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed;
9088#define glEndQueryIndexed glad_glEndQueryIndexed
9089typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint *params);
9090GLAPI PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv;
9091#define glGetQueryIndexediv glad_glGetQueryIndexediv
9092#endif 9329#endif
9093#ifndef GL_ARB_transform_feedback_instanced 9330#ifndef GL_ARB_transform_feedback_instanced
9094#define GL_ARB_transform_feedback_instanced 1 9331#define GL_ARB_transform_feedback_instanced 1
9095GLAPI int GLAD_GL_ARB_transform_feedback_instanced; 9332GLAPI int GLAD_GL_ARB_transform_feedback_instanced;
9096typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)(GLenum mode, GLuint id, GLsizei instancecount);
9097GLAPI PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced;
9098#define glDrawTransformFeedbackInstanced glad_glDrawTransformFeedbackInstanced
9099typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)(GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
9100GLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced;
9101#define glDrawTransformFeedbackStreamInstanced glad_glDrawTransformFeedbackStreamInstanced
9102#endif 9333#endif
9103#ifndef GL_ARB_transform_feedback_overflow_query 9334#ifndef GL_ARB_transform_feedback_overflow_query
9104#define GL_ARB_transform_feedback_overflow_query 1 9335#define GL_ARB_transform_feedback_overflow_query 1
@@ -9135,58 +9366,10 @@ GLAPI int GLAD_GL_ARB_vertex_array_object;
9135#ifndef GL_ARB_vertex_attrib_64bit 9366#ifndef GL_ARB_vertex_attrib_64bit
9136#define GL_ARB_vertex_attrib_64bit 1 9367#define GL_ARB_vertex_attrib_64bit 1
9137GLAPI int GLAD_GL_ARB_vertex_attrib_64bit; 9368GLAPI int GLAD_GL_ARB_vertex_attrib_64bit;
9138typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x);
9139GLAPI PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d;
9140#define glVertexAttribL1d glad_glVertexAttribL1d
9141typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y);
9142GLAPI PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d;
9143#define glVertexAttribL2d glad_glVertexAttribL2d
9144typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);
9145GLAPI PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d;
9146#define glVertexAttribL3d glad_glVertexAttribL3d
9147typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
9148GLAPI PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d;
9149#define glVertexAttribL4d glad_glVertexAttribL4d
9150typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble *v);
9151GLAPI PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv;
9152#define glVertexAttribL1dv glad_glVertexAttribL1dv
9153typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble *v);
9154GLAPI PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv;
9155#define glVertexAttribL2dv glad_glVertexAttribL2dv
9156typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble *v);
9157GLAPI PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv;
9158#define glVertexAttribL3dv glad_glVertexAttribL3dv
9159typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble *v);
9160GLAPI PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv;
9161#define glVertexAttribL4dv glad_glVertexAttribL4dv
9162typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
9163GLAPI PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer;
9164#define glVertexAttribLPointer glad_glVertexAttribLPointer
9165typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble *params);
9166GLAPI PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv;
9167#define glGetVertexAttribLdv glad_glGetVertexAttribLdv
9168#endif 9369#endif
9169#ifndef GL_ARB_vertex_attrib_binding 9370#ifndef GL_ARB_vertex_attrib_binding
9170#define GL_ARB_vertex_attrib_binding 1 9371#define GL_ARB_vertex_attrib_binding 1
9171GLAPI int GLAD_GL_ARB_vertex_attrib_binding; 9372GLAPI int GLAD_GL_ARB_vertex_attrib_binding;
9172typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
9173GLAPI PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer;
9174#define glBindVertexBuffer glad_glBindVertexBuffer
9175typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
9176GLAPI PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat;
9177#define glVertexAttribFormat glad_glVertexAttribFormat
9178typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
9179GLAPI PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat;
9180#define glVertexAttribIFormat glad_glVertexAttribIFormat
9181typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
9182GLAPI PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat;
9183#define glVertexAttribLFormat glad_glVertexAttribLFormat
9184typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex);
9185GLAPI PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding;
9186#define glVertexAttribBinding glad_glVertexAttribBinding
9187typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor);
9188GLAPI PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor;
9189#define glVertexBindingDivisor glad_glVertexBindingDivisor
9190#endif 9373#endif
9191#ifndef GL_ARB_vertex_blend 9374#ifndef GL_ARB_vertex_blend
9192#define GL_ARB_vertex_blend 1 9375#define GL_ARB_vertex_blend 1
@@ -9416,36 +9599,6 @@ GLAPI int GLAD_GL_ARB_vertex_type_2_10_10_10_rev;
9416#ifndef GL_ARB_viewport_array 9599#ifndef GL_ARB_viewport_array
9417#define GL_ARB_viewport_array 1 9600#define GL_ARB_viewport_array 1
9418GLAPI int GLAD_GL_ARB_viewport_array; 9601GLAPI int GLAD_GL_ARB_viewport_array;
9419typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat *v);
9420GLAPI PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv;
9421#define glViewportArrayv glad_glViewportArrayv
9422typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
9423GLAPI PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf;
9424#define glViewportIndexedf glad_glViewportIndexedf
9425typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat *v);
9426GLAPI PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv;
9427#define glViewportIndexedfv glad_glViewportIndexedfv
9428typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint *v);
9429GLAPI PFNGLSCISSORARRAYVPROC glad_glScissorArrayv;
9430#define glScissorArrayv glad_glScissorArrayv
9431typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
9432GLAPI PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed;
9433#define glScissorIndexed glad_glScissorIndexed
9434typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint *v);
9435GLAPI PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv;
9436#define glScissorIndexedv glad_glScissorIndexedv
9437typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble *v);
9438GLAPI PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv;
9439#define glDepthRangeArrayv glad_glDepthRangeArrayv
9440typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f);
9441GLAPI PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed;
9442#define glDepthRangeIndexed glad_glDepthRangeIndexed
9443typedef void (APIENTRYP PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat *data);
9444GLAPI PFNGLGETFLOATI_VPROC glad_glGetFloati_v;
9445#define glGetFloati_v glad_glGetFloati_v
9446typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble *data);
9447GLAPI PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v;
9448#define glGetDoublei_v glad_glGetDoublei_v
9449#endif 9602#endif
9450#ifndef GL_ARB_window_pos 9603#ifndef GL_ARB_window_pos
9451#define GL_ARB_window_pos 1 9604#define GL_ARB_window_pos 1
@@ -12173,39 +12326,6 @@ GLAPI int GLAD_GL_KHR_context_flush_control;
12173#ifndef GL_KHR_debug 12326#ifndef GL_KHR_debug
12174#define GL_KHR_debug 1 12327#define GL_KHR_debug 1
12175GLAPI int GLAD_GL_KHR_debug; 12328GLAPI int GLAD_GL_KHR_debug;
12176typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
12177GLAPI PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl;
12178#define glDebugMessageControl glad_glDebugMessageControl
12179typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
12180GLAPI PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert;
12181#define glDebugMessageInsert glad_glDebugMessageInsert
12182typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam);
12183GLAPI PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback;
12184#define glDebugMessageCallback glad_glDebugMessageCallback
12185typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
12186GLAPI PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog;
12187#define glGetDebugMessageLog glad_glGetDebugMessageLog
12188typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message);
12189GLAPI PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup;
12190#define glPushDebugGroup glad_glPushDebugGroup
12191typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC)(void);
12192GLAPI PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup;
12193#define glPopDebugGroup glad_glPopDebugGroup
12194typedef void (APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
12195GLAPI PFNGLOBJECTLABELPROC glad_glObjectLabel;
12196#define glObjectLabel glad_glObjectLabel
12197typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
12198GLAPI PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel;
12199#define glGetObjectLabel glad_glGetObjectLabel
12200typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void *ptr, GLsizei length, const GLchar *label);
12201GLAPI PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel;
12202#define glObjectPtrLabel glad_glObjectPtrLabel
12203typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
12204GLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel;
12205#define glGetObjectPtrLabel glad_glGetObjectPtrLabel
12206typedef void (APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void **params);
12207GLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv;
12208#define glGetPointerv glad_glGetPointerv
12209typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); 12329typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
12210GLAPI PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; 12330GLAPI PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR;
12211#define glDebugMessageControlKHR glad_glDebugMessageControlKHR 12331#define glDebugMessageControlKHR glad_glDebugMessageControlKHR
@@ -12597,6 +12717,10 @@ GLAPI PFNGLCALLCOMMANDLISTNVPROC glad_glCallCommandListNV;
12597#define GL_NV_compute_program5 1 12717#define GL_NV_compute_program5 1
12598GLAPI int GLAD_GL_NV_compute_program5; 12718GLAPI int GLAD_GL_NV_compute_program5;
12599#endif 12719#endif
12720#ifndef GL_NV_compute_shader_derivatives
12721#define GL_NV_compute_shader_derivatives 1
12722GLAPI int GLAD_GL_NV_compute_shader_derivatives;
12723#endif
12600#ifndef GL_NV_conditional_render 12724#ifndef GL_NV_conditional_render
12601#define GL_NV_conditional_render 1 12725#define GL_NV_conditional_render 1
12602GLAPI int GLAD_GL_NV_conditional_render; 12726GLAPI int GLAD_GL_NV_conditional_render;
@@ -12816,6 +12940,10 @@ GLAPI int GLAD_GL_NV_fragment_program4;
12816#define GL_NV_fragment_program_option 1 12940#define GL_NV_fragment_program_option 1
12817GLAPI int GLAD_GL_NV_fragment_program_option; 12941GLAPI int GLAD_GL_NV_fragment_program_option;
12818#endif 12942#endif
12943#ifndef GL_NV_fragment_shader_barycentric
12944#define GL_NV_fragment_shader_barycentric 1
12945GLAPI int GLAD_GL_NV_fragment_shader_barycentric;
12946#endif
12819#ifndef GL_NV_fragment_shader_interlock 12947#ifndef GL_NV_fragment_shader_interlock
12820#define GL_NV_fragment_shader_interlock 1 12948#define GL_NV_fragment_shader_interlock 1
12821GLAPI int GLAD_GL_NV_fragment_shader_interlock; 12949GLAPI int GLAD_GL_NV_fragment_shader_interlock;
@@ -13124,6 +13252,44 @@ GLAPI PFNGLGETINTERNALFORMATSAMPLEIVNVPROC glad_glGetInternalformatSampleivNV;
13124#define GL_NV_light_max_exponent 1 13252#define GL_NV_light_max_exponent 1
13125GLAPI int GLAD_GL_NV_light_max_exponent; 13253GLAPI int GLAD_GL_NV_light_max_exponent;
13126#endif 13254#endif
13255#ifndef GL_NV_memory_attachment
13256#define GL_NV_memory_attachment 1
13257GLAPI int GLAD_GL_NV_memory_attachment;
13258typedef void (APIENTRYP PFNGLGETMEMORYOBJECTDETACHEDRESOURCESUIVNVPROC)(GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint *params);
13259GLAPI PFNGLGETMEMORYOBJECTDETACHEDRESOURCESUIVNVPROC glad_glGetMemoryObjectDetachedResourcesuivNV;
13260#define glGetMemoryObjectDetachedResourcesuivNV glad_glGetMemoryObjectDetachedResourcesuivNV
13261typedef void (APIENTRYP PFNGLRESETMEMORYOBJECTPARAMETERNVPROC)(GLuint memory, GLenum pname);
13262GLAPI PFNGLRESETMEMORYOBJECTPARAMETERNVPROC glad_glResetMemoryObjectParameterNV;
13263#define glResetMemoryObjectParameterNV glad_glResetMemoryObjectParameterNV
13264typedef void (APIENTRYP PFNGLTEXATTACHMEMORYNVPROC)(GLenum target, GLuint memory, GLuint64 offset);
13265GLAPI PFNGLTEXATTACHMEMORYNVPROC glad_glTexAttachMemoryNV;
13266#define glTexAttachMemoryNV glad_glTexAttachMemoryNV
13267typedef void (APIENTRYP PFNGLBUFFERATTACHMEMORYNVPROC)(GLenum target, GLuint memory, GLuint64 offset);
13268GLAPI PFNGLBUFFERATTACHMEMORYNVPROC glad_glBufferAttachMemoryNV;
13269#define glBufferAttachMemoryNV glad_glBufferAttachMemoryNV
13270typedef void (APIENTRYP PFNGLTEXTUREATTACHMEMORYNVPROC)(GLuint texture, GLuint memory, GLuint64 offset);
13271GLAPI PFNGLTEXTUREATTACHMEMORYNVPROC glad_glTextureAttachMemoryNV;
13272#define glTextureAttachMemoryNV glad_glTextureAttachMemoryNV
13273typedef void (APIENTRYP PFNGLNAMEDBUFFERATTACHMEMORYNVPROC)(GLuint buffer, GLuint memory, GLuint64 offset);
13274GLAPI PFNGLNAMEDBUFFERATTACHMEMORYNVPROC glad_glNamedBufferAttachMemoryNV;
13275#define glNamedBufferAttachMemoryNV glad_glNamedBufferAttachMemoryNV
13276#endif
13277#ifndef GL_NV_mesh_shader
13278#define GL_NV_mesh_shader 1
13279GLAPI int GLAD_GL_NV_mesh_shader;
13280typedef void (APIENTRYP PFNGLDRAWMESHTASKSNVPROC)(GLuint first, GLuint count);
13281GLAPI PFNGLDRAWMESHTASKSNVPROC glad_glDrawMeshTasksNV;
13282#define glDrawMeshTasksNV glad_glDrawMeshTasksNV
13283typedef void (APIENTRYP PFNGLDRAWMESHTASKSINDIRECTNVPROC)(GLintptr indirect);
13284GLAPI PFNGLDRAWMESHTASKSINDIRECTNVPROC glad_glDrawMeshTasksIndirectNV;
13285#define glDrawMeshTasksIndirectNV glad_glDrawMeshTasksIndirectNV
13286typedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTNVPROC)(GLintptr indirect, GLsizei drawcount, GLsizei stride);
13287GLAPI PFNGLMULTIDRAWMESHTASKSINDIRECTNVPROC glad_glMultiDrawMeshTasksIndirectNV;
13288#define glMultiDrawMeshTasksIndirectNV glad_glMultiDrawMeshTasksIndirectNV
13289typedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTCOUNTNVPROC)(GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
13290GLAPI PFNGLMULTIDRAWMESHTASKSINDIRECTCOUNTNVPROC glad_glMultiDrawMeshTasksIndirectCountNV;
13291#define glMultiDrawMeshTasksIndirectCountNV glad_glMultiDrawMeshTasksIndirectCountNV
13292#endif
13127#ifndef GL_NV_multisample_coverage 13293#ifndef GL_NV_multisample_coverage
13128#define GL_NV_multisample_coverage 1 13294#define GL_NV_multisample_coverage 1
13129GLAPI int GLAD_GL_NV_multisample_coverage; 13295GLAPI int GLAD_GL_NV_multisample_coverage;
@@ -13503,6 +13669,10 @@ typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC)(GLenum stage, GL
13503GLAPI PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC glad_glGetCombinerStageParameterfvNV; 13669GLAPI PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC glad_glGetCombinerStageParameterfvNV;
13504#define glGetCombinerStageParameterfvNV glad_glGetCombinerStageParameterfvNV 13670#define glGetCombinerStageParameterfvNV glad_glGetCombinerStageParameterfvNV
13505#endif 13671#endif
13672#ifndef GL_NV_representative_fragment_test
13673#define GL_NV_representative_fragment_test 1
13674GLAPI int GLAD_GL_NV_representative_fragment_test;
13675#endif
13506#ifndef GL_NV_robustness_video_memory_purge 13676#ifndef GL_NV_robustness_video_memory_purge
13507#define GL_NV_robustness_video_memory_purge 1 13677#define GL_NV_robustness_video_memory_purge 1
13508GLAPI int GLAD_GL_NV_robustness_video_memory_purge; 13678GLAPI int GLAD_GL_NV_robustness_video_memory_purge;
@@ -13524,6 +13694,16 @@ GLAPI PFNGLRESOLVEDEPTHVALUESNVPROC glad_glResolveDepthValuesNV;
13524#define GL_NV_sample_mask_override_coverage 1 13694#define GL_NV_sample_mask_override_coverage 1
13525GLAPI int GLAD_GL_NV_sample_mask_override_coverage; 13695GLAPI int GLAD_GL_NV_sample_mask_override_coverage;
13526#endif 13696#endif
13697#ifndef GL_NV_scissor_exclusive
13698#define GL_NV_scissor_exclusive 1
13699GLAPI int GLAD_GL_NV_scissor_exclusive;
13700typedef void (APIENTRYP PFNGLSCISSOREXCLUSIVENVPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
13701GLAPI PFNGLSCISSOREXCLUSIVENVPROC glad_glScissorExclusiveNV;
13702#define glScissorExclusiveNV glad_glScissorExclusiveNV
13703typedef void (APIENTRYP PFNGLSCISSOREXCLUSIVEARRAYVNVPROC)(GLuint first, GLsizei count, const GLint *v);
13704GLAPI PFNGLSCISSOREXCLUSIVEARRAYVNVPROC glad_glScissorExclusiveArrayvNV;
13705#define glScissorExclusiveArrayvNV glad_glScissorExclusiveArrayvNV
13706#endif
13527#ifndef GL_NV_shader_atomic_counters 13707#ifndef GL_NV_shader_atomic_counters
13528#define GL_NV_shader_atomic_counters 1 13708#define GL_NV_shader_atomic_counters 1
13529GLAPI int GLAD_GL_NV_shader_atomic_counters; 13709GLAPI int GLAD_GL_NV_shader_atomic_counters;
@@ -13595,6 +13775,10 @@ GLAPI int GLAD_GL_NV_shader_buffer_store;
13595#define GL_NV_shader_storage_buffer_object 1 13775#define GL_NV_shader_storage_buffer_object 1
13596GLAPI int GLAD_GL_NV_shader_storage_buffer_object; 13776GLAPI int GLAD_GL_NV_shader_storage_buffer_object;
13597#endif 13777#endif
13778#ifndef GL_NV_shader_texture_footprint
13779#define GL_NV_shader_texture_footprint 1
13780GLAPI int GLAD_GL_NV_shader_texture_footprint;
13781#endif
13598#ifndef GL_NV_shader_thread_group 13782#ifndef GL_NV_shader_thread_group
13599#define GL_NV_shader_thread_group 1 13783#define GL_NV_shader_thread_group 1
13600GLAPI int GLAD_GL_NV_shader_thread_group; 13784GLAPI int GLAD_GL_NV_shader_thread_group;
@@ -13603,6 +13787,31 @@ GLAPI int GLAD_GL_NV_shader_thread_group;
13603#define GL_NV_shader_thread_shuffle 1 13787#define GL_NV_shader_thread_shuffle 1
13604GLAPI int GLAD_GL_NV_shader_thread_shuffle; 13788GLAPI int GLAD_GL_NV_shader_thread_shuffle;
13605#endif 13789#endif
13790#ifndef GL_NV_shading_rate_image
13791#define GL_NV_shading_rate_image 1
13792GLAPI int GLAD_GL_NV_shading_rate_image;
13793typedef void (APIENTRYP PFNGLBINDSHADINGRATEIMAGENVPROC)(GLuint texture);
13794GLAPI PFNGLBINDSHADINGRATEIMAGENVPROC glad_glBindShadingRateImageNV;
13795#define glBindShadingRateImageNV glad_glBindShadingRateImageNV
13796typedef void (APIENTRYP PFNGLGETSHADINGRATEIMAGEPALETTENVPROC)(GLuint viewport, GLuint entry, GLenum *rate);
13797GLAPI PFNGLGETSHADINGRATEIMAGEPALETTENVPROC glad_glGetShadingRateImagePaletteNV;
13798#define glGetShadingRateImagePaletteNV glad_glGetShadingRateImagePaletteNV
13799typedef void (APIENTRYP PFNGLGETSHADINGRATESAMPLELOCATIONIVNVPROC)(GLenum rate, GLuint samples, GLuint index, GLint *location);
13800GLAPI PFNGLGETSHADINGRATESAMPLELOCATIONIVNVPROC glad_glGetShadingRateSampleLocationivNV;
13801#define glGetShadingRateSampleLocationivNV glad_glGetShadingRateSampleLocationivNV
13802typedef void (APIENTRYP PFNGLSHADINGRATEIMAGEBARRIERNVPROC)(GLboolean synchronize);
13803GLAPI PFNGLSHADINGRATEIMAGEBARRIERNVPROC glad_glShadingRateImageBarrierNV;
13804#define glShadingRateImageBarrierNV glad_glShadingRateImageBarrierNV
13805typedef void (APIENTRYP PFNGLSHADINGRATEIMAGEPALETTENVPROC)(GLuint viewport, GLuint first, GLsizei count, const GLenum *rates);
13806GLAPI PFNGLSHADINGRATEIMAGEPALETTENVPROC glad_glShadingRateImagePaletteNV;
13807#define glShadingRateImagePaletteNV glad_glShadingRateImagePaletteNV
13808typedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERNVPROC)(GLenum order);
13809GLAPI PFNGLSHADINGRATESAMPLEORDERNVPROC glad_glShadingRateSampleOrderNV;
13810#define glShadingRateSampleOrderNV glad_glShadingRateSampleOrderNV
13811typedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERCUSTOMNVPROC)(GLenum rate, GLuint samples, const GLint *locations);
13812GLAPI PFNGLSHADINGRATESAMPLEORDERCUSTOMNVPROC glad_glShadingRateSampleOrderCustomNV;
13813#define glShadingRateSampleOrderCustomNV glad_glShadingRateSampleOrderCustomNV
13814#endif
13606#ifndef GL_NV_stereo_view_rendering 13815#ifndef GL_NV_stereo_view_rendering
13607#define GL_NV_stereo_view_rendering 1 13816#define GL_NV_stereo_view_rendering 1
13608GLAPI int GLAD_GL_NV_stereo_view_rendering; 13817GLAPI int GLAD_GL_NV_stereo_view_rendering;
@@ -13783,6 +13992,13 @@ typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC)(GLsizei numSurface, const
13783GLAPI PFNGLVDPAUUNMAPSURFACESNVPROC glad_glVDPAUUnmapSurfacesNV; 13992GLAPI PFNGLVDPAUUNMAPSURFACESNVPROC glad_glVDPAUUnmapSurfacesNV;
13784#define glVDPAUUnmapSurfacesNV glad_glVDPAUUnmapSurfacesNV 13993#define glVDPAUUnmapSurfacesNV glad_glVDPAUUnmapSurfacesNV
13785#endif 13994#endif
13995#ifndef GL_NV_vdpau_interop2
13996#define GL_NV_vdpau_interop2 1
13997GLAPI int GLAD_GL_NV_vdpau_interop2;
13998typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACEWITHPICTURESTRUCTURENVPROC)(const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames, GLboolean isFrameStructure);
13999GLAPI PFNGLVDPAUREGISTERVIDEOSURFACEWITHPICTURESTRUCTURENVPROC glad_glVDPAURegisterVideoSurfaceWithPictureStructureNV;
14000#define glVDPAURegisterVideoSurfaceWithPictureStructureNV glad_glVDPAURegisterVideoSurfaceWithPictureStructureNV
14001#endif
13786#ifndef GL_NV_vertex_array_range 14002#ifndef GL_NV_vertex_array_range
13787#define GL_NV_vertex_array_range 1 14003#define GL_NV_vertex_array_range 1
13788GLAPI int GLAD_GL_NV_vertex_array_range; 14004GLAPI int GLAD_GL_NV_vertex_array_range;
diff --git a/externals/glad/src/glad.c b/externals/glad/src/glad.c
index 1cf0890b9..384507806 100644
--- a/externals/glad/src/glad.c
+++ b/externals/glad/src/glad.c
@@ -1,10 +1,10 @@
1/* 1/*
2 2
3 OpenGL loader generated by glad 0.1.26 on Tue Aug 7 08:21:50 2018. 3 OpenGL loader generated by glad 0.1.28 on Sat Nov 17 22:59:18 2018.
4 4
5 Language/Generator: C/C++ 5 Language/Generator: C/C++
6 Specification: gl 6 Specification: gl
7 APIs: gl=3.3 7 APIs: gl=4.3
8 Profile: core 8 Profile: core
9 Extensions: 9 Extensions:
10 GL_3DFX_multisample, 10 GL_3DFX_multisample,
@@ -418,6 +418,7 @@
418 GL_NV_clip_space_w_scaling, 418 GL_NV_clip_space_w_scaling,
419 GL_NV_command_list, 419 GL_NV_command_list,
420 GL_NV_compute_program5, 420 GL_NV_compute_program5,
421 GL_NV_compute_shader_derivatives,
421 GL_NV_conditional_render, 422 GL_NV_conditional_render,
422 GL_NV_conservative_raster, 423 GL_NV_conservative_raster,
423 GL_NV_conservative_raster_dilate, 424 GL_NV_conservative_raster_dilate,
@@ -442,6 +443,7 @@
442 GL_NV_fragment_program2, 443 GL_NV_fragment_program2,
443 GL_NV_fragment_program4, 444 GL_NV_fragment_program4,
444 GL_NV_fragment_program_option, 445 GL_NV_fragment_program_option,
446 GL_NV_fragment_shader_barycentric,
445 GL_NV_fragment_shader_interlock, 447 GL_NV_fragment_shader_interlock,
446 GL_NV_framebuffer_mixed_samples, 448 GL_NV_framebuffer_mixed_samples,
447 GL_NV_framebuffer_multisample_coverage, 449 GL_NV_framebuffer_multisample_coverage,
@@ -456,6 +458,8 @@
456 GL_NV_half_float, 458 GL_NV_half_float,
457 GL_NV_internalformat_sample_query, 459 GL_NV_internalformat_sample_query,
458 GL_NV_light_max_exponent, 460 GL_NV_light_max_exponent,
461 GL_NV_memory_attachment,
462 GL_NV_mesh_shader,
459 GL_NV_multisample_coverage, 463 GL_NV_multisample_coverage,
460 GL_NV_multisample_filter_hint, 464 GL_NV_multisample_filter_hint,
461 GL_NV_occlusion_query, 465 GL_NV_occlusion_query,
@@ -472,9 +476,11 @@
472 GL_NV_query_resource_tag, 476 GL_NV_query_resource_tag,
473 GL_NV_register_combiners, 477 GL_NV_register_combiners,
474 GL_NV_register_combiners2, 478 GL_NV_register_combiners2,
479 GL_NV_representative_fragment_test,
475 GL_NV_robustness_video_memory_purge, 480 GL_NV_robustness_video_memory_purge,
476 GL_NV_sample_locations, 481 GL_NV_sample_locations,
477 GL_NV_sample_mask_override_coverage, 482 GL_NV_sample_mask_override_coverage,
483 GL_NV_scissor_exclusive,
478 GL_NV_shader_atomic_counters, 484 GL_NV_shader_atomic_counters,
479 GL_NV_shader_atomic_float, 485 GL_NV_shader_atomic_float,
480 GL_NV_shader_atomic_float64, 486 GL_NV_shader_atomic_float64,
@@ -483,8 +489,10 @@
483 GL_NV_shader_buffer_load, 489 GL_NV_shader_buffer_load,
484 GL_NV_shader_buffer_store, 490 GL_NV_shader_buffer_store,
485 GL_NV_shader_storage_buffer_object, 491 GL_NV_shader_storage_buffer_object,
492 GL_NV_shader_texture_footprint,
486 GL_NV_shader_thread_group, 493 GL_NV_shader_thread_group,
487 GL_NV_shader_thread_shuffle, 494 GL_NV_shader_thread_shuffle,
495 GL_NV_shading_rate_image,
488 GL_NV_stereo_view_rendering, 496 GL_NV_stereo_view_rendering,
489 GL_NV_tessellation_program5, 497 GL_NV_tessellation_program5,
490 GL_NV_texgen_emboss, 498 GL_NV_texgen_emboss,
@@ -503,6 +511,7 @@
503 GL_NV_transform_feedback2, 511 GL_NV_transform_feedback2,
504 GL_NV_uniform_buffer_unified_memory, 512 GL_NV_uniform_buffer_unified_memory,
505 GL_NV_vdpau_interop, 513 GL_NV_vdpau_interop,
514 GL_NV_vdpau_interop2,
506 GL_NV_vertex_array_range, 515 GL_NV_vertex_array_range,
507 GL_NV_vertex_array_range2, 516 GL_NV_vertex_array_range2,
508 GL_NV_vertex_attrib_integer_64bit, 517 GL_NV_vertex_attrib_integer_64bit,
@@ -599,9 +608,10 @@
599 Loader: True 608 Loader: True
600 Local files: False 609 Local files: False
601 Omit khrplatform: False 610 Omit khrplatform: False
611 Reproducible: False
602 612
603 Commandline: 613 Commandline:
604 --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_3DFX_multisample,GL_3DFX_tbuffer,GL_3DFX_texture_compression_FXT1,GL_AMD_blend_minmax_factor,GL_AMD_conservative_depth,GL_AMD_debug_output,GL_AMD_depth_clamp_separate,GL_AMD_draw_buffers_blend,GL_AMD_framebuffer_multisample_advanced,GL_AMD_framebuffer_sample_positions,GL_AMD_gcn_shader,GL_AMD_gpu_shader_half_float,GL_AMD_gpu_shader_int16,GL_AMD_gpu_shader_int64,GL_AMD_interleaved_elements,GL_AMD_multi_draw_indirect,GL_AMD_name_gen_delete,GL_AMD_occlusion_query_event,GL_AMD_performance_monitor,GL_AMD_pinned_memory,GL_AMD_query_buffer_object,GL_AMD_sample_positions,GL_AMD_seamless_cubemap_per_texture,GL_AMD_shader_atomic_counter_ops,GL_AMD_shader_ballot,GL_AMD_shader_explicit_vertex_parameter,GL_AMD_shader_gpu_shader_half_float_fetch,GL_AMD_shader_image_load_store_lod,GL_AMD_shader_stencil_export,GL_AMD_shader_trinary_minmax,GL_AMD_sparse_texture,GL_AMD_stencil_operation_extended,GL_AMD_texture_gather_bias_lod,GL_AMD_texture_texture4,GL_AMD_transform_feedback3_lines_triangles,GL_AMD_transform_feedback4,GL_AMD_vertex_shader_layer,GL_AMD_vertex_shader_tessellator,GL_AMD_vertex_shader_viewport_index,GL_APPLE_aux_depth_stencil,GL_APPLE_client_storage,GL_APPLE_element_array,GL_APPLE_fence,GL_APPLE_float_pixels,GL_APPLE_flush_buffer_range,GL_APPLE_object_purgeable,GL_APPLE_rgb_422,GL_APPLE_row_bytes,GL_APPLE_specular_vector,GL_APPLE_texture_range,GL_APPLE_transform_hint,GL_APPLE_vertex_array_object,GL_APPLE_vertex_array_range,GL_APPLE_vertex_program_evaluators,GL_APPLE_ycbcr_422,GL_ARB_ES2_compatibility,GL_ARB_ES3_1_compatibility,GL_ARB_ES3_2_compatibility,GL_ARB_ES3_compatibility,GL_ARB_arrays_of_arrays,GL_ARB_base_instance,GL_ARB_bindless_texture,GL_ARB_blend_func_extended,GL_ARB_buffer_storage,GL_ARB_cl_event,GL_ARB_clear_buffer_object,GL_ARB_clear_texture,GL_ARB_clip_control,GL_ARB_color_buffer_float,GL_ARB_compatibility,GL_ARB_compressed_texture_pixel_storage,GL_ARB_compute_shader,GL_ARB_compute_variable_group_size,GL_ARB_conditional_render_inverted,GL_ARB_conservative_depth,GL_ARB_copy_buffer,GL_ARB_copy_image,GL_ARB_cull_distance,GL_ARB_debug_output,GL_ARB_depth_buffer_float,GL_ARB_depth_clamp,GL_ARB_depth_texture,GL_ARB_derivative_control,GL_ARB_direct_state_access,GL_ARB_draw_buffers,GL_ARB_draw_buffers_blend,GL_ARB_draw_elements_base_vertex,GL_ARB_draw_indirect,GL_ARB_draw_instanced,GL_ARB_enhanced_layouts,GL_ARB_explicit_attrib_location,GL_ARB_explicit_uniform_location,GL_ARB_fragment_coord_conventions,GL_ARB_fragment_layer_viewport,GL_ARB_fragment_program,GL_ARB_fragment_program_shadow,GL_ARB_fragment_shader,GL_ARB_fragment_shader_interlock,GL_ARB_framebuffer_no_attachments,GL_ARB_framebuffer_object,GL_ARB_framebuffer_sRGB,GL_ARB_geometry_shader4,GL_ARB_get_program_binary,GL_ARB_get_texture_sub_image,GL_ARB_gl_spirv,GL_ARB_gpu_shader5,GL_ARB_gpu_shader_fp64,GL_ARB_gpu_shader_int64,GL_ARB_half_float_pixel,GL_ARB_half_float_vertex,GL_ARB_imaging,GL_ARB_indirect_parameters,GL_ARB_instanced_arrays,GL_ARB_internalformat_query,GL_ARB_internalformat_query2,GL_ARB_invalidate_subdata,GL_ARB_map_buffer_alignment,GL_ARB_map_buffer_range,GL_ARB_matrix_palette,GL_ARB_multi_bind,GL_ARB_multi_draw_indirect,GL_ARB_multisample,GL_ARB_multitexture,GL_ARB_occlusion_query,GL_ARB_occlusion_query2,GL_ARB_parallel_shader_compile,GL_ARB_pipeline_statistics_query,GL_ARB_pixel_buffer_object,GL_ARB_point_parameters,GL_ARB_point_sprite,GL_ARB_polygon_offset_clamp,GL_ARB_post_depth_coverage,GL_ARB_program_interface_query,GL_ARB_provoking_vertex,GL_ARB_query_buffer_object,GL_ARB_robust_buffer_access_behavior,GL_ARB_robustness,GL_ARB_robustness_isolation,GL_ARB_sample_locations,GL_ARB_sample_shading,GL_ARB_sampler_objects,GL_ARB_seamless_cube_map,GL_ARB_seamless_cubemap_per_texture,GL_ARB_separate_shader_objects,GL_ARB_shader_atomic_counter_ops,GL_ARB_shader_atomic_counters,GL_ARB_shader_ballot,GL_ARB_shader_bit_encoding,GL_ARB_shader_clock,GL_ARB_shader_draw_parameters,GL_ARB_shader_group_vote,GL_ARB_shader_image_load_store,GL_ARB_shader_image_size,GL_ARB_shader_objects,GL_ARB_shader_precision,GL_ARB_shader_stencil_export,GL_ARB_shader_storage_buffer_object,GL_ARB_shader_subroutine,GL_ARB_shader_texture_image_samples,GL_ARB_shader_texture_lod,GL_ARB_shader_viewport_layer_array,GL_ARB_shading_language_100,GL_ARB_shading_language_420pack,GL_ARB_shading_language_include,GL_ARB_shading_language_packing,GL_ARB_shadow,GL_ARB_shadow_ambient,GL_ARB_sparse_buffer,GL_ARB_sparse_texture,GL_ARB_sparse_texture2,GL_ARB_sparse_texture_clamp,GL_ARB_spirv_extensions,GL_ARB_stencil_texturing,GL_ARB_sync,GL_ARB_tessellation_shader,GL_ARB_texture_barrier,GL_ARB_texture_border_clamp,GL_ARB_texture_buffer_object,GL_ARB_texture_buffer_object_rgb32,GL_ARB_texture_buffer_range,GL_ARB_texture_compression,GL_ARB_texture_compression_bptc,GL_ARB_texture_compression_rgtc,GL_ARB_texture_cube_map,GL_ARB_texture_cube_map_array,GL_ARB_texture_env_add,GL_ARB_texture_env_combine,GL_ARB_texture_env_crossbar,GL_ARB_texture_env_dot3,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_filter_minmax,GL_ARB_texture_float,GL_ARB_texture_gather,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_texture_mirrored_repeat,GL_ARB_texture_multisample,GL_ARB_texture_non_power_of_two,GL_ARB_texture_query_levels,GL_ARB_texture_query_lod,GL_ARB_texture_rectangle,GL_ARB_texture_rg,GL_ARB_texture_rgb10_a2ui,GL_ARB_texture_stencil8,GL_ARB_texture_storage,GL_ARB_texture_storage_multisample,GL_ARB_texture_swizzle,GL_ARB_texture_view,GL_ARB_timer_query,GL_ARB_transform_feedback2,GL_ARB_transform_feedback3,GL_ARB_transform_feedback_instanced,GL_ARB_transform_feedback_overflow_query,GL_ARB_transpose_matrix,GL_ARB_uniform_buffer_object,GL_ARB_vertex_array_bgra,GL_ARB_vertex_array_object,GL_ARB_vertex_attrib_64bit,GL_ARB_vertex_attrib_binding,GL_ARB_vertex_blend,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_ARB_vertex_type_10f_11f_11f_rev,GL_ARB_vertex_type_2_10_10_10_rev,GL_ARB_viewport_array,GL_ARB_window_pos,GL_ATI_draw_buffers,GL_ATI_element_array,GL_ATI_envmap_bumpmap,GL_ATI_fragment_shader,GL_ATI_map_object_buffer,GL_ATI_meminfo,GL_ATI_pixel_format_float,GL_ATI_pn_triangles,GL_ATI_separate_stencil,GL_ATI_text_fragment_shader,GL_ATI_texture_env_combine3,GL_ATI_texture_float,GL_ATI_texture_mirror_once,GL_ATI_vertex_array_object,GL_ATI_vertex_attrib_array_object,GL_ATI_vertex_streams,GL_EXT_422_pixels,GL_EXT_EGL_image_storage,GL_EXT_abgr,GL_EXT_bgra,GL_EXT_bindable_uniform,GL_EXT_blend_color,GL_EXT_blend_equation_separate,GL_EXT_blend_func_separate,GL_EXT_blend_logic_op,GL_EXT_blend_minmax,GL_EXT_blend_subtract,GL_EXT_clip_volume_hint,GL_EXT_cmyka,GL_EXT_color_subtable,GL_EXT_compiled_vertex_array,GL_EXT_convolution,GL_EXT_coordinate_frame,GL_EXT_copy_texture,GL_EXT_cull_vertex,GL_EXT_debug_label,GL_EXT_debug_marker,GL_EXT_depth_bounds_test,GL_EXT_direct_state_access,GL_EXT_draw_buffers2,GL_EXT_draw_instanced,GL_EXT_draw_range_elements,GL_EXT_external_buffer,GL_EXT_fog_coord,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_multisample_blit_scaled,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_geometry_shader4,GL_EXT_gpu_program_parameters,GL_EXT_gpu_shader4,GL_EXT_histogram,GL_EXT_index_array_formats,GL_EXT_index_func,GL_EXT_index_material,GL_EXT_index_texture,GL_EXT_light_texture,GL_EXT_memory_object,GL_EXT_memory_object_fd,GL_EXT_memory_object_win32,GL_EXT_misc_attribute,GL_EXT_multi_draw_arrays,GL_EXT_multisample,GL_EXT_packed_depth_stencil,GL_EXT_packed_float,GL_EXT_packed_pixels,GL_EXT_paletted_texture,GL_EXT_pixel_buffer_object,GL_EXT_pixel_transform,GL_EXT_pixel_transform_color_table,GL_EXT_point_parameters,GL_EXT_polygon_offset,GL_EXT_polygon_offset_clamp,GL_EXT_post_depth_coverage,GL_EXT_provoking_vertex,GL_EXT_raster_multisample,GL_EXT_rescale_normal,GL_EXT_secondary_color,GL_EXT_semaphore,GL_EXT_semaphore_fd,GL_EXT_semaphore_win32,GL_EXT_separate_shader_objects,GL_EXT_separate_specular_color,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_framebuffer_fetch_non_coherent,GL_EXT_shader_image_load_formatted,GL_EXT_shader_image_load_store,GL_EXT_shader_integer_mix,GL_EXT_shadow_funcs,GL_EXT_shared_texture_palette,GL_EXT_sparse_texture2,GL_EXT_stencil_clear_tag,GL_EXT_stencil_two_side,GL_EXT_stencil_wrap,GL_EXT_subtexture,GL_EXT_texture,GL_EXT_texture3D,GL_EXT_texture_array,GL_EXT_texture_buffer_object,GL_EXT_texture_compression_latc,GL_EXT_texture_compression_rgtc,GL_EXT_texture_compression_s3tc,GL_EXT_texture_cube_map,GL_EXT_texture_env_add,GL_EXT_texture_env_combine,GL_EXT_texture_env_dot3,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_filter_minmax,GL_EXT_texture_integer,GL_EXT_texture_lod_bias,GL_EXT_texture_mirror_clamp,GL_EXT_texture_object,GL_EXT_texture_perturb_normal,GL_EXT_texture_sRGB,GL_EXT_texture_sRGB_decode,GL_EXT_texture_shared_exponent,GL_EXT_texture_snorm,GL_EXT_texture_swizzle,GL_EXT_timer_query,GL_EXT_transform_feedback,GL_EXT_vertex_array,GL_EXT_vertex_array_bgra,GL_EXT_vertex_attrib_64bit,GL_EXT_vertex_shader,GL_EXT_vertex_weighting,GL_EXT_win32_keyed_mutex,GL_EXT_window_rectangles,GL_EXT_x11_sync_object,GL_GREMEDY_frame_terminator,GL_GREMEDY_string_marker,GL_HP_convolution_border_modes,GL_HP_image_transform,GL_HP_occlusion_test,GL_HP_texture_lighting,GL_IBM_cull_vertex,GL_IBM_multimode_draw_arrays,GL_IBM_rasterpos_clip,GL_IBM_static_data,GL_IBM_texture_mirrored_repeat,GL_IBM_vertex_array_lists,GL_INGR_blend_func_separate,GL_INGR_color_clamp,GL_INGR_interlace_read,GL_INTEL_blackhole_render,GL_INTEL_conservative_rasterization,GL_INTEL_fragment_shader_ordering,GL_INTEL_framebuffer_CMAA,GL_INTEL_map_texture,GL_INTEL_parallel_arrays,GL_INTEL_performance_query,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_context_flush_control,GL_KHR_debug,GL_KHR_no_error,GL_KHR_parallel_shader_compile,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_MESAX_texture_stack,GL_MESA_pack_invert,GL_MESA_program_binary_formats,GL_MESA_resize_buffers,GL_MESA_shader_integer_functions,GL_MESA_tile_raster_order,GL_MESA_window_pos,GL_MESA_ycbcr_texture,GL_NVX_blend_equation_advanced_multi_draw_buffers,GL_NVX_conditional_render,GL_NVX_gpu_memory_info,GL_NVX_linked_gpu_multicast,GL_NV_alpha_to_coverage_dither_control,GL_NV_bindless_multi_draw_indirect,GL_NV_bindless_multi_draw_indirect_count,GL_NV_bindless_texture,GL_NV_blend_equation_advanced,GL_NV_blend_equation_advanced_coherent,GL_NV_blend_minmax_factor,GL_NV_blend_square,GL_NV_clip_space_w_scaling,GL_NV_command_list,GL_NV_compute_program5,GL_NV_conditional_render,GL_NV_conservative_raster,GL_NV_conservative_raster_dilate,GL_NV_conservative_raster_pre_snap,GL_NV_conservative_raster_pre_snap_triangles,GL_NV_conservative_raster_underestimation,GL_NV_copy_depth_to_color,GL_NV_copy_image,GL_NV_deep_texture3D,GL_NV_depth_buffer_float,GL_NV_depth_clamp,GL_NV_draw_texture,GL_NV_draw_vulkan_image,GL_NV_evaluators,GL_NV_explicit_multisample,GL_NV_fence,GL_NV_fill_rectangle,GL_NV_float_buffer,GL_NV_fog_distance,GL_NV_fragment_coverage_to_color,GL_NV_fragment_program,GL_NV_fragment_program2,GL_NV_fragment_program4,GL_NV_fragment_program_option,GL_NV_fragment_shader_interlock,GL_NV_framebuffer_mixed_samples,GL_NV_framebuffer_multisample_coverage,GL_NV_geometry_program4,GL_NV_geometry_shader4,GL_NV_geometry_shader_passthrough,GL_NV_gpu_multicast,GL_NV_gpu_program4,GL_NV_gpu_program5,GL_NV_gpu_program5_mem_extended,GL_NV_gpu_shader5,GL_NV_half_float,GL_NV_internalformat_sample_query,GL_NV_light_max_exponent,GL_NV_multisample_coverage,GL_NV_multisample_filter_hint,GL_NV_occlusion_query,GL_NV_packed_depth_stencil,GL_NV_parameter_buffer_object,GL_NV_parameter_buffer_object2,GL_NV_path_rendering,GL_NV_path_rendering_shared_edge,GL_NV_pixel_data_range,GL_NV_point_sprite,GL_NV_present_video,GL_NV_primitive_restart,GL_NV_query_resource,GL_NV_query_resource_tag,GL_NV_register_combiners,GL_NV_register_combiners2,GL_NV_robustness_video_memory_purge,GL_NV_sample_locations,GL_NV_sample_mask_override_coverage,GL_NV_shader_atomic_counters,GL_NV_shader_atomic_float,GL_NV_shader_atomic_float64,GL_NV_shader_atomic_fp16_vector,GL_NV_shader_atomic_int64,GL_NV_shader_buffer_load,GL_NV_shader_buffer_store,GL_NV_shader_storage_buffer_object,GL_NV_shader_thread_group,GL_NV_shader_thread_shuffle,GL_NV_stereo_view_rendering,GL_NV_tessellation_program5,GL_NV_texgen_emboss,GL_NV_texgen_reflection,GL_NV_texture_barrier,GL_NV_texture_compression_vtc,GL_NV_texture_env_combine4,GL_NV_texture_expand_normal,GL_NV_texture_multisample,GL_NV_texture_rectangle,GL_NV_texture_rectangle_compressed,GL_NV_texture_shader,GL_NV_texture_shader2,GL_NV_texture_shader3,GL_NV_transform_feedback,GL_NV_transform_feedback2,GL_NV_uniform_buffer_unified_memory,GL_NV_vdpau_interop,GL_NV_vertex_array_range,GL_NV_vertex_array_range2,GL_NV_vertex_attrib_integer_64bit,GL_NV_vertex_buffer_unified_memory,GL_NV_vertex_program,GL_NV_vertex_program1_1,GL_NV_vertex_program2,GL_NV_vertex_program2_option,GL_NV_vertex_program3,GL_NV_vertex_program4,GL_NV_video_capture,GL_NV_viewport_array2,GL_NV_viewport_swizzle,GL_OES_byte_coordinates,GL_OES_compressed_paletted_texture,GL_OES_fixed_point,GL_OES_query_matrix,GL_OES_read_format,GL_OES_single_precision,GL_OML_interlace,GL_OML_resample,GL_OML_subsample,GL_OVR_multiview,GL_OVR_multiview2,GL_PGI_misc_hints,GL_PGI_vertex_hints,GL_REND_screen_coordinates,GL_S3_s3tc,GL_SGIS_detail_texture,GL_SGIS_fog_function,GL_SGIS_generate_mipmap,GL_SGIS_multisample,GL_SGIS_pixel_texture,GL_SGIS_point_line_texgen,GL_SGIS_point_parameters,GL_SGIS_sharpen_texture,GL_SGIS_texture4D,GL_SGIS_texture_border_clamp,GL_SGIS_texture_color_mask,GL_SGIS_texture_edge_clamp,GL_SGIS_texture_filter4,GL_SGIS_texture_lod,GL_SGIS_texture_select,GL_SGIX_async,GL_SGIX_async_histogram,GL_SGIX_async_pixel,GL_SGIX_blend_alpha_minmax,GL_SGIX_calligraphic_fragment,GL_SGIX_clipmap,GL_SGIX_convolution_accuracy,GL_SGIX_depth_pass_instrument,GL_SGIX_depth_texture,GL_SGIX_flush_raster,GL_SGIX_fog_offset,GL_SGIX_fragment_lighting,GL_SGIX_framezoom,GL_SGIX_igloo_interface,GL_SGIX_instruments,GL_SGIX_interlace,GL_SGIX_ir_instrument1,GL_SGIX_list_priority,GL_SGIX_pixel_texture,GL_SGIX_pixel_tiles,GL_SGIX_polynomial_ffd,GL_SGIX_reference_plane,GL_SGIX_resample,GL_SGIX_scalebias_hint,GL_SGIX_shadow,GL_SGIX_shadow_ambient,GL_SGIX_sprite,GL_SGIX_subsample,GL_SGIX_tag_sample_buffer,GL_SGIX_texture_add_env,GL_SGIX_texture_coordinate_clamp,GL_SGIX_texture_lod_bias,GL_SGIX_texture_multi_buffer,GL_SGIX_texture_scale_bias,GL_SGIX_vertex_preclip,GL_SGIX_ycrcb,GL_SGIX_ycrcb_subsample,GL_SGIX_ycrcba,GL_SGI_color_matrix,GL_SGI_color_table,GL_SGI_texture_color_table,GL_SUNX_constant_data,GL_SUN_convolution_border_modes,GL_SUN_global_alpha,GL_SUN_mesh_array,GL_SUN_slice_accum,GL_SUN_triangle_list,GL_SUN_vertex,GL_WIN_phong_shading,GL_WIN_specular_fog" 614 --profile="core" --api="gl=4.3" --generator="c" --spec="gl" --extensions="GL_3DFX_multisample,GL_3DFX_tbuffer,GL_3DFX_texture_compression_FXT1,GL_AMD_blend_minmax_factor,GL_AMD_conservative_depth,GL_AMD_debug_output,GL_AMD_depth_clamp_separate,GL_AMD_draw_buffers_blend,GL_AMD_framebuffer_multisample_advanced,GL_AMD_framebuffer_sample_positions,GL_AMD_gcn_shader,GL_AMD_gpu_shader_half_float,GL_AMD_gpu_shader_int16,GL_AMD_gpu_shader_int64,GL_AMD_interleaved_elements,GL_AMD_multi_draw_indirect,GL_AMD_name_gen_delete,GL_AMD_occlusion_query_event,GL_AMD_performance_monitor,GL_AMD_pinned_memory,GL_AMD_query_buffer_object,GL_AMD_sample_positions,GL_AMD_seamless_cubemap_per_texture,GL_AMD_shader_atomic_counter_ops,GL_AMD_shader_ballot,GL_AMD_shader_explicit_vertex_parameter,GL_AMD_shader_gpu_shader_half_float_fetch,GL_AMD_shader_image_load_store_lod,GL_AMD_shader_stencil_export,GL_AMD_shader_trinary_minmax,GL_AMD_sparse_texture,GL_AMD_stencil_operation_extended,GL_AMD_texture_gather_bias_lod,GL_AMD_texture_texture4,GL_AMD_transform_feedback3_lines_triangles,GL_AMD_transform_feedback4,GL_AMD_vertex_shader_layer,GL_AMD_vertex_shader_tessellator,GL_AMD_vertex_shader_viewport_index,GL_APPLE_aux_depth_stencil,GL_APPLE_client_storage,GL_APPLE_element_array,GL_APPLE_fence,GL_APPLE_float_pixels,GL_APPLE_flush_buffer_range,GL_APPLE_object_purgeable,GL_APPLE_rgb_422,GL_APPLE_row_bytes,GL_APPLE_specular_vector,GL_APPLE_texture_range,GL_APPLE_transform_hint,GL_APPLE_vertex_array_object,GL_APPLE_vertex_array_range,GL_APPLE_vertex_program_evaluators,GL_APPLE_ycbcr_422,GL_ARB_ES2_compatibility,GL_ARB_ES3_1_compatibility,GL_ARB_ES3_2_compatibility,GL_ARB_ES3_compatibility,GL_ARB_arrays_of_arrays,GL_ARB_base_instance,GL_ARB_bindless_texture,GL_ARB_blend_func_extended,GL_ARB_buffer_storage,GL_ARB_cl_event,GL_ARB_clear_buffer_object,GL_ARB_clear_texture,GL_ARB_clip_control,GL_ARB_color_buffer_float,GL_ARB_compatibility,GL_ARB_compressed_texture_pixel_storage,GL_ARB_compute_shader,GL_ARB_compute_variable_group_size,GL_ARB_conditional_render_inverted,GL_ARB_conservative_depth,GL_ARB_copy_buffer,GL_ARB_copy_image,GL_ARB_cull_distance,GL_ARB_debug_output,GL_ARB_depth_buffer_float,GL_ARB_depth_clamp,GL_ARB_depth_texture,GL_ARB_derivative_control,GL_ARB_direct_state_access,GL_ARB_draw_buffers,GL_ARB_draw_buffers_blend,GL_ARB_draw_elements_base_vertex,GL_ARB_draw_indirect,GL_ARB_draw_instanced,GL_ARB_enhanced_layouts,GL_ARB_explicit_attrib_location,GL_ARB_explicit_uniform_location,GL_ARB_fragment_coord_conventions,GL_ARB_fragment_layer_viewport,GL_ARB_fragment_program,GL_ARB_fragment_program_shadow,GL_ARB_fragment_shader,GL_ARB_fragment_shader_interlock,GL_ARB_framebuffer_no_attachments,GL_ARB_framebuffer_object,GL_ARB_framebuffer_sRGB,GL_ARB_geometry_shader4,GL_ARB_get_program_binary,GL_ARB_get_texture_sub_image,GL_ARB_gl_spirv,GL_ARB_gpu_shader5,GL_ARB_gpu_shader_fp64,GL_ARB_gpu_shader_int64,GL_ARB_half_float_pixel,GL_ARB_half_float_vertex,GL_ARB_imaging,GL_ARB_indirect_parameters,GL_ARB_instanced_arrays,GL_ARB_internalformat_query,GL_ARB_internalformat_query2,GL_ARB_invalidate_subdata,GL_ARB_map_buffer_alignment,GL_ARB_map_buffer_range,GL_ARB_matrix_palette,GL_ARB_multi_bind,GL_ARB_multi_draw_indirect,GL_ARB_multisample,GL_ARB_multitexture,GL_ARB_occlusion_query,GL_ARB_occlusion_query2,GL_ARB_parallel_shader_compile,GL_ARB_pipeline_statistics_query,GL_ARB_pixel_buffer_object,GL_ARB_point_parameters,GL_ARB_point_sprite,GL_ARB_polygon_offset_clamp,GL_ARB_post_depth_coverage,GL_ARB_program_interface_query,GL_ARB_provoking_vertex,GL_ARB_query_buffer_object,GL_ARB_robust_buffer_access_behavior,GL_ARB_robustness,GL_ARB_robustness_isolation,GL_ARB_sample_locations,GL_ARB_sample_shading,GL_ARB_sampler_objects,GL_ARB_seamless_cube_map,GL_ARB_seamless_cubemap_per_texture,GL_ARB_separate_shader_objects,GL_ARB_shader_atomic_counter_ops,GL_ARB_shader_atomic_counters,GL_ARB_shader_ballot,GL_ARB_shader_bit_encoding,GL_ARB_shader_clock,GL_ARB_shader_draw_parameters,GL_ARB_shader_group_vote,GL_ARB_shader_image_load_store,GL_ARB_shader_image_size,GL_ARB_shader_objects,GL_ARB_shader_precision,GL_ARB_shader_stencil_export,GL_ARB_shader_storage_buffer_object,GL_ARB_shader_subroutine,GL_ARB_shader_texture_image_samples,GL_ARB_shader_texture_lod,GL_ARB_shader_viewport_layer_array,GL_ARB_shading_language_100,GL_ARB_shading_language_420pack,GL_ARB_shading_language_include,GL_ARB_shading_language_packing,GL_ARB_shadow,GL_ARB_shadow_ambient,GL_ARB_sparse_buffer,GL_ARB_sparse_texture,GL_ARB_sparse_texture2,GL_ARB_sparse_texture_clamp,GL_ARB_spirv_extensions,GL_ARB_stencil_texturing,GL_ARB_sync,GL_ARB_tessellation_shader,GL_ARB_texture_barrier,GL_ARB_texture_border_clamp,GL_ARB_texture_buffer_object,GL_ARB_texture_buffer_object_rgb32,GL_ARB_texture_buffer_range,GL_ARB_texture_compression,GL_ARB_texture_compression_bptc,GL_ARB_texture_compression_rgtc,GL_ARB_texture_cube_map,GL_ARB_texture_cube_map_array,GL_ARB_texture_env_add,GL_ARB_texture_env_combine,GL_ARB_texture_env_crossbar,GL_ARB_texture_env_dot3,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_filter_minmax,GL_ARB_texture_float,GL_ARB_texture_gather,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_texture_mirrored_repeat,GL_ARB_texture_multisample,GL_ARB_texture_non_power_of_two,GL_ARB_texture_query_levels,GL_ARB_texture_query_lod,GL_ARB_texture_rectangle,GL_ARB_texture_rg,GL_ARB_texture_rgb10_a2ui,GL_ARB_texture_stencil8,GL_ARB_texture_storage,GL_ARB_texture_storage_multisample,GL_ARB_texture_swizzle,GL_ARB_texture_view,GL_ARB_timer_query,GL_ARB_transform_feedback2,GL_ARB_transform_feedback3,GL_ARB_transform_feedback_instanced,GL_ARB_transform_feedback_overflow_query,GL_ARB_transpose_matrix,GL_ARB_uniform_buffer_object,GL_ARB_vertex_array_bgra,GL_ARB_vertex_array_object,GL_ARB_vertex_attrib_64bit,GL_ARB_vertex_attrib_binding,GL_ARB_vertex_blend,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_ARB_vertex_type_10f_11f_11f_rev,GL_ARB_vertex_type_2_10_10_10_rev,GL_ARB_viewport_array,GL_ARB_window_pos,GL_ATI_draw_buffers,GL_ATI_element_array,GL_ATI_envmap_bumpmap,GL_ATI_fragment_shader,GL_ATI_map_object_buffer,GL_ATI_meminfo,GL_ATI_pixel_format_float,GL_ATI_pn_triangles,GL_ATI_separate_stencil,GL_ATI_text_fragment_shader,GL_ATI_texture_env_combine3,GL_ATI_texture_float,GL_ATI_texture_mirror_once,GL_ATI_vertex_array_object,GL_ATI_vertex_attrib_array_object,GL_ATI_vertex_streams,GL_EXT_422_pixels,GL_EXT_EGL_image_storage,GL_EXT_abgr,GL_EXT_bgra,GL_EXT_bindable_uniform,GL_EXT_blend_color,GL_EXT_blend_equation_separate,GL_EXT_blend_func_separate,GL_EXT_blend_logic_op,GL_EXT_blend_minmax,GL_EXT_blend_subtract,GL_EXT_clip_volume_hint,GL_EXT_cmyka,GL_EXT_color_subtable,GL_EXT_compiled_vertex_array,GL_EXT_convolution,GL_EXT_coordinate_frame,GL_EXT_copy_texture,GL_EXT_cull_vertex,GL_EXT_debug_label,GL_EXT_debug_marker,GL_EXT_depth_bounds_test,GL_EXT_direct_state_access,GL_EXT_draw_buffers2,GL_EXT_draw_instanced,GL_EXT_draw_range_elements,GL_EXT_external_buffer,GL_EXT_fog_coord,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_multisample_blit_scaled,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_geometry_shader4,GL_EXT_gpu_program_parameters,GL_EXT_gpu_shader4,GL_EXT_histogram,GL_EXT_index_array_formats,GL_EXT_index_func,GL_EXT_index_material,GL_EXT_index_texture,GL_EXT_light_texture,GL_EXT_memory_object,GL_EXT_memory_object_fd,GL_EXT_memory_object_win32,GL_EXT_misc_attribute,GL_EXT_multi_draw_arrays,GL_EXT_multisample,GL_EXT_packed_depth_stencil,GL_EXT_packed_float,GL_EXT_packed_pixels,GL_EXT_paletted_texture,GL_EXT_pixel_buffer_object,GL_EXT_pixel_transform,GL_EXT_pixel_transform_color_table,GL_EXT_point_parameters,GL_EXT_polygon_offset,GL_EXT_polygon_offset_clamp,GL_EXT_post_depth_coverage,GL_EXT_provoking_vertex,GL_EXT_raster_multisample,GL_EXT_rescale_normal,GL_EXT_secondary_color,GL_EXT_semaphore,GL_EXT_semaphore_fd,GL_EXT_semaphore_win32,GL_EXT_separate_shader_objects,GL_EXT_separate_specular_color,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_framebuffer_fetch_non_coherent,GL_EXT_shader_image_load_formatted,GL_EXT_shader_image_load_store,GL_EXT_shader_integer_mix,GL_EXT_shadow_funcs,GL_EXT_shared_texture_palette,GL_EXT_sparse_texture2,GL_EXT_stencil_clear_tag,GL_EXT_stencil_two_side,GL_EXT_stencil_wrap,GL_EXT_subtexture,GL_EXT_texture,GL_EXT_texture3D,GL_EXT_texture_array,GL_EXT_texture_buffer_object,GL_EXT_texture_compression_latc,GL_EXT_texture_compression_rgtc,GL_EXT_texture_compression_s3tc,GL_EXT_texture_cube_map,GL_EXT_texture_env_add,GL_EXT_texture_env_combine,GL_EXT_texture_env_dot3,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_filter_minmax,GL_EXT_texture_integer,GL_EXT_texture_lod_bias,GL_EXT_texture_mirror_clamp,GL_EXT_texture_object,GL_EXT_texture_perturb_normal,GL_EXT_texture_sRGB,GL_EXT_texture_sRGB_decode,GL_EXT_texture_shared_exponent,GL_EXT_texture_snorm,GL_EXT_texture_swizzle,GL_EXT_timer_query,GL_EXT_transform_feedback,GL_EXT_vertex_array,GL_EXT_vertex_array_bgra,GL_EXT_vertex_attrib_64bit,GL_EXT_vertex_shader,GL_EXT_vertex_weighting,GL_EXT_win32_keyed_mutex,GL_EXT_window_rectangles,GL_EXT_x11_sync_object,GL_GREMEDY_frame_terminator,GL_GREMEDY_string_marker,GL_HP_convolution_border_modes,GL_HP_image_transform,GL_HP_occlusion_test,GL_HP_texture_lighting,GL_IBM_cull_vertex,GL_IBM_multimode_draw_arrays,GL_IBM_rasterpos_clip,GL_IBM_static_data,GL_IBM_texture_mirrored_repeat,GL_IBM_vertex_array_lists,GL_INGR_blend_func_separate,GL_INGR_color_clamp,GL_INGR_interlace_read,GL_INTEL_blackhole_render,GL_INTEL_conservative_rasterization,GL_INTEL_fragment_shader_ordering,GL_INTEL_framebuffer_CMAA,GL_INTEL_map_texture,GL_INTEL_parallel_arrays,GL_INTEL_performance_query,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_context_flush_control,GL_KHR_debug,GL_KHR_no_error,GL_KHR_parallel_shader_compile,GL_KHR_robust_buffer_access_behavior,GL_KHR_robustness,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_KHR_texture_compression_astc_sliced_3d,GL_MESAX_texture_stack,GL_MESA_pack_invert,GL_MESA_program_binary_formats,GL_MESA_resize_buffers,GL_MESA_shader_integer_functions,GL_MESA_tile_raster_order,GL_MESA_window_pos,GL_MESA_ycbcr_texture,GL_NVX_blend_equation_advanced_multi_draw_buffers,GL_NVX_conditional_render,GL_NVX_gpu_memory_info,GL_NVX_linked_gpu_multicast,GL_NV_alpha_to_coverage_dither_control,GL_NV_bindless_multi_draw_indirect,GL_NV_bindless_multi_draw_indirect_count,GL_NV_bindless_texture,GL_NV_blend_equation_advanced,GL_NV_blend_equation_advanced_coherent,GL_NV_blend_minmax_factor,GL_NV_blend_square,GL_NV_clip_space_w_scaling,GL_NV_command_list,GL_NV_compute_program5,GL_NV_compute_shader_derivatives,GL_NV_conditional_render,GL_NV_conservative_raster,GL_NV_conservative_raster_dilate,GL_NV_conservative_raster_pre_snap,GL_NV_conservative_raster_pre_snap_triangles,GL_NV_conservative_raster_underestimation,GL_NV_copy_depth_to_color,GL_NV_copy_image,GL_NV_deep_texture3D,GL_NV_depth_buffer_float,GL_NV_depth_clamp,GL_NV_draw_texture,GL_NV_draw_vulkan_image,GL_NV_evaluators,GL_NV_explicit_multisample,GL_NV_fence,GL_NV_fill_rectangle,GL_NV_float_buffer,GL_NV_fog_distance,GL_NV_fragment_coverage_to_color,GL_NV_fragment_program,GL_NV_fragment_program2,GL_NV_fragment_program4,GL_NV_fragment_program_option,GL_NV_fragment_shader_barycentric,GL_NV_fragment_shader_interlock,GL_NV_framebuffer_mixed_samples,GL_NV_framebuffer_multisample_coverage,GL_NV_geometry_program4,GL_NV_geometry_shader4,GL_NV_geometry_shader_passthrough,GL_NV_gpu_multicast,GL_NV_gpu_program4,GL_NV_gpu_program5,GL_NV_gpu_program5_mem_extended,GL_NV_gpu_shader5,GL_NV_half_float,GL_NV_internalformat_sample_query,GL_NV_light_max_exponent,GL_NV_memory_attachment,GL_NV_mesh_shader,GL_NV_multisample_coverage,GL_NV_multisample_filter_hint,GL_NV_occlusion_query,GL_NV_packed_depth_stencil,GL_NV_parameter_buffer_object,GL_NV_parameter_buffer_object2,GL_NV_path_rendering,GL_NV_path_rendering_shared_edge,GL_NV_pixel_data_range,GL_NV_point_sprite,GL_NV_present_video,GL_NV_primitive_restart,GL_NV_query_resource,GL_NV_query_resource_tag,GL_NV_register_combiners,GL_NV_register_combiners2,GL_NV_representative_fragment_test,GL_NV_robustness_video_memory_purge,GL_NV_sample_locations,GL_NV_sample_mask_override_coverage,GL_NV_scissor_exclusive,GL_NV_shader_atomic_counters,GL_NV_shader_atomic_float,GL_NV_shader_atomic_float64,GL_NV_shader_atomic_fp16_vector,GL_NV_shader_atomic_int64,GL_NV_shader_buffer_load,GL_NV_shader_buffer_store,GL_NV_shader_storage_buffer_object,GL_NV_shader_texture_footprint,GL_NV_shader_thread_group,GL_NV_shader_thread_shuffle,GL_NV_shading_rate_image,GL_NV_stereo_view_rendering,GL_NV_tessellation_program5,GL_NV_texgen_emboss,GL_NV_texgen_reflection,GL_NV_texture_barrier,GL_NV_texture_compression_vtc,GL_NV_texture_env_combine4,GL_NV_texture_expand_normal,GL_NV_texture_multisample,GL_NV_texture_rectangle,GL_NV_texture_rectangle_compressed,GL_NV_texture_shader,GL_NV_texture_shader2,GL_NV_texture_shader3,GL_NV_transform_feedback,GL_NV_transform_feedback2,GL_NV_uniform_buffer_unified_memory,GL_NV_vdpau_interop,GL_NV_vdpau_interop2,GL_NV_vertex_array_range,GL_NV_vertex_array_range2,GL_NV_vertex_attrib_integer_64bit,GL_NV_vertex_buffer_unified_memory,GL_NV_vertex_program,GL_NV_vertex_program1_1,GL_NV_vertex_program2,GL_NV_vertex_program2_option,GL_NV_vertex_program3,GL_NV_vertex_program4,GL_NV_video_capture,GL_NV_viewport_array2,GL_NV_viewport_swizzle,GL_OES_byte_coordinates,GL_OES_compressed_paletted_texture,GL_OES_fixed_point,GL_OES_query_matrix,GL_OES_read_format,GL_OES_single_precision,GL_OML_interlace,GL_OML_resample,GL_OML_subsample,GL_OVR_multiview,GL_OVR_multiview2,GL_PGI_misc_hints,GL_PGI_vertex_hints,GL_REND_screen_coordinates,GL_S3_s3tc,GL_SGIS_detail_texture,GL_SGIS_fog_function,GL_SGIS_generate_mipmap,GL_SGIS_multisample,GL_SGIS_pixel_texture,GL_SGIS_point_line_texgen,GL_SGIS_point_parameters,GL_SGIS_sharpen_texture,GL_SGIS_texture4D,GL_SGIS_texture_border_clamp,GL_SGIS_texture_color_mask,GL_SGIS_texture_edge_clamp,GL_SGIS_texture_filter4,GL_SGIS_texture_lod,GL_SGIS_texture_select,GL_SGIX_async,GL_SGIX_async_histogram,GL_SGIX_async_pixel,GL_SGIX_blend_alpha_minmax,GL_SGIX_calligraphic_fragment,GL_SGIX_clipmap,GL_SGIX_convolution_accuracy,GL_SGIX_depth_pass_instrument,GL_SGIX_depth_texture,GL_SGIX_flush_raster,GL_SGIX_fog_offset,GL_SGIX_fragment_lighting,GL_SGIX_framezoom,GL_SGIX_igloo_interface,GL_SGIX_instruments,GL_SGIX_interlace,GL_SGIX_ir_instrument1,GL_SGIX_list_priority,GL_SGIX_pixel_texture,GL_SGIX_pixel_tiles,GL_SGIX_polynomial_ffd,GL_SGIX_reference_plane,GL_SGIX_resample,GL_SGIX_scalebias_hint,GL_SGIX_shadow,GL_SGIX_shadow_ambient,GL_SGIX_sprite,GL_SGIX_subsample,GL_SGIX_tag_sample_buffer,GL_SGIX_texture_add_env,GL_SGIX_texture_coordinate_clamp,GL_SGIX_texture_lod_bias,GL_SGIX_texture_multi_buffer,GL_SGIX_texture_scale_bias,GL_SGIX_vertex_preclip,GL_SGIX_ycrcb,GL_SGIX_ycrcb_subsample,GL_SGIX_ycrcba,GL_SGI_color_matrix,GL_SGI_color_table,GL_SGI_texture_color_table,GL_SUNX_constant_data,GL_SUN_convolution_border_modes,GL_SUN_global_alpha,GL_SUN_mesh_array,GL_SUN_slice_accum,GL_SUN_triangle_list,GL_SUN_vertex,GL_WIN_phong_shading,GL_WIN_specular_fog"
605 Online: 615 Online:
606 Too many extensions 616 Too many extensions
607*/ 617*/
@@ -663,7 +673,7 @@ void close_gl(void) {
663#include <dlfcn.h> 673#include <dlfcn.h>
664static void* libGL; 674static void* libGL;
665 675
666#ifndef __APPLE__ 676#if !defined(__APPLE__) && !defined(__HAIKU__)
667typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); 677typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*);
668static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; 678static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
669#endif 679#endif
@@ -686,7 +696,7 @@ int open_gl(void) {
686 libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL); 696 libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL);
687 697
688 if(libGL != NULL) { 698 if(libGL != NULL) {
689#ifdef __APPLE__ 699#if defined(__APPLE__) || defined(__HAIKU__)
690 return 1; 700 return 1;
691#else 701#else
692 gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, 702 gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL,
@@ -713,7 +723,7 @@ void* get_proc(const char *namez) {
713 void* result = NULL; 723 void* result = NULL;
714 if(libGL == NULL) return NULL; 724 if(libGL == NULL) return NULL;
715 725
716#ifndef __APPLE__ 726#if !defined(__APPLE__) && !defined(__HAIKU__)
717 if(gladGetProcAddressPtr != NULL) { 727 if(gladGetProcAddressPtr != NULL) {
718 result = gladGetProcAddressPtr(namez); 728 result = gladGetProcAddressPtr(namez);
719 } 729 }
@@ -765,7 +775,11 @@ static int get_exts(void) {
765 num_exts_i = 0; 775 num_exts_i = 0;
766 glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); 776 glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i);
767 if (num_exts_i > 0) { 777 if (num_exts_i > 0) {
768 exts_i = (char **)realloc((void *)exts_i, (size_t)num_exts_i * (sizeof *exts_i)); 778 char **tmp_exts_i = (char **)realloc((void *)exts_i, (size_t)num_exts_i * (sizeof *exts_i));
779 if (tmp_exts_i == NULL) {
780 return 0;
781 }
782 exts_i = tmp_exts_i;
769 } 783 }
770 784
771 if (exts_i == NULL) { 785 if (exts_i == NULL) {
@@ -851,969 +865,1172 @@ int GLAD_GL_VERSION_3_0 = 0;
851int GLAD_GL_VERSION_3_1 = 0; 865int GLAD_GL_VERSION_3_1 = 0;
852int GLAD_GL_VERSION_3_2 = 0; 866int GLAD_GL_VERSION_3_2 = 0;
853int GLAD_GL_VERSION_3_3 = 0; 867int GLAD_GL_VERSION_3_3 = 0;
854PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; 868int GLAD_GL_VERSION_4_0 = 0;
855PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; 869int GLAD_GL_VERSION_4_1 = 0;
856PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; 870int GLAD_GL_VERSION_4_2 = 0;
857PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; 871int GLAD_GL_VERSION_4_3 = 0;
858PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; 872PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL;
859PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL; 873PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
860PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; 874PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
875PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;
876PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;
877PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL;
878PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
879PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
880PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
881PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
882PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
883PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;
884PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;
885PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
886PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture = NULL;
887PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL;
888PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
861PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL; 889PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
862PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; 890PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
863PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL; 891PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;
864PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; 892PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
865PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; 893PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer = NULL;
866PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; 894PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
867PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; 895PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
868PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL; 896PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
869PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL; 897PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL;
870PFNGLENABLEIPROC glad_glEnablei = NULL; 898PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL;
871PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL; 899PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
872PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
873PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
874PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
875PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
876PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
877PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
878PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
879PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; 900PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
880PFNGLHINTPROC glad_glHint = NULL; 901PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL;
881PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; 902PFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL;
882PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; 903PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
883PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL; 904PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
884PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; 905PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
885PFNGLPOINTSIZEPROC glad_glPointSize = NULL; 906PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
886PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; 907PFNGLCLAMPCOLORPROC glad_glClampColor = NULL;
887PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; 908PFNGLCLEARPROC glad_glClear = NULL;
888PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; 909PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData = NULL;
889PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; 910PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData = NULL;
890PFNGLWAITSYNCPROC glad_glWaitSync = NULL; 911PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;
891PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
892PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
893PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; 912PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;
894PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; 913PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;
895PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; 914PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
896PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; 915PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
897PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL; 916PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
917PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
918PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
919PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
920PFNGLCOLORMASKPROC glad_glColorMask = NULL;
898PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; 921PFNGLCOLORMASKIPROC glad_glColorMaski = NULL;
899PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; 922PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL;
900PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; 923PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL;
901PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL; 924PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL;
902PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL; 925PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL;
903PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL; 926PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
904PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; 927PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;
905PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; 928PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
906PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL; 929PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
930PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;
931PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
932PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
933PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
934PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL;
935PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;
936PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
937PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;
938PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
939PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
940PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
941PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
942PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL;
943PFNGLCULLFACEPROC glad_glCullFace = NULL;
944PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL;
945PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL;
946PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL;
947PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
907PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; 948PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
949PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
950PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL;
951PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
952PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
953PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
954PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
955PFNGLDELETESYNCPROC glad_glDeleteSync = NULL;
956PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
957PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL;
958PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
959PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
960PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
961PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
962PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL;
963PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL;
964PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
965PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
966PFNGLDISABLEPROC glad_glDisable = NULL;
967PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
968PFNGLDISABLEIPROC glad_glDisablei = NULL;
969PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL;
970PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect = NULL;
908PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; 971PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
909PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; 972PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL;
910PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; 973PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;
911PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL; 974PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance = NULL;
912PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; 975PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;
913PFNGLCLEARPROC glad_glClear = NULL; 976PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
914PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL; 977PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
915PFNGLISENABLEDPROC glad_glIsEnabled = NULL; 978PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;
916PFNGLSTENCILOPPROC glad_glStencilOp = NULL; 979PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL;
980PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
981PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance = NULL;
982PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;
983PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance = NULL;
984PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
985PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;
986PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL;
987PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced = NULL;
988PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL;
989PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced = NULL;
990PFNGLENABLEPROC glad_glEnable = NULL;
991PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
992PFNGLENABLEIPROC glad_glEnablei = NULL;
993PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;
994PFNGLENDQUERYPROC glad_glEndQuery = NULL;
995PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL;
996PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
997PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
998PFNGLFINISHPROC glad_glFinish = NULL;
999PFNGLFLUSHPROC glad_glFlush = NULL;
1000PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
1001PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = NULL;
1002PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
1003PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
1004PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;
917PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; 1005PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
918PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; 1006PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;
919PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; 1007PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
920PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; 1008PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
921PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; 1009PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
922PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
923PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;
924PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
925PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; 1010PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
1011PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL;
1012PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
1013PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
1014PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;
1015PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
1016PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;
1017PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
1018PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
1019PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv = NULL;
1020PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
1021PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL;
1022PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL;
1023PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL;
1024PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
1025PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
1026PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
1027PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;
1028PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
926PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; 1029PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
927PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; 1030PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
928PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; 1031PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;
929PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; 1032PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
930PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; 1033PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;
1034PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
1035PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
1036PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;
1037PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
1038PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL;
1039PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL;
1040PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;
1041PFNGLGETERRORPROC glad_glGetError = NULL;
1042PFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL;
1043PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
1044PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;
1045PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;
1046PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
1047PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv = NULL;
1048PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
1049PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;
1050PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;
1051PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
1052PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v = NULL;
1053PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL;
1054PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
1055PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL;
1056PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL;
1057PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;
1058PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL;
1059PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
1060PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv = NULL;
1061PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL;
1062PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL;
1063PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex = NULL;
1064PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation = NULL;
1065PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex = NULL;
1066PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL;
1067PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL;
1068PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL;
1069PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
1070PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL;
1071PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
1072PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
1073PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;
1074PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
931PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; 1075PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
1076PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
1077PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;
1078PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;
932PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL; 1079PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;
1080PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;
1081PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
1082PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;
1083PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
1084PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
1085PFNGLGETSTRINGPROC glad_glGetString = NULL;
1086PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
1087PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL;
1088PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL;
1089PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;
1090PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;
1091PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;
1092PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;
1093PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;
1094PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
1095PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
1096PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
1097PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
1098PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
933PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL; 1099PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
934PFNGLISSHADERPROC glad_glIsShader = NULL; 1100PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
935PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; 1101PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL;
936PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; 1102PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL;
937PFNGLENABLEPROC glad_glEnable = NULL;
938PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
939PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
940PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;
941PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL;
942PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;
943PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; 1103PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
1104PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
944PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; 1105PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
945PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; 1106PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
946PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; 1107PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
947PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; 1108PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL;
948PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
949PFNGLFLUSHPROC glad_glFlush = NULL;
950PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
951PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; 1109PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
952PFNGLFENCESYNCPROC glad_glFenceSync = NULL; 1110PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;
953PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL; 1111PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
954PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; 1112PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
955PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; 1113PFNGLHINTPROC glad_glHint = NULL;
956PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; 1114PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData = NULL;
957PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL; 1115PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData = NULL;
958PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; 1116PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL;
959PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL; 1117PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL;
960PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; 1118PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage = NULL;
961PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; 1119PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage = NULL;
962PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; 1120PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
963PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL; 1121PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
964PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
965PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
966PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;
967PFNGLISSYNCPROC glad_glIsSync = NULL;
968PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
969PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
970PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
971PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL;
972PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
973PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
974PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
975PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
976PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
977PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;
978PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
979PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
980PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
981PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
982PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
983PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; 1122PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;
984PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL; 1123PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
985PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL; 1124PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
986PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; 1125PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL;
987PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; 1126PFNGLISQUERYPROC glad_glIsQuery = NULL;
988PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; 1127PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
989PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; 1128PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
990PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; 1129PFNGLISSHADERPROC glad_glIsShader = NULL;
991PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; 1130PFNGLISSYNCPROC glad_glIsSync = NULL;
992PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; 1131PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
993PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; 1132PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL;
994PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; 1133PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;
995PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; 1134PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
996PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL; 1135PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
997PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; 1136PFNGLLOGICOPPROC glad_glLogicOp = NULL;
998PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
999PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; 1137PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;
1000PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; 1138PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
1001PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; 1139PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL;
1002PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; 1140PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL;
1003PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; 1141PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
1142PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect = NULL;
1004PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; 1143PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;
1005PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
1006PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
1007PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
1008PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
1009PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
1010PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
1011PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
1012PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
1013PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
1014PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;
1015PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL; 1144PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;
1016PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; 1145PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect = NULL;
1017PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; 1146PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL;
1018PFNGLFINISHPROC glad_glFinish = NULL; 1147PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL;
1019PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; 1148PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL;
1020PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;
1021PFNGLVIEWPORTPROC glad_glViewport = NULL;
1022PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
1023PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
1024PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
1025PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;
1026PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
1027PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;
1028PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
1029PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
1030PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
1031PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;
1032PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
1033PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
1034PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;
1035PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;
1036PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL; 1149PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL;
1037PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL; 1150PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL;
1038PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; 1151PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL;
1039PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; 1152PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL;
1040PFNGLGETSTRINGPROC glad_glGetString = NULL; 1153PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL;
1041PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;
1042PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
1043PFNGLENDQUERYPROC glad_glEndQuery = NULL;
1044PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL; 1154PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL;
1045PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;
1046PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
1047PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
1048PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
1049PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL; 1155PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL;
1050PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; 1156PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL;
1051PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; 1157PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL;
1052PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; 1158PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL;
1053PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; 1159PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL;
1054PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL; 1160PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL;
1161PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;
1162PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
1163PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;
1164PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
1165PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;
1166PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;
1167PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
1168PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
1169PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
1170PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL;
1171PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;
1172PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL;
1173PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL;
1174PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL;
1175PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL;
1176PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL;
1177PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL;
1178PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL;
1179PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL;
1180PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL;
1181PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL;
1182PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL;
1183PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL;
1184PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL;
1185PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL;
1186PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL;
1187PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL;
1188PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL;
1189PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL;
1190PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL;
1191PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL;
1192PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL;
1193PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL;
1194PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL;
1195PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL;
1196PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL;
1197PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL;
1198PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL;
1199PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL;
1200PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL;
1201PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL;
1202PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL;
1203PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL;
1204PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL;
1205PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL;
1206PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL;
1207PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL;
1208PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL;
1209PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL;
1210PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL;
1211PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL;
1212PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL;
1213PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL;
1214PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL;
1215PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL;
1216PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL;
1217PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL;
1218PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL;
1219PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL;
1220PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL;
1221PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL;
1222PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL;
1223PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL;
1224PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;
1225PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL;
1226PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;
1227PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
1228PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
1229PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;
1230PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
1231PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
1232PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;
1055PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; 1233PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
1056PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL; 1234PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;
1235PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;
1236PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;
1057PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL; 1237PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;
1238PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;
1239PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;
1240PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;
1241PFNGLSCISSORPROC glad_glScissor = NULL;
1242PFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL;
1243PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL;
1244PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL;
1245PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL;
1246PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL;
1247PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;
1248PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
1249PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding = NULL;
1250PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
1251PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
1252PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
1253PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
1254PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
1255PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
1256PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;
1257PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange = NULL;
1258PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL;
1259PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL;
1260PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL;
1261PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL;
1262PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL;
1263PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL;
1264PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL;
1265PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL;
1266PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;
1267PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
1268PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;
1269PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;
1270PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;
1271PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;
1272PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;
1273PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
1274PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
1275PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
1276PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
1277PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D = NULL;
1278PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL;
1279PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample = NULL;
1280PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL;
1281PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL;
1282PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;
1283PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
1284PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
1285PFNGLTEXTUREVIEWPROC glad_glTextureView = NULL;
1286PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
1287PFNGLUNIFORM1DPROC glad_glUniform1d = NULL;
1288PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL;
1058PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; 1289PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
1059PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; 1290PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
1060PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
1061PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; 1291PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
1062PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
1063PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
1064PFNGLDISABLEPROC glad_glDisable = NULL;
1065PFNGLLOGICOPPROC glad_glLogicOp = NULL;
1066PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
1067PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
1068PFNGLCULLFACEPROC glad_glCullFace = NULL;
1069PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
1070PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
1071PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;
1072PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;
1073PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
1074PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;
1075PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; 1292PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
1076PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; 1293PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;
1077PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; 1294PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
1078PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; 1295PFNGLUNIFORM2DPROC glad_glUniform2d = NULL;
1079PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL; 1296PFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL;
1080PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; 1297PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
1081PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL; 1298PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
1082PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; 1299PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
1083PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; 1300PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
1084PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; 1301PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
1085PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; 1302PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;
1086PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL; 1303PFNGLUNIFORM3DPROC glad_glUniform3d = NULL;
1087PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; 1304PFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL;
1088PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; 1305PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
1089PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; 1306PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
1090PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; 1307PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
1091PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL; 1308PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
1092PFNGLISPROGRAMPROC glad_glIsProgram = NULL; 1309PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
1093PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; 1310PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
1094PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; 1311PFNGLUNIFORM4DPROC glad_glUniform4d = NULL;
1095PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; 1312PFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL;
1096PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
1097PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
1098PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
1099PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;
1100PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; 1313PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
1101PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; 1314PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
1102PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; 1315PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
1103PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL; 1316PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
1104PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; 1317PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
1318PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;
1105PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL; 1319PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;
1106PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL; 1320PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL;
1107PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; 1321PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
1108PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; 1322PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL;
1109PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; 1323PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
1110PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; 1324PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL;
1111PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; 1325PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;
1112PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; 1326PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL;
1113PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; 1327PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
1328PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL;
1329PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;
1330PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL;
1331PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;
1332PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL;
1333PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
1334PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL;
1335PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
1336PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL;
1337PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
1338PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL;
1339PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
1340PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
1341PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL;
1342PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
1343PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL;
1344PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;
1345PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
1346PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
1347PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
1348PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;
1349PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;
1350PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;
1351PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;
1352PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
1353PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
1354PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;
1114PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; 1355PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;
1115PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; 1356PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;
1116PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; 1357PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;
1117PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; 1358PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
1118PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; 1359PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
1119PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; 1360PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;
1120PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; 1361PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;
1121PFNGLSCISSORPROC glad_glScissor = NULL; 1362PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;
1122PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL;
1123PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
1124PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL;
1125PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
1126PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
1127PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; 1363PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;
1128PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; 1364PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;
1129PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL; 1365PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;
1130PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL; 1366PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;
1131PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; 1367PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;
1132PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
1133PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
1134PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
1135PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
1136PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;
1137PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
1138PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
1139PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
1140PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; 1368PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;
1141PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; 1369PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;
1142PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; 1370PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;
1143PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; 1371PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;
1144PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; 1372PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
1145PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL; 1373PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
1146PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; 1374PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;
1147PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; 1375PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;
1148PFNGLCOLORMASKPROC glad_glColorMask = NULL; 1376PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;
1149PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; 1377PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;
1150PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; 1378PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;
1151PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
1152PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
1153PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; 1379PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;
1154PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; 1380PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding = NULL;
1155PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
1156PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;
1157PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
1158PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL;
1159PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL; 1381PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;
1160PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; 1382PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat = NULL;
1161PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; 1383PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;
1162PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL; 1384PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;
1163PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; 1385PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;
1164PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; 1386PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;
1165PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL; 1387PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;
1166PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
1167PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
1168PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
1169PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
1170PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
1171PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
1172PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
1173PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;
1174PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
1175PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
1176PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
1177PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
1178PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; 1388PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;
1179PFNGLDISABLEIPROC glad_glDisablei = NULL; 1389PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;
1180PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; 1390PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;
1181PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; 1391PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;
1392PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;
1393PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;
1182PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; 1394PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;
1183PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; 1395PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;
1184PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL; 1396PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;
1185PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; 1397PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;
1186PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; 1398PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;
1187PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; 1399PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;
1188PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; 1400PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;
1189PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; 1401PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
1190PFNGLBUFFERDATAPROC glad_glBufferData = NULL; 1402PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;
1191PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; 1403PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat = NULL;
1192PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL; 1404PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;
1193PFNGLGETERRORPROC glad_glGetError = NULL; 1405PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL;
1406PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL;
1407PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL;
1408PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL;
1409PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL;
1410PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL;
1411PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL;
1412PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL;
1413PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat = NULL;
1414PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL;
1415PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;
1416PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;
1194PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL; 1417PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;
1195PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; 1418PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;
1196PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; 1419PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;
1197PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
1198PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;
1199PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;
1200PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL; 1420PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;
1201PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL; 1421PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;
1202PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; 1422PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;
1203PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; 1423PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
1204PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; 1424PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor = NULL;
1205PFNGLISQUERYPROC glad_glIsQuery = NULL; 1425PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL;
1206PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; 1426PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL;
1207PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; 1427PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL;
1208PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; 1428PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL;
1209PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL; 1429PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL;
1210PFNGLISTEXTUREPROC glad_glIsTexture = NULL; 1430PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
1211PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; 1431PFNGLVIEWPORTPROC glad_glViewport = NULL;
1212PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; 1432PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL;
1213PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; 1433PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;
1214PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL; 1434PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
1215PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL; 1435PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
1216PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; 1436int GLAD_GL_3DFX_multisample = 0;
1217PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; 1437int GLAD_GL_3DFX_tbuffer = 0;
1218PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; 1438int GLAD_GL_3DFX_texture_compression_FXT1 = 0;
1219PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; 1439int GLAD_GL_AMD_blend_minmax_factor = 0;
1220PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; 1440int GLAD_GL_AMD_conservative_depth = 0;
1221PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; 1441int GLAD_GL_AMD_debug_output = 0;
1222PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; 1442int GLAD_GL_AMD_depth_clamp_separate = 0;
1223PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; 1443int GLAD_GL_AMD_draw_buffers_blend = 0;
1224PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL; 1444int GLAD_GL_AMD_framebuffer_multisample_advanced = 0;
1225PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; 1445int GLAD_GL_AMD_framebuffer_sample_positions = 0;
1226PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; 1446int GLAD_GL_AMD_gcn_shader = 0;
1227PFNGLFRONTFACEPROC glad_glFrontFace = NULL; 1447int GLAD_GL_AMD_gpu_shader_half_float = 0;
1228int GLAD_GL_SGIX_pixel_tiles = 0; 1448int GLAD_GL_AMD_gpu_shader_int16 = 0;
1229int GLAD_GL_EXT_post_depth_coverage = 0; 1449int GLAD_GL_AMD_gpu_shader_int64 = 0;
1230int GLAD_GL_APPLE_element_array = 0; 1450int GLAD_GL_AMD_interleaved_elements = 0;
1231int GLAD_GL_AMD_multi_draw_indirect = 0; 1451int GLAD_GL_AMD_multi_draw_indirect = 0;
1232int GLAD_GL_EXT_blend_subtract = 0; 1452int GLAD_GL_AMD_name_gen_delete = 0;
1233int GLAD_GL_SGIX_tag_sample_buffer = 0; 1453int GLAD_GL_AMD_occlusion_query_event = 0;
1234int GLAD_GL_NV_point_sprite = 0; 1454int GLAD_GL_AMD_performance_monitor = 0;
1235int GLAD_GL_IBM_texture_mirrored_repeat = 0; 1455int GLAD_GL_AMD_pinned_memory = 0;
1236int GLAD_GL_APPLE_transform_hint = 0; 1456int GLAD_GL_AMD_query_buffer_object = 0;
1237int GLAD_GL_ATI_separate_stencil = 0; 1457int GLAD_GL_AMD_sample_positions = 0;
1238int GLAD_GL_NV_shader_atomic_int64 = 0; 1458int GLAD_GL_AMD_seamless_cubemap_per_texture = 0;
1239int GLAD_GL_EXT_semaphore_win32 = 0; 1459int GLAD_GL_AMD_shader_atomic_counter_ops = 0;
1240int GLAD_GL_NV_vertex_program2_option = 0; 1460int GLAD_GL_AMD_shader_ballot = 0;
1241int GLAD_GL_EXT_texture_buffer_object = 0; 1461int GLAD_GL_AMD_shader_explicit_vertex_parameter = 0;
1242int GLAD_GL_ARB_vertex_blend = 0;
1243int GLAD_GL_OVR_multiview = 0;
1244int GLAD_GL_AMD_shader_gpu_shader_half_float_fetch = 0; 1462int GLAD_GL_AMD_shader_gpu_shader_half_float_fetch = 0;
1245int GLAD_GL_NV_vertex_program2 = 0; 1463int GLAD_GL_AMD_shader_image_load_store_lod = 0;
1246int GLAD_GL_ARB_program_interface_query = 0; 1464int GLAD_GL_AMD_shader_stencil_export = 0;
1247int GLAD_GL_EXT_misc_attribute = 0; 1465int GLAD_GL_AMD_shader_trinary_minmax = 0;
1248int GLAD_GL_NV_multisample_coverage = 0; 1466int GLAD_GL_AMD_sparse_texture = 0;
1249int GLAD_GL_ARB_shading_language_packing = 0; 1467int GLAD_GL_AMD_stencil_operation_extended = 0;
1250int GLAD_GL_EXT_texture_cube_map = 0; 1468int GLAD_GL_AMD_texture_gather_bias_lod = 0;
1251int GLAD_GL_NV_viewport_array2 = 0; 1469int GLAD_GL_AMD_texture_texture4 = 0;
1252int GLAD_GL_ARB_texture_stencil8 = 0; 1470int GLAD_GL_AMD_transform_feedback3_lines_triangles = 0;
1253int GLAD_GL_EXT_index_func = 0; 1471int GLAD_GL_AMD_transform_feedback4 = 0;
1254int GLAD_GL_EXT_memory_object_fd = 0; 1472int GLAD_GL_AMD_vertex_shader_layer = 0;
1255int GLAD_GL_OES_compressed_paletted_texture = 0; 1473int GLAD_GL_AMD_vertex_shader_tessellator = 0;
1256int GLAD_GL_MESA_shader_integer_functions = 0; 1474int GLAD_GL_AMD_vertex_shader_viewport_index = 0;
1257int GLAD_GL_NV_shader_buffer_load = 0; 1475int GLAD_GL_APPLE_aux_depth_stencil = 0;
1258int GLAD_GL_EXT_color_subtable = 0; 1476int GLAD_GL_APPLE_client_storage = 0;
1259int GLAD_GL_SUNX_constant_data = 0; 1477int GLAD_GL_APPLE_element_array = 0;
1260int GLAD_GL_EXT_texture_compression_s3tc = 0; 1478int GLAD_GL_APPLE_fence = 0;
1261int GLAD_GL_EXT_multi_draw_arrays = 0; 1479int GLAD_GL_APPLE_float_pixels = 0;
1262int GLAD_GL_ARB_shader_atomic_counters = 0; 1480int GLAD_GL_APPLE_flush_buffer_range = 0;
1263int GLAD_GL_ARB_arrays_of_arrays = 0; 1481int GLAD_GL_APPLE_object_purgeable = 0;
1264int GLAD_GL_NV_conditional_render = 0; 1482int GLAD_GL_APPLE_rgb_422 = 0;
1265int GLAD_GL_EXT_texture_env_combine = 0; 1483int GLAD_GL_APPLE_row_bytes = 0;
1266int GLAD_GL_NV_fog_distance = 0; 1484int GLAD_GL_APPLE_specular_vector = 0;
1267int GLAD_GL_SGIX_async_histogram = 0;
1268int GLAD_GL_MESA_resize_buffers = 0;
1269int GLAD_GL_NV_light_max_exponent = 0;
1270int GLAD_GL_NV_texture_env_combine4 = 0;
1271int GLAD_GL_ARB_spirv_extensions = 0;
1272int GLAD_GL_ARB_texture_view = 0;
1273int GLAD_GL_ARB_texture_env_combine = 0;
1274int GLAD_GL_ARB_map_buffer_range = 0;
1275int GLAD_GL_EXT_convolution = 0;
1276int GLAD_GL_NV_compute_program5 = 0;
1277int GLAD_GL_NV_vertex_attrib_integer_64bit = 0;
1278int GLAD_GL_EXT_paletted_texture = 0;
1279int GLAD_GL_ARB_texture_buffer_object = 0;
1280int GLAD_GL_ATI_pn_triangles = 0;
1281int GLAD_GL_SGIX_resample = 0;
1282int GLAD_GL_SGIX_flush_raster = 0;
1283int GLAD_GL_EXT_light_texture = 0;
1284int GLAD_GL_ARB_point_sprite = 0;
1285int GLAD_GL_SUN_convolution_border_modes = 0;
1286int GLAD_GL_EXT_semaphore_fd = 0;
1287int GLAD_GL_NV_parameter_buffer_object2 = 0;
1288int GLAD_GL_ARB_half_float_pixel = 0;
1289int GLAD_GL_NV_tessellation_program5 = 0;
1290int GLAD_GL_REND_screen_coordinates = 0;
1291int GLAD_GL_EXT_shared_texture_palette = 0;
1292int GLAD_GL_EXT_packed_float = 0;
1293int GLAD_GL_OML_subsample = 0;
1294int GLAD_GL_SGIX_vertex_preclip = 0;
1295int GLAD_GL_SGIX_texture_scale_bias = 0;
1296int GLAD_GL_AMD_draw_buffers_blend = 0;
1297int GLAD_GL_APPLE_texture_range = 0; 1485int GLAD_GL_APPLE_texture_range = 0;
1298int GLAD_GL_EXT_texture_array = 0; 1486int GLAD_GL_APPLE_transform_hint = 0;
1299int GLAD_GL_NV_texture_barrier = 0; 1487int GLAD_GL_APPLE_vertex_array_object = 0;
1300int GLAD_GL_ARB_texture_query_levels = 0; 1488int GLAD_GL_APPLE_vertex_array_range = 0;
1301int GLAD_GL_NV_texgen_emboss = 0; 1489int GLAD_GL_APPLE_vertex_program_evaluators = 0;
1302int GLAD_GL_EXT_texture_swizzle = 0; 1490int GLAD_GL_APPLE_ycbcr_422 = 0;
1303int GLAD_GL_ARB_texture_rg = 0; 1491int GLAD_GL_ARB_ES2_compatibility = 0;
1304int GLAD_GL_ARB_vertex_type_2_10_10_10_rev = 0; 1492int GLAD_GL_ARB_ES3_1_compatibility = 0;
1493int GLAD_GL_ARB_ES3_2_compatibility = 0;
1494int GLAD_GL_ARB_ES3_compatibility = 0;
1495int GLAD_GL_ARB_arrays_of_arrays = 0;
1496int GLAD_GL_ARB_base_instance = 0;
1497int GLAD_GL_ARB_bindless_texture = 0;
1498int GLAD_GL_ARB_blend_func_extended = 0;
1499int GLAD_GL_ARB_buffer_storage = 0;
1500int GLAD_GL_ARB_cl_event = 0;
1501int GLAD_GL_ARB_clear_buffer_object = 0;
1502int GLAD_GL_ARB_clear_texture = 0;
1503int GLAD_GL_ARB_clip_control = 0;
1504int GLAD_GL_ARB_color_buffer_float = 0;
1505int GLAD_GL_ARB_compatibility = 0;
1506int GLAD_GL_ARB_compressed_texture_pixel_storage = 0;
1507int GLAD_GL_ARB_compute_shader = 0;
1508int GLAD_GL_ARB_compute_variable_group_size = 0;
1509int GLAD_GL_ARB_conditional_render_inverted = 0;
1510int GLAD_GL_ARB_conservative_depth = 0;
1511int GLAD_GL_ARB_copy_buffer = 0;
1512int GLAD_GL_ARB_copy_image = 0;
1513int GLAD_GL_ARB_cull_distance = 0;
1514int GLAD_GL_ARB_debug_output = 0;
1515int GLAD_GL_ARB_depth_buffer_float = 0;
1516int GLAD_GL_ARB_depth_clamp = 0;
1517int GLAD_GL_ARB_depth_texture = 0;
1518int GLAD_GL_ARB_derivative_control = 0;
1519int GLAD_GL_ARB_direct_state_access = 0;
1520int GLAD_GL_ARB_draw_buffers = 0;
1521int GLAD_GL_ARB_draw_buffers_blend = 0;
1522int GLAD_GL_ARB_draw_elements_base_vertex = 0;
1523int GLAD_GL_ARB_draw_indirect = 0;
1524int GLAD_GL_ARB_draw_instanced = 0;
1525int GLAD_GL_ARB_enhanced_layouts = 0;
1526int GLAD_GL_ARB_explicit_attrib_location = 0;
1527int GLAD_GL_ARB_explicit_uniform_location = 0;
1528int GLAD_GL_ARB_fragment_coord_conventions = 0;
1529int GLAD_GL_ARB_fragment_layer_viewport = 0;
1530int GLAD_GL_ARB_fragment_program = 0;
1531int GLAD_GL_ARB_fragment_program_shadow = 0;
1305int GLAD_GL_ARB_fragment_shader = 0; 1532int GLAD_GL_ARB_fragment_shader = 0;
1306int GLAD_GL_3DFX_tbuffer = 0; 1533int GLAD_GL_ARB_fragment_shader_interlock = 0;
1307int GLAD_GL_GREMEDY_frame_terminator = 0; 1534int GLAD_GL_ARB_framebuffer_no_attachments = 0;
1308int GLAD_GL_IBM_cull_vertex = 0;
1309int GLAD_GL_EXT_separate_shader_objects = 0;
1310int GLAD_GL_NV_texture_multisample = 0;
1311int GLAD_GL_ARB_shader_objects = 0;
1312int GLAD_GL_ARB_framebuffer_object = 0; 1535int GLAD_GL_ARB_framebuffer_object = 0;
1313int GLAD_GL_EXT_external_buffer = 0; 1536int GLAD_GL_ARB_framebuffer_sRGB = 0;
1314int GLAD_GL_ATI_envmap_bumpmap = 0; 1537int GLAD_GL_ARB_geometry_shader4 = 0;
1315int GLAD_GL_AMD_shader_explicit_vertex_parameter = 0; 1538int GLAD_GL_ARB_get_program_binary = 0;
1539int GLAD_GL_ARB_get_texture_sub_image = 0;
1540int GLAD_GL_ARB_gl_spirv = 0;
1541int GLAD_GL_ARB_gpu_shader5 = 0;
1542int GLAD_GL_ARB_gpu_shader_fp64 = 0;
1543int GLAD_GL_ARB_gpu_shader_int64 = 0;
1544int GLAD_GL_ARB_half_float_pixel = 0;
1545int GLAD_GL_ARB_half_float_vertex = 0;
1546int GLAD_GL_ARB_imaging = 0;
1547int GLAD_GL_ARB_indirect_parameters = 0;
1548int GLAD_GL_ARB_instanced_arrays = 0;
1549int GLAD_GL_ARB_internalformat_query = 0;
1550int GLAD_GL_ARB_internalformat_query2 = 0;
1551int GLAD_GL_ARB_invalidate_subdata = 0;
1552int GLAD_GL_ARB_map_buffer_alignment = 0;
1553int GLAD_GL_ARB_map_buffer_range = 0;
1554int GLAD_GL_ARB_matrix_palette = 0;
1555int GLAD_GL_ARB_multi_bind = 0;
1556int GLAD_GL_ARB_multi_draw_indirect = 0;
1557int GLAD_GL_ARB_multisample = 0;
1558int GLAD_GL_ARB_multitexture = 0;
1559int GLAD_GL_ARB_occlusion_query = 0;
1560int GLAD_GL_ARB_occlusion_query2 = 0;
1561int GLAD_GL_ARB_parallel_shader_compile = 0;
1562int GLAD_GL_ARB_pipeline_statistics_query = 0;
1563int GLAD_GL_ARB_pixel_buffer_object = 0;
1564int GLAD_GL_ARB_point_parameters = 0;
1565int GLAD_GL_ARB_point_sprite = 0;
1566int GLAD_GL_ARB_polygon_offset_clamp = 0;
1567int GLAD_GL_ARB_post_depth_coverage = 0;
1568int GLAD_GL_ARB_program_interface_query = 0;
1569int GLAD_GL_ARB_provoking_vertex = 0;
1570int GLAD_GL_ARB_query_buffer_object = 0;
1316int GLAD_GL_ARB_robust_buffer_access_behavior = 0; 1571int GLAD_GL_ARB_robust_buffer_access_behavior = 0;
1317int GLAD_GL_ARB_shader_stencil_export = 0;
1318int GLAD_GL_NV_texture_rectangle = 0;
1319int GLAD_GL_ARB_enhanced_layouts = 0;
1320int GLAD_GL_ARB_texture_rectangle = 0;
1321int GLAD_GL_SGI_texture_color_table = 0;
1322int GLAD_GL_NV_viewport_swizzle = 0;
1323int GLAD_GL_ATI_map_object_buffer = 0;
1324int GLAD_GL_ARB_robustness = 0; 1572int GLAD_GL_ARB_robustness = 0;
1325int GLAD_GL_NV_pixel_data_range = 0; 1573int GLAD_GL_ARB_robustness_isolation = 0;
1326int GLAD_GL_EXT_framebuffer_blit = 0; 1574int GLAD_GL_ARB_sample_locations = 0;
1327int GLAD_GL_ARB_gpu_shader_fp64 = 0; 1575int GLAD_GL_ARB_sample_shading = 0;
1328int GLAD_GL_NV_command_list = 0; 1576int GLAD_GL_ARB_sampler_objects = 0;
1329int GLAD_GL_SGIX_depth_texture = 0; 1577int GLAD_GL_ARB_seamless_cube_map = 0;
1330int GLAD_GL_AMD_framebuffer_sample_positions = 0; 1578int GLAD_GL_ARB_seamless_cubemap_per_texture = 0;
1331int GLAD_GL_GREMEDY_string_marker = 0; 1579int GLAD_GL_ARB_separate_shader_objects = 0;
1332int GLAD_GL_ARB_texture_compression_bptc = 0;
1333int GLAD_GL_EXT_subtexture = 0;
1334int GLAD_GL_EXT_pixel_transform_color_table = 0;
1335int GLAD_GL_EXT_texture_compression_rgtc = 0;
1336int GLAD_GL_ARB_shader_atomic_counter_ops = 0; 1580int GLAD_GL_ARB_shader_atomic_counter_ops = 0;
1337int GLAD_GL_SGIX_depth_pass_instrument = 0; 1581int GLAD_GL_ARB_shader_atomic_counters = 0;
1338int GLAD_GL_EXT_gpu_program_parameters = 0; 1582int GLAD_GL_ARB_shader_ballot = 0;
1339int GLAD_GL_NV_evaluators = 0; 1583int GLAD_GL_ARB_shader_bit_encoding = 0;
1340int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent = 0;
1341int GLAD_GL_SGIS_texture_filter4 = 0;
1342int GLAD_GL_AMD_performance_monitor = 0;
1343int GLAD_GL_NV_geometry_shader4 = 0;
1344int GLAD_GL_EXT_stencil_clear_tag = 0;
1345int GLAD_GL_NV_vertex_program1_1 = 0;
1346int GLAD_GL_NV_present_video = 0;
1347int GLAD_GL_ARB_texture_compression_rgtc = 0;
1348int GLAD_GL_HP_convolution_border_modes = 0;
1349int GLAD_GL_EXT_shader_integer_mix = 0;
1350int GLAD_GL_SGIX_framezoom = 0;
1351int GLAD_GL_ARB_stencil_texturing = 0;
1352int GLAD_GL_ARB_shader_clock = 0; 1584int GLAD_GL_ARB_shader_clock = 0;
1353int GLAD_GL_NV_shader_atomic_fp16_vector = 0; 1585int GLAD_GL_ARB_shader_draw_parameters = 0;
1354int GLAD_GL_SGIX_fog_offset = 0; 1586int GLAD_GL_ARB_shader_group_vote = 0;
1355int GLAD_GL_ARB_draw_elements_base_vertex = 0; 1587int GLAD_GL_ARB_shader_image_load_store = 0;
1356int GLAD_GL_INGR_interlace_read = 0; 1588int GLAD_GL_ARB_shader_image_size = 0;
1357int GLAD_GL_NV_transform_feedback = 0; 1589int GLAD_GL_ARB_shader_objects = 0;
1358int GLAD_GL_NV_fragment_program = 0; 1590int GLAD_GL_ARB_shader_precision = 0;
1359int GLAD_GL_AMD_stencil_operation_extended = 0; 1591int GLAD_GL_ARB_shader_stencil_export = 0;
1360int GLAD_GL_ARB_seamless_cubemap_per_texture = 0; 1592int GLAD_GL_ARB_shader_storage_buffer_object = 0;
1361int GLAD_GL_ARB_instanced_arrays = 0; 1593int GLAD_GL_ARB_shader_subroutine = 0;
1362int GLAD_GL_ARB_get_texture_sub_image = 0; 1594int GLAD_GL_ARB_shader_texture_image_samples = 0;
1363int GLAD_GL_NV_vertex_array_range2 = 0; 1595int GLAD_GL_ARB_shader_texture_lod = 0;
1364int GLAD_GL_KHR_robustness = 0; 1596int GLAD_GL_ARB_shader_viewport_layer_array = 0;
1365int GLAD_GL_AMD_sparse_texture = 0; 1597int GLAD_GL_ARB_shading_language_100 = 0;
1366int GLAD_GL_ARB_clip_control = 0; 1598int GLAD_GL_ARB_shading_language_420pack = 0;
1367int GLAD_GL_NV_fragment_coverage_to_color = 0; 1599int GLAD_GL_ARB_shading_language_include = 0;
1368int GLAD_GL_NV_fence = 0; 1600int GLAD_GL_ARB_shading_language_packing = 0;
1601int GLAD_GL_ARB_shadow = 0;
1602int GLAD_GL_ARB_shadow_ambient = 0;
1603int GLAD_GL_ARB_sparse_buffer = 0;
1604int GLAD_GL_ARB_sparse_texture = 0;
1605int GLAD_GL_ARB_sparse_texture2 = 0;
1606int GLAD_GL_ARB_sparse_texture_clamp = 0;
1607int GLAD_GL_ARB_spirv_extensions = 0;
1608int GLAD_GL_ARB_stencil_texturing = 0;
1609int GLAD_GL_ARB_sync = 0;
1610int GLAD_GL_ARB_tessellation_shader = 0;
1611int GLAD_GL_ARB_texture_barrier = 0;
1612int GLAD_GL_ARB_texture_border_clamp = 0;
1613int GLAD_GL_ARB_texture_buffer_object = 0;
1614int GLAD_GL_ARB_texture_buffer_object_rgb32 = 0;
1369int GLAD_GL_ARB_texture_buffer_range = 0; 1615int GLAD_GL_ARB_texture_buffer_range = 0;
1370int GLAD_GL_SUN_mesh_array = 0; 1616int GLAD_GL_ARB_texture_compression = 0;
1371int GLAD_GL_ARB_vertex_attrib_binding = 0; 1617int GLAD_GL_ARB_texture_compression_bptc = 0;
1372int GLAD_GL_ARB_framebuffer_no_attachments = 0; 1618int GLAD_GL_ARB_texture_compression_rgtc = 0;
1373int GLAD_GL_ARB_cl_event = 0;
1374int GLAD_GL_EXT_vertex_weighting = 0;
1375int GLAD_GL_ARB_derivative_control = 0;
1376int GLAD_GL_NV_packed_depth_stencil = 0;
1377int GLAD_GL_OES_single_precision = 0;
1378int GLAD_GL_NV_primitive_restart = 0;
1379int GLAD_GL_SUN_global_alpha = 0;
1380int GLAD_GL_ARB_fragment_shader_interlock = 0;
1381int GLAD_GL_EXT_texture_object = 0;
1382int GLAD_GL_AMD_name_gen_delete = 0;
1383int GLAD_GL_NV_texture_compression_vtc = 0;
1384int GLAD_GL_NV_sample_mask_override_coverage = 0;
1385int GLAD_GL_NV_texture_shader3 = 0;
1386int GLAD_GL_MESA_tile_raster_order = 0;
1387int GLAD_GL_ARB_texture_filter_anisotropic = 0;
1388int GLAD_GL_EXT_texture = 0;
1389int GLAD_GL_ARB_buffer_storage = 0;
1390int GLAD_GL_AMD_shader_atomic_counter_ops = 0;
1391int GLAD_GL_APPLE_vertex_program_evaluators = 0;
1392int GLAD_GL_AMD_texture_gather_bias_lod = 0;
1393int GLAD_GL_NV_texgen_reflection = 0;
1394int GLAD_GL_ARB_explicit_uniform_location = 0;
1395int GLAD_GL_ARB_depth_buffer_float = 0;
1396int GLAD_GL_NV_path_rendering_shared_edge = 0;
1397int GLAD_GL_SGIX_shadow_ambient = 0;
1398int GLAD_GL_ARB_texture_cube_map = 0; 1619int GLAD_GL_ARB_texture_cube_map = 0;
1399int GLAD_GL_AMD_vertex_shader_viewport_index = 0; 1620int GLAD_GL_ARB_texture_cube_map_array = 0;
1400int GLAD_GL_SGIX_list_priority = 0; 1621int GLAD_GL_ARB_texture_env_add = 0;
1401int GLAD_GL_NV_vertex_buffer_unified_memory = 0; 1622int GLAD_GL_ARB_texture_env_combine = 0;
1402int GLAD_GL_NV_uniform_buffer_unified_memory = 0; 1623int GLAD_GL_ARB_texture_env_crossbar = 0;
1403int GLAD_GL_ARB_clear_texture = 0; 1624int GLAD_GL_ARB_texture_env_dot3 = 0;
1404int GLAD_GL_ATI_texture_env_combine3 = 0; 1625int GLAD_GL_ARB_texture_filter_anisotropic = 0;
1405int GLAD_GL_NV_depth_clamp = 0; 1626int GLAD_GL_ARB_texture_filter_minmax = 0;
1406int GLAD_GL_ARB_map_buffer_alignment = 0; 1627int GLAD_GL_ARB_texture_float = 0;
1407int GLAD_GL_EXT_memory_object = 0; 1628int GLAD_GL_ARB_texture_gather = 0;
1408int GLAD_GL_NV_blend_equation_advanced = 0; 1629int GLAD_GL_ARB_texture_mirror_clamp_to_edge = 0;
1409int GLAD_GL_SGIS_sharpen_texture = 0; 1630int GLAD_GL_ARB_texture_mirrored_repeat = 0;
1410int GLAD_GL_KHR_robust_buffer_access_behavior = 0; 1631int GLAD_GL_ARB_texture_multisample = 0;
1411int GLAD_GL_ARB_pipeline_statistics_query = 0; 1632int GLAD_GL_ARB_texture_non_power_of_two = 0;
1412int GLAD_GL_ARB_vertex_program = 0; 1633int GLAD_GL_ARB_texture_query_levels = 0;
1634int GLAD_GL_ARB_texture_query_lod = 0;
1635int GLAD_GL_ARB_texture_rectangle = 0;
1636int GLAD_GL_ARB_texture_rg = 0;
1413int GLAD_GL_ARB_texture_rgb10_a2ui = 0; 1637int GLAD_GL_ARB_texture_rgb10_a2ui = 0;
1414int GLAD_GL_OML_interlace = 0; 1638int GLAD_GL_ARB_texture_stencil8 = 0;
1415int GLAD_GL_ATI_pixel_format_float = 0; 1639int GLAD_GL_ARB_texture_storage = 0;
1416int GLAD_GL_NV_clip_space_w_scaling = 0; 1640int GLAD_GL_ARB_texture_storage_multisample = 0;
1641int GLAD_GL_ARB_texture_swizzle = 0;
1642int GLAD_GL_ARB_texture_view = 0;
1643int GLAD_GL_ARB_timer_query = 0;
1644int GLAD_GL_ARB_transform_feedback2 = 0;
1645int GLAD_GL_ARB_transform_feedback3 = 0;
1646int GLAD_GL_ARB_transform_feedback_instanced = 0;
1647int GLAD_GL_ARB_transform_feedback_overflow_query = 0;
1648int GLAD_GL_ARB_transpose_matrix = 0;
1649int GLAD_GL_ARB_uniform_buffer_object = 0;
1650int GLAD_GL_ARB_vertex_array_bgra = 0;
1651int GLAD_GL_ARB_vertex_array_object = 0;
1652int GLAD_GL_ARB_vertex_attrib_64bit = 0;
1653int GLAD_GL_ARB_vertex_attrib_binding = 0;
1654int GLAD_GL_ARB_vertex_blend = 0;
1417int GLAD_GL_ARB_vertex_buffer_object = 0; 1655int GLAD_GL_ARB_vertex_buffer_object = 0;
1418int GLAD_GL_EXT_shadow_funcs = 0; 1656int GLAD_GL_ARB_vertex_program = 0;
1657int GLAD_GL_ARB_vertex_shader = 0;
1658int GLAD_GL_ARB_vertex_type_10f_11f_11f_rev = 0;
1659int GLAD_GL_ARB_vertex_type_2_10_10_10_rev = 0;
1660int GLAD_GL_ARB_viewport_array = 0;
1661int GLAD_GL_ARB_window_pos = 0;
1662int GLAD_GL_ATI_draw_buffers = 0;
1663int GLAD_GL_ATI_element_array = 0;
1664int GLAD_GL_ATI_envmap_bumpmap = 0;
1665int GLAD_GL_ATI_fragment_shader = 0;
1666int GLAD_GL_ATI_map_object_buffer = 0;
1667int GLAD_GL_ATI_meminfo = 0;
1668int GLAD_GL_ATI_pixel_format_float = 0;
1669int GLAD_GL_ATI_pn_triangles = 0;
1670int GLAD_GL_ATI_separate_stencil = 0;
1419int GLAD_GL_ATI_text_fragment_shader = 0; 1671int GLAD_GL_ATI_text_fragment_shader = 0;
1420int GLAD_GL_NV_vertex_array_range = 0; 1672int GLAD_GL_ATI_texture_env_combine3 = 0;
1421int GLAD_GL_SGIX_fragment_lighting = 0; 1673int GLAD_GL_ATI_texture_float = 0;
1422int GLAD_GL_AMD_shader_ballot = 0; 1674int GLAD_GL_ATI_texture_mirror_once = 0;
1423int GLAD_GL_NV_texture_expand_normal = 0; 1675int GLAD_GL_ATI_vertex_array_object = 0;
1424int GLAD_GL_NV_framebuffer_multisample_coverage = 0;
1425int GLAD_GL_EXT_timer_query = 0;
1426int GLAD_GL_EXT_vertex_array_bgra = 0;
1427int GLAD_GL_NV_bindless_texture = 0;
1428int GLAD_GL_KHR_debug = 0;
1429int GLAD_GL_SGIS_texture_border_clamp = 0;
1430int GLAD_GL_ATI_vertex_attrib_array_object = 0; 1676int GLAD_GL_ATI_vertex_attrib_array_object = 0;
1431int GLAD_GL_SGIX_clipmap = 0; 1677int GLAD_GL_ATI_vertex_streams = 0;
1432int GLAD_GL_EXT_geometry_shader4 = 0; 1678int GLAD_GL_EXT_422_pixels = 0;
1433int GLAD_GL_ARB_shader_texture_image_samples = 0;
1434int GLAD_GL_MESA_ycbcr_texture = 0;
1435int GLAD_GL_MESAX_texture_stack = 0;
1436int GLAD_GL_AMD_seamless_cubemap_per_texture = 0;
1437int GLAD_GL_EXT_bindable_uniform = 0;
1438int GLAD_GL_KHR_texture_compression_astc_hdr = 0;
1439int GLAD_GL_ARB_shader_ballot = 0;
1440int GLAD_GL_KHR_blend_equation_advanced = 0;
1441int GLAD_GL_ARB_fragment_program_shadow = 0;
1442int GLAD_GL_ATI_element_array = 0;
1443int GLAD_GL_AMD_texture_texture4 = 0;
1444int GLAD_GL_SGIX_reference_plane = 0;
1445int GLAD_GL_EXT_stencil_two_side = 0;
1446int GLAD_GL_ARB_transform_feedback_overflow_query = 0;
1447int GLAD_GL_SGIX_texture_lod_bias = 0;
1448int GLAD_GL_KHR_no_error = 0;
1449int GLAD_GL_NV_explicit_multisample = 0;
1450int GLAD_GL_NV_stereo_view_rendering = 0;
1451int GLAD_GL_IBM_static_data = 0;
1452int GLAD_GL_EXT_clip_volume_hint = 0;
1453int GLAD_GL_EXT_texture_perturb_normal = 0;
1454int GLAD_GL_NV_fragment_program2 = 0;
1455int GLAD_GL_NV_fragment_program4 = 0;
1456int GLAD_GL_EXT_point_parameters = 0;
1457int GLAD_GL_PGI_misc_hints = 0;
1458int GLAD_GL_EXT_EGL_image_storage = 0; 1679int GLAD_GL_EXT_EGL_image_storage = 0;
1459int GLAD_GL_SGIX_subsample = 0; 1680int GLAD_GL_EXT_abgr = 0;
1460int GLAD_GL_AMD_shader_stencil_export = 0; 1681int GLAD_GL_EXT_bgra = 0;
1461int GLAD_GL_ARB_shader_texture_lod = 0; 1682int GLAD_GL_EXT_bindable_uniform = 0;
1462int GLAD_GL_ARB_vertex_shader = 0; 1683int GLAD_GL_EXT_blend_color = 0;
1463int GLAD_GL_ARB_depth_clamp = 0; 1684int GLAD_GL_EXT_blend_equation_separate = 0;
1464int GLAD_GL_SGIS_texture_select = 0; 1685int GLAD_GL_EXT_blend_func_separate = 0;
1465int GLAD_GL_NV_texture_shader = 0; 1686int GLAD_GL_EXT_blend_logic_op = 0;
1466int GLAD_GL_ARB_tessellation_shader = 0;
1467int GLAD_GL_EXT_draw_buffers2 = 0;
1468int GLAD_GL_ARB_vertex_attrib_64bit = 0;
1469int GLAD_GL_EXT_texture_filter_minmax = 0;
1470int GLAD_GL_NV_query_resource = 0;
1471int GLAD_GL_AMD_interleaved_elements = 0;
1472int GLAD_GL_ARB_fragment_program = 0;
1473int GLAD_GL_OML_resample = 0;
1474int GLAD_GL_APPLE_ycbcr_422 = 0;
1475int GLAD_GL_SGIX_texture_add_env = 0;
1476int GLAD_GL_ARB_shadow_ambient = 0;
1477int GLAD_GL_ARB_texture_storage = 0;
1478int GLAD_GL_EXT_pixel_buffer_object = 0;
1479int GLAD_GL_ARB_copy_image = 0;
1480int GLAD_GL_SGIS_pixel_texture = 0;
1481int GLAD_GL_SGIS_generate_mipmap = 0;
1482int GLAD_GL_SGIX_instruments = 0;
1483int GLAD_GL_ARB_fragment_layer_viewport = 0;
1484int GLAD_GL_ARB_shader_storage_buffer_object = 0;
1485int GLAD_GL_EXT_sparse_texture2 = 0;
1486int GLAD_GL_EXT_blend_minmax = 0; 1687int GLAD_GL_EXT_blend_minmax = 0;
1487int GLAD_GL_MESA_pack_invert = 0; 1688int GLAD_GL_EXT_blend_subtract = 0;
1488int GLAD_GL_ARB_base_instance = 0; 1689int GLAD_GL_EXT_clip_volume_hint = 0;
1489int GLAD_GL_SGIX_convolution_accuracy = 0;
1490int GLAD_GL_PGI_vertex_hints = 0;
1491int GLAD_GL_AMD_transform_feedback4 = 0;
1492int GLAD_GL_ARB_ES3_1_compatibility = 0;
1493int GLAD_GL_EXT_memory_object_win32 = 0;
1494int GLAD_GL_EXT_texture_integer = 0;
1495int GLAD_GL_ARB_texture_multisample = 0;
1496int GLAD_GL_ATI_vertex_streams = 0;
1497int GLAD_GL_AMD_gpu_shader_int64 = 0;
1498int GLAD_GL_S3_s3tc = 0;
1499int GLAD_GL_ARB_query_buffer_object = 0;
1500int GLAD_GL_AMD_vertex_shader_tessellator = 0;
1501int GLAD_GL_ARB_invalidate_subdata = 0;
1502int GLAD_GL_NV_draw_vulkan_image = 0;
1503int GLAD_GL_EXT_index_material = 0;
1504int GLAD_GL_NVX_linked_gpu_multicast = 0;
1505int GLAD_GL_NV_blend_equation_advanced_coherent = 0;
1506int GLAD_GL_KHR_texture_compression_astc_sliced_3d = 0;
1507int GLAD_GL_INTEL_parallel_arrays = 0;
1508int GLAD_GL_ATI_draw_buffers = 0;
1509int GLAD_GL_WIN_specular_fog = 0;
1510int GLAD_GL_EXT_cmyka = 0; 1690int GLAD_GL_EXT_cmyka = 0;
1511int GLAD_GL_SGIX_pixel_texture = 0; 1691int GLAD_GL_EXT_color_subtable = 0;
1512int GLAD_GL_APPLE_specular_vector = 0; 1692int GLAD_GL_EXT_compiled_vertex_array = 0;
1513int GLAD_GL_ARB_compatibility = 0; 1693int GLAD_GL_EXT_convolution = 0;
1514int GLAD_GL_ARB_timer_query = 0; 1694int GLAD_GL_EXT_coordinate_frame = 0;
1515int GLAD_GL_SGIX_interlace = 0; 1695int GLAD_GL_EXT_copy_texture = 0;
1516int GLAD_GL_NV_parameter_buffer_object = 0; 1696int GLAD_GL_EXT_cull_vertex = 0;
1517int GLAD_GL_AMD_shader_trinary_minmax = 0; 1697int GLAD_GL_EXT_debug_label = 0;
1518int GLAD_GL_ARB_direct_state_access = 0; 1698int GLAD_GL_EXT_debug_marker = 0;
1519int GLAD_GL_EXT_rescale_normal = 0; 1699int GLAD_GL_EXT_depth_bounds_test = 0;
1520int GLAD_GL_ARB_pixel_buffer_object = 0;
1521int GLAD_GL_ARB_uniform_buffer_object = 0;
1522int GLAD_GL_ARB_vertex_type_10f_11f_11f_rev = 0;
1523int GLAD_GL_ARB_texture_swizzle = 0;
1524int GLAD_GL_NV_transform_feedback2 = 0;
1525int GLAD_GL_SGIX_async_pixel = 0;
1526int GLAD_GL_NV_fragment_program_option = 0;
1527int GLAD_GL_ARB_explicit_attrib_location = 0;
1528int GLAD_GL_EXT_blend_color = 0;
1529int GLAD_GL_NV_shader_thread_group = 0;
1530int GLAD_GL_EXT_stencil_wrap = 0;
1531int GLAD_GL_EXT_index_array_formats = 0;
1532int GLAD_GL_OVR_multiview2 = 0;
1533int GLAD_GL_EXT_histogram = 0;
1534int GLAD_GL_EXT_polygon_offset = 0;
1535int GLAD_GL_SGIS_point_parameters = 0;
1536int GLAD_GL_SGIX_ycrcb = 0;
1537int GLAD_GL_EXT_direct_state_access = 0; 1700int GLAD_GL_EXT_direct_state_access = 0;
1538int GLAD_GL_ARB_cull_distance = 0; 1701int GLAD_GL_EXT_draw_buffers2 = 0;
1539int GLAD_GL_AMD_sample_positions = 0; 1702int GLAD_GL_EXT_draw_instanced = 0;
1540int GLAD_GL_NV_vertex_program = 0; 1703int GLAD_GL_EXT_draw_range_elements = 0;
1541int GLAD_GL_NV_shader_thread_shuffle = 0; 1704int GLAD_GL_EXT_external_buffer = 0;
1542int GLAD_GL_ARB_shader_precision = 0;
1543int GLAD_GL_EXT_vertex_shader = 0;
1544int GLAD_GL_EXT_blend_func_separate = 0;
1545int GLAD_GL_APPLE_fence = 0;
1546int GLAD_GL_NV_query_resource_tag = 0;
1547int GLAD_GL_OES_byte_coordinates = 0;
1548int GLAD_GL_ARB_transpose_matrix = 0;
1549int GLAD_GL_ARB_provoking_vertex = 0;
1550int GLAD_GL_EXT_fog_coord = 0; 1705int GLAD_GL_EXT_fog_coord = 0;
1551int GLAD_GL_EXT_vertex_array = 0; 1706int GLAD_GL_EXT_framebuffer_blit = 0;
1552int GLAD_GL_ARB_half_float_vertex = 0; 1707int GLAD_GL_EXT_framebuffer_multisample = 0;
1553int GLAD_GL_EXT_blend_equation_separate = 0; 1708int GLAD_GL_EXT_framebuffer_multisample_blit_scaled = 0;
1554int GLAD_GL_NV_framebuffer_mixed_samples = 0; 1709int GLAD_GL_EXT_framebuffer_object = 0;
1555int GLAD_GL_NVX_conditional_render = 0; 1710int GLAD_GL_EXT_framebuffer_sRGB = 0;
1556int GLAD_GL_ARB_multi_draw_indirect = 0; 1711int GLAD_GL_EXT_geometry_shader4 = 0;
1557int GLAD_GL_EXT_raster_multisample = 0; 1712int GLAD_GL_EXT_gpu_program_parameters = 0;
1558int GLAD_GL_NV_copy_image = 0; 1713int GLAD_GL_EXT_gpu_shader4 = 0;
1559int GLAD_GL_HP_texture_lighting = 0; 1714int GLAD_GL_EXT_histogram = 0;
1560int GLAD_GL_INTEL_framebuffer_CMAA = 0; 1715int GLAD_GL_EXT_index_array_formats = 0;
1561int GLAD_GL_ARB_transform_feedback2 = 0; 1716int GLAD_GL_EXT_index_func = 0;
1562int GLAD_GL_ARB_transform_feedback3 = 0; 1717int GLAD_GL_EXT_index_material = 0;
1563int GLAD_GL_SGIX_ycrcba = 0; 1718int GLAD_GL_EXT_index_texture = 0;
1564int GLAD_GL_EXT_debug_marker = 0; 1719int GLAD_GL_EXT_light_texture = 0;
1565int GLAD_GL_EXT_bgra = 0; 1720int GLAD_GL_EXT_memory_object = 0;
1566int GLAD_GL_ARB_sparse_texture_clamp = 0; 1721int GLAD_GL_EXT_memory_object_fd = 0;
1722int GLAD_GL_EXT_memory_object_win32 = 0;
1723int GLAD_GL_EXT_misc_attribute = 0;
1724int GLAD_GL_EXT_multi_draw_arrays = 0;
1725int GLAD_GL_EXT_multisample = 0;
1726int GLAD_GL_EXT_packed_depth_stencil = 0;
1727int GLAD_GL_EXT_packed_float = 0;
1728int GLAD_GL_EXT_packed_pixels = 0;
1729int GLAD_GL_EXT_paletted_texture = 0;
1730int GLAD_GL_EXT_pixel_buffer_object = 0;
1567int GLAD_GL_EXT_pixel_transform = 0; 1731int GLAD_GL_EXT_pixel_transform = 0;
1568int GLAD_GL_ARB_conservative_depth = 0; 1732int GLAD_GL_EXT_pixel_transform_color_table = 0;
1569int GLAD_GL_ATI_fragment_shader = 0; 1733int GLAD_GL_EXT_point_parameters = 0;
1570int GLAD_GL_ARB_vertex_array_object = 0; 1734int GLAD_GL_EXT_polygon_offset = 0;
1571int GLAD_GL_SUN_triangle_list = 0; 1735int GLAD_GL_EXT_polygon_offset_clamp = 0;
1736int GLAD_GL_EXT_post_depth_coverage = 0;
1737int GLAD_GL_EXT_provoking_vertex = 0;
1738int GLAD_GL_EXT_raster_multisample = 0;
1739int GLAD_GL_EXT_rescale_normal = 0;
1740int GLAD_GL_EXT_secondary_color = 0;
1741int GLAD_GL_EXT_semaphore = 0;
1742int GLAD_GL_EXT_semaphore_fd = 0;
1743int GLAD_GL_EXT_semaphore_win32 = 0;
1744int GLAD_GL_EXT_separate_shader_objects = 0;
1745int GLAD_GL_EXT_separate_specular_color = 0;
1746int GLAD_GL_EXT_shader_framebuffer_fetch = 0;
1747int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent = 0;
1748int GLAD_GL_EXT_shader_image_load_formatted = 0;
1749int GLAD_GL_EXT_shader_image_load_store = 0;
1750int GLAD_GL_EXT_shader_integer_mix = 0;
1751int GLAD_GL_EXT_shadow_funcs = 0;
1752int GLAD_GL_EXT_shared_texture_palette = 0;
1753int GLAD_GL_EXT_sparse_texture2 = 0;
1754int GLAD_GL_EXT_stencil_clear_tag = 0;
1755int GLAD_GL_EXT_stencil_two_side = 0;
1756int GLAD_GL_EXT_stencil_wrap = 0;
1757int GLAD_GL_EXT_subtexture = 0;
1758int GLAD_GL_EXT_texture = 0;
1759int GLAD_GL_EXT_texture3D = 0;
1760int GLAD_GL_EXT_texture_array = 0;
1761int GLAD_GL_EXT_texture_buffer_object = 0;
1762int GLAD_GL_EXT_texture_compression_latc = 0;
1763int GLAD_GL_EXT_texture_compression_rgtc = 0;
1764int GLAD_GL_EXT_texture_compression_s3tc = 0;
1765int GLAD_GL_EXT_texture_cube_map = 0;
1572int GLAD_GL_EXT_texture_env_add = 0; 1766int GLAD_GL_EXT_texture_env_add = 0;
1573int GLAD_GL_EXT_packed_depth_stencil = 0; 1767int GLAD_GL_EXT_texture_env_combine = 0;
1768int GLAD_GL_EXT_texture_env_dot3 = 0;
1769int GLAD_GL_EXT_texture_filter_anisotropic = 0;
1770int GLAD_GL_EXT_texture_filter_minmax = 0;
1771int GLAD_GL_EXT_texture_integer = 0;
1772int GLAD_GL_EXT_texture_lod_bias = 0;
1574int GLAD_GL_EXT_texture_mirror_clamp = 0; 1773int GLAD_GL_EXT_texture_mirror_clamp = 0;
1575int GLAD_GL_NV_multisample_filter_hint = 0; 1774int GLAD_GL_EXT_texture_object = 0;
1576int GLAD_GL_APPLE_float_pixels = 0; 1775int GLAD_GL_EXT_texture_perturb_normal = 0;
1577int GLAD_GL_ARB_transform_feedback_instanced = 0; 1776int GLAD_GL_EXT_texture_sRGB = 0;
1578int GLAD_GL_SGIX_async = 0;
1579int GLAD_GL_EXT_texture_compression_latc = 0;
1580int GLAD_GL_NV_robustness_video_memory_purge = 0;
1581int GLAD_GL_ARB_shading_language_100 = 0;
1582int GLAD_GL_INTEL_performance_query = 0;
1583int GLAD_GL_ARB_texture_mirror_clamp_to_edge = 0;
1584int GLAD_GL_NV_gpu_shader5 = 0;
1585int GLAD_GL_NV_bindless_multi_draw_indirect_count = 0;
1586int GLAD_GL_ARB_ES2_compatibility = 0;
1587int GLAD_GL_ARB_indirect_parameters = 0;
1588int GLAD_GL_EXT_window_rectangles = 0;
1589int GLAD_GL_NV_half_float = 0;
1590int GLAD_GL_ARB_ES3_2_compatibility = 0;
1591int GLAD_GL_ATI_texture_mirror_once = 0;
1592int GLAD_GL_IBM_rasterpos_clip = 0;
1593int GLAD_GL_EXT_semaphore = 0;
1594int GLAD_GL_SGIX_shadow = 0;
1595int GLAD_GL_EXT_polygon_offset_clamp = 0;
1596int GLAD_GL_NV_deep_texture3D = 0;
1597int GLAD_GL_ARB_shader_draw_parameters = 0;
1598int GLAD_GL_SGIX_calligraphic_fragment = 0;
1599int GLAD_GL_ARB_shader_bit_encoding = 0;
1600int GLAD_GL_EXT_compiled_vertex_array = 0;
1601int GLAD_GL_NV_depth_buffer_float = 0;
1602int GLAD_GL_NV_occlusion_query = 0;
1603int GLAD_GL_APPLE_flush_buffer_range = 0;
1604int GLAD_GL_ARB_imaging = 0;
1605int GLAD_GL_NV_shader_atomic_float = 0;
1606int GLAD_GL_ARB_draw_buffers_blend = 0;
1607int GLAD_GL_AMD_gcn_shader = 0;
1608int GLAD_GL_AMD_blend_minmax_factor = 0;
1609int GLAD_GL_EXT_texture_sRGB_decode = 0; 1777int GLAD_GL_EXT_texture_sRGB_decode = 0;
1610int GLAD_GL_ARB_shading_language_420pack = 0;
1611int GLAD_GL_ARB_shader_viewport_layer_array = 0;
1612int GLAD_GL_ATI_meminfo = 0;
1613int GLAD_GL_EXT_abgr = 0;
1614int GLAD_GL_AMD_pinned_memory = 0;
1615int GLAD_GL_EXT_texture_snorm = 0;
1616int GLAD_GL_SGIX_texture_coordinate_clamp = 0;
1617int GLAD_GL_ARB_clear_buffer_object = 0;
1618int GLAD_GL_ARB_multisample = 0;
1619int GLAD_GL_EXT_debug_label = 0;
1620int GLAD_GL_ARB_sample_shading = 0;
1621int GLAD_GL_NV_internalformat_sample_query = 0;
1622int GLAD_GL_INTEL_map_texture = 0;
1623int GLAD_GL_ARB_texture_env_crossbar = 0;
1624int GLAD_GL_EXT_422_pixels = 0;
1625int GLAD_GL_NV_blend_minmax_factor = 0;
1626int GLAD_GL_NV_conservative_raster_pre_snap_triangles = 0;
1627int GLAD_GL_ARB_compute_shader = 0;
1628int GLAD_GL_EXT_blend_logic_op = 0;
1629int GLAD_GL_ARB_blend_func_extended = 0;
1630int GLAD_GL_IBM_vertex_array_lists = 0;
1631int GLAD_GL_ARB_color_buffer_float = 0;
1632int GLAD_GL_ARB_bindless_texture = 0;
1633int GLAD_GL_ARB_window_pos = 0;
1634int GLAD_GL_ARB_internalformat_query = 0;
1635int GLAD_GL_ARB_shadow = 0;
1636int GLAD_GL_ARB_texture_mirrored_repeat = 0;
1637int GLAD_GL_EXT_shader_image_load_store = 0;
1638int GLAD_GL_EXT_copy_texture = 0;
1639int GLAD_GL_NV_register_combiners2 = 0;
1640int GLAD_GL_SGIX_ycrcb_subsample = 0;
1641int GLAD_GL_NV_alpha_to_coverage_dither_control = 0;
1642int GLAD_GL_SGIX_ir_instrument1 = 0;
1643int GLAD_GL_NV_draw_texture = 0;
1644int GLAD_GL_EXT_texture_shared_exponent = 0; 1778int GLAD_GL_EXT_texture_shared_exponent = 0;
1645int GLAD_GL_NV_texture_shader2 = 0; 1779int GLAD_GL_EXT_texture_snorm = 0;
1646int GLAD_GL_EXT_draw_instanced = 0; 1780int GLAD_GL_EXT_texture_swizzle = 0;
1647int GLAD_GL_NV_copy_depth_to_color = 0; 1781int GLAD_GL_EXT_timer_query = 0;
1648int GLAD_GL_ARB_viewport_array = 0; 1782int GLAD_GL_EXT_transform_feedback = 0;
1649int GLAD_GL_ARB_separate_shader_objects = 0; 1783int GLAD_GL_EXT_vertex_array = 0;
1650int GLAD_GL_NV_conservative_raster_pre_snap = 0; 1784int GLAD_GL_EXT_vertex_array_bgra = 0;
1651int GLAD_GL_EXT_depth_bounds_test = 0;
1652int GLAD_GL_HP_image_transform = 0;
1653int GLAD_GL_ARB_texture_env_add = 0;
1654int GLAD_GL_NV_video_capture = 0;
1655int GLAD_GL_ARB_sampler_objects = 0;
1656int GLAD_GL_ARB_matrix_palette = 0;
1657int GLAD_GL_SGIS_texture_color_mask = 0;
1658int GLAD_GL_EXT_packed_pixels = 0;
1659int GLAD_GL_EXT_coordinate_frame = 0;
1660int GLAD_GL_ARB_texture_compression = 0;
1661int GLAD_GL_ARB_multi_bind = 0;
1662int GLAD_GL_APPLE_aux_depth_stencil = 0;
1663int GLAD_GL_ARB_shader_subroutine = 0;
1664int GLAD_GL_EXT_framebuffer_sRGB = 0;
1665int GLAD_GL_ARB_texture_storage_multisample = 0;
1666int GLAD_GL_KHR_blend_equation_advanced_coherent = 0;
1667int GLAD_GL_EXT_vertex_attrib_64bit = 0; 1785int GLAD_GL_EXT_vertex_attrib_64bit = 0;
1668int GLAD_GL_NV_shader_atomic_float64 = 0; 1786int GLAD_GL_EXT_vertex_shader = 0;
1669int GLAD_GL_ARB_depth_texture = 0; 1787int GLAD_GL_EXT_vertex_weighting = 0;
1670int GLAD_GL_NV_shader_buffer_store = 0;
1671int GLAD_GL_OES_query_matrix = 0;
1672int GLAD_GL_MESA_window_pos = 0;
1673int GLAD_GL_NV_fill_rectangle = 0;
1674int GLAD_GL_NV_shader_storage_buffer_object = 0;
1675int GLAD_GL_ARB_texture_query_lod = 0;
1676int GLAD_GL_ARB_copy_buffer = 0;
1677int GLAD_GL_ARB_shader_image_size = 0;
1678int GLAD_GL_NV_shader_atomic_counters = 0;
1679int GLAD_GL_APPLE_object_purgeable = 0;
1680int GLAD_GL_ARB_occlusion_query = 0;
1681int GLAD_GL_INGR_color_clamp = 0;
1682int GLAD_GL_SGI_color_table = 0;
1683int GLAD_GL_NV_gpu_program5_mem_extended = 0;
1684int GLAD_GL_ARB_texture_cube_map_array = 0;
1685int GLAD_GL_SGIX_scalebias_hint = 0;
1686int GLAD_GL_EXT_gpu_shader4 = 0;
1687int GLAD_GL_NV_geometry_program4 = 0;
1688int GLAD_GL_EXT_framebuffer_multisample_blit_scaled = 0;
1689int GLAD_GL_AMD_debug_output = 0;
1690int GLAD_GL_ARB_texture_border_clamp = 0;
1691int GLAD_GL_EXT_win32_keyed_mutex = 0; 1788int GLAD_GL_EXT_win32_keyed_mutex = 0;
1692int GLAD_GL_ARB_fragment_coord_conventions = 0; 1789int GLAD_GL_EXT_window_rectangles = 0;
1693int GLAD_GL_ARB_multitexture = 0; 1790int GLAD_GL_EXT_x11_sync_object = 0;
1694int GLAD_GL_SGIX_polynomial_ffd = 0; 1791int GLAD_GL_GREMEDY_frame_terminator = 0;
1695int GLAD_GL_EXT_texture_env_dot3 = 0; 1792int GLAD_GL_GREMEDY_string_marker = 0;
1696int GLAD_GL_EXT_provoking_vertex = 0; 1793int GLAD_GL_HP_convolution_border_modes = 0;
1697int GLAD_GL_ARB_point_parameters = 0; 1794int GLAD_GL_HP_image_transform = 0;
1698int GLAD_GL_ARB_shader_image_load_store = 0;
1699int GLAD_GL_ARB_conditional_render_inverted = 0;
1700int GLAD_GL_HP_occlusion_test = 0; 1795int GLAD_GL_HP_occlusion_test = 0;
1701int GLAD_GL_ARB_ES3_compatibility = 0; 1796int GLAD_GL_HP_texture_lighting = 0;
1702int GLAD_GL_ARB_texture_barrier = 0; 1797int GLAD_GL_IBM_cull_vertex = 0;
1703int GLAD_GL_ARB_texture_buffer_object_rgb32 = 0; 1798int GLAD_GL_IBM_multimode_draw_arrays = 0;
1704int GLAD_GL_NV_bindless_multi_draw_indirect = 0; 1799int GLAD_GL_IBM_rasterpos_clip = 0;
1705int GLAD_GL_SGIX_texture_multi_buffer = 0; 1800int GLAD_GL_IBM_static_data = 0;
1801int GLAD_GL_IBM_texture_mirrored_repeat = 0;
1802int GLAD_GL_IBM_vertex_array_lists = 0;
1803int GLAD_GL_INGR_blend_func_separate = 0;
1804int GLAD_GL_INGR_color_clamp = 0;
1805int GLAD_GL_INGR_interlace_read = 0;
1706int GLAD_GL_INTEL_blackhole_render = 0; 1806int GLAD_GL_INTEL_blackhole_render = 0;
1707int GLAD_GL_AMD_shader_image_load_store_lod = 0; 1807int GLAD_GL_INTEL_conservative_rasterization = 0;
1708int GLAD_GL_KHR_texture_compression_astc_ldr = 0;
1709int GLAD_GL_3DFX_multisample = 0;
1710int GLAD_GL_INTEL_fragment_shader_ordering = 0; 1808int GLAD_GL_INTEL_fragment_shader_ordering = 0;
1711int GLAD_GL_ARB_texture_env_dot3 = 0; 1809int GLAD_GL_INTEL_framebuffer_CMAA = 0;
1712int GLAD_GL_NV_gpu_program4 = 0; 1810int GLAD_GL_INTEL_map_texture = 0;
1713int GLAD_GL_NV_gpu_program5 = 0; 1811int GLAD_GL_INTEL_parallel_arrays = 0;
1714int GLAD_GL_NV_float_buffer = 0; 1812int GLAD_GL_INTEL_performance_query = 0;
1715int GLAD_GL_SGIS_texture_edge_clamp = 0; 1813int GLAD_GL_KHR_blend_equation_advanced = 0;
1716int GLAD_GL_ARB_framebuffer_sRGB = 0; 1814int GLAD_GL_KHR_blend_equation_advanced_coherent = 0;
1717int GLAD_GL_SUN_slice_accum = 0; 1815int GLAD_GL_KHR_context_flush_control = 0;
1718int GLAD_GL_EXT_index_texture = 0; 1816int GLAD_GL_KHR_debug = 0;
1719int GLAD_GL_EXT_shader_image_load_formatted = 0; 1817int GLAD_GL_KHR_no_error = 0;
1720int GLAD_GL_ARB_geometry_shader4 = 0; 1818int GLAD_GL_KHR_parallel_shader_compile = 0;
1721int GLAD_GL_EXT_separate_specular_color = 0; 1819int GLAD_GL_KHR_robust_buffer_access_behavior = 0;
1722int GLAD_GL_AMD_depth_clamp_separate = 0; 1820int GLAD_GL_KHR_robustness = 0;
1723int GLAD_GL_NV_conservative_raster = 0; 1821int GLAD_GL_KHR_texture_compression_astc_hdr = 0;
1724int GLAD_GL_ARB_sparse_texture2 = 0; 1822int GLAD_GL_KHR_texture_compression_astc_ldr = 0;
1725int GLAD_GL_SGIX_sprite = 0; 1823int GLAD_GL_KHR_texture_compression_astc_sliced_3d = 0;
1726int GLAD_GL_ARB_get_program_binary = 0; 1824int GLAD_GL_MESAX_texture_stack = 0;
1727int GLAD_GL_AMD_occlusion_query_event = 0; 1825int GLAD_GL_MESA_pack_invert = 0;
1728int GLAD_GL_SGIS_multisample = 0; 1826int GLAD_GL_MESA_program_binary_formats = 0;
1729int GLAD_GL_EXT_framebuffer_object = 0; 1827int GLAD_GL_MESA_resize_buffers = 0;
1730int GLAD_GL_ARB_robustness_isolation = 0; 1828int GLAD_GL_MESA_shader_integer_functions = 0;
1731int GLAD_GL_ARB_vertex_array_bgra = 0; 1829int GLAD_GL_MESA_tile_raster_order = 0;
1732int GLAD_GL_APPLE_vertex_array_range = 0; 1830int GLAD_GL_MESA_window_pos = 0;
1733int GLAD_GL_AMD_query_buffer_object = 0; 1831int GLAD_GL_MESA_ycbcr_texture = 0;
1734int GLAD_GL_NV_register_combiners = 0;
1735int GLAD_GL_ARB_draw_buffers = 0;
1736int GLAD_GL_NVX_blend_equation_advanced_multi_draw_buffers = 0; 1832int GLAD_GL_NVX_blend_equation_advanced_multi_draw_buffers = 0;
1737int GLAD_GL_AMD_gpu_shader_int16 = 0; 1833int GLAD_GL_NVX_conditional_render = 0;
1738int GLAD_GL_ARB_debug_output = 0; 1834int GLAD_GL_NVX_gpu_memory_info = 0;
1739int GLAD_GL_EXT_shader_framebuffer_fetch = 0; 1835int GLAD_GL_NVX_linked_gpu_multicast = 0;
1740int GLAD_GL_SGI_color_matrix = 0; 1836int GLAD_GL_NV_alpha_to_coverage_dither_control = 0;
1741int GLAD_GL_EXT_cull_vertex = 0; 1837int GLAD_GL_NV_bindless_multi_draw_indirect = 0;
1742int GLAD_GL_AMD_framebuffer_multisample_advanced = 0; 1838int GLAD_GL_NV_bindless_multi_draw_indirect_count = 0;
1743int GLAD_GL_EXT_texture_sRGB = 0; 1839int GLAD_GL_NV_bindless_texture = 0;
1744int GLAD_GL_APPLE_row_bytes = 0; 1840int GLAD_GL_NV_blend_equation_advanced = 0;
1841int GLAD_GL_NV_blend_equation_advanced_coherent = 0;
1842int GLAD_GL_NV_blend_minmax_factor = 0;
1843int GLAD_GL_NV_blend_square = 0;
1844int GLAD_GL_NV_clip_space_w_scaling = 0;
1845int GLAD_GL_NV_command_list = 0;
1846int GLAD_GL_NV_compute_program5 = 0;
1847int GLAD_GL_NV_compute_shader_derivatives = 0;
1848int GLAD_GL_NV_conditional_render = 0;
1849int GLAD_GL_NV_conservative_raster = 0;
1850int GLAD_GL_NV_conservative_raster_dilate = 0;
1851int GLAD_GL_NV_conservative_raster_pre_snap = 0;
1852int GLAD_GL_NV_conservative_raster_pre_snap_triangles = 0;
1745int GLAD_GL_NV_conservative_raster_underestimation = 0; 1853int GLAD_GL_NV_conservative_raster_underestimation = 0;
1746int GLAD_GL_IBM_multimode_draw_arrays = 0; 1854int GLAD_GL_NV_copy_depth_to_color = 0;
1747int GLAD_GL_KHR_parallel_shader_compile = 0; 1855int GLAD_GL_NV_copy_image = 0;
1748int GLAD_GL_APPLE_vertex_array_object = 0; 1856int GLAD_GL_NV_deep_texture3D = 0;
1749int GLAD_GL_3DFX_texture_compression_FXT1 = 0; 1857int GLAD_GL_NV_depth_buffer_float = 0;
1858int GLAD_GL_NV_depth_clamp = 0;
1859int GLAD_GL_NV_draw_texture = 0;
1860int GLAD_GL_NV_draw_vulkan_image = 0;
1861int GLAD_GL_NV_evaluators = 0;
1862int GLAD_GL_NV_explicit_multisample = 0;
1863int GLAD_GL_NV_fence = 0;
1864int GLAD_GL_NV_fill_rectangle = 0;
1865int GLAD_GL_NV_float_buffer = 0;
1866int GLAD_GL_NV_fog_distance = 0;
1867int GLAD_GL_NV_fragment_coverage_to_color = 0;
1868int GLAD_GL_NV_fragment_program = 0;
1869int GLAD_GL_NV_fragment_program2 = 0;
1870int GLAD_GL_NV_fragment_program4 = 0;
1871int GLAD_GL_NV_fragment_program_option = 0;
1872int GLAD_GL_NV_fragment_shader_barycentric = 0;
1750int GLAD_GL_NV_fragment_shader_interlock = 0; 1873int GLAD_GL_NV_fragment_shader_interlock = 0;
1751int GLAD_GL_AMD_conservative_depth = 0; 1874int GLAD_GL_NV_framebuffer_mixed_samples = 0;
1752int GLAD_GL_ARB_texture_float = 0; 1875int GLAD_GL_NV_framebuffer_multisample_coverage = 0;
1753int GLAD_GL_ARB_compressed_texture_pixel_storage = 0; 1876int GLAD_GL_NV_geometry_program4 = 0;
1754int GLAD_GL_SGIS_detail_texture = 0; 1877int GLAD_GL_NV_geometry_shader4 = 0;
1755int GLAD_GL_NV_geometry_shader_passthrough = 0; 1878int GLAD_GL_NV_geometry_shader_passthrough = 0;
1756int GLAD_GL_ARB_draw_instanced = 0; 1879int GLAD_GL_NV_gpu_multicast = 0;
1757int GLAD_GL_OES_read_format = 0; 1880int GLAD_GL_NV_gpu_program4 = 0;
1758int GLAD_GL_ATI_texture_float = 0; 1881int GLAD_GL_NV_gpu_program5 = 0;
1759int GLAD_GL_ARB_texture_gather = 0; 1882int GLAD_GL_NV_gpu_program5_mem_extended = 0;
1760int GLAD_GL_AMD_vertex_shader_layer = 0; 1883int GLAD_GL_NV_gpu_shader5 = 0;
1761int GLAD_GL_ARB_shading_language_include = 0; 1884int GLAD_GL_NV_half_float = 0;
1762int GLAD_GL_APPLE_client_storage = 0; 1885int GLAD_GL_NV_internalformat_sample_query = 0;
1763int GLAD_GL_WIN_phong_shading = 0; 1886int GLAD_GL_NV_light_max_exponent = 0;
1764int GLAD_GL_INGR_blend_func_separate = 0; 1887int GLAD_GL_NV_memory_attachment = 0;
1888int GLAD_GL_NV_mesh_shader = 0;
1889int GLAD_GL_NV_multisample_coverage = 0;
1890int GLAD_GL_NV_multisample_filter_hint = 0;
1891int GLAD_GL_NV_occlusion_query = 0;
1892int GLAD_GL_NV_packed_depth_stencil = 0;
1893int GLAD_GL_NV_parameter_buffer_object = 0;
1894int GLAD_GL_NV_parameter_buffer_object2 = 0;
1765int GLAD_GL_NV_path_rendering = 0; 1895int GLAD_GL_NV_path_rendering = 0;
1766int GLAD_GL_NV_conservative_raster_dilate = 0; 1896int GLAD_GL_NV_path_rendering_shared_edge = 0;
1767int GLAD_GL_AMD_gpu_shader_half_float = 0; 1897int GLAD_GL_NV_pixel_data_range = 0;
1768int GLAD_GL_ARB_post_depth_coverage = 0; 1898int GLAD_GL_NV_point_sprite = 0;
1769int GLAD_GL_ARB_texture_non_power_of_two = 0; 1899int GLAD_GL_NV_present_video = 0;
1770int GLAD_GL_APPLE_rgb_422 = 0; 1900int GLAD_GL_NV_primitive_restart = 0;
1771int GLAD_GL_EXT_texture_lod_bias = 0; 1901int GLAD_GL_NV_query_resource = 0;
1772int GLAD_GL_ARB_gpu_shader_int64 = 0; 1902int GLAD_GL_NV_query_resource_tag = 0;
1773int GLAD_GL_ARB_seamless_cube_map = 0; 1903int GLAD_GL_NV_register_combiners = 0;
1774int GLAD_GL_ARB_shader_group_vote = 0; 1904int GLAD_GL_NV_register_combiners2 = 0;
1905int GLAD_GL_NV_representative_fragment_test = 0;
1906int GLAD_GL_NV_robustness_video_memory_purge = 0;
1907int GLAD_GL_NV_sample_locations = 0;
1908int GLAD_GL_NV_sample_mask_override_coverage = 0;
1909int GLAD_GL_NV_scissor_exclusive = 0;
1910int GLAD_GL_NV_shader_atomic_counters = 0;
1911int GLAD_GL_NV_shader_atomic_float = 0;
1912int GLAD_GL_NV_shader_atomic_float64 = 0;
1913int GLAD_GL_NV_shader_atomic_fp16_vector = 0;
1914int GLAD_GL_NV_shader_atomic_int64 = 0;
1915int GLAD_GL_NV_shader_buffer_load = 0;
1916int GLAD_GL_NV_shader_buffer_store = 0;
1917int GLAD_GL_NV_shader_storage_buffer_object = 0;
1918int GLAD_GL_NV_shader_texture_footprint = 0;
1919int GLAD_GL_NV_shader_thread_group = 0;
1920int GLAD_GL_NV_shader_thread_shuffle = 0;
1921int GLAD_GL_NV_shading_rate_image = 0;
1922int GLAD_GL_NV_stereo_view_rendering = 0;
1923int GLAD_GL_NV_tessellation_program5 = 0;
1924int GLAD_GL_NV_texgen_emboss = 0;
1925int GLAD_GL_NV_texgen_reflection = 0;
1926int GLAD_GL_NV_texture_barrier = 0;
1927int GLAD_GL_NV_texture_compression_vtc = 0;
1928int GLAD_GL_NV_texture_env_combine4 = 0;
1929int GLAD_GL_NV_texture_expand_normal = 0;
1930int GLAD_GL_NV_texture_multisample = 0;
1931int GLAD_GL_NV_texture_rectangle = 0;
1932int GLAD_GL_NV_texture_rectangle_compressed = 0;
1933int GLAD_GL_NV_texture_shader = 0;
1934int GLAD_GL_NV_texture_shader2 = 0;
1935int GLAD_GL_NV_texture_shader3 = 0;
1936int GLAD_GL_NV_transform_feedback = 0;
1937int GLAD_GL_NV_transform_feedback2 = 0;
1938int GLAD_GL_NV_uniform_buffer_unified_memory = 0;
1775int GLAD_GL_NV_vdpau_interop = 0; 1939int GLAD_GL_NV_vdpau_interop = 0;
1776int GLAD_GL_ARB_occlusion_query2 = 0; 1940int GLAD_GL_NV_vdpau_interop2 = 0;
1777int GLAD_GL_ARB_internalformat_query2 = 0; 1941int GLAD_GL_NV_vertex_array_range = 0;
1778int GLAD_GL_EXT_texture_filter_anisotropic = 0; 1942int GLAD_GL_NV_vertex_array_range2 = 0;
1779int GLAD_GL_SUN_vertex = 0; 1943int GLAD_GL_NV_vertex_attrib_integer_64bit = 0;
1780int GLAD_GL_EXT_transform_feedback = 0; 1944int GLAD_GL_NV_vertex_buffer_unified_memory = 0;
1781int GLAD_GL_SGIX_igloo_interface = 0; 1945int GLAD_GL_NV_vertex_program = 0;
1782int GLAD_GL_SGIS_texture_lod = 0; 1946int GLAD_GL_NV_vertex_program1_1 = 0;
1947int GLAD_GL_NV_vertex_program2 = 0;
1948int GLAD_GL_NV_vertex_program2_option = 0;
1783int GLAD_GL_NV_vertex_program3 = 0; 1949int GLAD_GL_NV_vertex_program3 = 0;
1784int GLAD_GL_ARB_draw_indirect = 0;
1785int GLAD_GL_NV_vertex_program4 = 0; 1950int GLAD_GL_NV_vertex_program4 = 0;
1786int GLAD_GL_AMD_transform_feedback3_lines_triangles = 0; 1951int GLAD_GL_NV_video_capture = 0;
1787int GLAD_GL_SGIS_fog_function = 0; 1952int GLAD_GL_NV_viewport_array2 = 0;
1788int GLAD_GL_EXT_x11_sync_object = 0; 1953int GLAD_GL_NV_viewport_swizzle = 0;
1789int GLAD_GL_ARB_sync = 0; 1954int GLAD_GL_OES_byte_coordinates = 0;
1790int GLAD_GL_NV_texture_rectangle_compressed = 0; 1955int GLAD_GL_OES_compressed_paletted_texture = 0;
1791int GLAD_GL_NV_sample_locations = 0;
1792int GLAD_GL_NV_gpu_multicast = 0;
1793int GLAD_GL_ARB_gl_spirv = 0;
1794int GLAD_GL_ARB_compute_variable_group_size = 0;
1795int GLAD_GL_OES_fixed_point = 0; 1956int GLAD_GL_OES_fixed_point = 0;
1796int GLAD_GL_MESA_program_binary_formats = 0; 1957int GLAD_GL_OES_query_matrix = 0;
1797int GLAD_GL_NV_blend_square = 0; 1958int GLAD_GL_OES_read_format = 0;
1798int GLAD_GL_EXT_framebuffer_multisample = 0; 1959int GLAD_GL_OES_single_precision = 0;
1799int GLAD_GL_ARB_gpu_shader5 = 0; 1960int GLAD_GL_OML_interlace = 0;
1800int GLAD_GL_SGIS_texture4D = 0; 1961int GLAD_GL_OML_resample = 0;
1801int GLAD_GL_EXT_texture3D = 0; 1962int GLAD_GL_OML_subsample = 0;
1802int GLAD_GL_EXT_multisample = 0; 1963int GLAD_GL_OVR_multiview = 0;
1803int GLAD_GL_EXT_secondary_color = 0; 1964int GLAD_GL_OVR_multiview2 = 0;
1804int GLAD_GL_INTEL_conservative_rasterization = 0; 1965int GLAD_GL_PGI_misc_hints = 0;
1805int GLAD_GL_ARB_texture_filter_minmax = 0; 1966int GLAD_GL_PGI_vertex_hints = 0;
1806int GLAD_GL_ATI_vertex_array_object = 0; 1967int GLAD_GL_REND_screen_coordinates = 0;
1807int GLAD_GL_ARB_parallel_shader_compile = 0; 1968int GLAD_GL_S3_s3tc = 0;
1808int GLAD_GL_NVX_gpu_memory_info = 0; 1969int GLAD_GL_SGIS_detail_texture = 0;
1809int GLAD_GL_ARB_sparse_texture = 0; 1970int GLAD_GL_SGIS_fog_function = 0;
1971int GLAD_GL_SGIS_generate_mipmap = 0;
1972int GLAD_GL_SGIS_multisample = 0;
1973int GLAD_GL_SGIS_pixel_texture = 0;
1810int GLAD_GL_SGIS_point_line_texgen = 0; 1974int GLAD_GL_SGIS_point_line_texgen = 0;
1811int GLAD_GL_ARB_sample_locations = 0; 1975int GLAD_GL_SGIS_point_parameters = 0;
1812int GLAD_GL_ARB_sparse_buffer = 0; 1976int GLAD_GL_SGIS_sharpen_texture = 0;
1813int GLAD_GL_ARB_polygon_offset_clamp = 0; 1977int GLAD_GL_SGIS_texture4D = 0;
1814int GLAD_GL_EXT_draw_range_elements = 0; 1978int GLAD_GL_SGIS_texture_border_clamp = 0;
1979int GLAD_GL_SGIS_texture_color_mask = 0;
1980int GLAD_GL_SGIS_texture_edge_clamp = 0;
1981int GLAD_GL_SGIS_texture_filter4 = 0;
1982int GLAD_GL_SGIS_texture_lod = 0;
1983int GLAD_GL_SGIS_texture_select = 0;
1984int GLAD_GL_SGIX_async = 0;
1985int GLAD_GL_SGIX_async_histogram = 0;
1986int GLAD_GL_SGIX_async_pixel = 0;
1815int GLAD_GL_SGIX_blend_alpha_minmax = 0; 1987int GLAD_GL_SGIX_blend_alpha_minmax = 0;
1816int GLAD_GL_KHR_context_flush_control = 0; 1988int GLAD_GL_SGIX_calligraphic_fragment = 0;
1989int GLAD_GL_SGIX_clipmap = 0;
1990int GLAD_GL_SGIX_convolution_accuracy = 0;
1991int GLAD_GL_SGIX_depth_pass_instrument = 0;
1992int GLAD_GL_SGIX_depth_texture = 0;
1993int GLAD_GL_SGIX_flush_raster = 0;
1994int GLAD_GL_SGIX_fog_offset = 0;
1995int GLAD_GL_SGIX_fragment_lighting = 0;
1996int GLAD_GL_SGIX_framezoom = 0;
1997int GLAD_GL_SGIX_igloo_interface = 0;
1998int GLAD_GL_SGIX_instruments = 0;
1999int GLAD_GL_SGIX_interlace = 0;
2000int GLAD_GL_SGIX_ir_instrument1 = 0;
2001int GLAD_GL_SGIX_list_priority = 0;
2002int GLAD_GL_SGIX_pixel_texture = 0;
2003int GLAD_GL_SGIX_pixel_tiles = 0;
2004int GLAD_GL_SGIX_polynomial_ffd = 0;
2005int GLAD_GL_SGIX_reference_plane = 0;
2006int GLAD_GL_SGIX_resample = 0;
2007int GLAD_GL_SGIX_scalebias_hint = 0;
2008int GLAD_GL_SGIX_shadow = 0;
2009int GLAD_GL_SGIX_shadow_ambient = 0;
2010int GLAD_GL_SGIX_sprite = 0;
2011int GLAD_GL_SGIX_subsample = 0;
2012int GLAD_GL_SGIX_tag_sample_buffer = 0;
2013int GLAD_GL_SGIX_texture_add_env = 0;
2014int GLAD_GL_SGIX_texture_coordinate_clamp = 0;
2015int GLAD_GL_SGIX_texture_lod_bias = 0;
2016int GLAD_GL_SGIX_texture_multi_buffer = 0;
2017int GLAD_GL_SGIX_texture_scale_bias = 0;
2018int GLAD_GL_SGIX_vertex_preclip = 0;
2019int GLAD_GL_SGIX_ycrcb = 0;
2020int GLAD_GL_SGIX_ycrcb_subsample = 0;
2021int GLAD_GL_SGIX_ycrcba = 0;
2022int GLAD_GL_SGI_color_matrix = 0;
2023int GLAD_GL_SGI_color_table = 0;
2024int GLAD_GL_SGI_texture_color_table = 0;
2025int GLAD_GL_SUNX_constant_data = 0;
2026int GLAD_GL_SUN_convolution_border_modes = 0;
2027int GLAD_GL_SUN_global_alpha = 0;
2028int GLAD_GL_SUN_mesh_array = 0;
2029int GLAD_GL_SUN_slice_accum = 0;
2030int GLAD_GL_SUN_triangle_list = 0;
2031int GLAD_GL_SUN_vertex = 0;
2032int GLAD_GL_WIN_phong_shading = 0;
2033int GLAD_GL_WIN_specular_fog = 0;
1817PFNGLTBUFFERMASK3DFXPROC glad_glTbufferMask3DFX = NULL; 2034PFNGLTBUFFERMASK3DFXPROC glad_glTbufferMask3DFX = NULL;
1818PFNGLDEBUGMESSAGEENABLEAMDPROC glad_glDebugMessageEnableAMD = NULL; 2035PFNGLDEBUGMESSAGEENABLEAMDPROC glad_glDebugMessageEnableAMD = NULL;
1819PFNGLDEBUGMESSAGEINSERTAMDPROC glad_glDebugMessageInsertAMD = NULL; 2036PFNGLDEBUGMESSAGEINSERTAMDPROC glad_glDebugMessageInsertAMD = NULL;
@@ -1921,16 +2138,8 @@ PFNGLMAPVERTEXATTRIB1DAPPLEPROC glad_glMapVertexAttrib1dAPPLE = NULL;
1921PFNGLMAPVERTEXATTRIB1FAPPLEPROC glad_glMapVertexAttrib1fAPPLE = NULL; 2138PFNGLMAPVERTEXATTRIB1FAPPLEPROC glad_glMapVertexAttrib1fAPPLE = NULL;
1922PFNGLMAPVERTEXATTRIB2DAPPLEPROC glad_glMapVertexAttrib2dAPPLE = NULL; 2139PFNGLMAPVERTEXATTRIB2DAPPLEPROC glad_glMapVertexAttrib2dAPPLE = NULL;
1923PFNGLMAPVERTEXATTRIB2FAPPLEPROC glad_glMapVertexAttrib2fAPPLE = NULL; 2140PFNGLMAPVERTEXATTRIB2FAPPLEPROC glad_glMapVertexAttrib2fAPPLE = NULL;
1924PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;
1925PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;
1926PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;
1927PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
1928PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
1929PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion = NULL; 2141PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion = NULL;
1930PFNGLPRIMITIVEBOUNDINGBOXARBPROC glad_glPrimitiveBoundingBoxARB = NULL; 2142PFNGLPRIMITIVEBOUNDINGBOXARBPROC glad_glPrimitiveBoundingBoxARB = NULL;
1931PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance = NULL;
1932PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance = NULL;
1933PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance = NULL;
1934PFNGLGETTEXTUREHANDLEARBPROC glad_glGetTextureHandleARB = NULL; 2143PFNGLGETTEXTUREHANDLEARBPROC glad_glGetTextureHandleARB = NULL;
1935PFNGLGETTEXTURESAMPLERHANDLEARBPROC glad_glGetTextureSamplerHandleARB = NULL; 2144PFNGLGETTEXTURESAMPLERHANDLEARBPROC glad_glGetTextureSamplerHandleARB = NULL;
1936PFNGLMAKETEXTUREHANDLERESIDENTARBPROC glad_glMakeTextureHandleResidentARB = NULL; 2145PFNGLMAKETEXTUREHANDLERESIDENTARBPROC glad_glMakeTextureHandleResidentARB = NULL;
@@ -1949,16 +2158,11 @@ PFNGLVERTEXATTRIBL1UI64VARBPROC glad_glVertexAttribL1ui64vARB = NULL;
1949PFNGLGETVERTEXATTRIBLUI64VARBPROC glad_glGetVertexAttribLui64vARB = NULL; 2158PFNGLGETVERTEXATTRIBLUI64VARBPROC glad_glGetVertexAttribLui64vARB = NULL;
1950PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL; 2159PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL;
1951PFNGLCREATESYNCFROMCLEVENTARBPROC glad_glCreateSyncFromCLeventARB = NULL; 2160PFNGLCREATESYNCFROMCLEVENTARBPROC glad_glCreateSyncFromCLeventARB = NULL;
1952PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData = NULL;
1953PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData = NULL;
1954PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL; 2161PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL;
1955PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL; 2162PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL;
1956PFNGLCLIPCONTROLPROC glad_glClipControl = NULL; 2163PFNGLCLIPCONTROLPROC glad_glClipControl = NULL;
1957PFNGLCLAMPCOLORARBPROC glad_glClampColorARB = NULL; 2164PFNGLCLAMPCOLORARBPROC glad_glClampColorARB = NULL;
1958PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL;
1959PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect = NULL;
1960PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC glad_glDispatchComputeGroupSizeARB = NULL; 2165PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC glad_glDispatchComputeGroupSizeARB = NULL;
1961PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL;
1962PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL; 2166PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL;
1963PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL; 2167PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL;
1964PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL; 2168PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL;
@@ -2065,8 +2269,6 @@ PFNGLBLENDEQUATIONIARBPROC glad_glBlendEquationiARB = NULL;
2065PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB = NULL; 2269PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB = NULL;
2066PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB = NULL; 2270PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB = NULL;
2067PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB = NULL; 2271PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB = NULL;
2068PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL;
2069PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL;
2070PFNGLDRAWARRAYSINSTANCEDARBPROC glad_glDrawArraysInstancedARB = NULL; 2272PFNGLDRAWARRAYSINSTANCEDARBPROC glad_glDrawArraysInstancedARB = NULL;
2071PFNGLDRAWELEMENTSINSTANCEDARBPROC glad_glDrawElementsInstancedARB = NULL; 2273PFNGLDRAWELEMENTSINSTANCEDARBPROC glad_glDrawElementsInstancedARB = NULL;
2072PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB = NULL; 2274PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB = NULL;
@@ -2088,36 +2290,13 @@ PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB = NU
2088PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB = NULL; 2290PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB = NULL;
2089PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB = NULL; 2291PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB = NULL;
2090PFNGLISPROGRAMARBPROC glad_glIsProgramARB = NULL; 2292PFNGLISPROGRAMARBPROC glad_glIsProgramARB = NULL;
2091PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = NULL;
2092PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv = NULL;
2093PFNGLPROGRAMPARAMETERIARBPROC glad_glProgramParameteriARB = NULL; 2293PFNGLPROGRAMPARAMETERIARBPROC glad_glProgramParameteriARB = NULL;
2094PFNGLFRAMEBUFFERTEXTUREARBPROC glad_glFramebufferTextureARB = NULL; 2294PFNGLFRAMEBUFFERTEXTUREARBPROC glad_glFramebufferTextureARB = NULL;
2095PFNGLFRAMEBUFFERTEXTURELAYERARBPROC glad_glFramebufferTextureLayerARB = NULL; 2295PFNGLFRAMEBUFFERTEXTURELAYERARBPROC glad_glFramebufferTextureLayerARB = NULL;
2096PFNGLFRAMEBUFFERTEXTUREFACEARBPROC glad_glFramebufferTextureFaceARB = NULL; 2296PFNGLFRAMEBUFFERTEXTUREFACEARBPROC glad_glFramebufferTextureFaceARB = NULL;
2097PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL;
2098PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL;
2099PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL;
2100PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage = NULL; 2297PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage = NULL;
2101PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage = NULL; 2298PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage = NULL;
2102PFNGLSPECIALIZESHADERARBPROC glad_glSpecializeShaderARB = NULL; 2299PFNGLSPECIALIZESHADERARBPROC glad_glSpecializeShaderARB = NULL;
2103PFNGLUNIFORM1DPROC glad_glUniform1d = NULL;
2104PFNGLUNIFORM2DPROC glad_glUniform2d = NULL;
2105PFNGLUNIFORM3DPROC glad_glUniform3d = NULL;
2106PFNGLUNIFORM4DPROC glad_glUniform4d = NULL;
2107PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL;
2108PFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL;
2109PFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL;
2110PFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL;
2111PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL;
2112PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL;
2113PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL;
2114PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL;
2115PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL;
2116PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL;
2117PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL;
2118PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL;
2119PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL;
2120PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL;
2121PFNGLUNIFORM1I64ARBPROC glad_glUniform1i64ARB = NULL; 2300PFNGLUNIFORM1I64ARBPROC glad_glUniform1i64ARB = NULL;
2122PFNGLUNIFORM2I64ARBPROC glad_glUniform2i64ARB = NULL; 2301PFNGLUNIFORM2I64ARBPROC glad_glUniform2i64ARB = NULL;
2123PFNGLUNIFORM3I64ARBPROC glad_glUniform3i64ARB = NULL; 2302PFNGLUNIFORM3I64ARBPROC glad_glUniform3i64ARB = NULL;
@@ -2189,14 +2368,6 @@ PFNGLRESETMINMAXPROC glad_glResetMinmax = NULL;
2189PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC glad_glMultiDrawArraysIndirectCountARB = NULL; 2368PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC glad_glMultiDrawArraysIndirectCountARB = NULL;
2190PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC glad_glMultiDrawElementsIndirectCountARB = NULL; 2369PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC glad_glMultiDrawElementsIndirectCountARB = NULL;
2191PFNGLVERTEXATTRIBDIVISORARBPROC glad_glVertexAttribDivisorARB = NULL; 2370PFNGLVERTEXATTRIBDIVISORARBPROC glad_glVertexAttribDivisorARB = NULL;
2192PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL;
2193PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v = NULL;
2194PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage = NULL;
2195PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage = NULL;
2196PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData = NULL;
2197PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData = NULL;
2198PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL;
2199PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL;
2200PFNGLCURRENTPALETTEMATRIXARBPROC glad_glCurrentPaletteMatrixARB = NULL; 2371PFNGLCURRENTPALETTEMATRIXARBPROC glad_glCurrentPaletteMatrixARB = NULL;
2201PFNGLMATRIXINDEXUBVARBPROC glad_glMatrixIndexubvARB = NULL; 2372PFNGLMATRIXINDEXUBVARBPROC glad_glMatrixIndexubvARB = NULL;
2202PFNGLMATRIXINDEXUSVARBPROC glad_glMatrixIndexusvARB = NULL; 2373PFNGLMATRIXINDEXUSVARBPROC glad_glMatrixIndexusvARB = NULL;
@@ -2208,8 +2379,6 @@ PFNGLBINDTEXTURESPROC glad_glBindTextures = NULL;
2208PFNGLBINDSAMPLERSPROC glad_glBindSamplers = NULL; 2379PFNGLBINDSAMPLERSPROC glad_glBindSamplers = NULL;
2209PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures = NULL; 2380PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures = NULL;
2210PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers = NULL; 2381PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers = NULL;
2211PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect = NULL;
2212PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect = NULL;
2213PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB = NULL; 2382PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB = NULL;
2214PFNGLACTIVETEXTUREARBPROC glad_glActiveTextureARB = NULL; 2383PFNGLACTIVETEXTUREARBPROC glad_glActiveTextureARB = NULL;
2215PFNGLCLIENTACTIVETEXTUREARBPROC glad_glClientActiveTextureARB = NULL; 2384PFNGLCLIENTACTIVETEXTUREARBPROC glad_glClientActiveTextureARB = NULL;
@@ -2257,12 +2426,6 @@ PFNGLMAXSHADERCOMPILERTHREADSARBPROC glad_glMaxShaderCompilerThreadsARB = NULL;
2257PFNGLPOINTPARAMETERFARBPROC glad_glPointParameterfARB = NULL; 2426PFNGLPOINTPARAMETERFARBPROC glad_glPointParameterfARB = NULL;
2258PFNGLPOINTPARAMETERFVARBPROC glad_glPointParameterfvARB = NULL; 2427PFNGLPOINTPARAMETERFVARBPROC glad_glPointParameterfvARB = NULL;
2259PFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp = NULL; 2428PFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp = NULL;
2260PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv = NULL;
2261PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex = NULL;
2262PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL;
2263PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL;
2264PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation = NULL;
2265PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex = NULL;
2266PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB = NULL; 2429PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB = NULL;
2267PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB = NULL; 2430PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB = NULL;
2268PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB = NULL; 2431PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB = NULL;
@@ -2287,69 +2450,6 @@ PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glFramebufferSampleLocationsfvARB
2287PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB = NULL; 2450PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB = NULL;
2288PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB = NULL; 2451PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB = NULL;
2289PFNGLMINSAMPLESHADINGARBPROC glad_glMinSampleShadingARB = NULL; 2452PFNGLMINSAMPLESHADINGARBPROC glad_glMinSampleShadingARB = NULL;
2290PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL;
2291PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL;
2292PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL;
2293PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL;
2294PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL;
2295PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL;
2296PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL;
2297PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL;
2298PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL;
2299PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL;
2300PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL;
2301PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL;
2302PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL;
2303PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL;
2304PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL;
2305PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL;
2306PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL;
2307PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL;
2308PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL;
2309PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL;
2310PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL;
2311PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL;
2312PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL;
2313PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL;
2314PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL;
2315PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL;
2316PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL;
2317PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL;
2318PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL;
2319PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL;
2320PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL;
2321PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL;
2322PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL;
2323PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL;
2324PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL;
2325PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL;
2326PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL;
2327PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL;
2328PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL;
2329PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL;
2330PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL;
2331PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL;
2332PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL;
2333PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL;
2334PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL;
2335PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL;
2336PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL;
2337PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL;
2338PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL;
2339PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL;
2340PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL;
2341PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL;
2342PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL;
2343PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL;
2344PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL;
2345PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL;
2346PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL;
2347PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL;
2348PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL;
2349PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL;
2350PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv = NULL;
2351PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture = NULL;
2352PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL;
2353PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB = NULL; 2453PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB = NULL;
2354PFNGLGETHANDLEARBPROC glad_glGetHandleARB = NULL; 2454PFNGLGETHANDLEARBPROC glad_glGetHandleARB = NULL;
2355PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB = NULL; 2455PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB = NULL;
@@ -2389,15 +2489,6 @@ PFNGLGETACTIVEUNIFORMARBPROC glad_glGetActiveUniformARB = NULL;
2389PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB = NULL; 2489PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB = NULL;
2390PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB = NULL; 2490PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB = NULL;
2391PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB = NULL; 2491PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB = NULL;
2392PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding = NULL;
2393PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL;
2394PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL;
2395PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL;
2396PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL;
2397PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL;
2398PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL;
2399PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL;
2400PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL;
2401PFNGLNAMEDSTRINGARBPROC glad_glNamedStringARB = NULL; 2492PFNGLNAMEDSTRINGARBPROC glad_glNamedStringARB = NULL;
2402PFNGLDELETENAMEDSTRINGARBPROC glad_glDeleteNamedStringARB = NULL; 2493PFNGLDELETENAMEDSTRINGARBPROC glad_glDeleteNamedStringARB = NULL;
2403PFNGLCOMPILESHADERINCLUDEARBPROC glad_glCompileShaderIncludeARB = NULL; 2494PFNGLCOMPILESHADERINCLUDEARBPROC glad_glCompileShaderIncludeARB = NULL;
@@ -2408,11 +2499,8 @@ PFNGLBUFFERPAGECOMMITMENTARBPROC glad_glBufferPageCommitmentARB = NULL;
2408PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC glad_glNamedBufferPageCommitmentEXT = NULL; 2499PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC glad_glNamedBufferPageCommitmentEXT = NULL;
2409PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC glad_glNamedBufferPageCommitmentARB = NULL; 2500PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC glad_glNamedBufferPageCommitmentARB = NULL;
2410PFNGLTEXPAGECOMMITMENTARBPROC glad_glTexPageCommitmentARB = NULL; 2501PFNGLTEXPAGECOMMITMENTARBPROC glad_glTexPageCommitmentARB = NULL;
2411PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL;
2412PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL;
2413PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier = NULL; 2502PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier = NULL;
2414PFNGLTEXBUFFERARBPROC glad_glTexBufferARB = NULL; 2503PFNGLTEXBUFFERARBPROC glad_glTexBufferARB = NULL;
2415PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange = NULL;
2416PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB = NULL; 2504PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB = NULL;
2417PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB = NULL; 2505PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB = NULL;
2418PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB = NULL; 2506PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB = NULL;
@@ -2420,45 +2508,10 @@ PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB = NULL;
2420PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB = NULL; 2508PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB = NULL;
2421PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB = NULL; 2509PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB = NULL;
2422PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB = NULL; 2510PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB = NULL;
2423PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D = NULL;
2424PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL;
2425PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL;
2426PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample = NULL;
2427PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL;
2428PFNGLTEXTUREVIEWPROC glad_glTextureView = NULL;
2429PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;
2430PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL;
2431PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;
2432PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL;
2433PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL;
2434PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;
2435PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL;
2436PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL;
2437PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL;
2438PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL;
2439PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL;
2440PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced = NULL;
2441PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced = NULL;
2442PFNGLLOADTRANSPOSEMATRIXFARBPROC glad_glLoadTransposeMatrixfARB = NULL; 2511PFNGLLOADTRANSPOSEMATRIXFARBPROC glad_glLoadTransposeMatrixfARB = NULL;
2443PFNGLLOADTRANSPOSEMATRIXDARBPROC glad_glLoadTransposeMatrixdARB = NULL; 2512PFNGLLOADTRANSPOSEMATRIXDARBPROC glad_glLoadTransposeMatrixdARB = NULL;
2444PFNGLMULTTRANSPOSEMATRIXFARBPROC glad_glMultTransposeMatrixfARB = NULL; 2513PFNGLMULTTRANSPOSEMATRIXFARBPROC glad_glMultTransposeMatrixfARB = NULL;
2445PFNGLMULTTRANSPOSEMATRIXDARBPROC glad_glMultTransposeMatrixdARB = NULL; 2514PFNGLMULTTRANSPOSEMATRIXDARBPROC glad_glMultTransposeMatrixdARB = NULL;
2446PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL;
2447PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL;
2448PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL;
2449PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL;
2450PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL;
2451PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL;
2452PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL;
2453PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL;
2454PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL;
2455PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL;
2456PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer = NULL;
2457PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat = NULL;
2458PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat = NULL;
2459PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat = NULL;
2460PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding = NULL;
2461PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor = NULL;
2462PFNGLWEIGHTBVARBPROC glad_glWeightbvARB = NULL; 2515PFNGLWEIGHTBVARBPROC glad_glWeightbvARB = NULL;
2463PFNGLWEIGHTSVARBPROC glad_glWeightsvARB = NULL; 2516PFNGLWEIGHTSVARBPROC glad_glWeightsvARB = NULL;
2464PFNGLWEIGHTIVARBPROC glad_glWeightivARB = NULL; 2517PFNGLWEIGHTIVARBPROC glad_glWeightivARB = NULL;
@@ -2526,16 +2579,6 @@ PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB = NULL;
2526PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB = NULL; 2579PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB = NULL;
2527PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB = NULL; 2580PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB = NULL;
2528PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB = NULL; 2581PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB = NULL;
2529PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL;
2530PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;
2531PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
2532PFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL;
2533PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL;
2534PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL;
2535PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL;
2536PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL;
2537PFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL;
2538PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL;
2539PFNGLWINDOWPOS2DARBPROC glad_glWindowPos2dARB = NULL; 2582PFNGLWINDOWPOS2DARBPROC glad_glWindowPos2dARB = NULL;
2540PFNGLWINDOWPOS2DVARBPROC glad_glWindowPos2dvARB = NULL; 2583PFNGLWINDOWPOS2DVARBPROC glad_glWindowPos2dvARB = NULL;
2541PFNGLWINDOWPOS2FARBPROC glad_glWindowPos2fARB = NULL; 2584PFNGLWINDOWPOS2FARBPROC glad_glWindowPos2fARB = NULL;
@@ -3237,17 +3280,6 @@ PFNGLGETPERFQUERYDATAINTELPROC glad_glGetPerfQueryDataINTEL = NULL;
3237PFNGLGETPERFQUERYIDBYNAMEINTELPROC glad_glGetPerfQueryIdByNameINTEL = NULL; 3280PFNGLGETPERFQUERYIDBYNAMEINTELPROC glad_glGetPerfQueryIdByNameINTEL = NULL;
3238PFNGLGETPERFQUERYINFOINTELPROC glad_glGetPerfQueryInfoINTEL = NULL; 3281PFNGLGETPERFQUERYINFOINTELPROC glad_glGetPerfQueryInfoINTEL = NULL;
3239PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR = NULL; 3282PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR = NULL;
3240PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL;
3241PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL;
3242PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL;
3243PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL;
3244PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL;
3245PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL;
3246PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL;
3247PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL;
3248PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL;
3249PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL;
3250PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;
3251PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR = NULL; 3283PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR = NULL;
3252PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR = NULL; 3284PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR = NULL;
3253PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR = NULL; 3285PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR = NULL;
@@ -3463,6 +3495,16 @@ PFNGLVERTEXATTRIBS2HVNVPROC glad_glVertexAttribs2hvNV = NULL;
3463PFNGLVERTEXATTRIBS3HVNVPROC glad_glVertexAttribs3hvNV = NULL; 3495PFNGLVERTEXATTRIBS3HVNVPROC glad_glVertexAttribs3hvNV = NULL;
3464PFNGLVERTEXATTRIBS4HVNVPROC glad_glVertexAttribs4hvNV = NULL; 3496PFNGLVERTEXATTRIBS4HVNVPROC glad_glVertexAttribs4hvNV = NULL;
3465PFNGLGETINTERNALFORMATSAMPLEIVNVPROC glad_glGetInternalformatSampleivNV = NULL; 3497PFNGLGETINTERNALFORMATSAMPLEIVNVPROC glad_glGetInternalformatSampleivNV = NULL;
3498PFNGLGETMEMORYOBJECTDETACHEDRESOURCESUIVNVPROC glad_glGetMemoryObjectDetachedResourcesuivNV = NULL;
3499PFNGLRESETMEMORYOBJECTPARAMETERNVPROC glad_glResetMemoryObjectParameterNV = NULL;
3500PFNGLTEXATTACHMEMORYNVPROC glad_glTexAttachMemoryNV = NULL;
3501PFNGLBUFFERATTACHMEMORYNVPROC glad_glBufferAttachMemoryNV = NULL;
3502PFNGLTEXTUREATTACHMEMORYNVPROC glad_glTextureAttachMemoryNV = NULL;
3503PFNGLNAMEDBUFFERATTACHMEMORYNVPROC glad_glNamedBufferAttachMemoryNV = NULL;
3504PFNGLDRAWMESHTASKSNVPROC glad_glDrawMeshTasksNV = NULL;
3505PFNGLDRAWMESHTASKSINDIRECTNVPROC glad_glDrawMeshTasksIndirectNV = NULL;
3506PFNGLMULTIDRAWMESHTASKSINDIRECTNVPROC glad_glMultiDrawMeshTasksIndirectNV = NULL;
3507PFNGLMULTIDRAWMESHTASKSINDIRECTCOUNTNVPROC glad_glMultiDrawMeshTasksIndirectCountNV = NULL;
3466PFNGLGENOCCLUSIONQUERIESNVPROC glad_glGenOcclusionQueriesNV = NULL; 3508PFNGLGENOCCLUSIONQUERIESNVPROC glad_glGenOcclusionQueriesNV = NULL;
3467PFNGLDELETEOCCLUSIONQUERIESNVPROC glad_glDeleteOcclusionQueriesNV = NULL; 3509PFNGLDELETEOCCLUSIONQUERIESNVPROC glad_glDeleteOcclusionQueriesNV = NULL;
3468PFNGLISOCCLUSIONQUERYNVPROC glad_glIsOcclusionQueryNV = NULL; 3510PFNGLISOCCLUSIONQUERYNVPROC glad_glIsOcclusionQueryNV = NULL;
@@ -3571,6 +3613,8 @@ PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC glad_glGetCombinerStageParameterfvNV = NU
3571PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glFramebufferSampleLocationsfvNV = NULL; 3613PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glFramebufferSampleLocationsfvNV = NULL;
3572PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glNamedFramebufferSampleLocationsfvNV = NULL; 3614PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glNamedFramebufferSampleLocationsfvNV = NULL;
3573PFNGLRESOLVEDEPTHVALUESNVPROC glad_glResolveDepthValuesNV = NULL; 3615PFNGLRESOLVEDEPTHVALUESNVPROC glad_glResolveDepthValuesNV = NULL;
3616PFNGLSCISSOREXCLUSIVENVPROC glad_glScissorExclusiveNV = NULL;
3617PFNGLSCISSOREXCLUSIVEARRAYVNVPROC glad_glScissorExclusiveArrayvNV = NULL;
3574PFNGLMAKEBUFFERRESIDENTNVPROC glad_glMakeBufferResidentNV = NULL; 3618PFNGLMAKEBUFFERRESIDENTNVPROC glad_glMakeBufferResidentNV = NULL;
3575PFNGLMAKEBUFFERNONRESIDENTNVPROC glad_glMakeBufferNonResidentNV = NULL; 3619PFNGLMAKEBUFFERNONRESIDENTNVPROC glad_glMakeBufferNonResidentNV = NULL;
3576PFNGLISBUFFERRESIDENTNVPROC glad_glIsBufferResidentNV = NULL; 3620PFNGLISBUFFERRESIDENTNVPROC glad_glIsBufferResidentNV = NULL;
@@ -3584,6 +3628,13 @@ PFNGLUNIFORMUI64NVPROC glad_glUniformui64NV = NULL;
3584PFNGLUNIFORMUI64VNVPROC glad_glUniformui64vNV = NULL; 3628PFNGLUNIFORMUI64VNVPROC glad_glUniformui64vNV = NULL;
3585PFNGLPROGRAMUNIFORMUI64NVPROC glad_glProgramUniformui64NV = NULL; 3629PFNGLPROGRAMUNIFORMUI64NVPROC glad_glProgramUniformui64NV = NULL;
3586PFNGLPROGRAMUNIFORMUI64VNVPROC glad_glProgramUniformui64vNV = NULL; 3630PFNGLPROGRAMUNIFORMUI64VNVPROC glad_glProgramUniformui64vNV = NULL;
3631PFNGLBINDSHADINGRATEIMAGENVPROC glad_glBindShadingRateImageNV = NULL;
3632PFNGLGETSHADINGRATEIMAGEPALETTENVPROC glad_glGetShadingRateImagePaletteNV = NULL;
3633PFNGLGETSHADINGRATESAMPLELOCATIONIVNVPROC glad_glGetShadingRateSampleLocationivNV = NULL;
3634PFNGLSHADINGRATEIMAGEBARRIERNVPROC glad_glShadingRateImageBarrierNV = NULL;
3635PFNGLSHADINGRATEIMAGEPALETTENVPROC glad_glShadingRateImagePaletteNV = NULL;
3636PFNGLSHADINGRATESAMPLEORDERNVPROC glad_glShadingRateSampleOrderNV = NULL;
3637PFNGLSHADINGRATESAMPLEORDERCUSTOMNVPROC glad_glShadingRateSampleOrderCustomNV = NULL;
3587PFNGLTEXTUREBARRIERNVPROC glad_glTextureBarrierNV = NULL; 3638PFNGLTEXTUREBARRIERNVPROC glad_glTextureBarrierNV = NULL;
3588PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC glad_glTexImage2DMultisampleCoverageNV = NULL; 3639PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC glad_glTexImage2DMultisampleCoverageNV = NULL;
3589PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC glad_glTexImage3DMultisampleCoverageNV = NULL; 3640PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC glad_glTexImage3DMultisampleCoverageNV = NULL;
@@ -3620,6 +3671,7 @@ PFNGLVDPAUGETSURFACEIVNVPROC glad_glVDPAUGetSurfaceivNV = NULL;
3620PFNGLVDPAUSURFACEACCESSNVPROC glad_glVDPAUSurfaceAccessNV = NULL; 3671PFNGLVDPAUSURFACEACCESSNVPROC glad_glVDPAUSurfaceAccessNV = NULL;
3621PFNGLVDPAUMAPSURFACESNVPROC glad_glVDPAUMapSurfacesNV = NULL; 3672PFNGLVDPAUMAPSURFACESNVPROC glad_glVDPAUMapSurfacesNV = NULL;
3622PFNGLVDPAUUNMAPSURFACESNVPROC glad_glVDPAUUnmapSurfacesNV = NULL; 3673PFNGLVDPAUUNMAPSURFACESNVPROC glad_glVDPAUUnmapSurfacesNV = NULL;
3674PFNGLVDPAUREGISTERVIDEOSURFACEWITHPICTURESTRUCTURENVPROC glad_glVDPAURegisterVideoSurfaceWithPictureStructureNV = NULL;
3623PFNGLFLUSHVERTEXARRAYRANGENVPROC glad_glFlushVertexArrayRangeNV = NULL; 3675PFNGLFLUSHVERTEXARRAYRANGENVPROC glad_glFlushVertexArrayRangeNV = NULL;
3624PFNGLVERTEXARRAYRANGENVPROC glad_glVertexArrayRangeNV = NULL; 3676PFNGLVERTEXARRAYRANGENVPROC glad_glVertexArrayRangeNV = NULL;
3625PFNGLVERTEXATTRIBL1I64NVPROC glad_glVertexAttribL1i64NV = NULL; 3677PFNGLVERTEXATTRIBL1I64NVPROC glad_glVertexAttribL1i64NV = NULL;
@@ -4439,6 +4491,209 @@ static void load_GL_VERSION_3_3(GLADloadproc load) {
4439 glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui"); 4491 glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui");
4440 glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv"); 4492 glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv");
4441} 4493}
4494static void load_GL_VERSION_4_0(GLADloadproc load) {
4495 if(!GLAD_GL_VERSION_4_0) return;
4496 glad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC)load("glMinSampleShading");
4497 glad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC)load("glBlendEquationi");
4498 glad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC)load("glBlendEquationSeparatei");
4499 glad_glBlendFunci = (PFNGLBLENDFUNCIPROC)load("glBlendFunci");
4500 glad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC)load("glBlendFuncSeparatei");
4501 glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC)load("glDrawArraysIndirect");
4502 glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC)load("glDrawElementsIndirect");
4503 glad_glUniform1d = (PFNGLUNIFORM1DPROC)load("glUniform1d");
4504 glad_glUniform2d = (PFNGLUNIFORM2DPROC)load("glUniform2d");
4505 glad_glUniform3d = (PFNGLUNIFORM3DPROC)load("glUniform3d");
4506 glad_glUniform4d = (PFNGLUNIFORM4DPROC)load("glUniform4d");
4507 glad_glUniform1dv = (PFNGLUNIFORM1DVPROC)load("glUniform1dv");
4508 glad_glUniform2dv = (PFNGLUNIFORM2DVPROC)load("glUniform2dv");
4509 glad_glUniform3dv = (PFNGLUNIFORM3DVPROC)load("glUniform3dv");
4510 glad_glUniform4dv = (PFNGLUNIFORM4DVPROC)load("glUniform4dv");
4511 glad_glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC)load("glUniformMatrix2dv");
4512 glad_glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC)load("glUniformMatrix3dv");
4513 glad_glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC)load("glUniformMatrix4dv");
4514 glad_glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC)load("glUniformMatrix2x3dv");
4515 glad_glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC)load("glUniformMatrix2x4dv");
4516 glad_glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC)load("glUniformMatrix3x2dv");
4517 glad_glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC)load("glUniformMatrix3x4dv");
4518 glad_glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC)load("glUniformMatrix4x2dv");
4519 glad_glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC)load("glUniformMatrix4x3dv");
4520 glad_glGetUniformdv = (PFNGLGETUNIFORMDVPROC)load("glGetUniformdv");
4521 glad_glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)load("glGetSubroutineUniformLocation");
4522 glad_glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC)load("glGetSubroutineIndex");
4523 glad_glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)load("glGetActiveSubroutineUniformiv");
4524 glad_glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)load("glGetActiveSubroutineUniformName");
4525 glad_glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC)load("glGetActiveSubroutineName");
4526 glad_glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC)load("glUniformSubroutinesuiv");
4527 glad_glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC)load("glGetUniformSubroutineuiv");
4528 glad_glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC)load("glGetProgramStageiv");
4529 glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)load("glPatchParameteri");
4530 glad_glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC)load("glPatchParameterfv");
4531 glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)load("glBindTransformFeedback");
4532 glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC)load("glDeleteTransformFeedbacks");
4533 glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)load("glGenTransformFeedbacks");
4534 glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC)load("glIsTransformFeedback");
4535 glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC)load("glPauseTransformFeedback");
4536 glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC)load("glResumeTransformFeedback");
4537 glad_glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC)load("glDrawTransformFeedback");
4538 glad_glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)load("glDrawTransformFeedbackStream");
4539 glad_glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC)load("glBeginQueryIndexed");
4540 glad_glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC)load("glEndQueryIndexed");
4541 glad_glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC)load("glGetQueryIndexediv");
4542}
4543static void load_GL_VERSION_4_1(GLADloadproc load) {
4544 if(!GLAD_GL_VERSION_4_1) return;
4545 glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler");
4546 glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary");
4547 glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat");
4548 glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef");
4549 glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf");
4550 glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)load("glGetProgramBinary");
4551 glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC)load("glProgramBinary");
4552 glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri");
4553 glad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC)load("glUseProgramStages");
4554 glad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC)load("glActiveShaderProgram");
4555 glad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC)load("glCreateShaderProgramv");
4556 glad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC)load("glBindProgramPipeline");
4557 glad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC)load("glDeleteProgramPipelines");
4558 glad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC)load("glGenProgramPipelines");
4559 glad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC)load("glIsProgramPipeline");
4560 glad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC)load("glGetProgramPipelineiv");
4561 glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri");
4562 glad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)load("glProgramUniform1i");
4563 glad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC)load("glProgramUniform1iv");
4564 glad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)load("glProgramUniform1f");
4565 glad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC)load("glProgramUniform1fv");
4566 glad_glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC)load("glProgramUniform1d");
4567 glad_glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC)load("glProgramUniform1dv");
4568 glad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC)load("glProgramUniform1ui");
4569 glad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC)load("glProgramUniform1uiv");
4570 glad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC)load("glProgramUniform2i");
4571 glad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC)load("glProgramUniform2iv");
4572 glad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC)load("glProgramUniform2f");
4573 glad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC)load("glProgramUniform2fv");
4574 glad_glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC)load("glProgramUniform2d");
4575 glad_glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC)load("glProgramUniform2dv");
4576 glad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC)load("glProgramUniform2ui");
4577 glad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC)load("glProgramUniform2uiv");
4578 glad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC)load("glProgramUniform3i");
4579 glad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC)load("glProgramUniform3iv");
4580 glad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)load("glProgramUniform3f");
4581 glad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC)load("glProgramUniform3fv");
4582 glad_glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC)load("glProgramUniform3d");
4583 glad_glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC)load("glProgramUniform3dv");
4584 glad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC)load("glProgramUniform3ui");
4585 glad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC)load("glProgramUniform3uiv");
4586 glad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC)load("glProgramUniform4i");
4587 glad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC)load("glProgramUniform4iv");
4588 glad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC)load("glProgramUniform4f");
4589 glad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC)load("glProgramUniform4fv");
4590 glad_glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC)load("glProgramUniform4d");
4591 glad_glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC)load("glProgramUniform4dv");
4592 glad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC)load("glProgramUniform4ui");
4593 glad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC)load("glProgramUniform4uiv");
4594 glad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC)load("glProgramUniformMatrix2fv");
4595 glad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC)load("glProgramUniformMatrix3fv");
4596 glad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)load("glProgramUniformMatrix4fv");
4597 glad_glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC)load("glProgramUniformMatrix2dv");
4598 glad_glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC)load("glProgramUniformMatrix3dv");
4599 glad_glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC)load("glProgramUniformMatrix4dv");
4600 glad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)load("glProgramUniformMatrix2x3fv");
4601 glad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)load("glProgramUniformMatrix3x2fv");
4602 glad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)load("glProgramUniformMatrix2x4fv");
4603 glad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)load("glProgramUniformMatrix4x2fv");
4604 glad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)load("glProgramUniformMatrix3x4fv");
4605 glad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)load("glProgramUniformMatrix4x3fv");
4606 glad_glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)load("glProgramUniformMatrix2x3dv");
4607 glad_glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)load("glProgramUniformMatrix3x2dv");
4608 glad_glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)load("glProgramUniformMatrix2x4dv");
4609 glad_glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)load("glProgramUniformMatrix4x2dv");
4610 glad_glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)load("glProgramUniformMatrix3x4dv");
4611 glad_glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)load("glProgramUniformMatrix4x3dv");
4612 glad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC)load("glValidateProgramPipeline");
4613 glad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC)load("glGetProgramPipelineInfoLog");
4614 glad_glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC)load("glVertexAttribL1d");
4615 glad_glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC)load("glVertexAttribL2d");
4616 glad_glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC)load("glVertexAttribL3d");
4617 glad_glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC)load("glVertexAttribL4d");
4618 glad_glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC)load("glVertexAttribL1dv");
4619 glad_glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC)load("glVertexAttribL2dv");
4620 glad_glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC)load("glVertexAttribL3dv");
4621 glad_glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC)load("glVertexAttribL4dv");
4622 glad_glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC)load("glVertexAttribLPointer");
4623 glad_glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC)load("glGetVertexAttribLdv");
4624 glad_glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC)load("glViewportArrayv");
4625 glad_glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC)load("glViewportIndexedf");
4626 glad_glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC)load("glViewportIndexedfv");
4627 glad_glScissorArrayv = (PFNGLSCISSORARRAYVPROC)load("glScissorArrayv");
4628 glad_glScissorIndexed = (PFNGLSCISSORINDEXEDPROC)load("glScissorIndexed");
4629 glad_glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC)load("glScissorIndexedv");
4630 glad_glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC)load("glDepthRangeArrayv");
4631 glad_glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC)load("glDepthRangeIndexed");
4632 glad_glGetFloati_v = (PFNGLGETFLOATI_VPROC)load("glGetFloati_v");
4633 glad_glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC)load("glGetDoublei_v");
4634}
4635static void load_GL_VERSION_4_2(GLADloadproc load) {
4636 if(!GLAD_GL_VERSION_4_2) return;
4637 glad_glDrawArraysInstancedBaseInstance = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)load("glDrawArraysInstancedBaseInstance");
4638 glad_glDrawElementsInstancedBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)load("glDrawElementsInstancedBaseInstance");
4639 glad_glDrawElementsInstancedBaseVertexBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)load("glDrawElementsInstancedBaseVertexBaseInstance");
4640 glad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC)load("glGetInternalformativ");
4641 glad_glGetActiveAtomicCounterBufferiv = (PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)load("glGetActiveAtomicCounterBufferiv");
4642 glad_glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)load("glBindImageTexture");
4643 glad_glMemoryBarrier = (PFNGLMEMORYBARRIERPROC)load("glMemoryBarrier");
4644 glad_glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)load("glTexStorage1D");
4645 glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)load("glTexStorage2D");
4646 glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)load("glTexStorage3D");
4647 glad_glDrawTransformFeedbackInstanced = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)load("glDrawTransformFeedbackInstanced");
4648 glad_glDrawTransformFeedbackStreamInstanced = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)load("glDrawTransformFeedbackStreamInstanced");
4649}
4650static void load_GL_VERSION_4_3(GLADloadproc load) {
4651 if(!GLAD_GL_VERSION_4_3) return;
4652 glad_glClearBufferData = (PFNGLCLEARBUFFERDATAPROC)load("glClearBufferData");
4653 glad_glClearBufferSubData = (PFNGLCLEARBUFFERSUBDATAPROC)load("glClearBufferSubData");
4654 glad_glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC)load("glDispatchCompute");
4655 glad_glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC)load("glDispatchComputeIndirect");
4656 glad_glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC)load("glCopyImageSubData");
4657 glad_glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC)load("glFramebufferParameteri");
4658 glad_glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC)load("glGetFramebufferParameteriv");
4659 glad_glGetInternalformati64v = (PFNGLGETINTERNALFORMATI64VPROC)load("glGetInternalformati64v");
4660 glad_glInvalidateTexSubImage = (PFNGLINVALIDATETEXSUBIMAGEPROC)load("glInvalidateTexSubImage");
4661 glad_glInvalidateTexImage = (PFNGLINVALIDATETEXIMAGEPROC)load("glInvalidateTexImage");
4662 glad_glInvalidateBufferSubData = (PFNGLINVALIDATEBUFFERSUBDATAPROC)load("glInvalidateBufferSubData");
4663 glad_glInvalidateBufferData = (PFNGLINVALIDATEBUFFERDATAPROC)load("glInvalidateBufferData");
4664 glad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC)load("glInvalidateFramebuffer");
4665 glad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC)load("glInvalidateSubFramebuffer");
4666 glad_glMultiDrawArraysIndirect = (PFNGLMULTIDRAWARRAYSINDIRECTPROC)load("glMultiDrawArraysIndirect");
4667 glad_glMultiDrawElementsIndirect = (PFNGLMULTIDRAWELEMENTSINDIRECTPROC)load("glMultiDrawElementsIndirect");
4668 glad_glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC)load("glGetProgramInterfaceiv");
4669 glad_glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC)load("glGetProgramResourceIndex");
4670 glad_glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)load("glGetProgramResourceName");
4671 glad_glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC)load("glGetProgramResourceiv");
4672 glad_glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC)load("glGetProgramResourceLocation");
4673 glad_glGetProgramResourceLocationIndex = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)load("glGetProgramResourceLocationIndex");
4674 glad_glShaderStorageBlockBinding = (PFNGLSHADERSTORAGEBLOCKBINDINGPROC)load("glShaderStorageBlockBinding");
4675 glad_glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC)load("glTexBufferRange");
4676 glad_glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC)load("glTexStorage2DMultisample");
4677 glad_glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)load("glTexStorage3DMultisample");
4678 glad_glTextureView = (PFNGLTEXTUREVIEWPROC)load("glTextureView");
4679 glad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)load("glBindVertexBuffer");
4680 glad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)load("glVertexAttribFormat");
4681 glad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)load("glVertexAttribIFormat");
4682 glad_glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC)load("glVertexAttribLFormat");
4683 glad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)load("glVertexAttribBinding");
4684 glad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC)load("glVertexBindingDivisor");
4685 glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load("glDebugMessageControl");
4686 glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load("glDebugMessageInsert");
4687 glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load("glDebugMessageCallback");
4688 glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load("glGetDebugMessageLog");
4689 glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load("glPushDebugGroup");
4690 glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load("glPopDebugGroup");
4691 glad_glObjectLabel = (PFNGLOBJECTLABELPROC)load("glObjectLabel");
4692 glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load("glGetObjectLabel");
4693 glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load("glObjectPtrLabel");
4694 glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load("glGetObjectPtrLabel");
4695 glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv");
4696}
4442static void load_GL_3DFX_tbuffer(GLADloadproc load) { 4697static void load_GL_3DFX_tbuffer(GLADloadproc load) {
4443 if(!GLAD_GL_3DFX_tbuffer) return; 4698 if(!GLAD_GL_3DFX_tbuffer) return;
4444 glad_glTbufferMask3DFX = (PFNGLTBUFFERMASK3DFXPROC)load("glTbufferMask3DFX"); 4699 glad_glTbufferMask3DFX = (PFNGLTBUFFERMASK3DFXPROC)load("glTbufferMask3DFX");
@@ -7054,6 +7309,22 @@ static void load_GL_NV_internalformat_sample_query(GLADloadproc load) {
7054 if(!GLAD_GL_NV_internalformat_sample_query) return; 7309 if(!GLAD_GL_NV_internalformat_sample_query) return;
7055 glad_glGetInternalformatSampleivNV = (PFNGLGETINTERNALFORMATSAMPLEIVNVPROC)load("glGetInternalformatSampleivNV"); 7310 glad_glGetInternalformatSampleivNV = (PFNGLGETINTERNALFORMATSAMPLEIVNVPROC)load("glGetInternalformatSampleivNV");
7056} 7311}
7312static void load_GL_NV_memory_attachment(GLADloadproc load) {
7313 if(!GLAD_GL_NV_memory_attachment) return;
7314 glad_glGetMemoryObjectDetachedResourcesuivNV = (PFNGLGETMEMORYOBJECTDETACHEDRESOURCESUIVNVPROC)load("glGetMemoryObjectDetachedResourcesuivNV");
7315 glad_glResetMemoryObjectParameterNV = (PFNGLRESETMEMORYOBJECTPARAMETERNVPROC)load("glResetMemoryObjectParameterNV");
7316 glad_glTexAttachMemoryNV = (PFNGLTEXATTACHMEMORYNVPROC)load("glTexAttachMemoryNV");
7317 glad_glBufferAttachMemoryNV = (PFNGLBUFFERATTACHMEMORYNVPROC)load("glBufferAttachMemoryNV");
7318 glad_glTextureAttachMemoryNV = (PFNGLTEXTUREATTACHMEMORYNVPROC)load("glTextureAttachMemoryNV");
7319 glad_glNamedBufferAttachMemoryNV = (PFNGLNAMEDBUFFERATTACHMEMORYNVPROC)load("glNamedBufferAttachMemoryNV");
7320}
7321static void load_GL_NV_mesh_shader(GLADloadproc load) {
7322 if(!GLAD_GL_NV_mesh_shader) return;
7323 glad_glDrawMeshTasksNV = (PFNGLDRAWMESHTASKSNVPROC)load("glDrawMeshTasksNV");
7324 glad_glDrawMeshTasksIndirectNV = (PFNGLDRAWMESHTASKSINDIRECTNVPROC)load("glDrawMeshTasksIndirectNV");
7325 glad_glMultiDrawMeshTasksIndirectNV = (PFNGLMULTIDRAWMESHTASKSINDIRECTNVPROC)load("glMultiDrawMeshTasksIndirectNV");
7326 glad_glMultiDrawMeshTasksIndirectCountNV = (PFNGLMULTIDRAWMESHTASKSINDIRECTCOUNTNVPROC)load("glMultiDrawMeshTasksIndirectCountNV");
7327}
7057static void load_GL_NV_occlusion_query(GLADloadproc load) { 7328static void load_GL_NV_occlusion_query(GLADloadproc load) {
7058 if(!GLAD_GL_NV_occlusion_query) return; 7329 if(!GLAD_GL_NV_occlusion_query) return;
7059 glad_glGenOcclusionQueriesNV = (PFNGLGENOCCLUSIONQUERIESNVPROC)load("glGenOcclusionQueriesNV"); 7330 glad_glGenOcclusionQueriesNV = (PFNGLGENOCCLUSIONQUERIESNVPROC)load("glGenOcclusionQueriesNV");
@@ -7217,6 +7488,11 @@ static void load_GL_NV_sample_locations(GLADloadproc load) {
7217 glad_glNamedFramebufferSampleLocationsfvNV = (PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC)load("glNamedFramebufferSampleLocationsfvNV"); 7488 glad_glNamedFramebufferSampleLocationsfvNV = (PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC)load("glNamedFramebufferSampleLocationsfvNV");
7218 glad_glResolveDepthValuesNV = (PFNGLRESOLVEDEPTHVALUESNVPROC)load("glResolveDepthValuesNV"); 7489 glad_glResolveDepthValuesNV = (PFNGLRESOLVEDEPTHVALUESNVPROC)load("glResolveDepthValuesNV");
7219} 7490}
7491static void load_GL_NV_scissor_exclusive(GLADloadproc load) {
7492 if(!GLAD_GL_NV_scissor_exclusive) return;
7493 glad_glScissorExclusiveNV = (PFNGLSCISSOREXCLUSIVENVPROC)load("glScissorExclusiveNV");
7494 glad_glScissorExclusiveArrayvNV = (PFNGLSCISSOREXCLUSIVEARRAYVNVPROC)load("glScissorExclusiveArrayvNV");
7495}
7220static void load_GL_NV_shader_buffer_load(GLADloadproc load) { 7496static void load_GL_NV_shader_buffer_load(GLADloadproc load) {
7221 if(!GLAD_GL_NV_shader_buffer_load) return; 7497 if(!GLAD_GL_NV_shader_buffer_load) return;
7222 glad_glMakeBufferResidentNV = (PFNGLMAKEBUFFERRESIDENTNVPROC)load("glMakeBufferResidentNV"); 7498 glad_glMakeBufferResidentNV = (PFNGLMAKEBUFFERRESIDENTNVPROC)load("glMakeBufferResidentNV");
@@ -7234,6 +7510,17 @@ static void load_GL_NV_shader_buffer_load(GLADloadproc load) {
7234 glad_glProgramUniformui64NV = (PFNGLPROGRAMUNIFORMUI64NVPROC)load("glProgramUniformui64NV"); 7510 glad_glProgramUniformui64NV = (PFNGLPROGRAMUNIFORMUI64NVPROC)load("glProgramUniformui64NV");
7235 glad_glProgramUniformui64vNV = (PFNGLPROGRAMUNIFORMUI64VNVPROC)load("glProgramUniformui64vNV"); 7511 glad_glProgramUniformui64vNV = (PFNGLPROGRAMUNIFORMUI64VNVPROC)load("glProgramUniformui64vNV");
7236} 7512}
7513static void load_GL_NV_shading_rate_image(GLADloadproc load) {
7514 if(!GLAD_GL_NV_shading_rate_image) return;
7515 glad_glBindShadingRateImageNV = (PFNGLBINDSHADINGRATEIMAGENVPROC)load("glBindShadingRateImageNV");
7516 glad_glGetShadingRateImagePaletteNV = (PFNGLGETSHADINGRATEIMAGEPALETTENVPROC)load("glGetShadingRateImagePaletteNV");
7517 glad_glGetShadingRateSampleLocationivNV = (PFNGLGETSHADINGRATESAMPLELOCATIONIVNVPROC)load("glGetShadingRateSampleLocationivNV");
7518 glad_glShadingRateImageBarrierNV = (PFNGLSHADINGRATEIMAGEBARRIERNVPROC)load("glShadingRateImageBarrierNV");
7519 glad_glShadingRateImageBarrierNV = (PFNGLSHADINGRATEIMAGEBARRIERNVPROC)load("glShadingRateImageBarrierNV");
7520 glad_glShadingRateImagePaletteNV = (PFNGLSHADINGRATEIMAGEPALETTENVPROC)load("glShadingRateImagePaletteNV");
7521 glad_glShadingRateSampleOrderNV = (PFNGLSHADINGRATESAMPLEORDERNVPROC)load("glShadingRateSampleOrderNV");
7522 glad_glShadingRateSampleOrderCustomNV = (PFNGLSHADINGRATESAMPLEORDERCUSTOMNVPROC)load("glShadingRateSampleOrderCustomNV");
7523}
7237static void load_GL_NV_texture_barrier(GLADloadproc load) { 7524static void load_GL_NV_texture_barrier(GLADloadproc load) {
7238 if(!GLAD_GL_NV_texture_barrier) return; 7525 if(!GLAD_GL_NV_texture_barrier) return;
7239 glad_glTextureBarrierNV = (PFNGLTEXTUREBARRIERNVPROC)load("glTextureBarrierNV"); 7526 glad_glTextureBarrierNV = (PFNGLTEXTUREBARRIERNVPROC)load("glTextureBarrierNV");
@@ -7285,6 +7572,10 @@ static void load_GL_NV_vdpau_interop(GLADloadproc load) {
7285 glad_glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)load("glVDPAUMapSurfacesNV"); 7572 glad_glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)load("glVDPAUMapSurfacesNV");
7286 glad_glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)load("glVDPAUUnmapSurfacesNV"); 7573 glad_glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)load("glVDPAUUnmapSurfacesNV");
7287} 7574}
7575static void load_GL_NV_vdpau_interop2(GLADloadproc load) {
7576 if(!GLAD_GL_NV_vdpau_interop2) return;
7577 glad_glVDPAURegisterVideoSurfaceWithPictureStructureNV = (PFNGLVDPAUREGISTERVIDEOSURFACEWITHPICTURESTRUCTURENVPROC)load("glVDPAURegisterVideoSurfaceWithPictureStructureNV");
7578}
7288static void load_GL_NV_vertex_array_range(GLADloadproc load) { 7579static void load_GL_NV_vertex_array_range(GLADloadproc load) {
7289 if(!GLAD_GL_NV_vertex_array_range) return; 7580 if(!GLAD_GL_NV_vertex_array_range) return;
7290 glad_glFlushVertexArrayRangeNV = (PFNGLFLUSHVERTEXARRAYRANGENVPROC)load("glFlushVertexArrayRangeNV"); 7581 glad_glFlushVertexArrayRangeNV = (PFNGLFLUSHVERTEXARRAYRANGENVPROC)load("glFlushVertexArrayRangeNV");
@@ -8224,6 +8515,7 @@ static int find_extensionsGL(void) {
8224 GLAD_GL_NV_clip_space_w_scaling = has_ext("GL_NV_clip_space_w_scaling"); 8515 GLAD_GL_NV_clip_space_w_scaling = has_ext("GL_NV_clip_space_w_scaling");
8225 GLAD_GL_NV_command_list = has_ext("GL_NV_command_list"); 8516 GLAD_GL_NV_command_list = has_ext("GL_NV_command_list");
8226 GLAD_GL_NV_compute_program5 = has_ext("GL_NV_compute_program5"); 8517 GLAD_GL_NV_compute_program5 = has_ext("GL_NV_compute_program5");
8518 GLAD_GL_NV_compute_shader_derivatives = has_ext("GL_NV_compute_shader_derivatives");
8227 GLAD_GL_NV_conditional_render = has_ext("GL_NV_conditional_render"); 8519 GLAD_GL_NV_conditional_render = has_ext("GL_NV_conditional_render");
8228 GLAD_GL_NV_conservative_raster = has_ext("GL_NV_conservative_raster"); 8520 GLAD_GL_NV_conservative_raster = has_ext("GL_NV_conservative_raster");
8229 GLAD_GL_NV_conservative_raster_dilate = has_ext("GL_NV_conservative_raster_dilate"); 8521 GLAD_GL_NV_conservative_raster_dilate = has_ext("GL_NV_conservative_raster_dilate");
@@ -8248,6 +8540,7 @@ static int find_extensionsGL(void) {
8248 GLAD_GL_NV_fragment_program2 = has_ext("GL_NV_fragment_program2"); 8540 GLAD_GL_NV_fragment_program2 = has_ext("GL_NV_fragment_program2");
8249 GLAD_GL_NV_fragment_program4 = has_ext("GL_NV_fragment_program4"); 8541 GLAD_GL_NV_fragment_program4 = has_ext("GL_NV_fragment_program4");
8250 GLAD_GL_NV_fragment_program_option = has_ext("GL_NV_fragment_program_option"); 8542 GLAD_GL_NV_fragment_program_option = has_ext("GL_NV_fragment_program_option");
8543 GLAD_GL_NV_fragment_shader_barycentric = has_ext("GL_NV_fragment_shader_barycentric");
8251 GLAD_GL_NV_fragment_shader_interlock = has_ext("GL_NV_fragment_shader_interlock"); 8544 GLAD_GL_NV_fragment_shader_interlock = has_ext("GL_NV_fragment_shader_interlock");
8252 GLAD_GL_NV_framebuffer_mixed_samples = has_ext("GL_NV_framebuffer_mixed_samples"); 8545 GLAD_GL_NV_framebuffer_mixed_samples = has_ext("GL_NV_framebuffer_mixed_samples");
8253 GLAD_GL_NV_framebuffer_multisample_coverage = has_ext("GL_NV_framebuffer_multisample_coverage"); 8546 GLAD_GL_NV_framebuffer_multisample_coverage = has_ext("GL_NV_framebuffer_multisample_coverage");
@@ -8262,6 +8555,8 @@ static int find_extensionsGL(void) {
8262 GLAD_GL_NV_half_float = has_ext("GL_NV_half_float"); 8555 GLAD_GL_NV_half_float = has_ext("GL_NV_half_float");
8263 GLAD_GL_NV_internalformat_sample_query = has_ext("GL_NV_internalformat_sample_query"); 8556 GLAD_GL_NV_internalformat_sample_query = has_ext("GL_NV_internalformat_sample_query");
8264 GLAD_GL_NV_light_max_exponent = has_ext("GL_NV_light_max_exponent"); 8557 GLAD_GL_NV_light_max_exponent = has_ext("GL_NV_light_max_exponent");
8558 GLAD_GL_NV_memory_attachment = has_ext("GL_NV_memory_attachment");
8559 GLAD_GL_NV_mesh_shader = has_ext("GL_NV_mesh_shader");
8265 GLAD_GL_NV_multisample_coverage = has_ext("GL_NV_multisample_coverage"); 8560 GLAD_GL_NV_multisample_coverage = has_ext("GL_NV_multisample_coverage");
8266 GLAD_GL_NV_multisample_filter_hint = has_ext("GL_NV_multisample_filter_hint"); 8561 GLAD_GL_NV_multisample_filter_hint = has_ext("GL_NV_multisample_filter_hint");
8267 GLAD_GL_NV_occlusion_query = has_ext("GL_NV_occlusion_query"); 8562 GLAD_GL_NV_occlusion_query = has_ext("GL_NV_occlusion_query");
@@ -8278,9 +8573,11 @@ static int find_extensionsGL(void) {
8278 GLAD_GL_NV_query_resource_tag = has_ext("GL_NV_query_resource_tag"); 8573 GLAD_GL_NV_query_resource_tag = has_ext("GL_NV_query_resource_tag");
8279 GLAD_GL_NV_register_combiners = has_ext("GL_NV_register_combiners"); 8574 GLAD_GL_NV_register_combiners = has_ext("GL_NV_register_combiners");
8280 GLAD_GL_NV_register_combiners2 = has_ext("GL_NV_register_combiners2"); 8575 GLAD_GL_NV_register_combiners2 = has_ext("GL_NV_register_combiners2");
8576 GLAD_GL_NV_representative_fragment_test = has_ext("GL_NV_representative_fragment_test");
8281 GLAD_GL_NV_robustness_video_memory_purge = has_ext("GL_NV_robustness_video_memory_purge"); 8577 GLAD_GL_NV_robustness_video_memory_purge = has_ext("GL_NV_robustness_video_memory_purge");
8282 GLAD_GL_NV_sample_locations = has_ext("GL_NV_sample_locations"); 8578 GLAD_GL_NV_sample_locations = has_ext("GL_NV_sample_locations");
8283 GLAD_GL_NV_sample_mask_override_coverage = has_ext("GL_NV_sample_mask_override_coverage"); 8579 GLAD_GL_NV_sample_mask_override_coverage = has_ext("GL_NV_sample_mask_override_coverage");
8580 GLAD_GL_NV_scissor_exclusive = has_ext("GL_NV_scissor_exclusive");
8284 GLAD_GL_NV_shader_atomic_counters = has_ext("GL_NV_shader_atomic_counters"); 8581 GLAD_GL_NV_shader_atomic_counters = has_ext("GL_NV_shader_atomic_counters");
8285 GLAD_GL_NV_shader_atomic_float = has_ext("GL_NV_shader_atomic_float"); 8582 GLAD_GL_NV_shader_atomic_float = has_ext("GL_NV_shader_atomic_float");
8286 GLAD_GL_NV_shader_atomic_float64 = has_ext("GL_NV_shader_atomic_float64"); 8583 GLAD_GL_NV_shader_atomic_float64 = has_ext("GL_NV_shader_atomic_float64");
@@ -8289,8 +8586,10 @@ static int find_extensionsGL(void) {
8289 GLAD_GL_NV_shader_buffer_load = has_ext("GL_NV_shader_buffer_load"); 8586 GLAD_GL_NV_shader_buffer_load = has_ext("GL_NV_shader_buffer_load");
8290 GLAD_GL_NV_shader_buffer_store = has_ext("GL_NV_shader_buffer_store"); 8587 GLAD_GL_NV_shader_buffer_store = has_ext("GL_NV_shader_buffer_store");
8291 GLAD_GL_NV_shader_storage_buffer_object = has_ext("GL_NV_shader_storage_buffer_object"); 8588 GLAD_GL_NV_shader_storage_buffer_object = has_ext("GL_NV_shader_storage_buffer_object");
8589 GLAD_GL_NV_shader_texture_footprint = has_ext("GL_NV_shader_texture_footprint");
8292 GLAD_GL_NV_shader_thread_group = has_ext("GL_NV_shader_thread_group"); 8590 GLAD_GL_NV_shader_thread_group = has_ext("GL_NV_shader_thread_group");
8293 GLAD_GL_NV_shader_thread_shuffle = has_ext("GL_NV_shader_thread_shuffle"); 8591 GLAD_GL_NV_shader_thread_shuffle = has_ext("GL_NV_shader_thread_shuffle");
8592 GLAD_GL_NV_shading_rate_image = has_ext("GL_NV_shading_rate_image");
8294 GLAD_GL_NV_stereo_view_rendering = has_ext("GL_NV_stereo_view_rendering"); 8593 GLAD_GL_NV_stereo_view_rendering = has_ext("GL_NV_stereo_view_rendering");
8295 GLAD_GL_NV_tessellation_program5 = has_ext("GL_NV_tessellation_program5"); 8594 GLAD_GL_NV_tessellation_program5 = has_ext("GL_NV_tessellation_program5");
8296 GLAD_GL_NV_texgen_emboss = has_ext("GL_NV_texgen_emboss"); 8595 GLAD_GL_NV_texgen_emboss = has_ext("GL_NV_texgen_emboss");
@@ -8309,6 +8608,7 @@ static int find_extensionsGL(void) {
8309 GLAD_GL_NV_transform_feedback2 = has_ext("GL_NV_transform_feedback2"); 8608 GLAD_GL_NV_transform_feedback2 = has_ext("GL_NV_transform_feedback2");
8310 GLAD_GL_NV_uniform_buffer_unified_memory = has_ext("GL_NV_uniform_buffer_unified_memory"); 8609 GLAD_GL_NV_uniform_buffer_unified_memory = has_ext("GL_NV_uniform_buffer_unified_memory");
8311 GLAD_GL_NV_vdpau_interop = has_ext("GL_NV_vdpau_interop"); 8610 GLAD_GL_NV_vdpau_interop = has_ext("GL_NV_vdpau_interop");
8611 GLAD_GL_NV_vdpau_interop2 = has_ext("GL_NV_vdpau_interop2");
8312 GLAD_GL_NV_vertex_array_range = has_ext("GL_NV_vertex_array_range"); 8612 GLAD_GL_NV_vertex_array_range = has_ext("GL_NV_vertex_array_range");
8313 GLAD_GL_NV_vertex_array_range2 = has_ext("GL_NV_vertex_array_range2"); 8613 GLAD_GL_NV_vertex_array_range2 = has_ext("GL_NV_vertex_array_range2");
8314 GLAD_GL_NV_vertex_attrib_integer_64bit = has_ext("GL_NV_vertex_attrib_integer_64bit"); 8614 GLAD_GL_NV_vertex_attrib_integer_64bit = has_ext("GL_NV_vertex_attrib_integer_64bit");
@@ -8454,8 +8754,12 @@ static void find_coreGL(void) {
8454 GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; 8754 GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;
8455 GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; 8755 GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;
8456 GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; 8756 GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3;
8457 if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 3)) { 8757 GLAD_GL_VERSION_4_0 = (major == 4 && minor >= 0) || major > 4;
8458 max_loaded_major = 3; 8758 GLAD_GL_VERSION_4_1 = (major == 4 && minor >= 1) || major > 4;
8759 GLAD_GL_VERSION_4_2 = (major == 4 && minor >= 2) || major > 4;
8760 GLAD_GL_VERSION_4_3 = (major == 4 && minor >= 3) || major > 4;
8761 if (GLVersion.major > 4 || (GLVersion.major >= 4 && GLVersion.minor >= 3)) {
8762 max_loaded_major = 4;
8459 max_loaded_minor = 3; 8763 max_loaded_minor = 3;
8460 } 8764 }
8461} 8765}
@@ -8478,6 +8782,10 @@ int gladLoadGLLoader(GLADloadproc load) {
8478 load_GL_VERSION_3_1(load); 8782 load_GL_VERSION_3_1(load);
8479 load_GL_VERSION_3_2(load); 8783 load_GL_VERSION_3_2(load);
8480 load_GL_VERSION_3_3(load); 8784 load_GL_VERSION_3_3(load);
8785 load_GL_VERSION_4_0(load);
8786 load_GL_VERSION_4_1(load);
8787 load_GL_VERSION_4_2(load);
8788 load_GL_VERSION_4_3(load);
8481 8789
8482 if (!find_extensionsGL()) return 0; 8790 if (!find_extensionsGL()) return 0;
8483 load_GL_3DFX_tbuffer(load); 8791 load_GL_3DFX_tbuffer(load);
@@ -8718,6 +9026,8 @@ int gladLoadGLLoader(GLADloadproc load) {
8718 load_GL_NV_gpu_shader5(load); 9026 load_GL_NV_gpu_shader5(load);
8719 load_GL_NV_half_float(load); 9027 load_GL_NV_half_float(load);
8720 load_GL_NV_internalformat_sample_query(load); 9028 load_GL_NV_internalformat_sample_query(load);
9029 load_GL_NV_memory_attachment(load);
9030 load_GL_NV_mesh_shader(load);
8721 load_GL_NV_occlusion_query(load); 9031 load_GL_NV_occlusion_query(load);
8722 load_GL_NV_parameter_buffer_object(load); 9032 load_GL_NV_parameter_buffer_object(load);
8723 load_GL_NV_path_rendering(load); 9033 load_GL_NV_path_rendering(load);
@@ -8730,12 +9040,15 @@ int gladLoadGLLoader(GLADloadproc load) {
8730 load_GL_NV_register_combiners(load); 9040 load_GL_NV_register_combiners(load);
8731 load_GL_NV_register_combiners2(load); 9041 load_GL_NV_register_combiners2(load);
8732 load_GL_NV_sample_locations(load); 9042 load_GL_NV_sample_locations(load);
9043 load_GL_NV_scissor_exclusive(load);
8733 load_GL_NV_shader_buffer_load(load); 9044 load_GL_NV_shader_buffer_load(load);
9045 load_GL_NV_shading_rate_image(load);
8734 load_GL_NV_texture_barrier(load); 9046 load_GL_NV_texture_barrier(load);
8735 load_GL_NV_texture_multisample(load); 9047 load_GL_NV_texture_multisample(load);
8736 load_GL_NV_transform_feedback(load); 9048 load_GL_NV_transform_feedback(load);
8737 load_GL_NV_transform_feedback2(load); 9049 load_GL_NV_transform_feedback2(load);
8738 load_GL_NV_vdpau_interop(load); 9050 load_GL_NV_vdpau_interop(load);
9051 load_GL_NV_vdpau_interop2(load);
8739 load_GL_NV_vertex_array_range(load); 9052 load_GL_NV_vertex_array_range(load);
8740 load_GL_NV_vertex_attrib_integer_64bit(load); 9053 load_GL_NV_vertex_attrib_integer_64bit(load);
8741 load_GL_NV_vertex_buffer_unified_memory(load); 9054 load_GL_NV_vertex_buffer_unified_memory(load);
diff --git a/externals/xbyak b/externals/xbyak
deleted file mode 160000
Subproject 1de435ed04c8e74775804da944d176baf0ce56e
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 23e5d3f10..2e59894ab 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -8,7 +8,7 @@
8#include "audio_core/codec.h" 8#include "audio_core/codec.h"
9#include "common/assert.h" 9#include "common/assert.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/hle/kernel/event.h" 11#include "core/hle/kernel/writable_event.h"
12#include "core/memory.h" 12#include "core/memory.h"
13 13
14namespace AudioCore { 14namespace AudioCore {
@@ -72,7 +72,7 @@ private:
72 EffectInStatus info{}; 72 EffectInStatus info{};
73}; 73};
74AudioRenderer::AudioRenderer(AudioRendererParameter params, 74AudioRenderer::AudioRenderer(AudioRendererParameter params,
75 Kernel::SharedPtr<Kernel::Event> buffer_event) 75 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event)
76 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), 76 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
77 effects(params.effect_count) { 77 effects(params.effect_count) {
78 78
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 046417da3..7826881bf 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -15,7 +15,7 @@
15#include "core/hle/kernel/object.h" 15#include "core/hle/kernel/object.h"
16 16
17namespace Kernel { 17namespace Kernel {
18class Event; 18class WritableEvent;
19} 19}
20 20
21namespace AudioCore { 21namespace AudioCore {
@@ -143,7 +143,7 @@ struct AuxInfo {
143 std::array<u8, 24> output_mix_buffers; 143 std::array<u8, 24> output_mix_buffers;
144 u32_le mix_buffer_count; 144 u32_le mix_buffer_count;
145 u32_le sample_rate; // Stored in the aux buffer currently 145 u32_le sample_rate; // Stored in the aux buffer currently
146 u32_le sampe_count; 146 u32_le sample_count;
147 u64_le send_buffer_info; 147 u64_le send_buffer_info;
148 u64_le send_buffer_base; 148 u64_le send_buffer_base;
149 149
@@ -208,7 +208,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
208 208
209class AudioRenderer { 209class AudioRenderer {
210public: 210public:
211 AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event); 211 AudioRenderer(AudioRendererParameter params,
212 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event);
212 ~AudioRenderer(); 213 ~AudioRenderer();
213 214
214 std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params); 215 std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
@@ -224,7 +225,7 @@ private:
224 class VoiceState; 225 class VoiceState;
225 226
226 AudioRendererParameter worker_params; 227 AudioRendererParameter worker_params;
227 Kernel::SharedPtr<Kernel::Event> buffer_event; 228 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event;
228 std::vector<VoiceState> voices; 229 std::vector<VoiceState> voices;
229 std::vector<EffectState> effects; 230 std::vector<EffectState> effects;
230 std::unique_ptr<AudioOut> audio_out; 231 std::unique_ptr<AudioOut> audio_out;
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index eccd8f64a..a5e71d879 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -44,7 +44,6 @@ add_library(common STATIC
44 detached_tasks.cpp 44 detached_tasks.cpp
45 detached_tasks.h 45 detached_tasks.h
46 bit_field.h 46 bit_field.h
47 bit_set.h
48 cityhash.cpp 47 cityhash.cpp
49 cityhash.h 48 cityhash.h
50 color.h 49 color.h
@@ -95,14 +94,9 @@ if(ARCHITECTURE_x86_64)
95 PRIVATE 94 PRIVATE
96 x64/cpu_detect.cpp 95 x64/cpu_detect.cpp
97 x64/cpu_detect.h 96 x64/cpu_detect.h
98 x64/xbyak_abi.h
99 x64/xbyak_util.h
100 ) 97 )
101endif() 98endif()
102 99
103create_target_directory_groups(common) 100create_target_directory_groups(common)
104 101
105target_link_libraries(common PUBLIC Boost::boost fmt microprofile) 102target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
106if (ARCHITECTURE_x86_64)
107 target_link_libraries(common PRIVATE xbyak)
108endif()
diff --git a/src/common/assert.h b/src/common/assert.h
index 0d4eddc19..6002f7ab1 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -52,5 +52,8 @@ __declspec(noinline, noreturn)
52#define DEBUG_ASSERT_MSG(_a_, _desc_, ...) 52#define DEBUG_ASSERT_MSG(_a_, _desc_, ...)
53#endif 53#endif
54 54
55#define UNIMPLEMENTED() LOG_CRITICAL(Debug, "Unimplemented code!") 55#define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!")
56#define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__) 56#define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
57
58#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
59#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index bf803da8d..21e07925d 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -117,21 +117,21 @@ private:
117 // We don't delete it because we want BitField to be trivially copyable. 117 // We don't delete it because we want BitField to be trivially copyable.
118 constexpr BitField& operator=(const BitField&) = default; 118 constexpr BitField& operator=(const BitField&) = default;
119 119
120 // StorageType is T for non-enum types and the underlying type of T if 120 // UnderlyingType is T for non-enum types and the underlying type of T if
121 // T is an enumeration. Note that T is wrapped within an enable_if in the 121 // T is an enumeration. Note that T is wrapped within an enable_if in the
122 // former case to workaround compile errors which arise when using 122 // former case to workaround compile errors which arise when using
123 // std::underlying_type<T>::type directly. 123 // std::underlying_type<T>::type directly.
124 using StorageType = typename std::conditional_t<std::is_enum<T>::value, std::underlying_type<T>, 124 using UnderlyingType = typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>,
125 std::enable_if<true, T>>::type; 125 std::enable_if<true, T>>::type;
126 126
127 // Unsigned version of StorageType 127 // We store the value as the unsigned type to avoid undefined behaviour on value shifting
128 using StorageTypeU = std::make_unsigned_t<StorageType>; 128 using StorageType = std::make_unsigned_t<UnderlyingType>;
129 129
130public: 130public:
131 /// Constants to allow limited introspection of fields if needed 131 /// Constants to allow limited introspection of fields if needed
132 static constexpr std::size_t position = Position; 132 static constexpr std::size_t position = Position;
133 static constexpr std::size_t bits = Bits; 133 static constexpr std::size_t bits = Bits;
134 static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; 134 static constexpr StorageType mask = (((StorageType)~0) >> (8 * sizeof(T) - bits)) << position;
135 135
136 /** 136 /**
137 * Formats a value by masking and shifting it according to the field parameters. A value 137 * Formats a value by masking and shifting it according to the field parameters. A value
@@ -148,11 +148,12 @@ public:
148 * union in a constexpr context. 148 * union in a constexpr context.
149 */ 149 */
150 static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { 150 static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) {
151 if (std::numeric_limits<T>::is_signed) { 151 if constexpr (std::numeric_limits<UnderlyingType>::is_signed) {
152 std::size_t shift = 8 * sizeof(T) - bits; 152 std::size_t shift = 8 * sizeof(T) - bits;
153 return (T)((storage << (shift - position)) >> shift); 153 return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >>
154 shift);
154 } else { 155 } else {
155 return (T)((storage & mask) >> position); 156 return static_cast<T>((storage & mask) >> position);
156 } 157 }
157 } 158 }
158 159
diff --git a/src/common/bit_set.h b/src/common/bit_set.h
deleted file mode 100644
index 5cd1352b2..000000000
--- a/src/common/bit_set.h
+++ /dev/null
@@ -1,244 +0,0 @@
1// This file is under the public domain.
2
3#pragma once
4
5#include <cstddef>
6#ifdef _WIN32
7#include <intrin.h>
8#endif
9#include <initializer_list>
10#include <new>
11#include <type_traits>
12#include "common/common_types.h"
13
14// namespace avoids conflict with OS X Carbon; don't use BitSet<T> directly
15namespace Common {
16
17// Helper functions:
18
19#ifdef _MSC_VER
20template <typename T>
21static inline int CountSetBits(T v) {
22 // from https://graphics.stanford.edu/~seander/bithacks.html
23 // GCC has this built in, but MSVC's intrinsic will only emit the actual
24 // POPCNT instruction, which we're not depending on
25 v = v - ((v >> 1) & (T) ~(T)0 / 3);
26 v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3);
27 v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15;
28 return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8;
29}
30static inline int LeastSignificantSetBit(u8 val) {
31 unsigned long index;
32 _BitScanForward(&index, val);
33 return (int)index;
34}
35static inline int LeastSignificantSetBit(u16 val) {
36 unsigned long index;
37 _BitScanForward(&index, val);
38 return (int)index;
39}
40static inline int LeastSignificantSetBit(u32 val) {
41 unsigned long index;
42 _BitScanForward(&index, val);
43 return (int)index;
44}
45static inline int LeastSignificantSetBit(u64 val) {
46 unsigned long index;
47 _BitScanForward64(&index, val);
48 return (int)index;
49}
50#else
51static inline int CountSetBits(u8 val) {
52 return __builtin_popcount(val);
53}
54static inline int CountSetBits(u16 val) {
55 return __builtin_popcount(val);
56}
57static inline int CountSetBits(u32 val) {
58 return __builtin_popcount(val);
59}
60static inline int CountSetBits(u64 val) {
61 return __builtin_popcountll(val);
62}
63static inline int LeastSignificantSetBit(u8 val) {
64 return __builtin_ctz(val);
65}
66static inline int LeastSignificantSetBit(u16 val) {
67 return __builtin_ctz(val);
68}
69static inline int LeastSignificantSetBit(u32 val) {
70 return __builtin_ctz(val);
71}
72static inline int LeastSignificantSetBit(u64 val) {
73 return __builtin_ctzll(val);
74}
75#endif
76
77// Similar to std::bitset, this is a class which encapsulates a bitset, i.e.
78// using the set bits of an integer to represent a set of integers. Like that
79// class, it acts like an array of bools:
80// BitSet32 bs;
81// bs[1] = true;
82// but also like the underlying integer ([0] = least significant bit):
83// BitSet32 bs2 = ...;
84// bs = (bs ^ bs2) & BitSet32(0xffff);
85// The following additional functionality is provided:
86// - Construction using an initializer list.
87// BitSet bs { 1, 2, 4, 8 };
88// - Efficiently iterating through the set bits:
89// for (int i : bs)
90// [i is the *index* of a set bit]
91// (This uses the appropriate CPU instruction to find the next set bit in one
92// operation.)
93// - Counting set bits using .Count() - see comment on that method.
94
95// TODO: use constexpr when MSVC gets out of the Dark Ages
96
97template <typename IntTy>
98class BitSet {
99 static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
100
101public:
102 // A reference to a particular bit, returned from operator[].
103 class Ref {
104 public:
105 Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
106 Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
107 operator bool() const {
108 return (m_bs->m_val & m_mask) != 0;
109 }
110 bool operator=(bool set) {
111 m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
112 return set;
113 }
114
115 private:
116 BitSet* m_bs;
117 IntTy m_mask;
118 };
119
120 // A STL-like iterator is required to be able to use range-based for loops.
121 class Iterator {
122 public:
123 Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {}
124 Iterator(IntTy val) : m_val(val), m_bit(0) {}
125 Iterator& operator=(Iterator other) {
126 new (this) Iterator(other);
127 return *this;
128 }
129 int operator*() {
130 return m_bit + ComputeLsb();
131 }
132 Iterator& operator++() {
133 int lsb = ComputeLsb();
134 m_val >>= lsb + 1;
135 m_bit += lsb + 1;
136 m_has_lsb = false;
137 return *this;
138 }
139 Iterator operator++(int _) {
140 Iterator other(*this);
141 ++*this;
142 return other;
143 }
144 bool operator==(Iterator other) const {
145 return m_val == other.m_val;
146 }
147 bool operator!=(Iterator other) const {
148 return m_val != other.m_val;
149 }
150
151 private:
152 int ComputeLsb() {
153 if (!m_has_lsb) {
154 m_lsb = LeastSignificantSetBit(m_val);
155 m_has_lsb = true;
156 }
157 return m_lsb;
158 }
159 IntTy m_val;
160 int m_bit;
161 int m_lsb = -1;
162 bool m_has_lsb = false;
163 };
164
165 BitSet() : m_val(0) {}
166 explicit BitSet(IntTy val) : m_val(val) {}
167 BitSet(std::initializer_list<int> init) {
168 m_val = 0;
169 for (int bit : init)
170 m_val |= (IntTy)1 << bit;
171 }
172
173 static BitSet AllTrue(std::size_t count) {
174 return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
175 }
176
177 Ref operator[](std::size_t bit) {
178 return Ref(this, (IntTy)1 << bit);
179 }
180 const Ref operator[](std::size_t bit) const {
181 return (*const_cast<BitSet*>(this))[bit];
182 }
183 bool operator==(BitSet other) const {
184 return m_val == other.m_val;
185 }
186 bool operator!=(BitSet other) const {
187 return m_val != other.m_val;
188 }
189 bool operator<(BitSet other) const {
190 return m_val < other.m_val;
191 }
192 bool operator>(BitSet other) const {
193 return m_val > other.m_val;
194 }
195 BitSet operator|(BitSet other) const {
196 return BitSet(m_val | other.m_val);
197 }
198 BitSet operator&(BitSet other) const {
199 return BitSet(m_val & other.m_val);
200 }
201 BitSet operator^(BitSet other) const {
202 return BitSet(m_val ^ other.m_val);
203 }
204 BitSet operator~() const {
205 return BitSet(~m_val);
206 }
207 BitSet& operator|=(BitSet other) {
208 return *this = *this | other;
209 }
210 BitSet& operator&=(BitSet other) {
211 return *this = *this & other;
212 }
213 BitSet& operator^=(BitSet other) {
214 return *this = *this ^ other;
215 }
216 operator u32() = delete;
217 operator bool() {
218 return m_val != 0;
219 }
220
221 // Warning: Even though on modern CPUs this is a single fast instruction,
222 // Dolphin's official builds do not currently assume POPCNT support on x86,
223 // so slower explicit bit twiddling is generated. Still should generally
224 // be faster than a loop.
225 unsigned int Count() const {
226 return CountSetBits(m_val);
227 }
228
229 Iterator begin() const {
230 return Iterator(m_val);
231 }
232 Iterator end() const {
233 return Iterator(0);
234 }
235
236 IntTy m_val;
237};
238
239} // namespace Common
240
241typedef Common::BitSet<u8> BitSet8;
242typedef Common::BitSet<u16> BitSet16;
243typedef Common::BitSet<u32> BitSet32;
244typedef Common::BitSet<u64> BitSet64;
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 343cdd902..94b4394c5 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -4,18 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
8#include <cstdlib> 7#include <cstdlib>
9#include <type_traits> 8#include <type_traits>
10 9
11namespace MathUtil { 10namespace MathUtil {
12 11
13static constexpr float PI = 3.14159265f; 12constexpr float PI = 3.14159265f;
14
15inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1,
16 unsigned length1) {
17 return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1));
18}
19 13
20template <class T> 14template <class T>
21struct Rectangle { 15struct Rectangle {
@@ -24,16 +18,16 @@ struct Rectangle {
24 T right{}; 18 T right{};
25 T bottom{}; 19 T bottom{};
26 20
27 Rectangle() = default; 21 constexpr Rectangle() = default;
28 22
29 Rectangle(T left, T top, T right, T bottom) 23 constexpr Rectangle(T left, T top, T right, T bottom)
30 : left(left), top(top), right(right), bottom(bottom) {} 24 : left(left), top(top), right(right), bottom(bottom) {}
31 25
32 T GetWidth() const { 26 T GetWidth() const {
33 return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); 27 return std::abs(static_cast<std::make_signed_t<T>>(right - left));
34 } 28 }
35 T GetHeight() const { 29 T GetHeight() const {
36 return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); 30 return std::abs(static_cast<std::make_signed_t<T>>(bottom - top));
37 } 31 }
38 Rectangle<T> TranslateX(const T x) const { 32 Rectangle<T> TranslateX(const T x) const {
39 return Rectangle{left + x, top, right + x, bottom}; 33 return Rectangle{left + x, top, right + x, bottom};
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 731d1db34..959f278aa 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -4,11 +4,10 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cctype> 6#include <cctype>
7#include <cerrno>
8#include <codecvt> 7#include <codecvt>
9#include <cstdio>
10#include <cstdlib> 8#include <cstdlib>
11#include <cstring> 9#include <locale>
10#include <sstream>
12#include "common/common_paths.h" 11#include "common/common_paths.h"
13#include "common/logging/log.h" 12#include "common/logging/log.h"
14#include "common/string_util.h" 13#include "common/string_util.h"
@@ -33,24 +32,6 @@ std::string ToUpper(std::string str) {
33 return str; 32 return str;
34} 33}
35 34
36// For Debugging. Read out an u8 array.
37std::string ArrayToString(const u8* data, std::size_t size, int line_len, bool spaces) {
38 std::ostringstream oss;
39 oss << std::setfill('0') << std::hex;
40
41 for (int line = 0; size; ++data, --size) {
42 oss << std::setw(2) << (int)*data;
43
44 if (line_len == ++line) {
45 oss << '\n';
46 line = 0;
47 } else if (spaces)
48 oss << ' ';
49 }
50
51 return oss.str();
52}
53
54std::string StringFromBuffer(const std::vector<u8>& data) { 35std::string StringFromBuffer(const std::vector<u8>& data) {
55 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); 36 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
56} 37}
@@ -75,40 +56,6 @@ std::string StripQuotes(const std::string& s) {
75 return s; 56 return s;
76} 57}
77 58
78bool TryParse(const std::string& str, u32* const output) {
79 char* endptr = nullptr;
80
81 // Reset errno to a value other than ERANGE
82 errno = 0;
83
84 unsigned long value = strtoul(str.c_str(), &endptr, 0);
85
86 if (!endptr || *endptr)
87 return false;
88
89 if (errno == ERANGE)
90 return false;
91
92#if ULONG_MAX > UINT_MAX
93 if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull)
94 return false;
95#endif
96
97 *output = static_cast<u32>(value);
98 return true;
99}
100
101bool TryParse(const std::string& str, bool* const output) {
102 if ("1" == str || "true" == ToLower(str))
103 *output = true;
104 else if ("0" == str || "false" == ToLower(str))
105 *output = false;
106 else
107 return false;
108
109 return true;
110}
111
112std::string StringFromBool(bool value) { 59std::string StringFromBool(bool value) {
113 return value ? "True" : "False"; 60 return value ? "True" : "False";
114} 61}
@@ -267,6 +214,15 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t
267 return std::string(buffer, len); 214 return std::string(buffer, len);
268} 215}
269 216
217std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
218 std::size_t max_len) {
219 std::size_t len = 0;
220 while (len < max_len && buffer[len] != '\0')
221 ++len;
222
223 return std::u16string(buffer.begin(), buffer.begin() + len);
224}
225
270const char* TrimSourcePath(const char* path, const char* root) { 226const char* TrimSourcePath(const char* path, const char* root) {
271 const char* p = path; 227 const char* p = path;
272 228
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 32bf6a19c..583fd05e6 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -5,8 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <iomanip>
9#include <sstream>
10#include <string> 8#include <string>
11#include <vector> 9#include <vector>
12#include "common/common_types.h" 10#include "common/common_types.h"
@@ -19,44 +17,13 @@ std::string ToLower(std::string str);
19/// Make a string uppercase 17/// Make a string uppercase
20std::string ToUpper(std::string str); 18std::string ToUpper(std::string str);
21 19
22std::string ArrayToString(const u8* data, std::size_t size, int line_len = 20, bool spaces = true);
23
24std::string StringFromBuffer(const std::vector<u8>& data); 20std::string StringFromBuffer(const std::vector<u8>& data);
25 21
26std::string StripSpaces(const std::string& s); 22std::string StripSpaces(const std::string& s);
27std::string StripQuotes(const std::string& s); 23std::string StripQuotes(const std::string& s);
28 24
29// Thousand separator. Turns 12345678 into 12,345,678
30template <typename I>
31std::string ThousandSeparate(I value, int spaces = 0) {
32 std::ostringstream oss;
33
34// std::locale("") seems to be broken on many platforms
35#if defined _WIN32 || (defined __linux__ && !defined __clang__)
36 oss.imbue(std::locale(""));
37#endif
38 oss << std::setw(spaces) << value;
39
40 return oss.str();
41}
42
43std::string StringFromBool(bool value); 25std::string StringFromBool(bool value);
44 26
45bool TryParse(const std::string& str, bool* output);
46bool TryParse(const std::string& str, u32* output);
47
48template <typename N>
49static bool TryParse(const std::string& str, N* const output) {
50 std::istringstream iss(str);
51
52 N tmp = 0;
53 if (iss >> tmp) {
54 *output = tmp;
55 return true;
56 } else
57 return false;
58}
59
60std::string TabsToSpaces(int tab_size, std::string in); 27std::string TabsToSpaces(int tab_size, std::string in);
61 28
62void SplitString(const std::string& str, char delim, std::vector<std::string>& output); 29void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
@@ -100,6 +67,14 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
100std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len); 67std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len);
101 68
102/** 69/**
70 * Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
71 * null-terminated, then the string ends at the greatest multiple of two less then or equal to
72 * max_len_bytes.
73 */
74std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
75 std::size_t max_len);
76
77/**
103 * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's 78 * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
104 * intended to be used to strip a system-specific build directory from the `__FILE__` macro, 79 * intended to be used to strip a system-specific build directory from the `__FILE__` macro,
105 * leaving only the path relative to the sources root. 80 * leaving only the path relative to the sources root.
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 9e207118f..5144c0d9f 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -25,23 +25,6 @@
25 25
26namespace Common { 26namespace Common {
27 27
28int CurrentThreadId() {
29#ifdef _MSC_VER
30 return GetCurrentThreadId();
31#elif defined __APPLE__
32 return mach_thread_self();
33#else
34 return 0;
35#endif
36}
37
38#ifdef _WIN32
39// Supporting functions
40void SleepCurrentThread(int ms) {
41 Sleep(ms);
42}
43#endif
44
45#ifdef _MSC_VER 28#ifdef _MSC_VER
46 29
47void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { 30void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
@@ -62,7 +45,7 @@ void SwitchCurrentThread() {
62 45
63// This is implemented much nicer in upcoming msvc++, see: 46// This is implemented much nicer in upcoming msvc++, see:
64// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx 47// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
65void SetCurrentThreadName(const char* szThreadName) { 48void SetCurrentThreadName(const char* name) {
66 static const DWORD MS_VC_EXCEPTION = 0x406D1388; 49 static const DWORD MS_VC_EXCEPTION = 0x406D1388;
67 50
68#pragma pack(push, 8) 51#pragma pack(push, 8)
@@ -75,7 +58,7 @@ void SetCurrentThreadName(const char* szThreadName) {
75#pragma pack(pop) 58#pragma pack(pop)
76 59
77 info.dwType = 0x1000; 60 info.dwType = 0x1000;
78 info.szName = szThreadName; 61 info.szName = name;
79 info.dwThreadID = -1; // dwThreadID; 62 info.dwThreadID = -1; // dwThreadID;
80 info.dwFlags = 0; 63 info.dwFlags = 0;
81 64
@@ -107,10 +90,6 @@ void SetCurrentThreadAffinity(u32 mask) {
107} 90}
108 91
109#ifndef _WIN32 92#ifndef _WIN32
110void SleepCurrentThread(int ms) {
111 usleep(1000 * ms);
112}
113
114void SwitchCurrentThread() { 93void SwitchCurrentThread() {
115 usleep(1000 * 1); 94 usleep(1000 * 1);
116} 95}
@@ -118,15 +97,15 @@ void SwitchCurrentThread() {
118 97
119// MinGW with the POSIX threading model does not support pthread_setname_np 98// MinGW with the POSIX threading model does not support pthread_setname_np
120#if !defined(_WIN32) || defined(_MSC_VER) 99#if !defined(_WIN32) || defined(_MSC_VER)
121void SetCurrentThreadName(const char* szThreadName) { 100void SetCurrentThreadName(const char* name) {
122#ifdef __APPLE__ 101#ifdef __APPLE__
123 pthread_setname_np(szThreadName); 102 pthread_setname_np(name);
124#elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 103#elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
125 pthread_set_name_np(pthread_self(), szThreadName); 104 pthread_set_name_np(pthread_self(), name);
126#elif defined(__NetBSD__) 105#elif defined(__NetBSD__)
127 pthread_setname_np(pthread_self(), "%s", (void*)szThreadName); 106 pthread_setname_np(pthread_self(), "%s", (void*)name);
128#else 107#else
129 pthread_setname_np(pthread_self(), szThreadName); 108 pthread_setname_np(pthread_self(), name);
130#endif 109#endif
131} 110}
132#endif 111#endif
diff --git a/src/common/thread.h b/src/common/thread.h
index 6cbdb96a3..2cf74452d 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -13,15 +13,8 @@
13 13
14namespace Common { 14namespace Common {
15 15
16int CurrentThreadId();
17
18void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
19void SetCurrentThreadAffinity(u32 mask);
20
21class Event { 16class Event {
22public: 17public:
23 Event() : is_set(false) {}
24
25 void Set() { 18 void Set() {
26 std::lock_guard<std::mutex> lk(mutex); 19 std::lock_guard<std::mutex> lk(mutex);
27 if (!is_set) { 20 if (!is_set) {
@@ -53,14 +46,14 @@ public:
53 } 46 }
54 47
55private: 48private:
56 bool is_set; 49 bool is_set = false;
57 std::condition_variable condvar; 50 std::condition_variable condvar;
58 std::mutex mutex; 51 std::mutex mutex;
59}; 52};
60 53
61class Barrier { 54class Barrier {
62public: 55public:
63 explicit Barrier(std::size_t count_) : count(count_), waiting(0), generation(0) {} 56 explicit Barrier(std::size_t count_) : count(count_) {}
64 57
65 /// Blocks until all "count" threads have called Sync() 58 /// Blocks until all "count" threads have called Sync()
66 void Sync() { 59 void Sync() {
@@ -80,12 +73,13 @@ public:
80private: 73private:
81 std::condition_variable condvar; 74 std::condition_variable condvar;
82 std::mutex mutex; 75 std::mutex mutex;
83 const std::size_t count; 76 std::size_t count;
84 std::size_t waiting; 77 std::size_t waiting = 0;
85 std::size_t generation; // Incremented once each time the barrier is used 78 std::size_t generation = 0; // Incremented once each time the barrier is used
86}; 79};
87 80
88void SleepCurrentThread(int ms); 81void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
82void SetCurrentThreadAffinity(u32 mask);
89void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms 83void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
90void SetCurrentThreadName(const char* name); 84void SetCurrentThreadName(const char* name);
91 85
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
deleted file mode 100644
index 636a5c0f9..000000000
--- a/src/common/x64/xbyak_abi.h
+++ /dev/null
@@ -1,222 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <initializer_list>
8#include <xbyak.h>
9#include "common/assert.h"
10#include "common/bit_set.h"
11
12namespace Common::X64 {
13
14inline int RegToIndex(const Xbyak::Reg& reg) {
15 using Kind = Xbyak::Reg::Kind;
16 ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
17 "RegSet only support GPRs and XMM registers.");
18 ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15.");
19 return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16);
20}
21
22inline Xbyak::Reg64 IndexToReg64(int reg_index) {
23 ASSERT(reg_index < 16);
24 return Xbyak::Reg64(reg_index);
25}
26
27inline Xbyak::Xmm IndexToXmm(int reg_index) {
28 ASSERT(reg_index >= 16 && reg_index < 32);
29 return Xbyak::Xmm(reg_index - 16);
30}
31
32inline Xbyak::Reg IndexToReg(int reg_index) {
33 if (reg_index < 16) {
34 return IndexToReg64(reg_index);
35 } else {
36 return IndexToXmm(reg_index);
37 }
38}
39
40inline BitSet32 BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
41 BitSet32 bits;
42 for (const Xbyak::Reg& reg : regs) {
43 bits[RegToIndex(reg)] = true;
44 }
45 return bits;
46}
47
48const BitSet32 ABI_ALL_GPRS(0x0000FFFF);
49const BitSet32 ABI_ALL_XMMS(0xFFFF0000);
50
51#ifdef _WIN32
52
53// Microsoft x64 ABI
54const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
55const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx;
56const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
57const Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
58const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
59
60const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
61 // GPRs
62 Xbyak::util::rcx,
63 Xbyak::util::rdx,
64 Xbyak::util::r8,
65 Xbyak::util::r9,
66 Xbyak::util::r10,
67 Xbyak::util::r11,
68 // XMMs
69 Xbyak::util::xmm0,
70 Xbyak::util::xmm1,
71 Xbyak::util::xmm2,
72 Xbyak::util::xmm3,
73 Xbyak::util::xmm4,
74 Xbyak::util::xmm5,
75});
76
77const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
78 // GPRs
79 Xbyak::util::rbx,
80 Xbyak::util::rsi,
81 Xbyak::util::rdi,
82 Xbyak::util::rbp,
83 Xbyak::util::r12,
84 Xbyak::util::r13,
85 Xbyak::util::r14,
86 Xbyak::util::r15,
87 // XMMs
88 Xbyak::util::xmm6,
89 Xbyak::util::xmm7,
90 Xbyak::util::xmm8,
91 Xbyak::util::xmm9,
92 Xbyak::util::xmm10,
93 Xbyak::util::xmm11,
94 Xbyak::util::xmm12,
95 Xbyak::util::xmm13,
96 Xbyak::util::xmm14,
97 Xbyak::util::xmm15,
98});
99
100constexpr std::size_t ABI_SHADOW_SPACE = 0x20;
101
102#else
103
104// System V x86-64 ABI
105const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
106const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi;
107const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
108const Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
109const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
110
111const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
112 // GPRs
113 Xbyak::util::rcx,
114 Xbyak::util::rdx,
115 Xbyak::util::rdi,
116 Xbyak::util::rsi,
117 Xbyak::util::r8,
118 Xbyak::util::r9,
119 Xbyak::util::r10,
120 Xbyak::util::r11,
121 // XMMs
122 Xbyak::util::xmm0,
123 Xbyak::util::xmm1,
124 Xbyak::util::xmm2,
125 Xbyak::util::xmm3,
126 Xbyak::util::xmm4,
127 Xbyak::util::xmm5,
128 Xbyak::util::xmm6,
129 Xbyak::util::xmm7,
130 Xbyak::util::xmm8,
131 Xbyak::util::xmm9,
132 Xbyak::util::xmm10,
133 Xbyak::util::xmm11,
134 Xbyak::util::xmm12,
135 Xbyak::util::xmm13,
136 Xbyak::util::xmm14,
137 Xbyak::util::xmm15,
138});
139
140const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
141 // GPRs
142 Xbyak::util::rbx,
143 Xbyak::util::rbp,
144 Xbyak::util::r12,
145 Xbyak::util::r13,
146 Xbyak::util::r14,
147 Xbyak::util::r15,
148});
149
150constexpr std::size_t ABI_SHADOW_SPACE = 0;
151
152#endif
153
154inline void ABI_CalculateFrameSize(BitSet32 regs, std::size_t rsp_alignment,
155 std::size_t needed_frame_size, s32* out_subtraction,
156 s32* out_xmm_offset) {
157 int count = (regs & ABI_ALL_GPRS).Count();
158 rsp_alignment -= count * 8;
159 std::size_t subtraction = 0;
160 int xmm_count = (regs & ABI_ALL_XMMS).Count();
161 if (xmm_count) {
162 // If we have any XMMs to save, we must align the stack here.
163 subtraction = rsp_alignment & 0xF;
164 }
165 subtraction += 0x10 * xmm_count;
166 std::size_t xmm_base_subtraction = subtraction;
167 subtraction += needed_frame_size;
168 subtraction += ABI_SHADOW_SPACE;
169 // Final alignment.
170 rsp_alignment -= subtraction;
171 subtraction += rsp_alignment & 0xF;
172
173 *out_subtraction = (s32)subtraction;
174 *out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
175}
176
177inline std::size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
178 std::size_t rsp_alignment,
179 std::size_t needed_frame_size = 0) {
180 s32 subtraction, xmm_offset;
181 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
182
183 for (int reg_index : (regs & ABI_ALL_GPRS)) {
184 code.push(IndexToReg64(reg_index));
185 }
186
187 if (subtraction != 0) {
188 code.sub(code.rsp, subtraction);
189 }
190
191 for (int reg_index : (regs & ABI_ALL_XMMS)) {
192 code.movaps(code.xword[code.rsp + xmm_offset], IndexToXmm(reg_index));
193 xmm_offset += 0x10;
194 }
195
196 return ABI_SHADOW_SPACE;
197}
198
199inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
200 std::size_t rsp_alignment,
201 std::size_t needed_frame_size = 0) {
202 s32 subtraction, xmm_offset;
203 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
204
205 for (int reg_index : (regs & ABI_ALL_XMMS)) {
206 code.movaps(IndexToXmm(reg_index), code.xword[code.rsp + xmm_offset]);
207 xmm_offset += 0x10;
208 }
209
210 if (subtraction != 0) {
211 code.add(code.rsp, subtraction);
212 }
213
214 // GPRs need to be popped in reverse order
215 for (int reg_index = 15; reg_index >= 0; reg_index--) {
216 if (regs[reg_index]) {
217 code.pop(IndexToReg64(reg_index));
218 }
219 }
220}
221
222} // namespace Common::X64
diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h
deleted file mode 100644
index 5cc8a8c76..000000000
--- a/src/common/x64/xbyak_util.h
+++ /dev/null
@@ -1,47 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <type_traits>
8#include <xbyak.h>
9#include "common/x64/xbyak_abi.h"
10
11namespace Common::X64 {
12
13// Constants for use with cmpps/cmpss
14enum {
15 CMP_EQ = 0,
16 CMP_LT = 1,
17 CMP_LE = 2,
18 CMP_UNORD = 3,
19 CMP_NEQ = 4,
20 CMP_NLT = 5,
21 CMP_NLE = 6,
22 CMP_ORD = 7,
23};
24
25inline bool IsWithin2G(uintptr_t ref, uintptr_t target) {
26 u64 distance = target - (ref + 5);
27 return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL);
28}
29
30inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
31 return IsWithin2G(reinterpret_cast<uintptr_t>(code.getCurr()), target);
32}
33
34template <typename T>
35inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
36 static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");
37 std::size_t addr = reinterpret_cast<std::size_t>(f);
38 if (IsWithin2G(code, addr)) {
39 code.call(f);
40 } else {
41 // ABI_RETURN is a safe temp register to use before a call
42 code.mov(ABI_RETURN, addr);
43 code.call(ABI_RETURN);
44 }
45}
46
47} // namespace Common::X64
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 2d61e2f2c..882c9ab59 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -12,6 +12,8 @@ add_library(core STATIC
12 core_timing.h 12 core_timing.h
13 core_timing_util.cpp 13 core_timing_util.cpp
14 core_timing_util.h 14 core_timing_util.h
15 cpu_core_manager.cpp
16 cpu_core_manager.h
15 crypto/aes_util.cpp 17 crypto/aes_util.cpp
16 crypto/aes_util.h 18 crypto/aes_util.h
17 crypto/encryption_layer.cpp 19 crypto/encryption_layer.cpp
@@ -81,6 +83,8 @@ add_library(core STATIC
81 file_sys/vfs_vector.h 83 file_sys/vfs_vector.h
82 file_sys/xts_archive.cpp 84 file_sys/xts_archive.cpp
83 file_sys/xts_archive.h 85 file_sys/xts_archive.h
86 frontend/applets/software_keyboard.cpp
87 frontend/applets/software_keyboard.h
84 frontend/emu_window.cpp 88 frontend/emu_window.cpp
85 frontend/emu_window.h 89 frontend/emu_window.h
86 frontend/framebuffer_layout.cpp 90 frontend/framebuffer_layout.cpp
@@ -97,8 +101,6 @@ add_library(core STATIC
97 hle/kernel/client_session.cpp 101 hle/kernel/client_session.cpp
98 hle/kernel/client_session.h 102 hle/kernel/client_session.h
99 hle/kernel/errors.h 103 hle/kernel/errors.h
100 hle/kernel/event.cpp
101 hle/kernel/event.h
102 hle/kernel/handle_table.cpp 104 hle/kernel/handle_table.cpp
103 hle/kernel/handle_table.h 105 hle/kernel/handle_table.h
104 hle/kernel/hle_ipc.cpp 106 hle/kernel/hle_ipc.cpp
@@ -111,6 +113,8 @@ add_library(core STATIC
111 hle/kernel/object.h 113 hle/kernel/object.h
112 hle/kernel/process.cpp 114 hle/kernel/process.cpp
113 hle/kernel/process.h 115 hle/kernel/process.h
116 hle/kernel/readable_event.cpp
117 hle/kernel/readable_event.h
114 hle/kernel/resource_limit.cpp 118 hle/kernel/resource_limit.cpp
115 hle/kernel/resource_limit.h 119 hle/kernel/resource_limit.h
116 hle/kernel/scheduler.cpp 120 hle/kernel/scheduler.cpp
@@ -133,6 +137,8 @@ add_library(core STATIC
133 hle/kernel/vm_manager.h 137 hle/kernel/vm_manager.h
134 hle/kernel/wait_object.cpp 138 hle/kernel/wait_object.cpp
135 hle/kernel/wait_object.h 139 hle/kernel/wait_object.h
140 hle/kernel/writable_event.cpp
141 hle/kernel/writable_event.h
136 hle/lock.cpp 142 hle/lock.cpp
137 hle/lock.h 143 hle/lock.h
138 hle/result.h 144 hle/result.h
@@ -154,6 +160,12 @@ add_library(core STATIC
154 hle/service/am/applet_ae.h 160 hle/service/am/applet_ae.h
155 hle/service/am/applet_oe.cpp 161 hle/service/am/applet_oe.cpp
156 hle/service/am/applet_oe.h 162 hle/service/am/applet_oe.h
163 hle/service/am/applets/applets.cpp
164 hle/service/am/applets/applets.h
165 hle/service/am/applets/software_keyboard.cpp
166 hle/service/am/applets/software_keyboard.h
167 hle/service/am/applets/stub_applet.cpp
168 hle/service/am/applets/stub_applet.h
157 hle/service/am/idle.cpp 169 hle/service/am/idle.cpp
158 hle/service/am/idle.h 170 hle/service/am/idle.h
159 hle/service/am/omm.cpp 171 hle/service/am/omm.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 6d5b5a2d0..795fabc65 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -14,6 +14,7 @@
14#include "core/core.h" 14#include "core/core.h"
15#include "core/core_cpu.h" 15#include "core/core_cpu.h"
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/cpu_core_manager.h"
17#include "core/file_sys/mode.h" 18#include "core/file_sys/mode.h"
18#include "core/file_sys/vfs_concat.h" 19#include "core/file_sys/vfs_concat.h"
19#include "core/file_sys/vfs_real.h" 20#include "core/file_sys/vfs_real.h"
@@ -23,12 +24,13 @@
23#include "core/hle/kernel/process.h" 24#include "core/hle/kernel/process.h"
24#include "core/hle/kernel/scheduler.h" 25#include "core/hle/kernel/scheduler.h"
25#include "core/hle/kernel/thread.h" 26#include "core/hle/kernel/thread.h"
27#include "core/hle/service/am/applets/software_keyboard.h"
26#include "core/hle/service/service.h" 28#include "core/hle/service/service.h"
27#include "core/hle/service/sm/sm.h" 29#include "core/hle/service/sm/sm.h"
28#include "core/loader/loader.h" 30#include "core/loader/loader.h"
29#include "core/perf_stats.h" 31#include "core/perf_stats.h"
30#include "core/settings.h"
31#include "core/telemetry_session.h" 32#include "core/telemetry_session.h"
33#include "frontend/applets/software_keyboard.h"
32#include "video_core/debug_utils/debug_utils.h" 34#include "video_core/debug_utils/debug_utils.h"
33#include "video_core/gpu.h" 35#include "video_core/gpu.h"
34#include "video_core/renderer_base.h" 36#include "video_core/renderer_base.h"
@@ -69,64 +71,22 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
69 71
70 return vfs->OpenFile(path, FileSys::Mode::Read); 72 return vfs->OpenFile(path, FileSys::Mode::Read);
71} 73}
72
73/// Runs a CPU core while the system is powered on
74void RunCpuCore(Cpu& cpu_state) {
75 while (Core::System::GetInstance().IsPoweredOn()) {
76 cpu_state.RunLoop(true);
77 }
78}
79} // Anonymous namespace 74} // Anonymous namespace
80 75
81struct System::Impl { 76struct System::Impl {
82 Cpu& CurrentCpuCore() { 77 Cpu& CurrentCpuCore() {
83 if (Settings::values.use_multi_core) { 78 return cpu_core_manager.GetCurrentCore();
84 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
85 ASSERT(search != thread_to_cpu.end());
86 ASSERT(search->second);
87 return *search->second;
88 }
89
90 // Otherwise, use single-threaded mode active_core variable
91 return *cpu_cores[active_core];
92 } 79 }
93 80
94 ResultStatus RunLoop(bool tight_loop) { 81 ResultStatus RunLoop(bool tight_loop) {
95 status = ResultStatus::Success; 82 status = ResultStatus::Success;
96 83
97 // Update thread_to_cpu in case Core 0 is run from a different host thread 84 cpu_core_manager.RunLoop(tight_loop);
98 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
99
100 if (GDBStub::IsServerEnabled()) {
101 GDBStub::HandlePacket();
102
103 // If the loop is halted and we want to step, use a tiny (1) number of instructions to
104 // execute. Otherwise, get out of the loop function.
105 if (GDBStub::GetCpuHaltFlag()) {
106 if (GDBStub::GetCpuStepFlag()) {
107 tight_loop = false;
108 } else {
109 return ResultStatus::Success;
110 }
111 }
112 }
113
114 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
115 cpu_cores[active_core]->RunLoop(tight_loop);
116 if (Settings::values.use_multi_core) {
117 // Cores 1-3 are run on other threads in this mode
118 break;
119 }
120 }
121
122 if (GDBStub::IsServerEnabled()) {
123 GDBStub::SetCpuStepFlag(false);
124 }
125 85
126 return status; 86 return status;
127 } 87 }
128 88
129 ResultStatus Init(Frontend::EmuWindow& emu_window) { 89 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
130 LOG_DEBUG(HW_Memory, "initialized OK"); 90 LOG_DEBUG(HW_Memory, "initialized OK");
131 91
132 CoreTiming::Init(); 92 CoreTiming::Init();
@@ -136,15 +96,13 @@ struct System::Impl {
136 if (virtual_filesystem == nullptr) 96 if (virtual_filesystem == nullptr)
137 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); 97 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
138 98
99 /// Create default implementations of applets if one is not provided.
100 if (software_keyboard == nullptr)
101 software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
102
139 auto main_process = Kernel::Process::Create(kernel, "main"); 103 auto main_process = Kernel::Process::Create(kernel, "main");
140 kernel.MakeCurrentProcess(main_process.get()); 104 kernel.MakeCurrentProcess(main_process.get());
141 105
142 cpu_barrier = std::make_unique<CpuBarrier>();
143 cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
144 for (std::size_t index = 0; index < cpu_cores.size(); ++index) {
145 cpu_cores[index] = std::make_unique<Cpu>(*cpu_exclusive_monitor, *cpu_barrier, index);
146 }
147
148 telemetry_session = std::make_unique<Core::TelemetrySession>(); 106 telemetry_session = std::make_unique<Core::TelemetrySession>();
149 service_manager = std::make_shared<Service::SM::ServiceManager>(); 107 service_manager = std::make_shared<Service::SM::ServiceManager>();
150 108
@@ -158,17 +116,8 @@ struct System::Impl {
158 116
159 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); 117 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
160 118
161 // Create threads for CPU cores 1-3, and build thread_to_cpu map 119 cpu_core_manager.Initialize(system);
162 // CPU core 0 is run on the main thread 120 is_powered_on = true;
163 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
164 if (Settings::values.use_multi_core) {
165 for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) {
166 cpu_core_threads[index] =
167 std::make_unique<std::thread>(RunCpuCore, std::ref(*cpu_cores[index + 1]));
168 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1].get();
169 }
170 }
171
172 LOG_DEBUG(Core, "Initialized OK"); 121 LOG_DEBUG(Core, "Initialized OK");
173 122
174 // Reset counters and set time origin to current frame 123 // Reset counters and set time origin to current frame
@@ -178,7 +127,8 @@ struct System::Impl {
178 return ResultStatus::Success; 127 return ResultStatus::Success;
179 } 128 }
180 129
181 ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 130 ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
131 const std::string& filepath) {
182 app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); 132 app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
183 133
184 if (!app_loader) { 134 if (!app_loader) {
@@ -195,7 +145,7 @@ struct System::Impl {
195 return ResultStatus::ErrorSystemMode; 145 return ResultStatus::ErrorSystemMode;
196 } 146 }
197 147
198 ResultStatus init_result{Init(emu_window)}; 148 ResultStatus init_result{Init(system, emu_window)};
199 if (init_result != ResultStatus::Success) { 149 if (init_result != ResultStatus::Success) {
200 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", 150 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
201 static_cast<int>(init_result)); 151 static_cast<int>(init_result));
@@ -225,6 +175,8 @@ struct System::Impl {
225 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", 175 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
226 perf_results.frametime * 1000.0); 176 perf_results.frametime * 1000.0);
227 177
178 is_powered_on = false;
179
228 // Shutdown emulation session 180 // Shutdown emulation session
229 renderer.reset(); 181 renderer.reset();
230 GDBStub::Shutdown(); 182 GDBStub::Shutdown();
@@ -234,19 +186,7 @@ struct System::Impl {
234 gpu_core.reset(); 186 gpu_core.reset();
235 187
236 // Close all CPU/threading state 188 // Close all CPU/threading state
237 cpu_barrier->NotifyEnd(); 189 cpu_core_manager.Shutdown();
238 if (Settings::values.use_multi_core) {
239 for (auto& thread : cpu_core_threads) {
240 thread->join();
241 thread.reset();
242 }
243 }
244 thread_to_cpu.clear();
245 for (auto& cpu_core : cpu_cores) {
246 cpu_core.reset();
247 }
248 cpu_exclusive_monitor.reset();
249 cpu_barrier.reset();
250 190
251 // Shutdown kernel and core timing 191 // Shutdown kernel and core timing
252 kernel.Shutdown(); 192 kernel.Shutdown();
@@ -283,11 +223,11 @@ struct System::Impl {
283 std::unique_ptr<VideoCore::RendererBase> renderer; 223 std::unique_ptr<VideoCore::RendererBase> renderer;
284 std::unique_ptr<Tegra::GPU> gpu_core; 224 std::unique_ptr<Tegra::GPU> gpu_core;
285 std::shared_ptr<Tegra::DebugContext> debug_context; 225 std::shared_ptr<Tegra::DebugContext> debug_context;
286 std::unique_ptr<ExclusiveMonitor> cpu_exclusive_monitor; 226 CpuCoreManager cpu_core_manager;
287 std::unique_ptr<CpuBarrier> cpu_barrier; 227 bool is_powered_on = false;
288 std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cpu_cores; 228
289 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads; 229 /// Frontend applets
290 std::size_t active_core{}; ///< Active core, only used in single thread mode 230 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
291 231
292 /// Service manager 232 /// Service manager
293 std::shared_ptr<Service::SM::ServiceManager> service_manager; 233 std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -298,9 +238,6 @@ struct System::Impl {
298 ResultStatus status = ResultStatus::Success; 238 ResultStatus status = ResultStatus::Success;
299 std::string status_details = ""; 239 std::string status_details = "";
300 240
301 /// Map of guest threads to CPU cores
302 std::map<std::thread::id, Cpu*> thread_to_cpu;
303
304 Core::PerfStats perf_stats; 241 Core::PerfStats perf_stats;
305 Core::FrameLimiter frame_limiter; 242 Core::FrameLimiter frame_limiter;
306}; 243};
@@ -325,17 +262,15 @@ System::ResultStatus System::SingleStep() {
325} 262}
326 263
327void System::InvalidateCpuInstructionCaches() { 264void System::InvalidateCpuInstructionCaches() {
328 for (auto& cpu : impl->cpu_cores) { 265 impl->cpu_core_manager.InvalidateAllInstructionCaches();
329 cpu->ArmInterface().ClearInstructionCache();
330 }
331} 266}
332 267
333System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 268System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
334 return impl->Load(emu_window, filepath); 269 return impl->Load(*this, emu_window, filepath);
335} 270}
336 271
337bool System::IsPoweredOn() const { 272bool System::IsPoweredOn() const {
338 return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); 273 return impl->is_powered_on;
339} 274}
340 275
341void System::PrepareReschedule() { 276void System::PrepareReschedule() {
@@ -399,21 +334,20 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
399} 334}
400 335
401Cpu& System::CpuCore(std::size_t core_index) { 336Cpu& System::CpuCore(std::size_t core_index) {
402 ASSERT(core_index < NUM_CPU_CORES); 337 return impl->cpu_core_manager.GetCore(core_index);
403 return *impl->cpu_cores[core_index];
404} 338}
405 339
406const Cpu& System::CpuCore(std::size_t core_index) const { 340const Cpu& System::CpuCore(std::size_t core_index) const {
407 ASSERT(core_index < NUM_CPU_CORES); 341 ASSERT(core_index < NUM_CPU_CORES);
408 return *impl->cpu_cores[core_index]; 342 return impl->cpu_core_manager.GetCore(core_index);
409} 343}
410 344
411ExclusiveMonitor& System::Monitor() { 345ExclusiveMonitor& System::Monitor() {
412 return *impl->cpu_exclusive_monitor; 346 return impl->cpu_core_manager.GetExclusiveMonitor();
413} 347}
414 348
415const ExclusiveMonitor& System::Monitor() const { 349const ExclusiveMonitor& System::Monitor() const {
416 return *impl->cpu_exclusive_monitor; 350 return impl->cpu_core_manager.GetExclusiveMonitor();
417} 351}
418 352
419Tegra::GPU& System::GPU() { 353Tegra::GPU& System::GPU() {
@@ -488,8 +422,16 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
488 return impl->virtual_filesystem; 422 return impl->virtual_filesystem;
489} 423}
490 424
425void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) {
426 impl->software_keyboard = std::move(applet);
427}
428
429const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const {
430 return *impl->software_keyboard;
431}
432
491System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { 433System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
492 return impl->Init(emu_window); 434 return impl->Init(*this, emu_window);
493} 435}
494 436
495void System::Shutdown() { 437void System::Shutdown() {
diff --git a/src/core/core.h b/src/core/core.h
index cfacceb81..be71bd437 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -13,6 +13,7 @@
13 13
14namespace Core::Frontend { 14namespace Core::Frontend {
15class EmuWindow; 15class EmuWindow;
16class SoftwareKeyboardApplet;
16} // namespace Core::Frontend 17} // namespace Core::Frontend
17 18
18namespace FileSys { 19namespace FileSys {
@@ -236,6 +237,10 @@ public:
236 237
237 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const; 238 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
238 239
240 void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet);
241
242 const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
243
239private: 244private:
240 System(); 245 System();
241 246
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
new file mode 100644
index 000000000..769a6fefa
--- /dev/null
+++ b/src/core/cpu_core_manager.cpp
@@ -0,0 +1,142 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/arm/exclusive_monitor.h"
7#include "core/core.h"
8#include "core/core_cpu.h"
9#include "core/cpu_core_manager.h"
10#include "core/gdbstub/gdbstub.h"
11#include "core/settings.h"
12
13namespace Core {
14namespace {
15void RunCpuCore(const System& system, Cpu& cpu_state) {
16 while (system.IsPoweredOn()) {
17 cpu_state.RunLoop(true);
18 }
19}
20} // Anonymous namespace
21
22CpuCoreManager::CpuCoreManager() = default;
23CpuCoreManager::~CpuCoreManager() = default;
24
25void CpuCoreManager::Initialize(System& system) {
26 barrier = std::make_unique<CpuBarrier>();
27 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
28
29 for (std::size_t index = 0; index < cores.size(); ++index) {
30 cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index);
31 }
32
33 // Create threads for CPU cores 1-3, and build thread_to_cpu map
34 // CPU core 0 is run on the main thread
35 thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
36 if (!Settings::values.use_multi_core) {
37 return;
38 }
39
40 for (std::size_t index = 0; index < core_threads.size(); ++index) {
41 core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
42 std::ref(*cores[index + 1]));
43 thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
44 }
45}
46
47void CpuCoreManager::Shutdown() {
48 barrier->NotifyEnd();
49 if (Settings::values.use_multi_core) {
50 for (auto& thread : core_threads) {
51 thread->join();
52 thread.reset();
53 }
54 }
55
56 thread_to_cpu.clear();
57 for (auto& cpu_core : cores) {
58 cpu_core.reset();
59 }
60
61 exclusive_monitor.reset();
62 barrier.reset();
63}
64
65Cpu& CpuCoreManager::GetCore(std::size_t index) {
66 return *cores.at(index);
67}
68
69const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
70 return *cores.at(index);
71}
72
73ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
74 return *exclusive_monitor;
75}
76
77const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
78 return *exclusive_monitor;
79}
80
81Cpu& CpuCoreManager::GetCurrentCore() {
82 if (Settings::values.use_multi_core) {
83 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
84 ASSERT(search != thread_to_cpu.end());
85 ASSERT(search->second);
86 return *search->second;
87 }
88
89 // Otherwise, use single-threaded mode active_core variable
90 return *cores[active_core];
91}
92
93const Cpu& CpuCoreManager::GetCurrentCore() const {
94 if (Settings::values.use_multi_core) {
95 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
96 ASSERT(search != thread_to_cpu.end());
97 ASSERT(search->second);
98 return *search->second;
99 }
100
101 // Otherwise, use single-threaded mode active_core variable
102 return *cores[active_core];
103}
104
105void CpuCoreManager::RunLoop(bool tight_loop) {
106 // Update thread_to_cpu in case Core 0 is run from a different host thread
107 thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
108
109 if (GDBStub::IsServerEnabled()) {
110 GDBStub::HandlePacket();
111
112 // If the loop is halted and we want to step, use a tiny (1) number of instructions to
113 // execute. Otherwise, get out of the loop function.
114 if (GDBStub::GetCpuHaltFlag()) {
115 if (GDBStub::GetCpuStepFlag()) {
116 tight_loop = false;
117 } else {
118 return;
119 }
120 }
121 }
122
123 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
124 cores[active_core]->RunLoop(tight_loop);
125 if (Settings::values.use_multi_core) {
126 // Cores 1-3 are run on other threads in this mode
127 break;
128 }
129 }
130
131 if (GDBStub::IsServerEnabled()) {
132 GDBStub::SetCpuStepFlag(false);
133 }
134}
135
136void CpuCoreManager::InvalidateAllInstructionCaches() {
137 for (auto& cpu : cores) {
138 cpu->ArmInterface().ClearInstructionCache();
139 }
140}
141
142} // namespace Core
diff --git a/src/core/cpu_core_manager.h b/src/core/cpu_core_manager.h
new file mode 100644
index 000000000..a4d70ec56
--- /dev/null
+++ b/src/core/cpu_core_manager.h
@@ -0,0 +1,59 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <map>
9#include <memory>
10#include <thread>
11
12namespace Core {
13
14class Cpu;
15class CpuBarrier;
16class ExclusiveMonitor;
17class System;
18
19class CpuCoreManager {
20public:
21 CpuCoreManager();
22 CpuCoreManager(const CpuCoreManager&) = delete;
23 CpuCoreManager(CpuCoreManager&&) = delete;
24
25 ~CpuCoreManager();
26
27 CpuCoreManager& operator=(const CpuCoreManager&) = delete;
28 CpuCoreManager& operator=(CpuCoreManager&&) = delete;
29
30 void Initialize(System& system);
31 void Shutdown();
32
33 Cpu& GetCore(std::size_t index);
34 const Cpu& GetCore(std::size_t index) const;
35
36 Cpu& GetCurrentCore();
37 const Cpu& GetCurrentCore() const;
38
39 ExclusiveMonitor& GetExclusiveMonitor();
40 const ExclusiveMonitor& GetExclusiveMonitor() const;
41
42 void RunLoop(bool tight_loop);
43
44 void InvalidateAllInstructionCaches();
45
46private:
47 static constexpr std::size_t NUM_CPU_CORES = 4;
48
49 std::unique_ptr<ExclusiveMonitor> exclusive_monitor;
50 std::unique_ptr<CpuBarrier> barrier;
51 std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores;
52 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads;
53 std::size_t active_core{}; ///< Active core, only used in single thread mode
54
55 /// Map of guest threads to CPU cores
56 std::map<std::thread::id, Cpu*> thread_to_cpu;
57};
58
59} // namespace Core
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 904afa039..ca12fb4ab 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -246,7 +246,6 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) {
246 } 246 }
247 247
248 std::vector<TicketRaw> out; 248 std::vector<TicketRaw> out;
249 u32 magic{};
250 for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { 249 for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) {
251 if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && 250 if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 &&
252 buffer[offset + 3] == 0x0) { 251 buffer[offset + 3] == 0x0) {
@@ -794,7 +793,7 @@ void KeyManager::DeriveBase() {
794 793
795void KeyManager::DeriveETicket(PartitionDataManager& data) { 794void KeyManager::DeriveETicket(PartitionDataManager& data) {
796 // ETicket keys 795 // ETicket keys
797 const auto es = Service::FileSystem::GetUnionContents()->GetEntry( 796 const auto es = Service::FileSystem::GetUnionContents().GetEntry(
798 0x0100000000000033, FileSys::ContentRecordType::Program); 797 0x0100000000000033, FileSys::ContentRecordType::Program);
799 798
800 if (es == nullptr) 799 if (es == nullptr)
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 76a2b7e86..e29f70b3a 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -8,8 +8,9 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_) 11BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_)
12 : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), 12 : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
13 dump_root(std::move(dump_root_)),
13 sysnand_cache(std::make_unique<RegisteredCache>( 14 sysnand_cache(std::make_unique<RegisteredCache>(
14 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))), 15 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
15 usrnand_cache(std::make_unique<RegisteredCache>( 16 usrnand_cache(std::make_unique<RegisteredCache>(
@@ -32,4 +33,10 @@ VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
32 return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id)); 33 return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
33} 34}
34 35
36VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const {
37 if (title_id == 0)
38 return nullptr;
39 return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id));
40}
41
35} // namespace FileSys 42} // namespace FileSys
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index 364d309bd..453c11ad2 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -17,17 +17,19 @@ class RegisteredCache;
17/// registered caches. 17/// registered caches.
18class BISFactory { 18class BISFactory {
19public: 19public:
20 explicit BISFactory(VirtualDir nand_root, VirtualDir load_root); 20 explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root);
21 ~BISFactory(); 21 ~BISFactory();
22 22
23 RegisteredCache* GetSystemNANDContents() const; 23 RegisteredCache* GetSystemNANDContents() const;
24 RegisteredCache* GetUserNANDContents() const; 24 RegisteredCache* GetUserNANDContents() const;
25 25
26 VirtualDir GetModificationLoadRoot(u64 title_id) const; 26 VirtualDir GetModificationLoadRoot(u64 title_id) const;
27 VirtualDir GetModificationDumpRoot(u64 title_id) const;
27 28
28private: 29private:
29 VirtualDir nand_root; 30 VirtualDir nand_root;
30 VirtualDir load_root; 31 VirtualDir load_root;
32 VirtualDir dump_root;
31 33
32 std::unique_ptr<RegisteredCache> sysnand_cache; 34 std::unique_ptr<RegisteredCache> sysnand_cache;
33 std::unique_ptr<RegisteredCache> usrnand_cache; 35 std::unique_ptr<RegisteredCache> usrnand_cache;
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 1ece55731..2c145bd09 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -176,7 +176,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
176 for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) { 176 for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) {
177 if (file->GetExtension() != "nca") 177 if (file->GetExtension() != "nca")
178 continue; 178 continue;
179 auto nca = std::make_shared<NCA>(file); 179 auto nca = std::make_shared<NCA>(file, nullptr, 0, keys);
180 // TODO(DarkLordZach): Add proper Rev1+ Support 180 // TODO(DarkLordZach): Add proper Rev1+ Support
181 if (nca->IsUpdate()) 181 if (nca->IsUpdate())
182 continue; 182 continue;
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index 8f62571cf..a350496f7 100644
--- a/src/core/file_sys/card_image.h
+++ b/src/core/file_sys/card_image.h
@@ -9,6 +9,7 @@
9#include <vector> 9#include <vector>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/crypto/key_manager.h"
12#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs.h"
13 14
14namespace Loader { 15namespace Loader {
@@ -31,7 +32,18 @@ enum class GamecardSize : u8 {
31}; 32};
32 33
33struct GamecardInfo { 34struct GamecardInfo {
34 std::array<u8, 0x70> data; 35 u64_le firmware_version;
36 u32_le access_control_flags;
37 u32_le read_wait_time1;
38 u32_le read_wait_time2;
39 u32_le write_wait_time1;
40 u32_le write_wait_time2;
41 u32_le firmware_mode;
42 u32_le cup_version;
43 std::array<u8, 4> reserved1;
44 u64_le update_partition_hash;
45 u64_le cup_id;
46 std::array<u8, 0x38> reserved2;
35}; 47};
36static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size."); 48static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size.");
37 49
@@ -107,5 +119,7 @@ private:
107 std::shared_ptr<NSP> secure_partition; 119 std::shared_ptr<NSP> secure_partition;
108 std::shared_ptr<NCA> program; 120 std::shared_ptr<NCA> program;
109 std::vector<std::shared_ptr<NCA>> ncas; 121 std::vector<std::shared_ptr<NCA>> ncas;
122
123 Core::Crypto::KeyManager keys;
110}; 124};
111} // namespace FileSys 125} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index b46fe893c..19b6f8600 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -101,8 +101,9 @@ static bool IsValidNCA(const NCAHeader& header) {
101 return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); 101 return header.magic == Common::MakeMagic('N', 'C', 'A', '3');
102} 102}
103 103
104NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) 104NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset,
105 : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) { 105 Core::Crypto::KeyManager keys_)
106 : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)), keys(std::move(keys_)) {
106 if (file == nullptr) { 107 if (file == nullptr) {
107 status = Loader::ResultStatus::ErrorNullFile; 108 status = Loader::ResultStatus::ErrorNullFile;
108 return; 109 return;
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 4bba55607..99294cbb4 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -79,7 +79,8 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) {
79class NCA : public ReadOnlyVfsDirectory { 79class NCA : public ReadOnlyVfsDirectory {
80public: 80public:
81 explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, 81 explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr,
82 u64 bktr_base_ivfc_offset = 0); 82 u64 bktr_base_ivfc_offset = 0,
83 Core::Crypto::KeyManager keys = Core::Crypto::KeyManager());
83 ~NCA() override; 84 ~NCA() override;
84 85
85 Loader::ResultStatus GetStatus() const; 86 Loader::ResultStatus GetStatus() const;
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index a012c2be9..e065e592f 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -8,13 +8,23 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11const std::array<const char*, 15> LANGUAGE_NAMES = { 11const std::array<const char*, 15> LANGUAGE_NAMES{{
12 "AmericanEnglish", "BritishEnglish", "Japanese", 12 "AmericanEnglish",
13 "French", "German", "LatinAmericanSpanish", 13 "BritishEnglish",
14 "Spanish", "Italian", "Dutch", 14 "Japanese",
15 "CanadianFrench", "Portugese", "Russian", 15 "French",
16 "Korean", "Taiwanese", "Chinese", 16 "German",
17}; 17 "LatinAmericanSpanish",
18 "Spanish",
19 "Italian",
20 "Dutch",
21 "CanadianFrench",
22 "Portuguese",
23 "Russian",
24 "Korean",
25 "Taiwanese",
26 "Chinese",
27}};
18 28
19std::string LanguageEntry::GetApplicationName() const { 29std::string LanguageEntry::GetApplicationName() const {
20 return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 30 return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(),
@@ -66,4 +76,10 @@ std::string NACP::GetVersionString() const {
66 return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), 76 return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(),
67 raw->version_string.size()); 77 raw->version_string.size());
68} 78}
79
80std::vector<u8> NACP::GetRawBytes() const {
81 std::vector<u8> out(sizeof(RawNACP));
82 std::memcpy(out.data(), raw.get(), sizeof(RawNACP));
83 return out;
84}
69} // namespace FileSys 85} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 141f7e056..bfaad46b4 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -81,6 +81,7 @@ public:
81 u64 GetTitleId() const; 81 u64 GetTitleId() const;
82 u64 GetDLCBaseTitleId() const; 82 u64 GetDLCBaseTitleId() const;
83 std::string GetVersionString() const; 83 std::string GetVersionString() const;
84 std::vector<u8> GetRawBytes() const;
84 85
85private: 86private:
86 std::unique_ptr<RawNACP> raw; 87 std::unique_ptr<RawNACP> raw;
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h
index fea0593c7..e4a4ee4ab 100644
--- a/src/core/file_sys/errors.h
+++ b/src/core/file_sys/errors.h
@@ -8,25 +8,10 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11namespace ErrCodes { 11constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1};
12enum { 12constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002};
13 NotFound = 1, 13constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001};
14 TitleNotFound = 1002, 14constexpr ResultCode ERROR_INVALID_OFFSET{ErrorModule::FS, 6061};
15 SdCardNotFound = 2001, 15constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::FS, 6062};
16 RomFSNotFound = 2520,
17};
18}
19
20constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrorModule::FS, ErrCodes::NotFound);
21
22// TODO(bunnei): Replace these with correct errors for Switch OS
23constexpr ResultCode ERROR_INVALID_PATH(-1);
24constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(-1);
25constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(-1);
26constexpr ResultCode ERROR_FILE_NOT_FOUND(-1);
27constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(-1);
28constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(-1);
29constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(-1);
30constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(-1);
31 16
32} // namespace FileSys 17} // namespace FileSys
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 0c1156989..6b14e08be 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -19,12 +19,18 @@
19#include "core/file_sys/vfs_vector.h" 19#include "core/file_sys/vfs_vector.h"
20#include "core/hle/service/filesystem/filesystem.h" 20#include "core/hle/service/filesystem/filesystem.h"
21#include "core/loader/loader.h" 21#include "core/loader/loader.h"
22#include "core/settings.h"
22 23
23namespace FileSys { 24namespace FileSys {
24 25
25constexpr u64 SINGLE_BYTE_MODULUS = 0x100; 26constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
26constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; 27constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
27 28
29constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
30 "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
31 "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
32};
33
28struct NSOBuildHeader { 34struct NSOBuildHeader {
29 u32_le magic; 35 u32_le magic;
30 INSERT_PADDING_BYTES(0x3C); 36 INSERT_PADDING_BYTES(0x3C);
@@ -56,19 +62,52 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
56 if (exefs == nullptr) 62 if (exefs == nullptr)
57 return exefs; 63 return exefs;
58 64
65 if (Settings::values.dump_exefs) {
66 LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
67 const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
68 if (dump_dir != nullptr) {
69 const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
70 VfsRawCopyD(exefs, exefs_dir);
71 }
72 }
73
59 const auto installed = Service::FileSystem::GetUnionContents(); 74 const auto installed = Service::FileSystem::GetUnionContents();
60 75
61 // Game Updates 76 // Game Updates
62 const auto update_tid = GetUpdateTitleID(title_id); 77 const auto update_tid = GetUpdateTitleID(title_id);
63 const auto update = installed->GetEntry(update_tid, ContentRecordType::Program); 78 const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
64 79
65 if (update != nullptr && update->GetExeFS() != nullptr && 80 if (update != nullptr && update->GetExeFS() != nullptr &&
66 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { 81 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
67 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", 82 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
68 FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); 83 FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
69 exefs = update->GetExeFS(); 84 exefs = update->GetExeFS();
70 } 85 }
71 86
87 // LayeredExeFS
88 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
89 if (load_dir != nullptr && load_dir->GetSize() > 0) {
90 auto patch_dirs = load_dir->GetSubdirectories();
91 std::sort(
92 patch_dirs.begin(), patch_dirs.end(),
93 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
94
95 std::vector<VirtualDir> layers;
96 layers.reserve(patch_dirs.size() + 1);
97 for (const auto& subdir : patch_dirs) {
98 auto exefs_dir = subdir->GetSubdirectory("exefs");
99 if (exefs_dir != nullptr)
100 layers.push_back(std::move(exefs_dir));
101 }
102 layers.push_back(exefs);
103
104 auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
105 if (layered != nullptr) {
106 LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully");
107 exefs = std::move(layered);
108 }
109 }
110
72 return exefs; 111 return exefs;
73} 112}
74 113
@@ -119,6 +158,18 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const {
119 const auto build_id_raw = Common::HexArrayToString(header.build_id); 158 const auto build_id_raw = Common::HexArrayToString(header.build_id);
120 const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1); 159 const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
121 160
161 if (Settings::values.dump_nso) {
162 LOG_INFO(Loader, "Dumping NSO for build_id={}, title_id={:016X}", build_id, title_id);
163 const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
164 if (dump_dir != nullptr) {
165 const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
166 const auto file = nso_dir->CreateFile(fmt::format("{}.nso", build_id));
167
168 file->Resize(nso.size());
169 file->WriteBytes(nso);
170 }
171 }
172
122 LOG_INFO(Loader, "Patching NSO for build_id={}", build_id); 173 LOG_INFO(Loader, "Patching NSO for build_id={}", build_id);
123 174
124 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 175 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
@@ -230,13 +281,13 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
230 281
231 // Game Updates 282 // Game Updates
232 const auto update_tid = GetUpdateTitleID(title_id); 283 const auto update_tid = GetUpdateTitleID(title_id);
233 const auto update = installed->GetEntryRaw(update_tid, type); 284 const auto update = installed.GetEntryRaw(update_tid, type);
234 if (update != nullptr) { 285 if (update != nullptr) {
235 const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset); 286 const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset);
236 if (new_nca->GetStatus() == Loader::ResultStatus::Success && 287 if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
237 new_nca->GetRomFS() != nullptr) { 288 new_nca->GetRomFS() != nullptr) {
238 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", 289 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
239 FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); 290 FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
240 romfs = new_nca->GetRomFS(); 291 romfs = new_nca->GetRomFS();
241 } 292 }
242 } else if (update_raw != nullptr) { 293 } else if (update_raw != nullptr) {
@@ -278,8 +329,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
278 if (nacp != nullptr) { 329 if (nacp != nullptr) {
279 out.insert_or_assign("Update", nacp->GetVersionString()); 330 out.insert_or_assign("Update", nacp->GetVersionString());
280 } else { 331 } else {
281 if (installed->HasEntry(update_tid, ContentRecordType::Program)) { 332 if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
282 const auto meta_ver = installed->GetEntryVersion(update_tid); 333 const auto meta_ver = installed.GetEntryVersion(update_tid);
283 if (meta_ver.value_or(0) == 0) { 334 if (meta_ver.value_or(0) == 0) {
284 out.insert_or_assign("Update", ""); 335 out.insert_or_assign("Update", "");
285 } else { 336 } else {
@@ -301,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
301 if (IsDirValidAndNonEmpty(exefs_dir)) { 352 if (IsDirValidAndNonEmpty(exefs_dir)) {
302 bool ips = false; 353 bool ips = false;
303 bool ipswitch = false; 354 bool ipswitch = false;
355 bool layeredfs = false;
304 356
305 for (const auto& file : exefs_dir->GetFiles()) { 357 for (const auto& file : exefs_dir->GetFiles()) {
306 if (file->GetExtension() == "ips") 358 if (file->GetExtension() == "ips") {
307 ips = true; 359 ips = true;
308 else if (file->GetExtension() == "pchtxt") 360 } else if (file->GetExtension() == "pchtxt") {
309 ipswitch = true; 361 ipswitch = true;
362 } else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(),
363 file->GetName()) != EXEFS_FILE_NAMES.end()) {
364 layeredfs = true;
365 }
310 } 366 }
311 367
312 if (ips) 368 if (ips)
313 AppendCommaIfNotEmpty(types, "IPS"); 369 AppendCommaIfNotEmpty(types, "IPS");
314 if (ipswitch) 370 if (ipswitch)
315 AppendCommaIfNotEmpty(types, "IPSwitch"); 371 AppendCommaIfNotEmpty(types, "IPSwitch");
372 if (layeredfs)
373 AppendCommaIfNotEmpty(types, "LayeredExeFS");
316 } 374 }
317 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) 375 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
318 AppendCommaIfNotEmpty(types, "LayeredFS"); 376 AppendCommaIfNotEmpty(types, "LayeredFS");
@@ -325,14 +383,13 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
325 } 383 }
326 384
327 // DLC 385 // DLC
328 const auto dlc_entries = installed->ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); 386 const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
329 std::vector<RegisteredCacheEntry> dlc_match; 387 std::vector<RegisteredCacheEntry> dlc_match;
330 dlc_match.reserve(dlc_entries.size()); 388 dlc_match.reserve(dlc_entries.size());
331 std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), 389 std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
332 [this, &installed](const RegisteredCacheEntry& entry) { 390 [this, &installed](const RegisteredCacheEntry& entry) {
333 return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && 391 return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
334 installed->GetEntry(entry)->GetStatus() == 392 installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
335 Loader::ResultStatus::Success;
336 }); 393 });
337 if (!dlc_match.empty()) { 394 if (!dlc_match.empty()) {
338 // Ensure sorted so DLC IDs show in order. 395 // Ensure sorted so DLC IDs show in order.
@@ -353,7 +410,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
353std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const { 410std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
354 const auto installed{Service::FileSystem::GetUnionContents()}; 411 const auto installed{Service::FileSystem::GetUnionContents()};
355 412
356 const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control); 413 const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
357 if (base_control_nca == nullptr) 414 if (base_control_nca == nullptr)
358 return {}; 415 return {};
359 416
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 96302a241..128199063 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -106,40 +106,42 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
106 106
107VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, 107VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
108 std::string_view path) const { 108 std::string_view path) const {
109 if (dir->GetFileRelative(path) != nullptr) 109 const auto file = dir->GetFileRelative(path);
110 return dir->GetFileRelative(path); 110 if (file != nullptr) {
111 if (dir->GetDirectoryRelative(path) != nullptr) { 111 return file;
112 const auto nca_dir = dir->GetDirectoryRelative(path); 112 }
113 VirtualFile file = nullptr;
114
115 const auto files = nca_dir->GetFiles();
116 if (files.size() == 1 && files[0]->GetName() == "00") {
117 file = files[0];
118 } else {
119 std::vector<VirtualFile> concat;
120 // Since the files are a two-digit hex number, max is FF.
121 for (std::size_t i = 0; i < 0x100; ++i) {
122 auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
123 if (next != nullptr) {
124 concat.push_back(std::move(next));
125 } else {
126 next = nca_dir->GetFile(fmt::format("{:02x}", i));
127 if (next != nullptr)
128 concat.push_back(std::move(next));
129 else
130 break;
131 }
132 }
133 113
134 if (concat.empty()) 114 const auto nca_dir = dir->GetDirectoryRelative(path);
135 return nullptr; 115 if (nca_dir == nullptr) {
116 return nullptr;
117 }
118
119 const auto files = nca_dir->GetFiles();
120 if (files.size() == 1 && files[0]->GetName() == "00") {
121 return files[0];
122 }
136 123
137 file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName()); 124 std::vector<VirtualFile> concat;
125 // Since the files are a two-digit hex number, max is FF.
126 for (std::size_t i = 0; i < 0x100; ++i) {
127 auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
128 if (next != nullptr) {
129 concat.push_back(std::move(next));
130 } else {
131 next = nca_dir->GetFile(fmt::format("{:02x}", i));
132 if (next != nullptr) {
133 concat.push_back(std::move(next));
134 } else {
135 break;
136 }
138 } 137 }
138 }
139 139
140 return file; 140 if (concat.empty()) {
141 return nullptr;
141 } 142 }
142 return nullptr; 143
144 return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
143} 145}
144 146
145VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { 147VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
@@ -225,7 +227,7 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) {
225 227
226 if (file == nullptr) 228 if (file == nullptr)
227 continue; 229 continue;
228 const auto nca = std::make_shared<NCA>(parser(file, id)); 230 const auto nca = std::make_shared<NCA>(parser(file, id), nullptr, 0, keys);
229 if (nca->GetStatus() != Loader::ResultStatus::Success || 231 if (nca->GetStatus() != Loader::ResultStatus::Success ||
230 nca->GetType() != NCAContentType::Meta) { 232 nca->GetType() != NCAContentType::Meta) {
231 continue; 233 continue;
@@ -315,7 +317,7 @@ std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType t
315 const auto raw = GetEntryRaw(title_id, type); 317 const auto raw = GetEntryRaw(title_id, type);
316 if (raw == nullptr) 318 if (raw == nullptr)
317 return nullptr; 319 return nullptr;
318 return std::make_unique<NCA>(raw); 320 return std::make_unique<NCA>(raw, nullptr, 0, keys);
319} 321}
320 322
321std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const { 323std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
@@ -378,22 +380,22 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
378 return out; 380 return out;
379} 381}
380 382
381static std::shared_ptr<NCA> GetNCAFromNSPForID(std::shared_ptr<NSP> nsp, const NcaID& id) { 383static std::shared_ptr<NCA> GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) {
382 const auto file = nsp->GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); 384 const auto file = nsp.GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false)));
383 if (file == nullptr) 385 if (file == nullptr)
384 return nullptr; 386 return nullptr;
385 return std::make_shared<NCA>(file); 387 return std::make_shared<NCA>(file);
386} 388}
387 389
388InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists, 390InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_exists,
389 const VfsCopyFunction& copy) { 391 const VfsCopyFunction& copy) {
390 return InstallEntry(xci->GetSecurePartitionNSP(), overwrite_if_exists, copy); 392 return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
391} 393}
392 394
393InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists, 395InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
394 const VfsCopyFunction& copy) { 396 const VfsCopyFunction& copy) {
395 const auto& ncas = nsp->GetNCAsCollapsed(); 397 const auto ncas = nsp.GetNCAsCollapsed();
396 const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { 398 const auto meta_iter = std::find_if(ncas.begin(), ncas.end(), [](const auto& nca) {
397 return nca->GetType() == NCAContentType::Meta; 399 return nca->GetType() == NCAContentType::Meta;
398 }); 400 });
399 401
@@ -407,7 +409,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw
407 const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); 409 const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
408 const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); 410 const auto meta_id = Common::HexStringToArray<16>(meta_id_raw);
409 411
410 const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id); 412 const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id);
411 if (res != InstallResult::Success) 413 if (res != InstallResult::Success)
412 return res; 414 return res;
413 415
@@ -419,7 +421,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw
419 const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); 421 const auto nca = GetNCAFromNSPForID(nsp, record.nca_id);
420 if (nca == nullptr) 422 if (nca == nullptr)
421 return InstallResult::ErrorCopyFailed; 423 return InstallResult::ErrorCopyFailed;
422 const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id); 424 const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id);
423 if (res2 != InstallResult::Success) 425 if (res2 != InstallResult::Success)
424 return res2; 426 return res2;
425 } 427 }
@@ -428,21 +430,21 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw
428 return InstallResult::Success; 430 return InstallResult::Success;
429} 431}
430 432
431InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, 433InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
432 bool overwrite_if_exists, const VfsCopyFunction& copy) { 434 bool overwrite_if_exists, const VfsCopyFunction& copy) {
433 CNMTHeader header{ 435 CNMTHeader header{
434 nca->GetTitleId(), ///< Title ID 436 nca.GetTitleId(), ///< Title ID
435 0, ///< Ignore/Default title version 437 0, ///< Ignore/Default title version
436 type, ///< Type 438 type, ///< Type
437 {}, ///< Padding 439 {}, ///< Padding
438 0x10, ///< Default table offset 440 0x10, ///< Default table offset
439 1, ///< 1 Content Entry 441 1, ///< 1 Content Entry
440 0, ///< No Meta Entries 442 0, ///< No Meta Entries
441 {}, ///< Padding 443 {}, ///< Padding
442 }; 444 };
443 OptionalHeader opt_header{0, 0}; 445 OptionalHeader opt_header{0, 0};
444 ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca->GetType()), {}}; 446 ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
445 const auto& data = nca->GetBaseFile()->ReadBytes(0x100000); 447 const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
446 mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); 448 mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0);
447 memcpy(&c_rec.nca_id, &c_rec.hash, 16); 449 memcpy(&c_rec.nca_id, &c_rec.hash, 16);
448 const CNMT new_cnmt(header, opt_header, {c_rec}, {}); 450 const CNMT new_cnmt(header, opt_header, {c_rec}, {});
@@ -451,10 +453,10 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType
451 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); 453 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
452} 454}
453 455
454InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, 456InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
455 bool overwrite_if_exists, 457 bool overwrite_if_exists,
456 std::optional<NcaID> override_id) { 458 std::optional<NcaID> override_id) {
457 const auto in = nca->GetBaseFile(); 459 const auto in = nca.GetBaseFile();
458 Core::Crypto::SHA256Hash hash{}; 460 Core::Crypto::SHA256Hash hash{};
459 461
460 // Calculate NcaID 462 // Calculate NcaID
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 6cfb16017..3b77af4e0 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -6,12 +6,12 @@
6 6
7#include <array> 7#include <array>
8#include <functional> 8#include <functional>
9#include <map>
10#include <memory> 9#include <memory>
11#include <string> 10#include <string>
12#include <vector> 11#include <vector>
13#include <boost/container/flat_map.hpp> 12#include <boost/container/flat_map.hpp>
14#include "common/common_types.h" 13#include "common/common_types.h"
14#include "core/crypto/key_manager.h"
15#include "core/file_sys/vfs.h" 15#include "core/file_sys/vfs.h"
16 16
17namespace FileSys { 17namespace FileSys {
@@ -103,17 +103,16 @@ public:
103 103
104 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure 104 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
105 // there is a meta NCA and all of them are accessible. 105 // there is a meta NCA and all of them are accessible.
106 InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false, 106 InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
107 const VfsCopyFunction& copy = &VfsRawCopy); 107 const VfsCopyFunction& copy = &VfsRawCopy);
108 InstallResult InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists = false, 108 InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false,
109 const VfsCopyFunction& copy = &VfsRawCopy); 109 const VfsCopyFunction& copy = &VfsRawCopy);
110 110
111 // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this 111 // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this
112 // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a 112 // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a
113 // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. 113 // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there.
114 // TODO(DarkLordZach): Author real meta-type NCAs and install those. 114 // TODO(DarkLordZach): Author real meta-type NCAs and install those.
115 InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type, 115 InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
116 bool overwrite_if_exists = false,
117 const VfsCopyFunction& copy = &VfsRawCopy); 116 const VfsCopyFunction& copy = &VfsRawCopy);
118 117
119private: 118private:
@@ -127,12 +126,14 @@ private:
127 std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; 126 std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
128 VirtualFile GetFileAtID(NcaID id) const; 127 VirtualFile GetFileAtID(NcaID id) const;
129 VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; 128 VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const;
130 InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, 129 InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
131 bool overwrite_if_exists, std::optional<NcaID> override_id = {}); 130 bool overwrite_if_exists, std::optional<NcaID> override_id = {});
132 bool RawInstallYuzuMeta(const CNMT& cnmt); 131 bool RawInstallYuzuMeta(const CNMT& cnmt);
133 132
134 VirtualDir dir; 133 VirtualDir dir;
135 RegisteredCacheParsingFunction parser; 134 RegisteredCacheParsingFunction parser;
135 Core::Crypto::KeyManager keys;
136
136 // maps tid -> NcaID of meta 137 // maps tid -> NcaID of meta
137 boost::container::flat_map<u64, NcaID> meta_id; 138 boost::container::flat_map<u64, NcaID> meta_id;
138 // maps tid -> meta 139 // maps tid -> meta
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 0b645b106..6ad1e4f86 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
48 48
49 switch (storage) { 49 switch (storage) {
50 case StorageId::None: 50 case StorageId::None:
51 res = Service::FileSystem::GetUnionContents()->GetEntry(title_id, type); 51 res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type);
52 break; 52 break;
53 case StorageId::NandSystem: 53 case StorageId::NandSystem:
54 res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type); 54 res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index ef1aaebbb..5434f2149 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -83,28 +83,32 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr
83 return MakeResult<VirtualDir>(std::move(out)); 83 return MakeResult<VirtualDir>(std::move(out));
84} 84}
85 85
86std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, 86VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const {
87 u128 user_id, u64 save_id) { 87 return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space));
88 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should 88}
89 // be interpreted as the title id of the current process.
90 if (type == SaveDataType::SaveData && title_id == 0)
91 title_id = Core::CurrentProcess()->GetTitleID();
92
93 std::string out;
94 89
90std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
95 switch (space) { 91 switch (space) {
96 case SaveDataSpaceId::NandSystem: 92 case SaveDataSpaceId::NandSystem:
97 out = "/system/"; 93 return "/system/";
98 break;
99 case SaveDataSpaceId::NandUser: 94 case SaveDataSpaceId::NandUser:
100 out = "/user/"; 95 return "/user/";
101 break;
102 case SaveDataSpaceId::TemporaryStorage: 96 case SaveDataSpaceId::TemporaryStorage:
103 out = "/temp/"; 97 return "/temp/";
104 break;
105 default: 98 default:
106 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); 99 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
100 return "/unrecognized/"; ///< To prevent corruption when ignoring asserts.
107 } 101 }
102}
103
104std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
105 u128 user_id, u64 save_id) {
106 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
107 // be interpreted as the title id of the current process.
108 if (type == SaveDataType::SaveData && title_id == 0)
109 title_id = Core::CurrentProcess()->GetTitleID();
110
111 std::string out = GetSaveDataSpaceIdPath(space);
108 112
109 switch (type) { 113 switch (type) {
110 case SaveDataType::SystemSaveData: 114 case SaveDataType::SystemSaveData:
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index d69ef6741..2a0088040 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -52,6 +52,9 @@ public:
52 52
53 ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); 53 ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
54 54
55 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
56
57 static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
55 static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, 58 static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
56 u128 user_id, u64 save_id); 59 u128 user_id, u64 save_id);
57 60
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 2aaba4179..e1a4210db 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -252,7 +252,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
252 continue; 252 continue;
253 } 253 }
254 254
255 auto next_nca = std::make_shared<NCA>(next_file); 255 auto next_nca = std::make_shared<NCA>(next_file, nullptr, 0, keys);
256 if (next_nca->GetType() == NCAContentType::Program) 256 if (next_nca->GetType() == NCAContentType::Program)
257 program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); 257 program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
258 if (next_nca->GetStatus() == Loader::ResultStatus::Success || 258 if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 338080b7e..9a28ed5bb 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -70,6 +70,8 @@ private:
70 std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas; 70 std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas;
71 std::vector<VirtualFile> ticket_files; 71 std::vector<VirtualFile> ticket_files;
72 72
73 Core::Crypto::KeyManager keys;
74
73 VirtualFile romfs; 75 VirtualFile romfs;
74 VirtualDir exefs; 76 VirtualDir exefs;
75}; 77};
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 7b584de7f..e33327ef0 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -384,6 +384,28 @@ bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
384 return success; 384 return success;
385} 385}
386 386
387bool VfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
388 auto dir = GetSubdirectory(name);
389 if (dir == nullptr) {
390 return false;
391 }
392
393 bool success = true;
394 for (const auto& file : dir->GetFiles()) {
395 if (!dir->DeleteFile(file->GetName())) {
396 success = false;
397 }
398 }
399
400 for (const auto& sdir : dir->GetSubdirectories()) {
401 if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
402 success = false;
403 }
404 }
405
406 return success;
407}
408
387bool VfsDirectory::Copy(std::string_view src, std::string_view dest) { 409bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
388 const auto f1 = GetFile(src); 410 const auto f1 = GetFile(src);
389 auto f2 = CreateFile(dest); 411 auto f2 = CreateFile(dest);
@@ -431,10 +453,34 @@ std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name)
431 return nullptr; 453 return nullptr;
432} 454}
433 455
456std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
457 return nullptr;
458}
459
460std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
461 return nullptr;
462}
463
464std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
465 return nullptr;
466}
467
468std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
469 return nullptr;
470}
471
434bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) { 472bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) {
435 return false; 473 return false;
436} 474}
437 475
476bool ReadOnlyVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
477 return false;
478}
479
480bool ReadOnlyVfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
481 return false;
482}
483
438bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) { 484bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
439 return false; 485 return false;
440} 486}
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 002f99d4e..e5641b255 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -245,12 +245,18 @@ public:
245 // any failure. 245 // any failure.
246 virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path); 246 virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
247 247
248 // Deletes the subdirectory with name and returns true on success. 248 // Deletes the subdirectory with the given name and returns true on success.
249 virtual bool DeleteSubdirectory(std::string_view name) = 0; 249 virtual bool DeleteSubdirectory(std::string_view name) = 0;
250 // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes 250
251 // the subdirectory. Returns true on success. 251 // Deletes all subdirectories and files within the provided directory and then deletes
252 // the directory itself. Returns true on success.
252 virtual bool DeleteSubdirectoryRecursive(std::string_view name); 253 virtual bool DeleteSubdirectoryRecursive(std::string_view name);
253 // Returnes whether or not the file with name name was deleted successfully. 254
255 // Deletes all subdirectories and files within the provided directory.
256 // Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory.
257 virtual bool CleanSubdirectoryRecursive(std::string_view name);
258
259 // Returns whether or not the file with name name was deleted successfully.
254 virtual bool DeleteFile(std::string_view name) = 0; 260 virtual bool DeleteFile(std::string_view name) = 0;
255 261
256 // Returns whether or not this directory was renamed to name. 262 // Returns whether or not this directory was renamed to name.
@@ -276,7 +282,13 @@ public:
276 bool IsReadable() const override; 282 bool IsReadable() const override;
277 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; 283 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
278 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; 284 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
285 std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override;
286 std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
287 std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override;
288 std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
279 bool DeleteSubdirectory(std::string_view name) override; 289 bool DeleteSubdirectory(std::string_view name) override;
290 bool DeleteSubdirectoryRecursive(std::string_view name) override;
291 bool CleanSubdirectoryRecursive(std::string_view name) override;
280 bool DeleteFile(std::string_view name) override; 292 bool DeleteFile(std::string_view name) override;
281 bool Rename(std::string_view name) override; 293 bool Rename(std::string_view name) override;
282}; 294};
diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp
new file mode 100644
index 000000000..856ed33da
--- /dev/null
+++ b/src/core/frontend/applets/software_keyboard.cpp
@@ -0,0 +1,29 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/backend.h"
6#include "common/string_util.h"
7#include "core/frontend/applets/software_keyboard.h"
8
9namespace Core::Frontend {
10SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
11
12void DefaultSoftwareKeyboardApplet::RequestText(
13 std::function<void(std::optional<std::u16string>)> out,
14 SoftwareKeyboardParameters parameters) const {
15 if (parameters.initial_text.empty())
16 out(u"yuzu");
17
18 out(parameters.initial_text);
19}
20
21void DefaultSoftwareKeyboardApplet::SendTextCheckDialog(
22 std::u16string error_message, std::function<void()> finished_check) const {
23 LOG_WARNING(Service_AM,
24 "(STUBBED) called - Default fallback software keyboard does not support text "
25 "check! (error_message={})",
26 Common::UTF16ToUTF8(error_message));
27 finished_check();
28}
29} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h
new file mode 100644
index 000000000..f9b202664
--- /dev/null
+++ b/src/core/frontend/applets/software_keyboard.h
@@ -0,0 +1,54 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <optional>
9#include <string>
10#include "common/bit_field.h"
11#include "common/common_types.h"
12
13namespace Core::Frontend {
14struct SoftwareKeyboardParameters {
15 std::u16string submit_text;
16 std::u16string header_text;
17 std::u16string sub_text;
18 std::u16string guide_text;
19 std::u16string initial_text;
20 std::size_t max_length;
21 bool password;
22 bool cursor_at_beginning;
23
24 union {
25 u8 value;
26
27 BitField<1, 1, u8> disable_space;
28 BitField<2, 1, u8> disable_address;
29 BitField<3, 1, u8> disable_percent;
30 BitField<4, 1, u8> disable_slash;
31 BitField<6, 1, u8> disable_number;
32 BitField<7, 1, u8> disable_download_code;
33 };
34};
35
36class SoftwareKeyboardApplet {
37public:
38 virtual ~SoftwareKeyboardApplet();
39
40 virtual void RequestText(std::function<void(std::optional<std::u16string>)> out,
41 SoftwareKeyboardParameters parameters) const = 0;
42 virtual void SendTextCheckDialog(std::u16string error_message,
43 std::function<void()> finished_check) const = 0;
44};
45
46class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
47public:
48 void RequestText(std::function<void(std::optional<std::u16string>)> out,
49 SoftwareKeyboardParameters parameters) const override;
50 void SendTextCheckDialog(std::u16string error_message,
51 std::function<void()> finished_check) const override;
52};
53
54} // namespace Core::Frontend
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index 39bdf4e21..16fdcd376 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -132,4 +132,11 @@ using MotionDevice = InputDevice<std::tuple<Math::Vec3<float>, Math::Vec3<float>
132 */ 132 */
133using TouchDevice = InputDevice<std::tuple<float, float, bool>>; 133using TouchDevice = InputDevice<std::tuple<float, float, bool>>;
134 134
135/**
136 * A mouse device is an input device that returns a tuple of two floats and four ints.
137 * The first two floats are X and Y device coordinates of the mouse (from 0-1).
138 * The s32s are the mouse wheel.
139 */
140using MouseDevice = InputDevice<std::tuple<float, float, s32, s32>>;
141
135} // namespace Input 142} // namespace Input
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index bdcc889e0..e6b5171ee 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -71,10 +71,6 @@ constexpr u32 PSTATE_REGISTER = 33;
71constexpr u32 UC_ARM64_REG_Q0 = 34; 71constexpr u32 UC_ARM64_REG_Q0 = 34;
72constexpr u32 FPCR_REGISTER = 66; 72constexpr u32 FPCR_REGISTER = 66;
73 73
74// TODO/WiP - Used while working on support for FPU
75constexpr u32 TODO_DUMMY_REG_997 = 997;
76constexpr u32 TODO_DUMMY_REG_998 = 998;
77
78// For sample XML files see the GDB source /gdb/features 74// For sample XML files see the GDB source /gdb/features
79// GDB also wants the l character at the start 75// GDB also wants the l character at the start
80// This XML defines what the registers are for this specific ARM device 76// This XML defines what the registers are for this specific ARM device
@@ -260,6 +256,36 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
260 } 256 }
261} 257}
262 258
259static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) {
260 if (!thread) {
261 return u128{0};
262 }
263
264 auto& thread_context = thread->GetContext();
265
266 if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
267 return thread_context.vector_registers[id - UC_ARM64_REG_Q0];
268 } else if (id == FPCR_REGISTER) {
269 return u128{thread_context.fpcr, 0};
270 } else {
271 return u128{0};
272 }
273}
274
275static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) {
276 if (!thread) {
277 return;
278 }
279
280 auto& thread_context = thread->GetContext();
281
282 if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
283 thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
284 } else if (id == FPCR_REGISTER) {
285 thread_context.fpcr = static_cast<u32>(val[0]);
286 }
287}
288
263/** 289/**
264 * Turns hex string character into the equivalent byte. 290 * Turns hex string character into the equivalent byte.
265 * 291 *
@@ -409,6 +435,27 @@ static u64 GdbHexToLong(const u8* src) {
409 return output; 435 return output;
410} 436}
411 437
438/**
439 * Convert a gdb-formatted hex string into a u128.
440 *
441 * @param src Pointer to hex string.
442 */
443static u128 GdbHexToU128(const u8* src) {
444 u128 output;
445
446 for (int i = 0; i < 16; i += 2) {
447 output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]);
448 output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]);
449 }
450
451 for (int i = 0; i < 16; i += 2) {
452 output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]);
453 output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]);
454 }
455
456 return output;
457}
458
412/// Read a byte from the gdb client. 459/// Read a byte from the gdb client.
413static u8 ReadByte() { 460static u8 ReadByte() {
414 u8 c; 461 u8 c;
@@ -599,8 +646,7 @@ static void HandleQuery() {
599 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { 646 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
600 const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList(); 647 const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList();
601 for (const auto& thread : threads) { 648 for (const auto& thread : threads) {
602 val += fmt::format("{:x}", thread->GetThreadID()); 649 val += fmt::format("{:x},", thread->GetThreadID());
603 val += ",";
604 } 650 }
605 } 651 }
606 val.pop_back(); 652 val.pop_back();
@@ -791,11 +837,15 @@ static void ReadRegister() {
791 } else if (id == PSTATE_REGISTER) { 837 } else if (id == PSTATE_REGISTER) {
792 IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); 838 IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
793 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { 839 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
794 LongToGdbHex(reply, RegRead(id, current_thread)); 840 u128 r = FpuRead(id, current_thread);
841 LongToGdbHex(reply, r[0]);
842 LongToGdbHex(reply + 16, r[1]);
795 } else if (id == FPCR_REGISTER) { 843 } else if (id == FPCR_REGISTER) {
796 LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); 844 u128 r = FpuRead(id, current_thread);
797 } else { 845 IntToGdbHex(reply, static_cast<u32>(r[0]));
798 LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); 846 } else if (id == FPCR_REGISTER + 1) {
847 u128 r = FpuRead(id, current_thread);
848 IntToGdbHex(reply, static_cast<u32>(r[0] >> 32));
799 } 849 }
800 850
801 SendReply(reinterpret_cast<char*>(reply)); 851 SendReply(reinterpret_cast<char*>(reply));
@@ -822,13 +872,18 @@ static void ReadRegisters() {
822 872
823 bufptr += 8; 873 bufptr += 8;
824 874
825 for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { 875 u128 r;
826 LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); 876
877 for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) {
878 r = FpuRead(reg, current_thread);
879 LongToGdbHex(bufptr + reg * 32, r[0]);
880 LongToGdbHex(bufptr + reg * 32 + 16, r[1]);
827 } 881 }
828 882
829 bufptr += 32 * 32; 883 bufptr += 32 * 32;
830 884
831 LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread)); 885 r = FpuRead(FPCR_REGISTER, current_thread);
886 IntToGdbHex(bufptr, static_cast<u32>(r[0]));
832 887
833 bufptr += 8; 888 bufptr += 8;
834 889
@@ -853,14 +908,12 @@ static void WriteRegister() {
853 } else if (id == PSTATE_REGISTER) { 908 } else if (id == PSTATE_REGISTER) {
854 RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); 909 RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
855 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { 910 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
856 RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); 911 FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread);
857 } else if (id == FPCR_REGISTER) { 912 } else if (id == FPCR_REGISTER) {
858 RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); 913 } else if (id == FPCR_REGISTER + 1) {
859 } else {
860 RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
861 } 914 }
862 915
863 // Update Unicorn context skipping scheduler, no running threads at this point 916 // Update ARM context, skipping scheduler - no running threads at this point
864 Core::System::GetInstance() 917 Core::System::GetInstance()
865 .ArmInterface(current_core) 918 .ArmInterface(current_core)
866 .LoadContext(current_thread->GetContext()); 919 .LoadContext(current_thread->GetContext());
@@ -885,13 +938,13 @@ static void WriteRegisters() {
885 } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { 938 } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
886 RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); 939 RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
887 } else if (reg == FPCR_REGISTER) { 940 } else if (reg == FPCR_REGISTER) {
888 RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); 941 RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
889 } else { 942 } else if (reg == FPCR_REGISTER + 1) {
890 UNIMPLEMENTED(); 943 RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
891 } 944 }
892 } 945 }
893 946
894 // Update Unicorn context skipping scheduler, no running threads at this point 947 // Update ARM context, skipping scheduler - no running threads at this point
895 Core::System::GetInstance() 948 Core::System::GetInstance()
896 .ArmInterface(current_core) 949 .ArmInterface(current_core)
897 .LoadContext(current_thread->GetContext()); 950 .LoadContext(current_thread->GetContext());
@@ -917,12 +970,6 @@ static void ReadMemory() {
917 SendReply("E01"); 970 SendReply("E01");
918 } 971 }
919 972
920 const auto& vm_manager = Core::CurrentProcess()->VMManager();
921 if (addr < vm_manager.GetCodeRegionBaseAddress() ||
922 addr >= vm_manager.GetMapRegionEndAddress()) {
923 return SendReply("E00");
924 }
925
926 if (!Memory::IsValidVirtualAddress(addr)) { 973 if (!Memory::IsValidVirtualAddress(addr)) {
927 return SendReply("E00"); 974 return SendReply("E00");
928 } 975 }
@@ -967,7 +1014,7 @@ void Break(bool is_memory_break) {
967static void Step() { 1014static void Step() {
968 if (command_length > 1) { 1015 if (command_length > 1) {
969 RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); 1016 RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread);
970 // Update Unicorn context skipping scheduler, no running threads at this point 1017 // Update ARM context, skipping scheduler - no running threads at this point
971 Core::System::GetInstance() 1018 Core::System::GetInstance()
972 .ArmInterface(current_core) 1019 .ArmInterface(current_core)
973 .LoadContext(current_thread->GetContext()); 1020 .LoadContext(current_thread->GetContext());
@@ -1010,7 +1057,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
1010 breakpoint.addr = addr; 1057 breakpoint.addr = addr;
1011 breakpoint.len = len; 1058 breakpoint.len = len;
1012 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); 1059 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
1013 static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}}; 1060 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
1014 Memory::WriteBlock(addr, btrap.data(), btrap.size()); 1061 Memory::WriteBlock(addr, btrap.data(), btrap.size());
1015 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 1062 Core::System::GetInstance().InvalidateCpuInstructionCaches();
1016 p.insert({addr, breakpoint}); 1063 p.insert({addr, breakpoint});
@@ -1321,13 +1368,15 @@ void SetCpuStepFlag(bool is_step) {
1321} 1368}
1322 1369
1323void SendTrap(Kernel::Thread* thread, int trap) { 1370void SendTrap(Kernel::Thread* thread, int trap) {
1324 if (send_trap) { 1371 if (!send_trap) {
1325 if (!halt_loop || current_thread == thread) { 1372 return;
1326 current_thread = thread;
1327 SendSignal(thread, trap);
1328 }
1329 halt_loop = true;
1330 send_trap = false;
1331 } 1373 }
1374
1375 if (!halt_loop || current_thread == thread) {
1376 current_thread = thread;
1377 SendSignal(thread, trap);
1378 }
1379 halt_loop = true;
1380 send_trap = false;
1332} 1381}
1333}; // namespace GDBStub 1382}; // namespace GDBStub
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index ee698c8a7..8b58d701d 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -8,58 +8,28 @@
8 8
9namespace Kernel { 9namespace Kernel {
10 10
11namespace ErrCodes { 11// Confirmed Switch kernel error codes
12enum {
13 // Confirmed Switch OS error codes
14 MaxConnectionsReached = 7,
15 InvalidSize = 101,
16 InvalidAddress = 102,
17 HandleTableFull = 105,
18 InvalidMemoryState = 106,
19 InvalidMemoryPermissions = 108,
20 InvalidMemoryRange = 110,
21 InvalidThreadPriority = 112,
22 InvalidProcessorId = 113,
23 InvalidHandle = 114,
24 InvalidPointer = 115,
25 InvalidCombination = 116,
26 Timeout = 117,
27 SynchronizationCanceled = 118,
28 TooLarge = 119,
29 InvalidEnumValue = 120,
30 NoSuchEntry = 121,
31 AlreadyRegistered = 122,
32 SessionClosed = 123,
33 InvalidState = 125,
34 ResourceLimitExceeded = 132,
35};
36}
37 12
38// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always 13constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
39// double check that the code matches before re-using the constant. 14constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
40 15constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
41constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull); 16constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
42constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(ErrorModule::Kernel, ErrCodes::SessionClosed); 17constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
43constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge); 18constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
44constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(ErrorModule::Kernel, 19constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110};
45 ErrCodes::MaxConnectionsReached); 20constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113};
46constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue); 21constexpr ResultCode ERR_INVALID_THREAD_PRIORITY{ErrorModule::Kernel, 112};
47constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(ErrorModule::Kernel, 22constexpr ResultCode ERR_INVALID_HANDLE{ErrorModule::Kernel, 114};
48 ErrCodes::InvalidCombination); 23constexpr ResultCode ERR_INVALID_POINTER{ErrorModule::Kernel, 115};
49constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress); 24constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116};
50constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); 25constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117};
51constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, 26constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118};
52 ErrCodes::InvalidMemoryPermissions); 27constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119};
53constexpr ResultCode ERR_INVALID_MEMORY_RANGE(ErrorModule::Kernel, ErrCodes::InvalidMemoryRange); 28constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120};
54constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); 29constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121};
55constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); 30constexpr ResultCode ERR_ALREADY_REGISTERED{ErrorModule::Kernel, 122};
56constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); 31constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE{ErrorModule::Kernel, 123};
57constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered); 32constexpr ResultCode ERR_INVALID_STATE{ErrorModule::Kernel, 125};
58constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); 33constexpr ResultCode ERR_RESOURCE_LIMIT_EXCEEDED{ErrorModule::Kernel, 132};
59constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
60 ErrCodes::InvalidThreadPriority);
61constexpr ResultCode ERR_INVALID_POINTER(ErrorModule::Kernel, ErrCodes::InvalidPointer);
62constexpr ResultCode ERR_NOT_FOUND(ErrorModule::Kernel, ErrCodes::NoSuchEntry);
63constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout);
64 34
65} // namespace Kernel 35} // namespace Kernel
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 5ee5c05e3..c8acde5b1 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -12,12 +12,23 @@
12#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
13 13
14namespace Kernel { 14namespace Kernel {
15namespace {
16constexpr u16 GetSlot(Handle handle) {
17 return handle >> 15;
18}
19
20constexpr u16 GetGeneration(Handle handle) {
21 return handle & 0x7FFF;
22}
23} // Anonymous namespace
15 24
16HandleTable::HandleTable() { 25HandleTable::HandleTable() {
17 next_generation = 1; 26 next_generation = 1;
18 Clear(); 27 Clear();
19} 28}
20 29
30HandleTable::~HandleTable() = default;
31
21ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { 32ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
22 DEBUG_ASSERT(obj != nullptr); 33 DEBUG_ASSERT(obj != nullptr);
23 34
@@ -31,9 +42,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
31 u16 generation = next_generation++; 42 u16 generation = next_generation++;
32 43
33 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. 44 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
34 // CTR-OS doesn't use generation 0, so skip straight to 1. 45 // Horizon OS uses zero to represent an invalid handle, so skip to 1.
35 if (next_generation >= (1 << 15)) 46 if (next_generation >= (1 << 15)) {
36 next_generation = 1; 47 next_generation = 1;
48 }
37 49
38 generations[slot] = generation; 50 generations[slot] = generation;
39 objects[slot] = std::move(obj); 51 objects[slot] = std::move(obj);
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index 9e2f33e8a..6b7927fd8 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -13,6 +13,7 @@
13namespace Kernel { 13namespace Kernel {
14 14
15enum KernelHandle : Handle { 15enum KernelHandle : Handle {
16 InvalidHandle = 0,
16 CurrentThread = 0xFFFF8000, 17 CurrentThread = 0xFFFF8000,
17 CurrentProcess = 0xFFFF8001, 18 CurrentProcess = 0xFFFF8001,
18}; 19};
@@ -43,6 +44,7 @@ enum KernelHandle : Handle {
43class HandleTable final : NonCopyable { 44class HandleTable final : NonCopyable {
44public: 45public:
45 HandleTable(); 46 HandleTable();
47 ~HandleTable();
46 48
47 /** 49 /**
48 * Allocates a handle for the given object. 50 * Allocates a handle for the given object.
@@ -89,18 +91,8 @@ public:
89 void Clear(); 91 void Clear();
90 92
91private: 93private:
92 /** 94 /// This is the maximum limit of handles allowed per process in Horizon
93 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further 95 static constexpr std::size_t MAX_COUNT = 1024;
94 * reduced by ExHeader values, but this is not emulated here.
95 */
96 static const std::size_t MAX_COUNT = 4096;
97
98 static u16 GetSlot(Handle handle) {
99 return handle >> 15;
100 }
101 static u16 GetGeneration(Handle handle) {
102 return handle & 0x7FFF;
103 }
104 96
105 /// Stores the Object referenced by the handle or null if the slot is empty. 97 /// Stores the Object referenced by the handle or null if the slot is empty.
106 std::array<SharedPtr<Object>, MAX_COUNT> objects; 98 std::array<SharedPtr<Object>, MAX_COUNT> objects;
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 68d5376cb..61ce7d7e4 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -15,13 +15,14 @@
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "core/core.h" 16#include "core/core.h"
17#include "core/hle/ipc_helpers.h" 17#include "core/hle/ipc_helpers.h"
18#include "core/hle/kernel/event.h"
19#include "core/hle/kernel/handle_table.h" 18#include "core/hle/kernel/handle_table.h"
20#include "core/hle/kernel/hle_ipc.h" 19#include "core/hle/kernel/hle_ipc.h"
21#include "core/hle/kernel/kernel.h" 20#include "core/hle/kernel/kernel.h"
22#include "core/hle/kernel/object.h" 21#include "core/hle/kernel/object.h"
23#include "core/hle/kernel/process.h" 22#include "core/hle/kernel/process.h"
23#include "core/hle/kernel/readable_event.h"
24#include "core/hle/kernel/server_session.h" 24#include "core/hle/kernel/server_session.h"
25#include "core/hle/kernel/writable_event.h"
25#include "core/memory.h" 26#include "core/memory.h"
26 27
27namespace Kernel { 28namespace Kernel {
@@ -36,11 +37,9 @@ void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& s
36 boost::range::remove_erase(connected_sessions, server_session); 37 boost::range::remove_erase(connected_sessions, server_session);
37} 38}
38 39
39SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, 40SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
40 const std::string& reason, u64 timeout, 41 SharedPtr<Thread> thread, const std::string& reason, u64 timeout, WakeupCallback&& callback,
41 WakeupCallback&& callback, 42 SharedPtr<WritableEvent> writable_event) {
42 Kernel::SharedPtr<Kernel::Event> event) {
43
44 // Put the client thread to sleep until the wait event is signaled or the timeout expires. 43 // Put the client thread to sleep until the wait event is signaled or the timeout expires.
45 thread->SetWakeupCallback([context = *this, callback]( 44 thread->SetWakeupCallback([context = *this, callback](
46 ThreadWakeupReason reason, SharedPtr<Thread> thread, 45 ThreadWakeupReason reason, SharedPtr<Thread> thread,
@@ -51,23 +50,25 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
51 return true; 50 return true;
52 }); 51 });
53 52
54 if (!event) { 53 auto& kernel = Core::System::GetInstance().Kernel();
54 if (!writable_event) {
55 // Create event if not provided 55 // Create event if not provided
56 auto& kernel = Core::System::GetInstance().Kernel(); 56 const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
57 event = 57 "HLE Pause Event: " + reason);
58 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); 58 writable_event = pair.writable;
59 } 59 }
60 60
61 event->Clear(); 61 const auto readable_event{writable_event->GetReadableEvent()};
62 writable_event->Clear();
62 thread->SetStatus(ThreadStatus::WaitHLEEvent); 63 thread->SetStatus(ThreadStatus::WaitHLEEvent);
63 thread->SetWaitObjects({event}); 64 thread->SetWaitObjects({readable_event});
64 event->AddWaitingThread(thread); 65 readable_event->AddWaitingThread(thread);
65 66
66 if (timeout > 0) { 67 if (timeout > 0) {
67 thread->WakeAfterDelay(timeout); 68 thread->WakeAfterDelay(timeout);
68 } 69 }
69 70
70 return event; 71 return writable_event;
71} 72}
72 73
73HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) 74HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index a38e34b74..e5c0610cd 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -24,10 +24,11 @@ class ServiceFrameworkBase;
24namespace Kernel { 24namespace Kernel {
25 25
26class Domain; 26class Domain;
27class Event;
28class HandleTable; 27class HandleTable;
29class HLERequestContext; 28class HLERequestContext;
30class Process; 29class Process;
30class ReadableEvent;
31class WritableEvent;
31 32
32/** 33/**
33 * Interface implemented by HLE Session handlers. 34 * Interface implemented by HLE Session handlers.
@@ -119,12 +120,13 @@ public:
119 * @param callback Callback to be invoked when the thread is resumed. This callback must write 120 * @param callback Callback to be invoked when the thread is resumed. This callback must write
120 * the entire command response once again, regardless of the state of it before this function 121 * the entire command response once again, regardless of the state of it before this function
121 * was called. 122 * was called.
122 * @param event Event to use to wake up the thread. If unspecified, an event will be created. 123 * @param writable_event Event to use to wake up the thread. If unspecified, an event will be
124 * created.
123 * @returns Event that when signaled will resume the thread and call the callback function. 125 * @returns Event that when signaled will resume the thread and call the callback function.
124 */ 126 */
125 SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason, 127 SharedPtr<WritableEvent> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
126 u64 timeout, WakeupCallback&& callback, 128 u64 timeout, WakeupCallback&& callback,
127 Kernel::SharedPtr<Kernel::Event> event = nullptr); 129 SharedPtr<WritableEvent> writable_event = nullptr);
128 130
129 /// Populates this context with data from the requesting process/thread. 131 /// Populates this context with data from the requesting process/thread.
130 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, 132 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1fd4ba5d2..e441c5bc6 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -105,7 +105,7 @@ struct KernelCore::Impl {
105 void Initialize(KernelCore& kernel) { 105 void Initialize(KernelCore& kernel) {
106 Shutdown(); 106 Shutdown();
107 107
108 InitializeResourceLimits(kernel); 108 InitializeSystemResourceLimit(kernel);
109 InitializeThreads(); 109 InitializeThreads();
110 InitializeTimers(); 110 InitializeTimers();
111 } 111 }
@@ -118,7 +118,7 @@ struct KernelCore::Impl {
118 process_list.clear(); 118 process_list.clear();
119 current_process = nullptr; 119 current_process = nullptr;
120 120
121 resource_limits.fill(nullptr); 121 system_resource_limit = nullptr;
122 122
123 thread_wakeup_callback_handle_table.Clear(); 123 thread_wakeup_callback_handle_table.Clear();
124 thread_wakeup_event_type = nullptr; 124 thread_wakeup_event_type = nullptr;
@@ -129,63 +129,17 @@ struct KernelCore::Impl {
129 named_ports.clear(); 129 named_ports.clear();
130 } 130 }
131 131
132 void InitializeResourceLimits(KernelCore& kernel) { 132 // Creates the default system resource limit
133 // Create the four resource limits that the system uses 133 void InitializeSystemResourceLimit(KernelCore& kernel) {
134 // Create the APPLICATION resource limit 134 system_resource_limit = ResourceLimit::Create(kernel, "System");
135 SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create(kernel, "Applications"); 135
136 resource_limit->max_priority = 0x18; 136 // If setting the default system values fails, then something seriously wrong has occurred.
137 resource_limit->max_commit = 0x4000000; 137 ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000)
138 resource_limit->max_threads = 0x20; 138 .IsSuccess());
139 resource_limit->max_events = 0x20; 139 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess());
140 resource_limit->max_mutexes = 0x20; 140 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess());
141 resource_limit->max_semaphores = 0x8; 141 ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess());
142 resource_limit->max_timers = 0x8; 142 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
143 resource_limit->max_shared_mems = 0x10;
144 resource_limit->max_address_arbiters = 0x2;
145 resource_limit->max_cpu_time = 0x1E;
146 resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit;
147
148 // Create the SYS_APPLET resource limit
149 resource_limit = ResourceLimit::Create(kernel, "System Applets");
150 resource_limit->max_priority = 0x4;
151 resource_limit->max_commit = 0x5E00000;
152 resource_limit->max_threads = 0x1D;
153 resource_limit->max_events = 0xB;
154 resource_limit->max_mutexes = 0x8;
155 resource_limit->max_semaphores = 0x4;
156 resource_limit->max_timers = 0x4;
157 resource_limit->max_shared_mems = 0x8;
158 resource_limit->max_address_arbiters = 0x3;
159 resource_limit->max_cpu_time = 0x2710;
160 resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit;
161
162 // Create the LIB_APPLET resource limit
163 resource_limit = ResourceLimit::Create(kernel, "Library Applets");
164 resource_limit->max_priority = 0x4;
165 resource_limit->max_commit = 0x600000;
166 resource_limit->max_threads = 0xE;
167 resource_limit->max_events = 0x8;
168 resource_limit->max_mutexes = 0x8;
169 resource_limit->max_semaphores = 0x4;
170 resource_limit->max_timers = 0x4;
171 resource_limit->max_shared_mems = 0x8;
172 resource_limit->max_address_arbiters = 0x1;
173 resource_limit->max_cpu_time = 0x2710;
174 resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit;
175
176 // Create the OTHER resource limit
177 resource_limit = ResourceLimit::Create(kernel, "Others");
178 resource_limit->max_priority = 0x4;
179 resource_limit->max_commit = 0x2180000;
180 resource_limit->max_threads = 0xE1;
181 resource_limit->max_events = 0x108;
182 resource_limit->max_mutexes = 0x25;
183 resource_limit->max_semaphores = 0x43;
184 resource_limit->max_timers = 0x2C;
185 resource_limit->max_shared_mems = 0x1F;
186 resource_limit->max_address_arbiters = 0x2D;
187 resource_limit->max_cpu_time = 0x3E8;
188 resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit;
189 } 143 }
190 144
191 void InitializeThreads() { 145 void InitializeThreads() {
@@ -208,7 +162,7 @@ struct KernelCore::Impl {
208 std::vector<SharedPtr<Process>> process_list; 162 std::vector<SharedPtr<Process>> process_list;
209 Process* current_process = nullptr; 163 Process* current_process = nullptr;
210 164
211 std::array<SharedPtr<ResourceLimit>, 4> resource_limits; 165 SharedPtr<ResourceLimit> system_resource_limit;
212 166
213 /// The event type of the generic timer callback event 167 /// The event type of the generic timer callback event
214 CoreTiming::EventType* timer_callback_event_type = nullptr; 168 CoreTiming::EventType* timer_callback_event_type = nullptr;
@@ -239,9 +193,8 @@ void KernelCore::Shutdown() {
239 impl->Shutdown(); 193 impl->Shutdown();
240} 194}
241 195
242SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory( 196SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
243 ResourceLimitCategory category) const { 197 return impl->system_resource_limit;
244 return impl->resource_limits.at(static_cast<std::size_t>(category));
245} 198}
246 199
247SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { 200SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 7f822d524..ea00c89f5 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -24,8 +24,6 @@ class ResourceLimit;
24class Thread; 24class Thread;
25class Timer; 25class Timer;
26 26
27enum class ResourceLimitCategory : u8;
28
29/// Represents a single instance of the kernel. 27/// Represents a single instance of the kernel.
30class KernelCore { 28class KernelCore {
31private: 29private:
@@ -47,8 +45,8 @@ public:
47 /// Clears all resources in use by the kernel instance. 45 /// Clears all resources in use by the kernel instance.
48 void Shutdown(); 46 void Shutdown();
49 47
50 /// Retrieves a shared pointer to a ResourceLimit identified by the given category. 48 /// Retrieves a shared pointer to the system resource limit instance.
51 SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const; 49 SharedPtr<ResourceLimit> GetSystemResourceLimit() const;
52 50
53 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. 51 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
54 SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; 52 SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index d87a62bb9..bb1b68778 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -13,7 +13,7 @@ Object::~Object() = default;
13 13
14bool Object::IsWaitable() const { 14bool Object::IsWaitable() const {
15 switch (GetHandleType()) { 15 switch (GetHandleType()) {
16 case HandleType::Event: 16 case HandleType::ReadableEvent:
17 case HandleType::Thread: 17 case HandleType::Thread:
18 case HandleType::Timer: 18 case HandleType::Timer:
19 case HandleType::ServerPort: 19 case HandleType::ServerPort:
@@ -21,6 +21,7 @@ bool Object::IsWaitable() const {
21 return true; 21 return true;
22 22
23 case HandleType::Unknown: 23 case HandleType::Unknown:
24 case HandleType::WritableEvent:
24 case HandleType::SharedMemory: 25 case HandleType::SharedMemory:
25 case HandleType::Process: 26 case HandleType::Process:
26 case HandleType::AddressArbiter: 27 case HandleType::AddressArbiter:
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index c9f4d0bb3..f1606a204 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -19,7 +19,8 @@ using Handle = u32;
19 19
20enum class HandleType : u32 { 20enum class HandleType : u32 {
21 Unknown, 21 Unknown,
22 Event, 22 WritableEvent,
23 ReadableEvent,
23 SharedMemory, 24 SharedMemory,
24 Thread, 25 Thread,
25 Process, 26 Process,
@@ -33,9 +34,9 @@ enum class HandleType : u32 {
33}; 34};
34 35
35enum class ResetType { 36enum class ResetType {
36 OneShot, 37 OneShot, ///< Reset automatically on object acquisition
37 Sticky, 38 Sticky, ///< Never reset automatically
38 Pulse, 39 Pulse, ///< Reset automatically on wakeup
39}; 40};
40 41
41class Object : NonCopyable { 42class Object : NonCopyable {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 420218d59..4ecb8c926 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -4,12 +4,11 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <memory> 6#include <memory>
7#include <random>
7#include "common/assert.h" 8#include "common/assert.h"
8#include "common/common_funcs.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/file_sys/program_metadata.h" 11#include "core/file_sys/program_metadata.h"
12#include "core/hle/kernel/errors.h"
13#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
15#include "core/hle/kernel/resource_limit.h" 14#include "core/hle/kernel/resource_limit.h"
@@ -17,6 +16,7 @@
17#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
18#include "core/hle/kernel/vm_manager.h" 17#include "core/hle/kernel/vm_manager.h"
19#include "core/memory.h" 18#include "core/memory.h"
19#include "core/settings.h"
20 20
21namespace Kernel { 21namespace Kernel {
22 22
@@ -29,16 +29,25 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
29 process->name = std::move(name); 29 process->name = std::move(name);
30 process->flags.raw = 0; 30 process->flags.raw = 0;
31 process->flags.memory_region.Assign(MemoryRegion::APPLICATION); 31 process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
32 process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION); 32 process->resource_limit = kernel.GetSystemResourceLimit();
33 process->status = ProcessStatus::Created; 33 process->status = ProcessStatus::Created;
34 process->program_id = 0; 34 process->program_id = 0;
35 process->process_id = kernel.CreateNewProcessID(); 35 process->process_id = kernel.CreateNewProcessID();
36 process->svc_access_mask.set(); 36 process->svc_access_mask.set();
37 37
38 std::mt19937 rng(Settings::values.rng_seed.value_or(0));
39 std::uniform_int_distribution<u64> distribution;
40 std::generate(process->random_entropy.begin(), process->random_entropy.end(),
41 [&] { return distribution(rng); });
42
38 kernel.AppendNewProcess(process); 43 kernel.AppendNewProcess(process);
39 return process; 44 return process;
40} 45}
41 46
47SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
48 return resource_limit;
49}
50
42void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { 51void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
43 program_id = metadata.GetTitleID(); 52 program_id = metadata.GetTitleID();
44 is_64bit_process = metadata.Is64BitProgram(); 53 is_64bit_process = metadata.Is64BitProgram();
@@ -241,83 +250,15 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
241} 250}
242 251
243ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { 252ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
244 if (target < vm_manager.GetHeapRegionBaseAddress() || 253 return vm_manager.HeapAllocate(target, size, perms);
245 target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
246 return ERR_INVALID_ADDRESS;
247 }
248
249 if (heap_memory == nullptr) {
250 // Initialize heap
251 heap_memory = std::make_shared<std::vector<u8>>();
252 heap_start = heap_end = target;
253 } else {
254 vm_manager.UnmapRange(heap_start, heap_end - heap_start);
255 }
256
257 // If necessary, expand backing vector to cover new heap extents.
258 if (target < heap_start) {
259 heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
260 heap_start = target;
261 vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
262 }
263 if (target + size > heap_end) {
264 heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
265 heap_end = target + size;
266 vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
267 }
268 ASSERT(heap_end - heap_start == heap_memory->size());
269
270 CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start,
271 size, MemoryState::Heap));
272 vm_manager.Reprotect(vma, perms);
273
274 heap_used = size;
275
276 return MakeResult<VAddr>(heap_end - size);
277} 254}
278 255
279ResultCode Process::HeapFree(VAddr target, u32 size) { 256ResultCode Process::HeapFree(VAddr target, u32 size) {
280 if (target < vm_manager.GetHeapRegionBaseAddress() || 257 return vm_manager.HeapFree(target, size);
281 target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
282 return ERR_INVALID_ADDRESS;
283 }
284
285 if (size == 0) {
286 return RESULT_SUCCESS;
287 }
288
289 ResultCode result = vm_manager.UnmapRange(target, size);
290 if (result.IsError())
291 return result;
292
293 heap_used -= size;
294
295 return RESULT_SUCCESS;
296} 258}
297 259
298ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { 260ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) {
299 auto vma = vm_manager.FindVMA(src_addr); 261 return vm_manager.MirrorMemory(dst_addr, src_addr, size, state);
300
301 ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
302 ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
303
304 // The returned VMA might be a bigger one encompassing the desired address.
305 auto vma_offset = src_addr - vma->first;
306 ASSERT_MSG(vma_offset + size <= vma->second.size,
307 "Shared memory exceeds bounds of mapped block");
308
309 const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
310 std::size_t backing_block_offset = vma->second.offset + vma_offset;
311
312 CASCADE_RESULT(auto new_vma,
313 vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
314 MemoryState::Mapped));
315 // Protect mirror with permissions from old region
316 vm_manager.Reprotect(new_vma, vma->second.permissions);
317 // Remove permissions from old region
318 vm_manager.Reprotect(vma, VMAPermission::None);
319
320 return RESULT_SUCCESS;
321} 262}
322 263
323ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { 264ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 8d2616c79..49345aa66 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -119,6 +119,8 @@ struct CodeSet final {
119 119
120class Process final : public Object { 120class Process final : public Object {
121public: 121public:
122 static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
123
122 static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name); 124 static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name);
123 125
124 std::string GetTypeName() const override { 126 std::string GetTypeName() const override {
@@ -169,14 +171,7 @@ public:
169 } 171 }
170 172
171 /// Gets the resource limit descriptor for this process 173 /// Gets the resource limit descriptor for this process
172 ResourceLimit& GetResourceLimit() { 174 SharedPtr<ResourceLimit> GetResourceLimit() const;
173 return *resource_limit;
174 }
175
176 /// Gets the resource limit descriptor for this process
177 const ResourceLimit& GetResourceLimit() const {
178 return *resource_limit;
179 }
180 175
181 /// Gets the default CPU ID for this process 176 /// Gets the default CPU ID for this process
182 u8 GetDefaultProcessorID() const { 177 u8 GetDefaultProcessorID() const {
@@ -212,6 +207,11 @@ public:
212 total_process_running_time_ticks += ticks; 207 total_process_running_time_ticks += ticks;
213 } 208 }
214 209
210 /// Gets 8 bytes of random data for svcGetInfo RandomEntropy
211 u64 GetRandomEntropy(std::size_t index) const {
212 return random_entropy.at(index);
213 }
214
215 /** 215 /**
216 * Loads process-specifics configuration info with metadata provided 216 * Loads process-specifics configuration info with metadata provided
217 * by an executable. 217 * by an executable.
@@ -251,7 +251,8 @@ public:
251 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); 251 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
252 ResultCode HeapFree(VAddr target, u32 size); 252 ResultCode HeapFree(VAddr target, u32 size);
253 253
254 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size); 254 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size,
255 MemoryState state = MemoryState::Mapped);
255 256
256 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); 257 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
257 258
@@ -292,17 +293,6 @@ private:
292 u32 allowed_thread_priority_mask = 0xFFFFFFFF; 293 u32 allowed_thread_priority_mask = 0xFFFFFFFF;
293 u32 is_virtual_address_memory_enabled = 0; 294 u32 is_virtual_address_memory_enabled = 0;
294 295
295 // Memory used to back the allocations in the regular heap. A single vector is used to cover
296 // the entire virtual address space extents that bound the allocations, including any holes.
297 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
298 // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
299 std::shared_ptr<std::vector<u8>> heap_memory;
300
301 // The left/right bounds of the address space covered by heap_memory.
302 VAddr heap_start = 0;
303 VAddr heap_end = 0;
304 u64 heap_used = 0;
305
306 /// The Thread Local Storage area is allocated as processes create threads, 296 /// The Thread Local Storage area is allocated as processes create threads,
307 /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part 297 /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
308 /// holds the TLS for a specific thread. This vector contains which parts are in use for each 298 /// holds the TLS for a specific thread. This vector contains which parts are in use for each
@@ -321,6 +311,9 @@ private:
321 /// Per-process handle table for storing created object handles in. 311 /// Per-process handle table for storing created object handles in.
322 HandleTable handle_table; 312 HandleTable handle_table;
323 313
314 /// Random values for svcGetInfo RandomEntropy
315 std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
316
324 std::string name; 317 std::string name;
325}; 318};
326 319
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/readable_event.cpp
index 8967e602e..92e16b4e6 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -4,46 +4,37 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/hle/kernel/event.h"
8#include "core/hle/kernel/object.h" 7#include "core/hle/kernel/object.h"
8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/kernel/thread.h" 9#include "core/hle/kernel/thread.h"
10#include "core/hle/kernel/writable_event.h"
10 11
11namespace Kernel { 12namespace Kernel {
12 13
13Event::Event(KernelCore& kernel) : WaitObject{kernel} {} 14ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
14Event::~Event() = default; 15ReadableEvent::~ReadableEvent() = default;
15 16
16SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) { 17bool ReadableEvent::ShouldWait(Thread* thread) const {
17 SharedPtr<Event> evt(new Event(kernel));
18
19 evt->signaled = false;
20 evt->reset_type = reset_type;
21 evt->name = std::move(name);
22
23 return evt;
24}
25
26bool Event::ShouldWait(Thread* thread) const {
27 return !signaled; 18 return !signaled;
28} 19}
29 20
30void Event::Acquire(Thread* thread) { 21void ReadableEvent::Acquire(Thread* thread) {
31 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 22 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
32 23
33 if (reset_type == ResetType::OneShot) 24 if (reset_type == ResetType::OneShot)
34 signaled = false; 25 signaled = false;
35} 26}
36 27
37void Event::Signal() { 28void ReadableEvent::Signal() {
38 signaled = true; 29 signaled = true;
39 WakeupAllWaitingThreads(); 30 WakeupAllWaitingThreads();
40} 31}
41 32
42void Event::Clear() { 33void ReadableEvent::Clear() {
43 signaled = false; 34 signaled = false;
44} 35}
45 36
46void Event::WakeupAllWaitingThreads() { 37void ReadableEvent::WakeupAllWaitingThreads() {
47 WaitObject::WakeupAllWaitingThreads(); 38 WaitObject::WakeupAllWaitingThreads();
48 39
49 if (reset_type == ResetType::Pulse) 40 if (reset_type == ResetType::Pulse)
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h
new file mode 100644
index 000000000..867ff3051
--- /dev/null
+++ b/src/core/hle/kernel/readable_event.h
@@ -0,0 +1,55 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/kernel/object.h"
8#include "core/hle/kernel/wait_object.h"
9
10namespace Kernel {
11
12class KernelCore;
13class WritableEvent;
14
15class ReadableEvent final : public WaitObject {
16 friend class WritableEvent;
17
18public:
19 ~ReadableEvent() override;
20
21 std::string GetTypeName() const override {
22 return "ReadableEvent";
23 }
24 std::string GetName() const override {
25 return name;
26 }
27
28 ResetType GetResetType() const {
29 return reset_type;
30 }
31
32 static const HandleType HANDLE_TYPE = HandleType::ReadableEvent;
33 HandleType GetHandleType() const override {
34 return HANDLE_TYPE;
35 }
36
37 bool ShouldWait(Thread* thread) const override;
38 void Acquire(Thread* thread) override;
39
40 void WakeupAllWaitingThreads() override;
41
42 void Clear();
43
44private:
45 explicit ReadableEvent(KernelCore& kernel);
46
47 void Signal();
48
49 ResetType reset_type;
50 bool signaled;
51
52 std::string name; ///< Name of event (optional)
53};
54
55} // namespace Kernel
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index b253a680f..2f9695005 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -2,12 +2,16 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include "core/hle/kernel/errors.h"
6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/hle/kernel/resource_limit.h" 6#include "core/hle/kernel/resource_limit.h"
7#include "core/hle/result.h"
9 8
10namespace Kernel { 9namespace Kernel {
10namespace {
11constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
12 return static_cast<std::size_t>(type);
13}
14} // Anonymous namespace
11 15
12ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} 16ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
13ResourceLimit::~ResourceLimit() = default; 17ResourceLimit::~ResourceLimit() = default;
@@ -19,59 +23,22 @@ SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string n
19 return resource_limit; 23 return resource_limit;
20} 24}
21 25
22s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { 26s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
23 switch (resource) { 27 return values.at(ResourceTypeToIndex(resource));
24 case ResourceType::Commit: 28}
25 return current_commit; 29
26 case ResourceType::Thread: 30s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
27 return current_threads; 31 return limits.at(ResourceTypeToIndex(resource));
28 case ResourceType::Event:
29 return current_events;
30 case ResourceType::Mutex:
31 return current_mutexes;
32 case ResourceType::Semaphore:
33 return current_semaphores;
34 case ResourceType::Timer:
35 return current_timers;
36 case ResourceType::SharedMemory:
37 return current_shared_mems;
38 case ResourceType::AddressArbiter:
39 return current_address_arbiters;
40 case ResourceType::CPUTime:
41 return current_cpu_time;
42 default:
43 LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
44 UNIMPLEMENTED();
45 return 0;
46 }
47} 32}
48 33
49u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { 34ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) {
50 switch (resource) { 35 const auto index = ResourceTypeToIndex(resource);
51 case ResourceType::Priority: 36
52 return max_priority; 37 if (value < values[index]) {
53 case ResourceType::Commit: 38 return ERR_INVALID_STATE;
54 return max_commit;
55 case ResourceType::Thread:
56 return max_threads;
57 case ResourceType::Event:
58 return max_events;
59 case ResourceType::Mutex:
60 return max_mutexes;
61 case ResourceType::Semaphore:
62 return max_semaphores;
63 case ResourceType::Timer:
64 return max_timers;
65 case ResourceType::SharedMemory:
66 return max_shared_mems;
67 case ResourceType::AddressArbiter:
68 return max_address_arbiters;
69 case ResourceType::CPUTime:
70 return max_cpu_time;
71 default:
72 LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
73 UNIMPLEMENTED();
74 return 0;
75 } 39 }
40
41 values[index] = value;
42 return RESULT_SUCCESS;
76} 43}
77} // namespace Kernel 44} // namespace Kernel
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 219e49562..59dc11c22 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -4,33 +4,31 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "core/hle/kernel/object.h" 9#include "core/hle/kernel/object.h"
9 10
11union ResultCode;
12
10namespace Kernel { 13namespace Kernel {
11 14
12class KernelCore; 15class KernelCore;
13 16
14enum class ResourceLimitCategory : u8 { 17enum class ResourceType : u32 {
15 APPLICATION = 0, 18 PhysicalMemory,
16 SYS_APPLET = 1, 19 Threads,
17 LIB_APPLET = 2, 20 Events,
18 OTHER = 3 21 TransferMemory,
19}; 22 Sessions,
20 23
21enum class ResourceType { 24 // Used as a count, not an actual type.
22 Priority = 0, 25 ResourceTypeCount
23 Commit = 1,
24 Thread = 2,
25 Event = 3,
26 Mutex = 4,
27 Semaphore = 5,
28 Timer = 6,
29 SharedMemory = 7,
30 AddressArbiter = 8,
31 CPUTime = 9,
32}; 26};
33 27
28constexpr bool IsValidResourceType(ResourceType type) {
29 return type < ResourceType::ResourceTypeCount;
30}
31
34class ResourceLimit final : public Object { 32class ResourceLimit final : public Object {
35public: 33public:
36 /** 34 /**
@@ -55,61 +53,51 @@ public:
55 * @param resource Requested resource type 53 * @param resource Requested resource type
56 * @returns The current value of the resource type 54 * @returns The current value of the resource type
57 */ 55 */
58 s32 GetCurrentResourceValue(ResourceType resource) const; 56 s64 GetCurrentResourceValue(ResourceType resource) const;
59 57
60 /** 58 /**
61 * Gets the max value for the specified resource. 59 * Gets the max value for the specified resource.
62 * @param resource Requested resource type 60 * @param resource Requested resource type
63 * @returns The max value of the resource type 61 * @returns The max value of the resource type
64 */ 62 */
65 u32 GetMaxResourceValue(ResourceType resource) const; 63 s64 GetMaxResourceValue(ResourceType resource) const;
66
67 /// Name of resource limit object.
68 std::string name;
69
70 /// Max thread priority that a process in this category can create
71 s32 max_priority = 0;
72
73 /// Max memory that processes in this category can use
74 s32 max_commit = 0;
75 64
76 ///< Max number of objects that can be collectively created by the processes in this category 65 /**
77 s32 max_threads = 0; 66 * Sets the limit value for a given resource type.
78 s32 max_events = 0; 67 *
79 s32 max_mutexes = 0; 68 * @param resource The resource type to apply the limit to.
80 s32 max_semaphores = 0; 69 * @param value The limit to apply to the given resource type.
81 s32 max_timers = 0; 70 *
82 s32 max_shared_mems = 0; 71 * @return A result code indicating if setting the limit value
83 s32 max_address_arbiters = 0; 72 * was successful or not.
73 *
74 * @note The supplied limit value *must* be greater than or equal to
75 * the current resource value for the given resource type,
76 * otherwise ERR_INVALID_STATE will be returned.
77 */
78 ResultCode SetLimitValue(ResourceType resource, s64 value);
84 79
85 /// Max CPU time that the processes in this category can utilize 80private:
86 s32 max_cpu_time = 0; 81 explicit ResourceLimit(KernelCore& kernel);
82 ~ResourceLimit() override;
87 83
88 // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind 84 // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
89 // that APPLICATION resource limits should not be affected by the objects created by service 85 // functions
90 // modules. 86 //
91 // Currently we have no way of distinguishing if a Create was called by the running application, 87 // Currently we have no way of distinguishing if a Create was called by the running application,
92 // or by a service module. Approach this once we have separated the service modules into their 88 // or by a service module. Approach this once we have separated the service modules into their
93 // own processes 89 // own processes
94 90
95 /// Current memory that the processes in this category are using 91 using ResourceArray =
96 s32 current_commit = 0; 92 std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>;
97 93
98 ///< Current number of objects among all processes in this category 94 /// Maximum values a resource type may reach.
99 s32 current_threads = 0; 95 ResourceArray limits{};
100 s32 current_events = 0; 96 /// Current resource limit values.
101 s32 current_mutexes = 0; 97 ResourceArray values{};
102 s32 current_semaphores = 0;
103 s32 current_timers = 0;
104 s32 current_shared_mems = 0;
105 s32 current_address_arbiters = 0;
106 98
107 /// Current CPU time that the processes in this category are utilizing 99 /// Name of resource limit object.
108 s32 current_cpu_time = 0; 100 std::string name;
109
110private:
111 explicit ResourceLimit(KernelCore& kernel);
112 ~ResourceLimit() override;
113}; 101};
114 102
115} // namespace Kernel 103} // namespace Kernel
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index a016a86b6..0494581f5 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -61,7 +61,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Proce
61} 61}
62 62
63SharedPtr<SharedMemory> SharedMemory::CreateForApplet( 63SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
64 KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size, 64 KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, std::size_t offset, u64 size,
65 MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { 65 MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
66 SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); 66 SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
67 67
@@ -78,10 +78,10 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
78 return shared_memory; 78 return shared_memory;
79} 79}
80 80
81ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions, 81ResultCode SharedMemory::Map(Process& target_process, VAddr address, MemoryPermission permissions,
82 MemoryPermission other_permissions) { 82 MemoryPermission other_permissions) {
83 const MemoryPermission own_other_permissions = 83 const MemoryPermission own_other_permissions =
84 target_process == owner_process ? this->permissions : this->other_permissions; 84 &target_process == owner_process ? this->permissions : this->other_permissions;
85 85
86 // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare 86 // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare
87 if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { 87 if (base_address == 0 && other_permissions != MemoryPermission::DontCare) {
@@ -106,7 +106,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
106 VAddr target_address = address; 106 VAddr target_address = address;
107 107
108 // Map the memory block into the target process 108 // Map the memory block into the target process
109 auto result = target_process->VMManager().MapMemoryBlock( 109 auto result = target_process.VMManager().MapMemoryBlock(
110 target_address, backing_block, backing_block_offset, size, MemoryState::Shared); 110 target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
111 if (result.Failed()) { 111 if (result.Failed()) {
112 LOG_ERROR( 112 LOG_ERROR(
@@ -116,14 +116,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
116 return result.Code(); 116 return result.Code();
117 } 117 }
118 118
119 return target_process->VMManager().ReprotectRange(target_address, size, 119 return target_process.VMManager().ReprotectRange(target_address, size,
120 ConvertPermissions(permissions)); 120 ConvertPermissions(permissions));
121} 121}
122 122
123ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { 123ResultCode SharedMemory::Unmap(Process& target_process, VAddr address) {
124 // TODO(Subv): Verify what happens if the application tries to unmap an address that is not 124 // TODO(Subv): Verify what happens if the application tries to unmap an address that is not
125 // mapped to a SharedMemory. 125 // mapped to a SharedMemory.
126 return target_process->VMManager().UnmapRange(address, size); 126 return target_process.VMManager().UnmapRange(address, size);
127} 127}
128 128
129VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { 129VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
@@ -132,7 +132,11 @@ VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
132 return static_cast<VMAPermission>(masked_permissions); 132 return static_cast<VMAPermission>(masked_permissions);
133} 133}
134 134
135u8* SharedMemory::GetPointer(u32 offset) { 135u8* SharedMemory::GetPointer(std::size_t offset) {
136 return backing_block->data() + backing_block_offset + offset;
137}
138
139const u8* SharedMemory::GetPointer(std::size_t offset) const {
136 return backing_block->data() + backing_block_offset + offset; 140 return backing_block->data() + backing_block_offset + offset;
137} 141}
138 142
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 2c06bb7ce..0b48db699 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -64,7 +64,7 @@ public:
64 */ 64 */
65 static SharedPtr<SharedMemory> CreateForApplet(KernelCore& kernel, 65 static SharedPtr<SharedMemory> CreateForApplet(KernelCore& kernel,
66 std::shared_ptr<std::vector<u8>> heap_block, 66 std::shared_ptr<std::vector<u8>> heap_block,
67 u32 offset, u32 size, 67 std::size_t offset, u64 size,
68 MemoryPermission permissions, 68 MemoryPermission permissions,
69 MemoryPermission other_permissions, 69 MemoryPermission other_permissions,
70 std::string name = "Unknown Applet"); 70 std::string name = "Unknown Applet");
@@ -81,6 +81,11 @@ public:
81 return HANDLE_TYPE; 81 return HANDLE_TYPE;
82 } 82 }
83 83
84 /// Gets the size of the underlying memory block in bytes.
85 u64 GetSize() const {
86 return size;
87 }
88
84 /** 89 /**
85 * Converts the specified MemoryPermission into the equivalent VMAPermission. 90 * Converts the specified MemoryPermission into the equivalent VMAPermission.
86 * @param permission The MemoryPermission to convert. 91 * @param permission The MemoryPermission to convert.
@@ -94,44 +99,51 @@ public:
94 * @param permissions Memory block map permissions (specified by SVC field) 99 * @param permissions Memory block map permissions (specified by SVC field)
95 * @param other_permissions Memory block map other permissions (specified by SVC field) 100 * @param other_permissions Memory block map other permissions (specified by SVC field)
96 */ 101 */
97 ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, 102 ResultCode Map(Process& target_process, VAddr address, MemoryPermission permissions,
98 MemoryPermission other_permissions); 103 MemoryPermission other_permissions);
99 104
100 /** 105 /**
101 * Unmaps a shared memory block from the specified address in system memory 106 * Unmaps a shared memory block from the specified address in system memory
102 * @param target_process Process from which to umap the memory block. 107 * @param target_process Process from which to unmap the memory block.
103 * @param address Address in system memory where the shared memory block is mapped 108 * @param address Address in system memory where the shared memory block is mapped
104 * @return Result code of the unmap operation 109 * @return Result code of the unmap operation
105 */ 110 */
106 ResultCode Unmap(Process* target_process, VAddr address); 111 ResultCode Unmap(Process& target_process, VAddr address);
107 112
108 /** 113 /**
109 * Gets a pointer to the shared memory block 114 * Gets a pointer to the shared memory block
110 * @param offset Offset from the start of the shared memory block to get pointer 115 * @param offset Offset from the start of the shared memory block to get pointer
111 * @return Pointer to the shared memory block from the specified offset 116 * @return A pointer to the shared memory block from the specified offset
112 */ 117 */
113 u8* GetPointer(u32 offset = 0); 118 u8* GetPointer(std::size_t offset = 0);
119
120 /**
121 * Gets a constant pointer to the shared memory block
122 * @param offset Offset from the start of the shared memory block to get pointer
123 * @return A constant pointer to the shared memory block from the specified offset
124 */
125 const u8* GetPointer(std::size_t offset = 0) const;
126
127private:
128 explicit SharedMemory(KernelCore& kernel);
129 ~SharedMemory() override;
114 130
115 /// Process that created this shared memory block.
116 SharedPtr<Process> owner_process;
117 /// Address of shared memory block in the owner process if specified.
118 VAddr base_address;
119 /// Backing memory for this shared memory block. 131 /// Backing memory for this shared memory block.
120 std::shared_ptr<std::vector<u8>> backing_block; 132 std::shared_ptr<std::vector<u8>> backing_block;
121 /// Offset into the backing block for this shared memory. 133 /// Offset into the backing block for this shared memory.
122 std::size_t backing_block_offset; 134 std::size_t backing_block_offset = 0;
123 /// Size of the memory block. Page-aligned. 135 /// Size of the memory block. Page-aligned.
124 u64 size; 136 u64 size = 0;
125 /// Permission restrictions applied to the process which created the block. 137 /// Permission restrictions applied to the process which created the block.
126 MemoryPermission permissions; 138 MemoryPermission permissions{};
127 /// Permission restrictions applied to other processes mapping the block. 139 /// Permission restrictions applied to other processes mapping the block.
128 MemoryPermission other_permissions; 140 MemoryPermission other_permissions{};
141 /// Process that created this shared memory block.
142 SharedPtr<Process> owner_process;
143 /// Address of shared memory block in the owner process if specified.
144 VAddr base_address = 0;
129 /// Name of shared memory object. 145 /// Name of shared memory object.
130 std::string name; 146 std::string name;
131
132private:
133 explicit SharedMemory(KernelCore& kernel);
134 ~SharedMemory() override;
135}; 147};
136 148
137} // namespace Kernel 149} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 7e8e87c33..e6c77f9db 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -20,17 +20,18 @@
20#include "core/hle/kernel/address_arbiter.h" 20#include "core/hle/kernel/address_arbiter.h"
21#include "core/hle/kernel/client_port.h" 21#include "core/hle/kernel/client_port.h"
22#include "core/hle/kernel/client_session.h" 22#include "core/hle/kernel/client_session.h"
23#include "core/hle/kernel/event.h"
24#include "core/hle/kernel/handle_table.h" 23#include "core/hle/kernel/handle_table.h"
25#include "core/hle/kernel/kernel.h" 24#include "core/hle/kernel/kernel.h"
26#include "core/hle/kernel/mutex.h" 25#include "core/hle/kernel/mutex.h"
27#include "core/hle/kernel/process.h" 26#include "core/hle/kernel/process.h"
27#include "core/hle/kernel/readable_event.h"
28#include "core/hle/kernel/resource_limit.h" 28#include "core/hle/kernel/resource_limit.h"
29#include "core/hle/kernel/scheduler.h" 29#include "core/hle/kernel/scheduler.h"
30#include "core/hle/kernel/shared_memory.h" 30#include "core/hle/kernel/shared_memory.h"
31#include "core/hle/kernel/svc.h" 31#include "core/hle/kernel/svc.h"
32#include "core/hle/kernel/svc_wrap.h" 32#include "core/hle/kernel/svc_wrap.h"
33#include "core/hle/kernel/thread.h" 33#include "core/hle/kernel/thread.h"
34#include "core/hle/kernel/writable_event.h"
34#include "core/hle/lock.h" 35#include "core/hle/lock.h"
35#include "core/hle/result.h" 36#include "core/hle/result.h"
36#include "core/hle/service/service.h" 37#include "core/hle/service/service.h"
@@ -62,56 +63,129 @@ bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) {
62 vm.GetNewMapRegionEndAddress()); 63 vm.GetNewMapRegionEndAddress());
63} 64}
64 65
66// 8 GiB
67constexpr u64 MAIN_MEMORY_SIZE = 0x200000000;
68
65// Helper function that performs the common sanity checks for svcMapMemory 69// Helper function that performs the common sanity checks for svcMapMemory
66// and svcUnmapMemory. This is doable, as both functions perform their sanitizing 70// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
67// in the same order. 71// in the same order.
68ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, 72ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr,
69 u64 size) { 73 u64 size) {
70 if (!Common::Is4KBAligned(dst_addr) || !Common::Is4KBAligned(src_addr)) { 74 if (!Common::Is4KBAligned(dst_addr)) {
75 LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr);
71 return ERR_INVALID_ADDRESS; 76 return ERR_INVALID_ADDRESS;
72 } 77 }
73 78
74 if (size == 0 || !Common::Is4KBAligned(size)) { 79 if (!Common::Is4KBAligned(src_addr)) {
80 LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr);
81 return ERR_INVALID_SIZE;
82 }
83
84 if (size == 0) {
85 LOG_ERROR(Kernel_SVC, "Size is 0");
86 return ERR_INVALID_SIZE;
87 }
88
89 if (!Common::Is4KBAligned(size)) {
90 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
75 return ERR_INVALID_SIZE; 91 return ERR_INVALID_SIZE;
76 } 92 }
77 93
78 if (!IsValidAddressRange(dst_addr, size)) { 94 if (!IsValidAddressRange(dst_addr, size)) {
95 LOG_ERROR(Kernel_SVC,
96 "Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
97 dst_addr, size);
79 return ERR_INVALID_ADDRESS_STATE; 98 return ERR_INVALID_ADDRESS_STATE;
80 } 99 }
81 100
82 if (!IsValidAddressRange(src_addr, size)) { 101 if (!IsValidAddressRange(src_addr, size)) {
102 LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
103 src_addr, size);
83 return ERR_INVALID_ADDRESS_STATE; 104 return ERR_INVALID_ADDRESS_STATE;
84 } 105 }
85 106
86 if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { 107 if (!IsInsideAddressSpace(vm_manager, src_addr, size)) {
108 LOG_ERROR(Kernel_SVC,
109 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
110 src_addr, size);
87 return ERR_INVALID_ADDRESS_STATE; 111 return ERR_INVALID_ADDRESS_STATE;
88 } 112 }
89 113
90 if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { 114 if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) {
115 LOG_ERROR(Kernel_SVC,
116 "Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}",
117 dst_addr, size);
91 return ERR_INVALID_MEMORY_RANGE; 118 return ERR_INVALID_MEMORY_RANGE;
92 } 119 }
93 120
94 const VAddr dst_end_address = dst_addr + size; 121 const VAddr dst_end_address = dst_addr + size;
95 if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() && 122 if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() &&
96 vm_manager.GetHeapRegionEndAddress() > dst_addr) { 123 vm_manager.GetHeapRegionEndAddress() > dst_addr) {
124 LOG_ERROR(Kernel_SVC,
125 "Destination does not fit within the heap region, addr=0x{:016X}, "
126 "size=0x{:016X}, end_addr=0x{:016X}",
127 dst_addr, size, dst_end_address);
97 return ERR_INVALID_MEMORY_RANGE; 128 return ERR_INVALID_MEMORY_RANGE;
98 } 129 }
99 130
100 if (dst_end_address > vm_manager.GetMapRegionBaseAddress() && 131 if (dst_end_address > vm_manager.GetMapRegionBaseAddress() &&
101 vm_manager.GetMapRegionEndAddress() > dst_addr) { 132 vm_manager.GetMapRegionEndAddress() > dst_addr) {
133 LOG_ERROR(Kernel_SVC,
134 "Destination does not fit within the map region, addr=0x{:016X}, "
135 "size=0x{:016X}, end_addr=0x{:016X}",
136 dst_addr, size, dst_end_address);
102 return ERR_INVALID_MEMORY_RANGE; 137 return ERR_INVALID_MEMORY_RANGE;
103 } 138 }
104 139
105 return RESULT_SUCCESS; 140 return RESULT_SUCCESS;
106} 141}
142
143enum class ResourceLimitValueType {
144 CurrentValue,
145 LimitValue,
146};
147
148ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type,
149 ResourceLimitValueType value_type) {
150 const auto type = static_cast<ResourceType>(resource_type);
151 if (!IsValidResourceType(type)) {
152 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
153 return ERR_INVALID_ENUM_VALUE;
154 }
155
156 const auto& kernel = Core::System::GetInstance().Kernel();
157 const auto* const current_process = kernel.CurrentProcess();
158 ASSERT(current_process != nullptr);
159
160 const auto resource_limit_object =
161 current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
162 if (!resource_limit_object) {
163 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
164 resource_limit);
165 return ERR_INVALID_HANDLE;
166 }
167
168 if (value_type == ResourceLimitValueType::CurrentValue) {
169 return MakeResult(resource_limit_object->GetCurrentResourceValue(type));
170 }
171
172 return MakeResult(resource_limit_object->GetMaxResourceValue(type));
173}
107} // Anonymous namespace 174} // Anonymous namespace
108 175
109/// Set the process heap to a given Size. It can both extend and shrink the heap. 176/// Set the process heap to a given Size. It can both extend and shrink the heap.
110static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { 177static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
111 LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); 178 LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
112 179
113 // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB. 180 // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB.
114 if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) { 181 if ((heap_size % 0x200000) != 0) {
182 LOG_ERROR(Kernel_SVC, "The heap size is not a multiple of 2MB, heap_size=0x{:016X}",
183 heap_size);
184 return ERR_INVALID_SIZE;
185 }
186
187 if (heap_size >= 0x200000000) {
188 LOG_ERROR(Kernel_SVC, "The heap size is not less than 8GB, heap_size=0x{:016X}", heap_size);
115 return ERR_INVALID_SIZE; 189 return ERR_INVALID_SIZE;
116 } 190 }
117 191
@@ -122,6 +196,63 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
122 return RESULT_SUCCESS; 196 return RESULT_SUCCESS;
123} 197}
124 198
199static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
200 LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot);
201
202 if (!Common::Is4KBAligned(addr)) {
203 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
204 return ERR_INVALID_ADDRESS;
205 }
206
207 if (size == 0) {
208 LOG_ERROR(Kernel_SVC, "Size is 0");
209 return ERR_INVALID_SIZE;
210 }
211
212 if (!Common::Is4KBAligned(size)) {
213 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
214 return ERR_INVALID_SIZE;
215 }
216
217 if (!IsValidAddressRange(addr, size)) {
218 LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
219 addr, size);
220 return ERR_INVALID_ADDRESS_STATE;
221 }
222
223 const auto permission = static_cast<MemoryPermission>(prot);
224 if (permission != MemoryPermission::None && permission != MemoryPermission::Read &&
225 permission != MemoryPermission::ReadWrite) {
226 LOG_ERROR(Kernel_SVC, "Invalid memory permission specified, Got memory permission=0x{:08X}",
227 static_cast<u32>(permission));
228 return ERR_INVALID_MEMORY_PERMISSIONS;
229 }
230
231 auto* const current_process = Core::CurrentProcess();
232 auto& vm_manager = current_process->VMManager();
233
234 if (!IsInsideAddressSpace(vm_manager, addr, size)) {
235 LOG_ERROR(Kernel_SVC,
236 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
237 size);
238 return ERR_INVALID_ADDRESS_STATE;
239 }
240
241 const VMManager::VMAHandle iter = vm_manager.FindVMA(addr);
242 if (iter == vm_manager.vma_map.end()) {
243 LOG_ERROR(Kernel_SVC, "Unable to find VMA for address=0x{:016X}", addr);
244 return ERR_INVALID_ADDRESS_STATE;
245 }
246
247 LOG_WARNING(Kernel_SVC, "Uniformity check on protected memory is not implemented.");
248 // TODO: Performs a uniformity check to make sure only protected memory is changed (it doesn't
249 // make sense to allow changing permissions on kernel memory itself, etc).
250
251 const auto converted_permissions = SharedMemory::ConvertPermissions(permission);
252
253 return vm_manager.ReprotectRange(addr, size, converted_permissions);
254}
255
125static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) { 256static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) {
126 LOG_WARNING(Kernel_SVC, 257 LOG_WARNING(Kernel_SVC,
127 "(STUBBED) called, addr=0x{:X}, size=0x{:X}, state0=0x{:X}, state1=0x{:X}", addr, 258 "(STUBBED) called, addr=0x{:X}, size=0x{:X}, state0=0x{:X}, state1=0x{:X}", addr,
@@ -164,6 +295,9 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
164/// Connect to an OS service given the port name, returns the handle to the port to out 295/// Connect to an OS service given the port name, returns the handle to the port to out
165static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) { 296static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) {
166 if (!Memory::IsValidVirtualAddress(port_name_address)) { 297 if (!Memory::IsValidVirtualAddress(port_name_address)) {
298 LOG_ERROR(Kernel_SVC,
299 "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
300 port_name_address);
167 return ERR_NOT_FOUND; 301 return ERR_NOT_FOUND;
168 } 302 }
169 303
@@ -171,7 +305,9 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
171 // Read 1 char beyond the max allowed port name to detect names that are too long. 305 // Read 1 char beyond the max allowed port name to detect names that are too long.
172 std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); 306 std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
173 if (port_name.size() > PortNameMaxLength) { 307 if (port_name.size() > PortNameMaxLength) {
174 return ERR_PORT_NAME_TOO_LONG; 308 LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
309 port_name.size());
310 return ERR_OUT_OF_RANGE;
175 } 311 }
176 312
177 LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); 313 LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
@@ -219,6 +355,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
219 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 355 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
220 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 356 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
221 if (!thread) { 357 if (!thread) {
358 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle);
222 return ERR_INVALID_HANDLE; 359 return ERR_INVALID_HANDLE;
223 } 360 }
224 361
@@ -233,6 +370,8 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
233 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 370 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
234 const SharedPtr<Process> process = handle_table.Get<Process>(process_handle); 371 const SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
235 if (!process) { 372 if (!process) {
373 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
374 process_handle);
236 return ERR_INVALID_HANDLE; 375 return ERR_INVALID_HANDLE;
237 } 376 }
238 377
@@ -262,13 +401,20 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
262 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", 401 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
263 handles_address, handle_count, nano_seconds); 402 handles_address, handle_count, nano_seconds);
264 403
265 if (!Memory::IsValidVirtualAddress(handles_address)) 404 if (!Memory::IsValidVirtualAddress(handles_address)) {
405 LOG_ERROR(Kernel_SVC,
406 "Handle address is not a valid virtual address, handle_address=0x{:016X}",
407 handles_address);
266 return ERR_INVALID_POINTER; 408 return ERR_INVALID_POINTER;
409 }
267 410
268 static constexpr u64 MaxHandles = 0x40; 411 static constexpr u64 MaxHandles = 0x40;
269 412
270 if (handle_count > MaxHandles) 413 if (handle_count > MaxHandles) {
271 return ResultCode(ErrorModule::Kernel, ErrCodes::TooLarge); 414 LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}",
415 MaxHandles, handle_count);
416 return ERR_OUT_OF_RANGE;
417 }
272 418
273 auto* const thread = GetCurrentThread(); 419 auto* const thread = GetCurrentThread();
274 420
@@ -281,6 +427,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
281 const auto object = handle_table.Get<WaitObject>(handle); 427 const auto object = handle_table.Get<WaitObject>(handle);
282 428
283 if (object == nullptr) { 429 if (object == nullptr) {
430 LOG_ERROR(Kernel_SVC, "Object is a nullptr");
284 return ERR_INVALID_HANDLE; 431 return ERR_INVALID_HANDLE;
285 } 432 }
286 433
@@ -304,11 +451,13 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
304 451
305 // If a timeout value of 0 was provided, just return the Timeout error code instead of 452 // If a timeout value of 0 was provided, just return the Timeout error code instead of
306 // suspending the thread. 453 // suspending the thread.
307 if (nano_seconds == 0) 454 if (nano_seconds == 0) {
308 return RESULT_TIMEOUT; 455 return RESULT_TIMEOUT;
456 }
309 457
310 for (auto& object : objects) 458 for (auto& object : objects) {
311 object->AddWaitingThread(thread); 459 object->AddWaitingThread(thread);
460 }
312 461
313 thread->SetWaitObjects(std::move(objects)); 462 thread->SetWaitObjects(std::move(objects));
314 thread->SetStatus(ThreadStatus::WaitSynchAny); 463 thread->SetStatus(ThreadStatus::WaitSynchAny);
@@ -329,12 +478,13 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
329 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 478 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
330 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 479 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
331 if (!thread) { 480 if (!thread) {
481 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
482 thread_handle);
332 return ERR_INVALID_HANDLE; 483 return ERR_INVALID_HANDLE;
333 } 484 }
334 485
335 ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); 486 ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny);
336 thread->SetWaitSynchronizationResult( 487 thread->SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED);
337 ResultCode(ErrorModule::Kernel, ErrCodes::SynchronizationCanceled));
338 thread->ResumeFromWait(); 488 thread->ResumeFromWait();
339 return RESULT_SUCCESS; 489 return RESULT_SUCCESS;
340} 490}
@@ -348,10 +498,13 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
348 holding_thread_handle, mutex_addr, requesting_thread_handle); 498 holding_thread_handle, mutex_addr, requesting_thread_handle);
349 499
350 if (Memory::IsKernelVirtualAddress(mutex_addr)) { 500 if (Memory::IsKernelVirtualAddress(mutex_addr)) {
501 LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}",
502 mutex_addr);
351 return ERR_INVALID_ADDRESS_STATE; 503 return ERR_INVALID_ADDRESS_STATE;
352 } 504 }
353 505
354 if (!Common::IsWordAligned(mutex_addr)) { 506 if (!Common::IsWordAligned(mutex_addr)) {
507 LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr);
355 return ERR_INVALID_ADDRESS; 508 return ERR_INVALID_ADDRESS;
356 } 509 }
357 510
@@ -365,10 +518,13 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
365 LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); 518 LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
366 519
367 if (Memory::IsKernelVirtualAddress(mutex_addr)) { 520 if (Memory::IsKernelVirtualAddress(mutex_addr)) {
521 LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}",
522 mutex_addr);
368 return ERR_INVALID_ADDRESS_STATE; 523 return ERR_INVALID_ADDRESS_STATE;
369 } 524 }
370 525
371 if (!Common::IsWordAligned(mutex_addr)) { 526 if (!Common::IsWordAligned(mutex_addr)) {
527 LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr);
372 return ERR_INVALID_ADDRESS; 528 return ERR_INVALID_ADDRESS;
373 } 529 }
374 530
@@ -506,7 +662,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
506 TotalMemoryUsage = 6, 662 TotalMemoryUsage = 6,
507 TotalHeapUsage = 7, 663 TotalHeapUsage = 7,
508 IsCurrentProcessBeingDebugged = 8, 664 IsCurrentProcessBeingDebugged = 8,
509 ResourceHandleLimit = 9, 665 RegisterResourceLimit = 9,
510 IdleTickCount = 10, 666 IdleTickCount = 10,
511 RandomEntropy = 11, 667 RandomEntropy = 11,
512 PerformanceCounter = 0xF0000002, 668 PerformanceCounter = 0xF0000002,
@@ -526,77 +682,172 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
526 ThreadTickCount = 0xF0000002, 682 ThreadTickCount = 0xF0000002,
527 }; 683 };
528 684
529 const auto* current_process = Core::CurrentProcess(); 685 const auto info_id_type = static_cast<GetInfoType>(info_id);
530 const auto& vm_manager = current_process->VMManager();
531 686
532 switch (static_cast<GetInfoType>(info_id)) { 687 switch (info_id_type) {
533 case GetInfoType::AllowedCpuIdBitmask: 688 case GetInfoType::AllowedCpuIdBitmask:
534 *result = current_process->GetAllowedProcessorMask();
535 break;
536 case GetInfoType::AllowedThreadPrioBitmask: 689 case GetInfoType::AllowedThreadPrioBitmask:
537 *result = current_process->GetAllowedThreadPriorityMask();
538 break;
539 case GetInfoType::MapRegionBaseAddr: 690 case GetInfoType::MapRegionBaseAddr:
540 *result = vm_manager.GetMapRegionBaseAddress();
541 break;
542 case GetInfoType::MapRegionSize: 691 case GetInfoType::MapRegionSize:
543 *result = vm_manager.GetMapRegionSize();
544 break;
545 case GetInfoType::HeapRegionBaseAddr: 692 case GetInfoType::HeapRegionBaseAddr:
546 *result = vm_manager.GetHeapRegionBaseAddress();
547 break;
548 case GetInfoType::HeapRegionSize: 693 case GetInfoType::HeapRegionSize:
549 *result = vm_manager.GetHeapRegionSize();
550 break;
551 case GetInfoType::TotalMemoryUsage:
552 *result = vm_manager.GetTotalMemoryUsage();
553 break;
554 case GetInfoType::TotalHeapUsage:
555 *result = vm_manager.GetTotalHeapUsage();
556 break;
557 case GetInfoType::IsCurrentProcessBeingDebugged:
558 *result = 0;
559 break;
560 case GetInfoType::RandomEntropy:
561 *result = 0;
562 break;
563 case GetInfoType::ASLRRegionBaseAddr: 694 case GetInfoType::ASLRRegionBaseAddr:
564 *result = vm_manager.GetASLRRegionBaseAddress();
565 break;
566 case GetInfoType::ASLRRegionSize: 695 case GetInfoType::ASLRRegionSize:
567 *result = vm_manager.GetASLRRegionSize();
568 break;
569 case GetInfoType::NewMapRegionBaseAddr: 696 case GetInfoType::NewMapRegionBaseAddr:
570 *result = vm_manager.GetNewMapRegionBaseAddress();
571 break;
572 case GetInfoType::NewMapRegionSize: 697 case GetInfoType::NewMapRegionSize:
573 *result = vm_manager.GetNewMapRegionSize(); 698 case GetInfoType::TotalMemoryUsage:
574 break; 699 case GetInfoType::TotalHeapUsage:
575 case GetInfoType::IsVirtualAddressMemoryEnabled: 700 case GetInfoType::IsVirtualAddressMemoryEnabled:
576 *result = current_process->IsVirtualMemoryEnabled(); 701 case GetInfoType::PersonalMmHeapUsage:
577 break;
578 case GetInfoType::TitleId: 702 case GetInfoType::TitleId:
579 *result = current_process->GetTitleID(); 703 case GetInfoType::UserExceptionContextAddr: {
580 break; 704 if (info_sub_id != 0) {
705 return ERR_INVALID_ENUM_VALUE;
706 }
707
708 const auto& current_process_handle_table = Core::CurrentProcess()->GetHandleTable();
709 const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle));
710 if (!process) {
711 return ERR_INVALID_HANDLE;
712 }
713
714 switch (info_id_type) {
715 case GetInfoType::AllowedCpuIdBitmask:
716 *result = process->GetAllowedProcessorMask();
717 return RESULT_SUCCESS;
718
719 case GetInfoType::AllowedThreadPrioBitmask:
720 *result = process->GetAllowedThreadPriorityMask();
721 return RESULT_SUCCESS;
722
723 case GetInfoType::MapRegionBaseAddr:
724 *result = process->VMManager().GetMapRegionBaseAddress();
725 return RESULT_SUCCESS;
726
727 case GetInfoType::MapRegionSize:
728 *result = process->VMManager().GetMapRegionSize();
729 return RESULT_SUCCESS;
730
731 case GetInfoType::HeapRegionBaseAddr:
732 *result = process->VMManager().GetHeapRegionBaseAddress();
733 return RESULT_SUCCESS;
734
735 case GetInfoType::HeapRegionSize:
736 *result = process->VMManager().GetHeapRegionSize();
737 return RESULT_SUCCESS;
738
739 case GetInfoType::ASLRRegionBaseAddr:
740 *result = process->VMManager().GetASLRRegionBaseAddress();
741 return RESULT_SUCCESS;
742
743 case GetInfoType::ASLRRegionSize:
744 *result = process->VMManager().GetASLRRegionSize();
745 return RESULT_SUCCESS;
746
747 case GetInfoType::NewMapRegionBaseAddr:
748 *result = process->VMManager().GetNewMapRegionBaseAddress();
749 return RESULT_SUCCESS;
750
751 case GetInfoType::NewMapRegionSize:
752 *result = process->VMManager().GetNewMapRegionSize();
753 return RESULT_SUCCESS;
754
755 case GetInfoType::TotalMemoryUsage:
756 *result = process->VMManager().GetTotalMemoryUsage();
757 return RESULT_SUCCESS;
758
759 case GetInfoType::TotalHeapUsage:
760 *result = process->VMManager().GetTotalHeapUsage();
761 return RESULT_SUCCESS;
762
763 case GetInfoType::IsVirtualAddressMemoryEnabled:
764 *result = process->IsVirtualMemoryEnabled();
765 return RESULT_SUCCESS;
766
767 case GetInfoType::TitleId:
768 *result = process->GetTitleID();
769 return RESULT_SUCCESS;
770
771 case GetInfoType::UserExceptionContextAddr:
772 LOG_WARNING(Kernel_SVC,
773 "(STUBBED) Attempted to query user exception context address, returned 0");
774 *result = 0;
775 return RESULT_SUCCESS;
776
777 default:
778 break;
779 }
780
781 LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
782 return ERR_INVALID_ENUM_VALUE;
783 }
784
785 case GetInfoType::IsCurrentProcessBeingDebugged:
786 *result = 0;
787 return RESULT_SUCCESS;
788
789 case GetInfoType::RegisterResourceLimit: {
790 if (handle != 0) {
791 return ERR_INVALID_HANDLE;
792 }
793
794 if (info_sub_id != 0) {
795 return ERR_INVALID_COMBINATION;
796 }
797
798 Process* const current_process = Core::CurrentProcess();
799 HandleTable& handle_table = current_process->GetHandleTable();
800 const auto resource_limit = current_process->GetResourceLimit();
801 if (!resource_limit) {
802 *result = KernelHandle::InvalidHandle;
803 // Yes, the kernel considers this a successful operation.
804 return RESULT_SUCCESS;
805 }
806
807 const auto table_result = handle_table.Create(resource_limit);
808 if (table_result.Failed()) {
809 return table_result.Code();
810 }
811
812 *result = *table_result;
813 return RESULT_SUCCESS;
814 }
815
816 case GetInfoType::RandomEntropy:
817 if (handle != 0) {
818 LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
819 handle);
820 return ERR_INVALID_HANDLE;
821 }
822
823 if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) {
824 LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
825 Process::RANDOM_ENTROPY_SIZE, info_sub_id);
826 return ERR_INVALID_COMBINATION;
827 }
828
829 *result = Core::CurrentProcess()->GetRandomEntropy(info_sub_id);
830 return RESULT_SUCCESS;
831
581 case GetInfoType::PrivilegedProcessId: 832 case GetInfoType::PrivilegedProcessId:
582 LOG_WARNING(Kernel_SVC, 833 LOG_WARNING(Kernel_SVC,
583 "(STUBBED) Attempted to query privileged process id bounds, returned 0"); 834 "(STUBBED) Attempted to query privileged process id bounds, returned 0");
584 *result = 0; 835 *result = 0;
585 break; 836 return RESULT_SUCCESS;
586 case GetInfoType::UserExceptionContextAddr: 837
587 LOG_WARNING(Kernel_SVC,
588 "(STUBBED) Attempted to query user exception context address, returned 0");
589 *result = 0;
590 break;
591 case GetInfoType::ThreadTickCount: { 838 case GetInfoType::ThreadTickCount: {
592 constexpr u64 num_cpus = 4; 839 constexpr u64 num_cpus = 4;
593 if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { 840 if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
594 return ERR_INVALID_COMBINATION_KERNEL; 841 LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
842 info_sub_id);
843 return ERR_INVALID_COMBINATION;
595 } 844 }
596 845
597 const auto thread = 846 const auto thread =
598 current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle)); 847 Core::CurrentProcess()->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
599 if (!thread) { 848 if (!thread) {
849 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
850 static_cast<Handle>(handle));
600 return ERR_INVALID_HANDLE; 851 return ERR_INVALID_HANDLE;
601 } 852 }
602 853
@@ -616,13 +867,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
616 } 867 }
617 868
618 *result = out_ticks; 869 *result = out_ticks;
619 break; 870 return RESULT_SUCCESS;
620 } 871 }
872
621 default: 873 default:
622 UNIMPLEMENTED(); 874 LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
875 return ERR_INVALID_ENUM_VALUE;
623 } 876 }
624
625 return RESULT_SUCCESS;
626} 877}
627 878
628/// Sets the thread activity 879/// Sets the thread activity
@@ -638,14 +889,22 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
638 const auto* current_process = Core::CurrentProcess(); 889 const auto* current_process = Core::CurrentProcess();
639 const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); 890 const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
640 if (!thread) { 891 if (!thread) {
892 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
641 return ERR_INVALID_HANDLE; 893 return ERR_INVALID_HANDLE;
642 } 894 }
643 895
644 if (thread->GetOwnerProcess() != current_process) { 896 if (thread->GetOwnerProcess() != current_process) {
897 LOG_ERROR(Kernel_SVC,
898 "The current process does not own the current thread, thread_handle={:08X} "
899 "thread_pid={}, "
900 "current_process_pid={}",
901 handle, thread->GetOwnerProcess()->GetProcessID(),
902 current_process->GetProcessID());
645 return ERR_INVALID_HANDLE; 903 return ERR_INVALID_HANDLE;
646 } 904 }
647 905
648 if (thread == GetCurrentThread()) { 906 if (thread == GetCurrentThread()) {
907 LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
649 return ERR_ALREADY_REGISTERED; 908 return ERR_ALREADY_REGISTERED;
650 } 909 }
651 910
@@ -666,9 +925,12 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
666 925
667/// Gets the priority for the specified thread 926/// Gets the priority for the specified thread
668static ResultCode GetThreadPriority(u32* priority, Handle handle) { 927static ResultCode GetThreadPriority(u32* priority, Handle handle) {
928 LOG_TRACE(Kernel_SVC, "called");
929
669 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 930 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
670 const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); 931 const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle);
671 if (!thread) { 932 if (!thread) {
933 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
672 return ERR_INVALID_HANDLE; 934 return ERR_INVALID_HANDLE;
673 } 935 }
674 936
@@ -678,21 +940,21 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) {
678 940
679/// Sets the priority for the specified thread 941/// Sets the priority for the specified thread
680static ResultCode SetThreadPriority(Handle handle, u32 priority) { 942static ResultCode SetThreadPriority(Handle handle, u32 priority) {
943 LOG_TRACE(Kernel_SVC, "called");
944
681 if (priority > THREADPRIO_LOWEST) { 945 if (priority > THREADPRIO_LOWEST) {
946 LOG_ERROR(
947 Kernel_SVC,
948 "An invalid priority was specified, expected {} but got {} for thread_handle={:08X}",
949 THREADPRIO_LOWEST, priority, handle);
682 return ERR_INVALID_THREAD_PRIORITY; 950 return ERR_INVALID_THREAD_PRIORITY;
683 } 951 }
684 952
685 const auto* const current_process = Core::CurrentProcess(); 953 const auto* const current_process = Core::CurrentProcess();
686 954
687 // Note: The kernel uses the current process's resource limit instead of
688 // the one from the thread owner's resource limit.
689 const ResourceLimit& resource_limit = current_process->GetResourceLimit();
690 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
691 return ERR_INVALID_THREAD_PRIORITY;
692 }
693
694 SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); 955 SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
695 if (!thread) { 956 if (!thread) {
957 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
696 return ERR_INVALID_HANDLE; 958 return ERR_INVALID_HANDLE;
697 } 959 }
698 960
@@ -715,36 +977,50 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
715 shared_memory_handle, addr, size, permissions); 977 shared_memory_handle, addr, size, permissions);
716 978
717 if (!Common::Is4KBAligned(addr)) { 979 if (!Common::Is4KBAligned(addr)) {
980 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
718 return ERR_INVALID_ADDRESS; 981 return ERR_INVALID_ADDRESS;
719 } 982 }
720 983
721 if (size == 0 || !Common::Is4KBAligned(size)) { 984 if (size == 0) {
985 LOG_ERROR(Kernel_SVC, "Size is 0");
986 return ERR_INVALID_SIZE;
987 }
988
989 if (!Common::Is4KBAligned(size)) {
990 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
722 return ERR_INVALID_SIZE; 991 return ERR_INVALID_SIZE;
723 } 992 }
724 993
725 if (!IsValidAddressRange(addr, size)) { 994 if (!IsValidAddressRange(addr, size)) {
995 LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
996 addr, size);
726 return ERR_INVALID_ADDRESS_STATE; 997 return ERR_INVALID_ADDRESS_STATE;
727 } 998 }
728 999
729 const auto permissions_type = static_cast<MemoryPermission>(permissions); 1000 const auto permissions_type = static_cast<MemoryPermission>(permissions);
730 if (permissions_type != MemoryPermission::Read && 1001 if (permissions_type != MemoryPermission::Read &&
731 permissions_type != MemoryPermission::ReadWrite) { 1002 permissions_type != MemoryPermission::ReadWrite) {
732 LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions); 1003 LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}",
1004 permissions);
733 return ERR_INVALID_MEMORY_PERMISSIONS; 1005 return ERR_INVALID_MEMORY_PERMISSIONS;
734 } 1006 }
735 1007
736 auto* const current_process = Core::CurrentProcess(); 1008 auto* const current_process = Core::CurrentProcess();
737 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); 1009 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
738 if (!shared_memory) { 1010 if (!shared_memory) {
1011 LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
1012 shared_memory_handle);
739 return ERR_INVALID_HANDLE; 1013 return ERR_INVALID_HANDLE;
740 } 1014 }
741 1015
742 const auto& vm_manager = current_process->VMManager(); 1016 const auto& vm_manager = current_process->VMManager();
743 if (!vm_manager.IsWithinASLRRegion(addr, size)) { 1017 if (!vm_manager.IsWithinASLRRegion(addr, size)) {
1018 LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}",
1019 addr, size);
744 return ERR_INVALID_MEMORY_RANGE; 1020 return ERR_INVALID_MEMORY_RANGE;
745 } 1021 }
746 1022
747 return shared_memory->Map(current_process, addr, permissions_type, MemoryPermission::DontCare); 1023 return shared_memory->Map(*current_process, addr, permissions_type, MemoryPermission::DontCare);
748} 1024}
749 1025
750static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { 1026static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
@@ -752,37 +1028,53 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
752 shared_memory_handle, addr, size); 1028 shared_memory_handle, addr, size);
753 1029
754 if (!Common::Is4KBAligned(addr)) { 1030 if (!Common::Is4KBAligned(addr)) {
1031 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
755 return ERR_INVALID_ADDRESS; 1032 return ERR_INVALID_ADDRESS;
756 } 1033 }
757 1034
758 if (size == 0 || !Common::Is4KBAligned(size)) { 1035 if (size == 0) {
1036 LOG_ERROR(Kernel_SVC, "Size is 0");
1037 return ERR_INVALID_SIZE;
1038 }
1039
1040 if (!Common::Is4KBAligned(size)) {
1041 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
759 return ERR_INVALID_SIZE; 1042 return ERR_INVALID_SIZE;
760 } 1043 }
761 1044
762 if (!IsValidAddressRange(addr, size)) { 1045 if (!IsValidAddressRange(addr, size)) {
1046 LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
1047 addr, size);
763 return ERR_INVALID_ADDRESS_STATE; 1048 return ERR_INVALID_ADDRESS_STATE;
764 } 1049 }
765 1050
766 auto* const current_process = Core::CurrentProcess(); 1051 auto* const current_process = Core::CurrentProcess();
767 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); 1052 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
768 if (!shared_memory) { 1053 if (!shared_memory) {
1054 LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
1055 shared_memory_handle);
769 return ERR_INVALID_HANDLE; 1056 return ERR_INVALID_HANDLE;
770 } 1057 }
771 1058
772 const auto& vm_manager = current_process->VMManager(); 1059 const auto& vm_manager = current_process->VMManager();
773 if (!vm_manager.IsWithinASLRRegion(addr, size)) { 1060 if (!vm_manager.IsWithinASLRRegion(addr, size)) {
1061 LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}",
1062 addr, size);
774 return ERR_INVALID_MEMORY_RANGE; 1063 return ERR_INVALID_MEMORY_RANGE;
775 } 1064 }
776 1065
777 return shared_memory->Unmap(current_process, addr); 1066 return shared_memory->Unmap(*current_process, addr);
778} 1067}
779 1068
780/// Query process memory 1069/// Query process memory
781static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, 1070static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/,
782 Handle process_handle, u64 addr) { 1071 Handle process_handle, u64 addr) {
1072 LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
783 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1073 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
784 SharedPtr<Process> process = handle_table.Get<Process>(process_handle); 1074 SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
785 if (!process) { 1075 if (!process) {
1076 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
1077 process_handle);
786 return ERR_INVALID_HANDLE; 1078 return ERR_INVALID_HANDLE;
787 } 1079 }
788 auto vma = process->VMManager().FindVMA(addr); 1080 auto vma = process->VMManager().FindVMA(addr);
@@ -798,8 +1090,6 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
798 memory_info->size = vma->second.size; 1090 memory_info->size = vma->second.size;
799 memory_info->type = static_cast<u32>(vma->second.meminfo_state); 1091 memory_info->type = static_cast<u32>(vma->second.meminfo_state);
800 } 1092 }
801
802 LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
803 return RESULT_SUCCESS; 1093 return RESULT_SUCCESS;
804} 1094}
805 1095
@@ -828,15 +1118,18 @@ static void ExitProcess() {
828/// Creates a new thread 1118/// Creates a new thread
829static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, 1119static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
830 u32 priority, s32 processor_id) { 1120 u32 priority, s32 processor_id) {
1121 LOG_TRACE(Kernel_SVC,
1122 "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, "
1123 "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
1124 entry_point, arg, stack_top, priority, processor_id, *out_handle);
1125
831 if (priority > THREADPRIO_LOWEST) { 1126 if (priority > THREADPRIO_LOWEST) {
1127 LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}",
1128 THREADPRIO_LOWEST, priority);
832 return ERR_INVALID_THREAD_PRIORITY; 1129 return ERR_INVALID_THREAD_PRIORITY;
833 } 1130 }
834 1131
835 auto* const current_process = Core::CurrentProcess(); 1132 auto* const current_process = Core::CurrentProcess();
836 const ResourceLimit& resource_limit = current_process->GetResourceLimit();
837 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
838 return ERR_INVALID_THREAD_PRIORITY;
839 }
840 1133
841 if (processor_id == THREADPROCESSORID_DEFAULT) { 1134 if (processor_id == THREADPROCESSORID_DEFAULT) {
842 // Set the target CPU to the one specified in the process' exheader. 1135 // Set the target CPU to the one specified in the process' exheader.
@@ -863,6 +1156,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
863 1156
864 const auto new_guest_handle = current_process->GetHandleTable().Create(thread); 1157 const auto new_guest_handle = current_process->GetHandleTable().Create(thread);
865 if (new_guest_handle.Failed()) { 1158 if (new_guest_handle.Failed()) {
1159 LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}",
1160 new_guest_handle.Code().raw);
866 return new_guest_handle.Code(); 1161 return new_guest_handle.Code();
867 } 1162 }
868 thread->SetGuestHandle(*new_guest_handle); 1163 thread->SetGuestHandle(*new_guest_handle);
@@ -870,11 +1165,6 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
870 1165
871 Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); 1166 Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
872 1167
873 LOG_TRACE(Kernel_SVC,
874 "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
875 "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
876 entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
877
878 return RESULT_SUCCESS; 1168 return RESULT_SUCCESS;
879} 1169}
880 1170
@@ -885,6 +1175,8 @@ static ResultCode StartThread(Handle thread_handle) {
885 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1175 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
886 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1176 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
887 if (!thread) { 1177 if (!thread) {
1178 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
1179 thread_handle);
888 return ERR_INVALID_HANDLE; 1180 return ERR_INVALID_HANDLE;
889 } 1181 }
890 1182
@@ -1064,10 +1356,12 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout
1064 address, type, value, timeout); 1356 address, type, value, timeout);
1065 // If the passed address is a kernel virtual address, return invalid memory state. 1357 // If the passed address is a kernel virtual address, return invalid memory state.
1066 if (Memory::IsKernelVirtualAddress(address)) { 1358 if (Memory::IsKernelVirtualAddress(address)) {
1359 LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
1067 return ERR_INVALID_ADDRESS_STATE; 1360 return ERR_INVALID_ADDRESS_STATE;
1068 } 1361 }
1069 // If the address is not properly aligned to 4 bytes, return invalid address. 1362 // If the address is not properly aligned to 4 bytes, return invalid address.
1070 if (address % sizeof(u32) != 0) { 1363 if (!Common::IsWordAligned(address)) {
1364 LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address);
1071 return ERR_INVALID_ADDRESS; 1365 return ERR_INVALID_ADDRESS;
1072 } 1366 }
1073 1367
@@ -1079,6 +1373,10 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout
1079 case AddressArbiter::ArbitrationType::WaitIfEqual: 1373 case AddressArbiter::ArbitrationType::WaitIfEqual:
1080 return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); 1374 return AddressArbiter::WaitForAddressIfEqual(address, value, timeout);
1081 default: 1375 default:
1376 LOG_ERROR(Kernel_SVC,
1377 "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan "
1378 "or WaitIfEqual but got {}",
1379 type);
1082 return ERR_INVALID_ENUM_VALUE; 1380 return ERR_INVALID_ENUM_VALUE;
1083 } 1381 }
1084} 1382}
@@ -1089,10 +1387,12 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
1089 address, type, value, num_to_wake); 1387 address, type, value, num_to_wake);
1090 // If the passed address is a kernel virtual address, return invalid memory state. 1388 // If the passed address is a kernel virtual address, return invalid memory state.
1091 if (Memory::IsKernelVirtualAddress(address)) { 1389 if (Memory::IsKernelVirtualAddress(address)) {
1390 LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
1092 return ERR_INVALID_ADDRESS_STATE; 1391 return ERR_INVALID_ADDRESS_STATE;
1093 } 1392 }
1094 // If the address is not properly aligned to 4 bytes, return invalid address. 1393 // If the address is not properly aligned to 4 bytes, return invalid address.
1095 if (address % sizeof(u32) != 0) { 1394 if (!Common::IsWordAligned(address)) {
1395 LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address);
1096 return ERR_INVALID_ADDRESS; 1396 return ERR_INVALID_ADDRESS;
1097 } 1397 }
1098 1398
@@ -1105,12 +1405,18 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
1105 return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, 1405 return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,
1106 num_to_wake); 1406 num_to_wake);
1107 default: 1407 default:
1408 LOG_ERROR(Kernel_SVC,
1409 "Invalid signal type, expected Signal, IncrementAndSignalIfEqual "
1410 "or ModifyByWaitingCountAndSignalIfEqual but got {}",
1411 type);
1108 return ERR_INVALID_ENUM_VALUE; 1412 return ERR_INVALID_ENUM_VALUE;
1109 } 1413 }
1110} 1414}
1111 1415
1112/// This returns the total CPU ticks elapsed since the CPU was powered-on 1416/// This returns the total CPU ticks elapsed since the CPU was powered-on
1113static u64 GetSystemTick() { 1417static u64 GetSystemTick() {
1418 LOG_TRACE(Kernel_SVC, "called");
1419
1114 const u64 result{CoreTiming::GetTicks()}; 1420 const u64 result{CoreTiming::GetTicks()};
1115 1421
1116 // Advance time to defeat dumb games that busy-wait for the frame to end. 1422 // Advance time to defeat dumb games that busy-wait for the frame to end.
@@ -1129,10 +1435,10 @@ static ResultCode CloseHandle(Handle handle) {
1129 1435
1130/// Reset an event 1436/// Reset an event
1131static ResultCode ResetSignal(Handle handle) { 1437static ResultCode ResetSignal(Handle handle) {
1132 LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle); 1438 LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
1133 1439
1134 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1440 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1135 auto event = handle_table.Get<Event>(handle); 1441 auto event = handle_table.Get<ReadableEvent>(handle);
1136 1442
1137 ASSERT(event != nullptr); 1443 ASSERT(event != nullptr);
1138 1444
@@ -1142,9 +1448,39 @@ static ResultCode ResetSignal(Handle handle) {
1142 1448
1143/// Creates a TransferMemory object 1449/// Creates a TransferMemory object
1144static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { 1450static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) {
1145 LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, 1451 LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size,
1146 permissions); 1452 permissions);
1147 *handle = 0; 1453
1454 if (!Common::Is4KBAligned(addr)) {
1455 LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr);
1456 return ERR_INVALID_ADDRESS;
1457 }
1458
1459 if (!Common::Is4KBAligned(size) || size == 0) {
1460 LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size);
1461 return ERR_INVALID_ADDRESS;
1462 }
1463
1464 if (!IsValidAddressRange(addr, size)) {
1465 LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})",
1466 addr, size);
1467 return ERR_INVALID_ADDRESS_STATE;
1468 }
1469
1470 const auto perms = static_cast<MemoryPermission>(permissions);
1471 if (perms != MemoryPermission::None && perms != MemoryPermission::Read &&
1472 perms != MemoryPermission::ReadWrite) {
1473 LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})",
1474 permissions);
1475 return ERR_INVALID_MEMORY_PERMISSIONS;
1476 }
1477
1478 auto& kernel = Core::System::GetInstance().Kernel();
1479 auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1480 const auto shared_mem_handle = SharedMemory::Create(
1481 kernel, handle_table.Get<Process>(CurrentProcess), size, perms, perms, addr);
1482
1483 CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
1148 return RESULT_SUCCESS; 1484 return RESULT_SUCCESS;
1149} 1485}
1150 1486
@@ -1154,6 +1490,8 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
1154 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1490 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1155 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1491 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1156 if (!thread) { 1492 if (!thread) {
1493 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
1494 thread_handle);
1157 return ERR_INVALID_HANDLE; 1495 return ERR_INVALID_HANDLE;
1158 } 1496 }
1159 1497
@@ -1164,12 +1502,14 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
1164} 1502}
1165 1503
1166static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { 1504static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
1167 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle, 1505 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:016X}, core=0x{:X}", thread_handle,
1168 mask, core); 1506 mask, core);
1169 1507
1170 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1508 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1171 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1509 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1172 if (!thread) { 1510 if (!thread) {
1511 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
1512 thread_handle);
1173 return ERR_INVALID_HANDLE; 1513 return ERR_INVALID_HANDLE;
1174 } 1514 }
1175 1515
@@ -1184,7 +1524,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
1184 } 1524 }
1185 1525
1186 if (mask == 0) { 1526 if (mask == 0) {
1187 return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); 1527 LOG_ERROR(Kernel_SVC, "Mask is 0");
1528 return ERR_INVALID_COMBINATION;
1188 } 1529 }
1189 1530
1190 /// This value is used to only change the affinity mask without changing the current ideal core. 1531 /// This value is used to only change the affinity mask without changing the current ideal core.
@@ -1193,12 +1534,15 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
1193 if (core == OnlyChangeMask) { 1534 if (core == OnlyChangeMask) {
1194 core = thread->GetIdealCore(); 1535 core = thread->GetIdealCore();
1195 } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) { 1536 } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) {
1196 return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); 1537 LOG_ERROR(Kernel_SVC, "Invalid core specified, got {}", core);
1538 return ERR_INVALID_PROCESSOR_ID;
1197 } 1539 }
1198 1540
1199 // Error out if the input core isn't enabled in the input mask. 1541 // Error out if the input core isn't enabled in the input mask.
1200 if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { 1542 if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) {
1201 return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); 1543 LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}",
1544 core, mask);
1545 return ERR_INVALID_COMBINATION;
1202 } 1546 }
1203 1547
1204 thread->ChangeCore(core, mask); 1548 thread->ChangeCore(core, mask);
@@ -1210,21 +1554,36 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
1210 u32 remote_permissions) { 1554 u32 remote_permissions) {
1211 LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, 1555 LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
1212 local_permissions, remote_permissions); 1556 local_permissions, remote_permissions);
1557 if (size == 0) {
1558 LOG_ERROR(Kernel_SVC, "Size is 0");
1559 return ERR_INVALID_SIZE;
1560 }
1561 if (!Common::Is4KBAligned(size)) {
1562 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
1563 return ERR_INVALID_SIZE;
1564 }
1213 1565
1214 // Size must be a multiple of 4KB and be less than or equal to 1566 if (size >= MAIN_MEMORY_SIZE) {
1215 // approx. 8 GB (actually (1GB - 512B) * 8) 1567 LOG_ERROR(Kernel_SVC, "Size is not less than 8GB, 0x{:016X}", size);
1216 if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) {
1217 return ERR_INVALID_SIZE; 1568 return ERR_INVALID_SIZE;
1218 } 1569 }
1219 1570
1220 const auto local_perms = static_cast<MemoryPermission>(local_permissions); 1571 const auto local_perms = static_cast<MemoryPermission>(local_permissions);
1221 if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { 1572 if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) {
1573 LOG_ERROR(Kernel_SVC,
1574 "Invalid local memory permissions, expected Read or ReadWrite but got "
1575 "local_permissions={}",
1576 static_cast<u32>(local_permissions));
1222 return ERR_INVALID_MEMORY_PERMISSIONS; 1577 return ERR_INVALID_MEMORY_PERMISSIONS;
1223 } 1578 }
1224 1579
1225 const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); 1580 const auto remote_perms = static_cast<MemoryPermission>(remote_permissions);
1226 if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && 1581 if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite &&
1227 remote_perms != MemoryPermission::DontCare) { 1582 remote_perms != MemoryPermission::DontCare) {
1583 LOG_ERROR(Kernel_SVC,
1584 "Invalid remote memory permissions, expected Read, ReadWrite or DontCare but got "
1585 "remote_permissions={}",
1586 static_cast<u32>(remote_permissions));
1228 return ERR_INVALID_MEMORY_PERMISSIONS; 1587 return ERR_INVALID_MEMORY_PERMISSIONS;
1229 } 1588 }
1230 1589
@@ -1238,16 +1597,67 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
1238 return RESULT_SUCCESS; 1597 return RESULT_SUCCESS;
1239} 1598}
1240 1599
1600static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) {
1601 LOG_DEBUG(Kernel_SVC, "called");
1602
1603 auto& kernel = Core::System::GetInstance().Kernel();
1604 const auto [readable_event, writable_event] =
1605 WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent");
1606
1607 HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
1608
1609 const auto write_create_result = handle_table.Create(writable_event);
1610 if (write_create_result.Failed()) {
1611 return write_create_result.Code();
1612 }
1613 *write_handle = *write_create_result;
1614
1615 const auto read_create_result = handle_table.Create(readable_event);
1616 if (read_create_result.Failed()) {
1617 handle_table.Close(*write_create_result);
1618 return read_create_result.Code();
1619 }
1620 *read_handle = *read_create_result;
1621
1622 LOG_DEBUG(Kernel_SVC,
1623 "successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}",
1624 *write_create_result, *read_create_result);
1625 return RESULT_SUCCESS;
1626}
1627
1241static ResultCode ClearEvent(Handle handle) { 1628static ResultCode ClearEvent(Handle handle) {
1242 LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); 1629 LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
1243 1630
1244 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1631 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1245 SharedPtr<Event> evt = handle_table.Get<Event>(handle); 1632
1246 if (evt == nullptr) { 1633 auto writable_event = handle_table.Get<WritableEvent>(handle);
1634 if (writable_event) {
1635 writable_event->Clear();
1636 return RESULT_SUCCESS;
1637 }
1638
1639 auto readable_event = handle_table.Get<ReadableEvent>(handle);
1640 if (readable_event) {
1641 readable_event->Clear();
1642 return RESULT_SUCCESS;
1643 }
1644
1645 LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle);
1646 return ERR_INVALID_HANDLE;
1647}
1648
1649static ResultCode SignalEvent(Handle handle) {
1650 LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle);
1651
1652 HandleTable& handle_table = Core::CurrentProcess()->GetHandleTable();
1653 auto writable_event = handle_table.Get<WritableEvent>(handle);
1654
1655 if (!writable_event) {
1656 LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle);
1247 return ERR_INVALID_HANDLE; 1657 return ERR_INVALID_HANDLE;
1248 } 1658 }
1249 1659
1250 evt->Clear(); 1660 writable_event->Signal();
1251 return RESULT_SUCCESS; 1661 return RESULT_SUCCESS;
1252} 1662}
1253 1663
@@ -1262,11 +1672,14 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
1262 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1672 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1263 const auto process = handle_table.Get<Process>(process_handle); 1673 const auto process = handle_table.Get<Process>(process_handle);
1264 if (!process) { 1674 if (!process) {
1675 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
1676 process_handle);
1265 return ERR_INVALID_HANDLE; 1677 return ERR_INVALID_HANDLE;
1266 } 1678 }
1267 1679
1268 const auto info_type = static_cast<InfoType>(type); 1680 const auto info_type = static_cast<InfoType>(type);
1269 if (info_type != InfoType::Status) { 1681 if (info_type != InfoType::Status) {
1682 LOG_ERROR(Kernel_SVC, "Expected info_type to be Status but got {} instead", type);
1270 return ERR_INVALID_ENUM_VALUE; 1683 return ERR_INVALID_ENUM_VALUE;
1271 } 1684 }
1272 1685
@@ -1274,6 +1687,87 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
1274 return RESULT_SUCCESS; 1687 return RESULT_SUCCESS;
1275} 1688}
1276 1689
1690static ResultCode CreateResourceLimit(Handle* out_handle) {
1691 LOG_DEBUG(Kernel_SVC, "called");
1692
1693 auto& kernel = Core::System::GetInstance().Kernel();
1694 auto resource_limit = ResourceLimit::Create(kernel);
1695
1696 auto* const current_process = kernel.CurrentProcess();
1697 ASSERT(current_process != nullptr);
1698
1699 const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit));
1700 if (handle.Failed()) {
1701 return handle.Code();
1702 }
1703
1704 *out_handle = *handle;
1705 return RESULT_SUCCESS;
1706}
1707
1708static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_limit,
1709 u32 resource_type) {
1710 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
1711
1712 const auto limit_value = RetrieveResourceLimitValue(resource_limit, resource_type,
1713 ResourceLimitValueType::LimitValue);
1714 if (limit_value.Failed()) {
1715 return limit_value.Code();
1716 }
1717
1718 *out_value = static_cast<u64>(*limit_value);
1719 return RESULT_SUCCESS;
1720}
1721
1722static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_limit,
1723 u32 resource_type) {
1724 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
1725
1726 const auto current_value = RetrieveResourceLimitValue(resource_limit, resource_type,
1727 ResourceLimitValueType::CurrentValue);
1728 if (current_value.Failed()) {
1729 return current_value.Code();
1730 }
1731
1732 *out_value = static_cast<u64>(*current_value);
1733 return RESULT_SUCCESS;
1734}
1735
1736static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource_type, u64 value) {
1737 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
1738 resource_type, value);
1739
1740 const auto type = static_cast<ResourceType>(resource_type);
1741 if (!IsValidResourceType(type)) {
1742 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
1743 return ERR_INVALID_ENUM_VALUE;
1744 }
1745
1746 auto& kernel = Core::System::GetInstance().Kernel();
1747 auto* const current_process = kernel.CurrentProcess();
1748 ASSERT(current_process != nullptr);
1749
1750 auto resource_limit_object =
1751 current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
1752 if (!resource_limit_object) {
1753 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
1754 resource_limit);
1755 return ERR_INVALID_HANDLE;
1756 }
1757
1758 const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value));
1759 if (set_result.IsError()) {
1760 LOG_ERROR(
1761 Kernel_SVC,
1762 "Attempted to lower resource limit ({}) for category '{}' below its current value ({})",
1763 resource_limit_object->GetMaxResourceValue(type), resource_type,
1764 resource_limit_object->GetCurrentResourceValue(type));
1765 return set_result;
1766 }
1767
1768 return RESULT_SUCCESS;
1769}
1770
1277namespace { 1771namespace {
1278struct FunctionDef { 1772struct FunctionDef {
1279 using Func = void(); 1773 using Func = void();
@@ -1287,7 +1781,7 @@ struct FunctionDef {
1287static const FunctionDef SVC_Table[] = { 1781static const FunctionDef SVC_Table[] = {
1288 {0x00, nullptr, "Unknown"}, 1782 {0x00, nullptr, "Unknown"},
1289 {0x01, SvcWrap<SetHeapSize>, "SetHeapSize"}, 1783 {0x01, SvcWrap<SetHeapSize>, "SetHeapSize"},
1290 {0x02, nullptr, "SetMemoryPermission"}, 1784 {0x02, SvcWrap<SetMemoryPermission>, "SetMemoryPermission"},
1291 {0x03, SvcWrap<SetMemoryAttribute>, "SetMemoryAttribute"}, 1785 {0x03, SvcWrap<SetMemoryAttribute>, "SetMemoryAttribute"},
1292 {0x04, SvcWrap<MapMemory>, "MapMemory"}, 1786 {0x04, SvcWrap<MapMemory>, "MapMemory"},
1293 {0x05, SvcWrap<UnmapMemory>, "UnmapMemory"}, 1787 {0x05, SvcWrap<UnmapMemory>, "UnmapMemory"},
@@ -1302,7 +1796,7 @@ static const FunctionDef SVC_Table[] = {
1302 {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"}, 1796 {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"},
1303 {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, 1797 {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"},
1304 {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, 1798 {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"},
1305 {0x11, nullptr, "SignalEvent"}, 1799 {0x11, SvcWrap<SignalEvent>, "SignalEvent"},
1306 {0x12, SvcWrap<ClearEvent>, "ClearEvent"}, 1800 {0x12, SvcWrap<ClearEvent>, "ClearEvent"},
1307 {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"}, 1801 {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"},
1308 {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"}, 1802 {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"},
@@ -1333,8 +1827,8 @@ static const FunctionDef SVC_Table[] = {
1333 {0x2D, nullptr, "UnmapPhysicalMemory"}, 1827 {0x2D, nullptr, "UnmapPhysicalMemory"},
1334 {0x2E, nullptr, "GetFutureThreadInfo"}, 1828 {0x2E, nullptr, "GetFutureThreadInfo"},
1335 {0x2F, nullptr, "GetLastThreadInfo"}, 1829 {0x2F, nullptr, "GetLastThreadInfo"},
1336 {0x30, nullptr, "GetResourceLimitLimitValue"}, 1830 {0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"},
1337 {0x31, nullptr, "GetResourceLimitCurrentValue"}, 1831 {0x31, SvcWrap<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"},
1338 {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, 1832 {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
1339 {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, 1833 {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
1340 {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, 1834 {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
@@ -1354,7 +1848,7 @@ static const FunctionDef SVC_Table[] = {
1354 {0x42, nullptr, "ReplyAndReceiveLight"}, 1848 {0x42, nullptr, "ReplyAndReceiveLight"},
1355 {0x43, nullptr, "ReplyAndReceive"}, 1849 {0x43, nullptr, "ReplyAndReceive"},
1356 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, 1850 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"},
1357 {0x45, nullptr, "CreateEvent"}, 1851 {0x45, SvcWrap<CreateEvent>, "CreateEvent"},
1358 {0x46, nullptr, "Unknown"}, 1852 {0x46, nullptr, "Unknown"},
1359 {0x47, nullptr, "Unknown"}, 1853 {0x47, nullptr, "Unknown"},
1360 {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, 1854 {0x48, nullptr, "MapPhysicalMemoryUnsafe"},
@@ -1410,8 +1904,8 @@ static const FunctionDef SVC_Table[] = {
1410 {0x7A, nullptr, "StartProcess"}, 1904 {0x7A, nullptr, "StartProcess"},
1411 {0x7B, nullptr, "TerminateProcess"}, 1905 {0x7B, nullptr, "TerminateProcess"},
1412 {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, 1906 {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"},
1413 {0x7D, nullptr, "CreateResourceLimit"}, 1907 {0x7D, SvcWrap<CreateResourceLimit>, "CreateResourceLimit"},
1414 {0x7E, nullptr, "SetResourceLimitLimitValue"}, 1908 {0x7E, SvcWrap<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
1415 {0x7F, nullptr, "CallSecureMonitor"}, 1909 {0x7F, nullptr, "CallSecureMonitor"},
1416}; 1910};
1417 1911
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index b09753c80..24aef46c9 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -43,6 +43,14 @@ void SvcWrap() {
43 FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw); 43 FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
44} 44}
45 45
46template <ResultCode func(u32*)>
47void SvcWrap() {
48 u32 param = 0;
49 const u32 retval = func(&param).raw;
50 Core::CurrentArmInterface().SetReg(1, param);
51 FuncReturn(retval);
52}
53
46template <ResultCode func(u32*, u32)> 54template <ResultCode func(u32*, u32)>
47void SvcWrap() { 55void SvcWrap() {
48 u32 param_1 = 0; 56 u32 param_1 = 0;
@@ -51,6 +59,19 @@ void SvcWrap() {
51 FuncReturn(retval); 59 FuncReturn(retval);
52} 60}
53 61
62template <ResultCode func(u32*, u32*)>
63void SvcWrap() {
64 u32 param_1 = 0;
65 u32 param_2 = 0;
66 const u32 retval = func(&param_1, &param_2).raw;
67
68 auto& arm_interface = Core::CurrentArmInterface();
69 arm_interface.SetReg(1, param_1);
70 arm_interface.SetReg(2, param_2);
71
72 FuncReturn(retval);
73}
74
54template <ResultCode func(u32*, u64)> 75template <ResultCode func(u32*, u64)>
55void SvcWrap() { 76void SvcWrap() {
56 u32 param_1 = 0; 77 u32 param_1 = 0;
@@ -121,6 +142,11 @@ void SvcWrap() {
121 FuncReturn(func(Param(0), Param(1), Param(2)).raw); 142 FuncReturn(func(Param(0), Param(1), Param(2)).raw);
122} 143}
123 144
145template <ResultCode func(u64, u64, u32)>
146void SvcWrap() {
147 FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2))).raw);
148}
149
124template <ResultCode func(u32, u64, u64, u32)> 150template <ResultCode func(u32, u64, u64, u32)>
125void SvcWrap() { 151void SvcWrap() {
126 FuncReturn( 152 FuncReturn(
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index dd5cd9ced..4ffb76818 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -142,36 +142,7 @@ void Thread::ResumeFromWait() {
142 142
143 status = ThreadStatus::Ready; 143 status = ThreadStatus::Ready;
144 144
145 std::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask); 145 ChangeScheduler();
146 if (!new_processor_id) {
147 new_processor_id = processor_id;
148 }
149 if (ideal_core != -1 &&
150 Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) {
151 new_processor_id = ideal_core;
152 }
153
154 ASSERT(*new_processor_id < 4);
155
156 // Add thread to new core's scheduler
157 auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id);
158
159 if (*new_processor_id != processor_id) {
160 // Remove thread from previous core's scheduler
161 scheduler->RemoveThread(this);
162 next_scheduler->AddThread(this, current_priority);
163 }
164
165 processor_id = *new_processor_id;
166
167 // If the thread was ready, unschedule from the previous core and schedule on the new core
168 scheduler->UnscheduleThread(this, current_priority);
169 next_scheduler->ScheduleThread(this, current_priority);
170
171 // Change thread's scheduler
172 scheduler = next_scheduler;
173
174 Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
175} 146}
176 147
177/** 148/**
@@ -364,42 +335,45 @@ void Thread::UpdatePriority() {
364void Thread::ChangeCore(u32 core, u64 mask) { 335void Thread::ChangeCore(u32 core, u64 mask) {
365 ideal_core = core; 336 ideal_core = core;
366 affinity_mask = mask; 337 affinity_mask = mask;
338 ChangeScheduler();
339}
367 340
341void Thread::ChangeScheduler() {
368 if (status != ThreadStatus::Ready) { 342 if (status != ThreadStatus::Ready) {
369 return; 343 return;
370 } 344 }
371 345
346 auto& system = Core::System::GetInstance();
372 std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)}; 347 std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)};
373 348
374 if (!new_processor_id) { 349 if (!new_processor_id) {
375 new_processor_id = processor_id; 350 new_processor_id = processor_id;
376 } 351 }
377 if (ideal_core != -1 && 352 if (ideal_core != -1 && system.Scheduler(ideal_core).GetCurrentThread() == nullptr) {
378 Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) {
379 new_processor_id = ideal_core; 353 new_processor_id = ideal_core;
380 } 354 }
381 355
382 ASSERT(*new_processor_id < 4); 356 ASSERT(*new_processor_id < 4);
383 357
384 // Add thread to new core's scheduler 358 // Add thread to new core's scheduler
385 auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id); 359 auto& next_scheduler = system.Scheduler(*new_processor_id);
386 360
387 if (*new_processor_id != processor_id) { 361 if (*new_processor_id != processor_id) {
388 // Remove thread from previous core's scheduler 362 // Remove thread from previous core's scheduler
389 scheduler->RemoveThread(this); 363 scheduler->RemoveThread(this);
390 next_scheduler->AddThread(this, current_priority); 364 next_scheduler.AddThread(this, current_priority);
391 } 365 }
392 366
393 processor_id = *new_processor_id; 367 processor_id = *new_processor_id;
394 368
395 // If the thread was ready, unschedule from the previous core and schedule on the new core 369 // If the thread was ready, unschedule from the previous core and schedule on the new core
396 scheduler->UnscheduleThread(this, current_priority); 370 scheduler->UnscheduleThread(this, current_priority);
397 next_scheduler->ScheduleThread(this, current_priority); 371 next_scheduler.ScheduleThread(this, current_priority);
398 372
399 // Change thread's scheduler 373 // Change thread's scheduler
400 scheduler = next_scheduler; 374 scheduler = &next_scheduler;
401 375
402 Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); 376 system.CpuCore(processor_id).PrepareReschedule();
403} 377}
404 378
405bool Thread::AllWaitObjectsReady() { 379bool Thread::AllWaitObjectsReady() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 4a6e11239..d384d50db 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -374,6 +374,8 @@ private:
374 explicit Thread(KernelCore& kernel); 374 explicit Thread(KernelCore& kernel);
375 ~Thread() override; 375 ~Thread() override;
376 376
377 void ChangeScheduler();
378
377 Core::ARM_Interface::ThreadContext context{}; 379 Core::ARM_Interface::ThreadContext context{};
378 380
379 u32 thread_id = 0; 381 u32 thread_id = 0;
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 1a92c8f70..100f8f6bf 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -243,6 +243,85 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p
243 return RESULT_SUCCESS; 243 return RESULT_SUCCESS;
244} 244}
245 245
246ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
247 if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() ||
248 target + size < target) {
249 return ERR_INVALID_ADDRESS;
250 }
251
252 if (heap_memory == nullptr) {
253 // Initialize heap
254 heap_memory = std::make_shared<std::vector<u8>>();
255 heap_start = heap_end = target;
256 } else {
257 UnmapRange(heap_start, heap_end - heap_start);
258 }
259
260 // If necessary, expand backing vector to cover new heap extents.
261 if (target < heap_start) {
262 heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
263 heap_start = target;
264 RefreshMemoryBlockMappings(heap_memory.get());
265 }
266 if (target + size > heap_end) {
267 heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
268 heap_end = target + size;
269 RefreshMemoryBlockMappings(heap_memory.get());
270 }
271 ASSERT(heap_end - heap_start == heap_memory->size());
272
273 CASCADE_RESULT(auto vma, MapMemoryBlock(target, heap_memory, target - heap_start, size,
274 MemoryState::Heap));
275 Reprotect(vma, perms);
276
277 heap_used = size;
278
279 return MakeResult<VAddr>(heap_end - size);
280}
281
282ResultCode VMManager::HeapFree(VAddr target, u64 size) {
283 if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() ||
284 target + size < target) {
285 return ERR_INVALID_ADDRESS;
286 }
287
288 if (size == 0) {
289 return RESULT_SUCCESS;
290 }
291
292 const ResultCode result = UnmapRange(target, size);
293 if (result.IsError()) {
294 return result;
295 }
296
297 heap_used -= size;
298 return RESULT_SUCCESS;
299}
300
301ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) {
302 const auto vma = FindVMA(src_addr);
303
304 ASSERT_MSG(vma != vma_map.end(), "Invalid memory address");
305 ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
306
307 // The returned VMA might be a bigger one encompassing the desired address.
308 const auto vma_offset = src_addr - vma->first;
309 ASSERT_MSG(vma_offset + size <= vma->second.size,
310 "Shared memory exceeds bounds of mapped block");
311
312 const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
313 const std::size_t backing_block_offset = vma->second.offset + vma_offset;
314
315 CASCADE_RESULT(auto new_vma,
316 MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, state));
317 // Protect mirror with permissions from old region
318 Reprotect(new_vma, vma->second.permissions);
319 // Remove permissions from old region
320 Reprotect(vma, VMAPermission::None);
321
322 return RESULT_SUCCESS;
323}
324
246void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { 325void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) {
247 // If this ever proves to have a noticeable performance impact, allow users of the function to 326 // If this ever proves to have a noticeable performance impact, allow users of the function to
248 // specify a specific range of addresses to limit the scan to. 327 // specify a specific range of addresses to limit the scan to.
@@ -495,8 +574,7 @@ u64 VMManager::GetTotalMemoryUsage() const {
495} 574}
496 575
497u64 VMManager::GetTotalHeapUsage() const { 576u64 VMManager::GetTotalHeapUsage() const {
498 LOG_WARNING(Kernel, "(STUBBED) called"); 577 return heap_used;
499 return 0x0;
500} 578}
501 579
502VAddr VMManager::GetAddressSpaceBaseAddress() const { 580VAddr VMManager::GetAddressSpaceBaseAddress() const {
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 2447cbb8f..d522404fe 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -186,6 +186,12 @@ public:
186 /// Changes the permissions of a range of addresses, splitting VMAs as necessary. 186 /// Changes the permissions of a range of addresses, splitting VMAs as necessary.
187 ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms); 187 ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
188 188
189 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
190 ResultCode HeapFree(VAddr target, u64 size);
191
192 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size,
193 MemoryState state = MemoryState::Mapped);
194
189 /** 195 /**
190 * Scans all VMAs and updates the page table range of any that use the given vector as backing 196 * Scans all VMAs and updates the page table range of any that use the given vector as backing
191 * memory. This should be called after any operation that causes reallocation of the vector. 197 * memory. This should be called after any operation that causes reallocation of the vector.
@@ -343,5 +349,15 @@ private:
343 349
344 VAddr tls_io_region_base = 0; 350 VAddr tls_io_region_base = 0;
345 VAddr tls_io_region_end = 0; 351 VAddr tls_io_region_end = 0;
352
353 // Memory used to back the allocations in the regular heap. A single vector is used to cover
354 // the entire virtual address space extents that bound the allocations, including any holes.
355 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
356 // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
357 std::shared_ptr<std::vector<u8>> heap_memory;
358 // The left/right bounds of the address space covered by heap_memory.
359 VAddr heap_start = 0;
360 VAddr heap_end = 0;
361 u64 heap_used = 0;
346}; 362};
347} // namespace Kernel 363} // namespace Kernel
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp
new file mode 100644
index 000000000..a58ea6ec8
--- /dev/null
+++ b/src/core/hle/kernel/writable_event.cpp
@@ -0,0 +1,52 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include "common/assert.h"
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/object.h"
9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/thread.h"
11#include "core/hle/kernel/writable_event.h"
12
13namespace Kernel {
14
15WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {}
16WritableEvent::~WritableEvent() = default;
17
18EventPair WritableEvent::CreateEventPair(KernelCore& kernel, ResetType reset_type,
19 std::string name) {
20 SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel));
21 SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel));
22
23 writable_event->name = name + ":Writable";
24 writable_event->readable = readable_event;
25 readable_event->name = name + ":Readable";
26 readable_event->signaled = false;
27 readable_event->reset_type = reset_type;
28
29 return {std::move(readable_event), std::move(writable_event)};
30}
31
32SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const {
33 return readable;
34}
35
36ResetType WritableEvent::GetResetType() const {
37 return readable->reset_type;
38}
39
40void WritableEvent::Signal() {
41 readable->Signal();
42}
43
44void WritableEvent::Clear() {
45 readable->Clear();
46}
47
48bool WritableEvent::IsSignaled() const {
49 return readable->signaled;
50}
51
52} // namespace Kernel
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/writable_event.h
index 27d6126b0..8fa8d68ee 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/writable_event.h
@@ -11,49 +11,52 @@
11namespace Kernel { 11namespace Kernel {
12 12
13class KernelCore; 13class KernelCore;
14class ReadableEvent;
15class WritableEvent;
14 16
15class Event final : public WaitObject { 17struct EventPair {
18 SharedPtr<ReadableEvent> readable;
19 SharedPtr<WritableEvent> writable;
20};
21
22class WritableEvent final : public Object {
16public: 23public:
24 ~WritableEvent() override;
25
17 /** 26 /**
18 * Creates an event 27 * Creates an event
19 * @param kernel The kernel instance to create this event under. 28 * @param kernel The kernel instance to create this event under.
20 * @param reset_type ResetType describing how to create event 29 * @param reset_type ResetType describing how to create event
21 * @param name Optional name of event 30 * @param name Optional name of event
22 */ 31 */
23 static SharedPtr<Event> Create(KernelCore& kernel, ResetType reset_type, 32 static EventPair CreateEventPair(KernelCore& kernel, ResetType reset_type,
24 std::string name = "Unknown"); 33 std::string name = "Unknown");
25 34
26 std::string GetTypeName() const override { 35 std::string GetTypeName() const override {
27 return "Event"; 36 return "WritableEvent";
28 } 37 }
29 std::string GetName() const override { 38 std::string GetName() const override {
30 return name; 39 return name;
31 } 40 }
32 41
33 static const HandleType HANDLE_TYPE = HandleType::Event; 42 static const HandleType HANDLE_TYPE = HandleType::WritableEvent;
34 HandleType GetHandleType() const override { 43 HandleType GetHandleType() const override {
35 return HANDLE_TYPE; 44 return HANDLE_TYPE;
36 } 45 }
37 46
38 ResetType GetResetType() const { 47 SharedPtr<ReadableEvent> GetReadableEvent() const;
39 return reset_type;
40 }
41
42 bool ShouldWait(Thread* thread) const override;
43 void Acquire(Thread* thread) override;
44 48
45 void WakeupAllWaitingThreads() override; 49 ResetType GetResetType() const;
46 50
47 void Signal(); 51 void Signal();
48 void Clear(); 52 void Clear();
53 bool IsSignaled() const;
49 54
50private: 55private:
51 explicit Event(KernelCore& kernel); 56 explicit WritableEvent(KernelCore& kernel);
52 ~Event() override;
53 57
54 ResetType reset_type; ///< Current ResetType 58 SharedPtr<ReadableEvent> readable;
55 59
56 bool signaled; ///< Whether the event has already been signaled
57 std::string name; ///< Name of event (optional) 60 std::string name; ///< Name of event (optional)
58}; 61};
59 62
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index c6b18cfba..bfb77cc31 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -19,8 +19,6 @@
19enum class ErrorDescription : u32 { 19enum class ErrorDescription : u32 {
20 Success = 0, 20 Success = 0,
21 RemoteProcessDead = 301, 21 RemoteProcessDead = 301,
22 InvalidOffset = 6061,
23 InvalidLength = 6062,
24}; 22};
25 23
26/** 24/**
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 8318eff5f..1f8ed265e 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -21,17 +21,6 @@
21 21
22namespace Service::Account { 22namespace Service::Account {
23 23
24// TODO: RE this structure
25struct UserData {
26 INSERT_PADDING_WORDS(1);
27 u32 icon_id;
28 u8 bg_color_id;
29 INSERT_PADDING_BYTES(0x7);
30 INSERT_PADDING_BYTES(0x10);
31 INSERT_PADDING_BYTES(0x60);
32};
33static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
34
35// Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg 24// Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg
36// used as a backup should the one on disk not exist 25// used as a backup should the one on disk not exist
37constexpr u32 backup_jpeg_size = 107; 26constexpr u32 backup_jpeg_size = 107;
@@ -72,9 +61,11 @@ private:
72 void Get(Kernel::HLERequestContext& ctx) { 61 void Get(Kernel::HLERequestContext& ctx) {
73 LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); 62 LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
74 ProfileBase profile_base{}; 63 ProfileBase profile_base{};
75 std::array<u8, MAX_DATA> data{}; 64 ProfileData data{};
76 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { 65 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
77 ctx.WriteBuffer(data); 66 std::array<u8, sizeof(ProfileData)> raw_data;
67 std::memcpy(raw_data.data(), &data, sizeof(ProfileData));
68 ctx.WriteBuffer(raw_data);
78 IPC::ResponseBuilder rb{ctx, 16}; 69 IPC::ResponseBuilder rb{ctx, 16};
79 rb.Push(RESULT_SUCCESS); 70 rb.Push(RESULT_SUCCESS);
80 rb.PushRaw(profile_base); 71 rb.PushRaw(profile_base);
@@ -216,10 +207,11 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
216void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { 207void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
217 IPC::RequestParser rp{ctx}; 208 IPC::RequestParser rp{ctx};
218 UUID user_id = rp.PopRaw<UUID>(); 209 UUID user_id = rp.PopRaw<UUID>();
210 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
211
219 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 212 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
220 rb.Push(RESULT_SUCCESS); 213 rb.Push(RESULT_SUCCESS);
221 rb.PushIpcInterface<IProfile>(user_id, *profile_manager); 214 rb.PushIpcInterface<IProfile>(user_id, *profile_manager);
222 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
223} 215}
224 216
225void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { 217void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) {
@@ -236,10 +228,10 @@ void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx
236} 228}
237 229
238void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { 230void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
231 LOG_DEBUG(Service_ACC, "called");
239 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 232 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
240 rb.Push(RESULT_SUCCESS); 233 rb.Push(RESULT_SUCCESS);
241 rb.PushIpcInterface<IManagerForApplication>(); 234 rb.PushIpcInterface<IManagerForApplication>();
242 LOG_DEBUG(Service_ACC, "called");
243} 235}
244 236
245void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { 237void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
@@ -252,8 +244,10 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
252 rb.PushRaw<u128>(INVALID_UUID); 244 rb.PushRaw<u128>(INVALID_UUID);
253 return; 245 return;
254 } 246 }
255 auto user_list = profile_manager->GetAllUsers(); 247
256 if (user_list.empty()) { 248 const auto user_list = profile_manager->GetAllUsers();
249 if (std::all_of(user_list.begin(), user_list.end(),
250 [](const auto& user) { return user.uuid == INVALID_UUID; })) {
257 rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code 251 rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code
258 rb.PushRaw<u128>(INVALID_UUID); 252 rb.PushRaw<u128>(INVALID_UUID);
259 return; 253 return;
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index c08394e4c..1316d0b07 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -2,8 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
5#include <random> 6#include <random>
6 7
8#include <fmt/format.h>
9
7#include "common/file_util.h" 10#include "common/file_util.h"
8#include "core/hle/service/acc/profile_manager.h" 11#include "core/hle/service/acc/profile_manager.h"
9#include "core/settings.h" 12#include "core/settings.h"
@@ -15,7 +18,7 @@ struct UserRaw {
15 UUID uuid2; 18 UUID uuid2;
16 u64 timestamp; 19 u64 timestamp;
17 ProfileUsername username; 20 ProfileUsername username;
18 INSERT_PADDING_BYTES(0x80); 21 ProfileData extra_data;
19}; 22};
20static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); 23static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size.");
21 24
@@ -39,6 +42,19 @@ UUID UUID::Generate() {
39 return UUID{distribution(gen), distribution(gen)}; 42 return UUID{distribution(gen), distribution(gen)};
40} 43}
41 44
45std::string UUID::Format() const {
46 return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
47}
48
49std::string UUID::FormatSwitch() const {
50 std::array<u8, 16> s{};
51 std::memcpy(s.data(), uuid.data(), sizeof(u128));
52 return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
53 ":02x}{:02x}{:02x}{:02x}{:02x}",
54 s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
55 s[12], s[13], s[14], s[15]);
56}
57
42ProfileManager::ProfileManager() { 58ProfileManager::ProfileManager() {
43 ParseUserSaveFile(); 59 ParseUserSaveFile();
44 60
@@ -325,11 +341,12 @@ void ProfileManager::ParseUserSaveFile() {
325 return; 341 return;
326 } 342 }
327 343
328 for (std::size_t i = 0; i < MAX_USERS; ++i) { 344 for (const auto& user : data.users) {
329 const auto& user = data.users[i]; 345 if (user.uuid == UUID(INVALID_UUID)) {
346 continue;
347 }
330 348
331 if (user.uuid != UUID(INVALID_UUID)) 349 AddUser({user.uuid, user.username, user.timestamp, user.extra_data, false});
332 AddUser({user.uuid, user.username, user.timestamp, {}, false});
333 } 350 }
334 351
335 std::stable_partition(profiles.begin(), profiles.end(), 352 std::stable_partition(profiles.begin(), profiles.end(),
@@ -344,6 +361,7 @@ void ProfileManager::WriteUserSaveFile() {
344 raw.users[i].uuid2 = profiles[i].user_uuid; 361 raw.users[i].uuid2 = profiles[i].user_uuid;
345 raw.users[i].uuid = profiles[i].user_uuid; 362 raw.users[i].uuid = profiles[i].user_uuid;
346 raw.users[i].timestamp = profiles[i].creation_time; 363 raw.users[i].timestamp = profiles[i].creation_time;
364 raw.users[i].extra_data = profiles[i].data;
347 } 365 }
348 366
349 const auto raw_path = 367 const auto raw_path =
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 747c46c20..c4ce2e0b3 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -13,7 +13,6 @@
13 13
14namespace Service::Account { 14namespace Service::Account {
15constexpr std::size_t MAX_USERS = 8; 15constexpr std::size_t MAX_USERS = 8;
16constexpr std::size_t MAX_DATA = 128;
17constexpr u128 INVALID_UUID{{0, 0}}; 16constexpr u128 INVALID_UUID{{0, 0}};
18 17
19struct UUID { 18struct UUID {
@@ -42,26 +41,28 @@ struct UUID {
42 void Invalidate() { 41 void Invalidate() {
43 uuid = INVALID_UUID; 42 uuid = INVALID_UUID;
44 } 43 }
45 std::string Format() const {
46 return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
47 }
48 44
49 std::string FormatSwitch() const { 45 std::string Format() const;
50 std::array<u8, 16> s{}; 46 std::string FormatSwitch() const;
51 std::memcpy(s.data(), uuid.data(), sizeof(u128));
52 return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
53 ":02x}{:02x}{:02x}{:02x}{:02x}",
54 s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
55 s[12], s[13], s[14], s[15]);
56 }
57}; 47};
58static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); 48static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
59 49
60constexpr std::size_t profile_username_size = 32; 50constexpr std::size_t profile_username_size = 32;
61using ProfileUsername = std::array<u8, profile_username_size>; 51using ProfileUsername = std::array<u8, profile_username_size>;
62using ProfileData = std::array<u8, MAX_DATA>;
63using UserIDArray = std::array<UUID, MAX_USERS>; 52using UserIDArray = std::array<UUID, MAX_USERS>;
64 53
54/// Contains extra data related to a user.
55/// TODO: RE this structure
56struct ProfileData {
57 INSERT_PADDING_WORDS(1);
58 u32 icon_id;
59 u8 bg_color_id;
60 INSERT_PADDING_BYTES(0x7);
61 INSERT_PADDING_BYTES(0x10);
62 INSERT_PADDING_BYTES(0x60);
63};
64static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size");
65
65/// This holds general information about a users profile. This is where we store all the information 66/// This holds general information about a users profile. This is where we store all the information
66/// based on a specific user 67/// based on a specific user
67struct ProfileInfo { 68struct ProfileInfo {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 0477ce66e..3a7b6da84 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -6,14 +6,21 @@
6#include <cinttypes> 6#include <cinttypes>
7#include <cstring> 7#include <cstring>
8#include <stack> 8#include <stack>
9#include "audio_core/audio_renderer.h"
9#include "core/core.h" 10#include "core/core.h"
10#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/event.h" 12#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/readable_event.h"
15#include "core/hle/kernel/shared_memory.h"
16#include "core/hle/kernel/writable_event.h"
13#include "core/hle/service/acc/profile_manager.h" 17#include "core/hle/service/acc/profile_manager.h"
14#include "core/hle/service/am/am.h" 18#include "core/hle/service/am/am.h"
15#include "core/hle/service/am/applet_ae.h" 19#include "core/hle/service/am/applet_ae.h"
16#include "core/hle/service/am/applet_oe.h" 20#include "core/hle/service/am/applet_oe.h"
21#include "core/hle/service/am/applets/applets.h"
22#include "core/hle/service/am/applets/software_keyboard.h"
23#include "core/hle/service/am/applets/stub_applet.h"
17#include "core/hle/service/am/idle.h" 24#include "core/hle/service/am/idle.h"
18#include "core/hle/service/am/omm.h" 25#include "core/hle/service/am/omm.h"
19#include "core/hle/service/am/spsm.h" 26#include "core/hle/service/am/spsm.h"
@@ -28,6 +35,13 @@
28 35
29namespace Service::AM { 36namespace Service::AM {
30 37
38constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2};
39constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
40
41enum class AppletId : u32 {
42 SoftwareKeyboard = 0x11,
43};
44
31constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; 45constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA;
32 46
33struct LaunchParameters { 47struct LaunchParameters {
@@ -196,15 +210,16 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
196 RegisterHandlers(functions); 210 RegisterHandlers(functions);
197 211
198 auto& kernel = Core::System::GetInstance().Kernel(); 212 auto& kernel = Core::System::GetInstance().Kernel();
199 launchable_event = 213 launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
200 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); 214 "ISelfController:LaunchableEvent");
201} 215}
202 216
203ISelfController::~ISelfController() = default; 217ISelfController::~ISelfController() = default;
204 218
205void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { 219void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
206 // Takes 3 input u8s with each field located immediately after the previous u8, these are 220 // Takes 3 input u8s with each field located immediately after the previous
207 // bool flags. No output. 221 // u8, these are bool flags. No output.
222 LOG_WARNING(Service_AM, "(STUBBED) called");
208 223
209 IPC::RequestParser rp{ctx}; 224 IPC::RequestParser rp{ctx};
210 225
@@ -217,159 +232,156 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
217 232
218 IPC::ResponseBuilder rb{ctx, 2}; 233 IPC::ResponseBuilder rb{ctx, 2};
219 rb.Push(RESULT_SUCCESS); 234 rb.Push(RESULT_SUCCESS);
220
221 LOG_WARNING(Service_AM, "(STUBBED) called");
222} 235}
223 236
224void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { 237void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
238 LOG_WARNING(Service_AM, "(STUBBED) called");
239
225 IPC::ResponseBuilder rb{ctx, 2}; 240 IPC::ResponseBuilder rb{ctx, 2};
226 rb.Push(RESULT_SUCCESS); 241 rb.Push(RESULT_SUCCESS);
227
228 LOG_WARNING(Service_AM, "(STUBBED) called");
229} 242}
230 243
231void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { 244void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
232 IPC::RequestParser rp{ctx}; 245 IPC::RequestParser rp{ctx};
233 246
234 bool flag = rp.Pop<bool>(); 247 bool flag = rp.Pop<bool>();
248 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
235 249
236 IPC::ResponseBuilder rb{ctx, 2}; 250 IPC::ResponseBuilder rb{ctx, 2};
237 rb.Push(RESULT_SUCCESS); 251 rb.Push(RESULT_SUCCESS);
238
239 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
240} 252}
241 253
242void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { 254void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
255 LOG_WARNING(Service_AM, "(STUBBED) called");
256
243 IPC::ResponseBuilder rb{ctx, 2}; 257 IPC::ResponseBuilder rb{ctx, 2};
244 rb.Push(RESULT_SUCCESS); 258 rb.Push(RESULT_SUCCESS);
245
246 LOG_WARNING(Service_AM, "(STUBBED) called");
247} 259}
248 260
249void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { 261void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) {
250 IPC::RequestParser rp{ctx}; 262 IPC::RequestParser rp{ctx};
251 263
252 bool flag = rp.Pop<bool>(); 264 bool flag = rp.Pop<bool>();
265 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
253 266
254 IPC::ResponseBuilder rb{ctx, 2}; 267 IPC::ResponseBuilder rb{ctx, 2};
255 rb.Push(RESULT_SUCCESS); 268 rb.Push(RESULT_SUCCESS);
256
257 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
258} 269}
259 270
260void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { 271void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) {
261 // Takes 3 input u8s with each field located immediately after the previous u8, these are 272 // Takes 3 input u8s with each field located immediately after the previous
262 // bool flags. No output. 273 // u8, these are bool flags. No output.
263 IPC::RequestParser rp{ctx}; 274 IPC::RequestParser rp{ctx};
264 275
265 bool enabled = rp.Pop<bool>(); 276 bool enabled = rp.Pop<bool>();
277 LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
266 278
267 IPC::ResponseBuilder rb{ctx, 2}; 279 IPC::ResponseBuilder rb{ctx, 2};
268 rb.Push(RESULT_SUCCESS); 280 rb.Push(RESULT_SUCCESS);
269
270 LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
271} 281}
272 282
273void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { 283void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
284 LOG_WARNING(Service_AM, "(STUBBED) called");
285
274 IPC::ResponseBuilder rb{ctx, 2}; 286 IPC::ResponseBuilder rb{ctx, 2};
275 rb.Push(RESULT_SUCCESS); 287 rb.Push(RESULT_SUCCESS);
276
277 LOG_WARNING(Service_AM, "(STUBBED) called");
278} 288}
279 289
280void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { 290void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
291 LOG_WARNING(Service_AM, "(STUBBED) called");
292
281 IPC::ResponseBuilder rb{ctx, 2}; 293 IPC::ResponseBuilder rb{ctx, 2};
282 rb.Push(RESULT_SUCCESS); 294 rb.Push(RESULT_SUCCESS);
283
284 LOG_WARNING(Service_AM, "(STUBBED) called");
285} 295}
286 296
287void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { 297void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
288 launchable_event->Signal(); 298 LOG_WARNING(Service_AM, "(STUBBED) called");
299
300 launchable_event.writable->Signal();
289 301
290 IPC::ResponseBuilder rb{ctx, 2, 1}; 302 IPC::ResponseBuilder rb{ctx, 2, 1};
291 rb.Push(RESULT_SUCCESS); 303 rb.Push(RESULT_SUCCESS);
292 rb.PushCopyObjects(launchable_event); 304 rb.PushCopyObjects(launchable_event.readable);
293
294 LOG_WARNING(Service_AM, "(STUBBED) called");
295} 305}
296 306
297void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { 307void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
308 LOG_WARNING(Service_AM, "(STUBBED) called");
309
298 IPC::ResponseBuilder rb{ctx, 2}; 310 IPC::ResponseBuilder rb{ctx, 2};
299 rb.Push(RESULT_SUCCESS); 311 rb.Push(RESULT_SUCCESS);
300
301 LOG_WARNING(Service_AM, "(STUBBED) called");
302} 312}
303 313
304void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { 314void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
305 // TODO(Subv): Find out how AM determines the display to use, for now just create the layer 315 LOG_WARNING(Service_AM, "(STUBBED) called");
306 // in the Default display. 316 // TODO(Subv): Find out how AM determines the display to use, for now just
317 // create the layer in the Default display.
307 u64 display_id = nvflinger->OpenDisplay("Default"); 318 u64 display_id = nvflinger->OpenDisplay("Default");
308 u64 layer_id = nvflinger->CreateLayer(display_id); 319 u64 layer_id = nvflinger->CreateLayer(display_id);
309 320
310 IPC::ResponseBuilder rb{ctx, 4}; 321 IPC::ResponseBuilder rb{ctx, 4};
311 rb.Push(RESULT_SUCCESS); 322 rb.Push(RESULT_SUCCESS);
312 rb.Push(layer_id); 323 rb.Push(layer_id);
313
314 LOG_WARNING(Service_AM, "(STUBBED) called");
315} 324}
316 325
317void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { 326void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
327 LOG_WARNING(Service_AM, "(STUBBED) called");
328
318 IPC::ResponseBuilder rb{ctx, 2}; 329 IPC::ResponseBuilder rb{ctx, 2};
319 rb.Push(RESULT_SUCCESS); 330 rb.Push(RESULT_SUCCESS);
320
321 LOG_WARNING(Service_AM, "(STUBBED) called");
322} 331}
323 332
324void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { 333void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
325 IPC::RequestParser rp{ctx}; 334 IPC::RequestParser rp{ctx};
326 idle_time_detection_extension = rp.Pop<u32>(); 335 idle_time_detection_extension = rp.Pop<u32>();
336 LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
337 idle_time_detection_extension);
338
327 IPC::ResponseBuilder rb{ctx, 2}; 339 IPC::ResponseBuilder rb{ctx, 2};
328 rb.Push(RESULT_SUCCESS); 340 rb.Push(RESULT_SUCCESS);
329
330 LOG_WARNING(Service_AM, "(STUBBED) called");
331} 341}
332 342
333void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { 343void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
344 LOG_WARNING(Service_AM, "(STUBBED) called");
345
334 IPC::ResponseBuilder rb{ctx, 3}; 346 IPC::ResponseBuilder rb{ctx, 3};
335 rb.Push(RESULT_SUCCESS); 347 rb.Push(RESULT_SUCCESS);
336 rb.Push<u32>(idle_time_detection_extension); 348 rb.Push<u32>(idle_time_detection_extension);
337
338 LOG_WARNING(Service_AM, "(STUBBED) called");
339} 349}
340 350
341AppletMessageQueue::AppletMessageQueue() { 351AppletMessageQueue::AppletMessageQueue() {
342 auto& kernel = Core::System::GetInstance().Kernel(); 352 auto& kernel = Core::System::GetInstance().Kernel();
343 on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, 353 on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
344 "AMMessageQueue:OnMessageRecieved"); 354 "AMMessageQueue:OnMessageRecieved");
345 on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 355 on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
346 "AMMessageQueue:OperationModeChanged"); 356 kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged");
347} 357}
348 358
349AppletMessageQueue::~AppletMessageQueue() = default; 359AppletMessageQueue::~AppletMessageQueue() = default;
350 360
351const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const { 361const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent()
352 return on_new_message; 362 const {
363 return on_new_message.readable;
353} 364}
354 365
355const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const { 366const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
356 return on_operation_mode_changed; 367 const {
368 return on_operation_mode_changed.readable;
357} 369}
358 370
359void AppletMessageQueue::PushMessage(AppletMessage msg) { 371void AppletMessageQueue::PushMessage(AppletMessage msg) {
360 messages.push(msg); 372 messages.push(msg);
361 on_new_message->Signal(); 373 on_new_message.writable->Signal();
362} 374}
363 375
364AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { 376AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
365 if (messages.empty()) { 377 if (messages.empty()) {
366 on_new_message->Clear(); 378 on_new_message.writable->Clear();
367 return AppletMessage::NoMessage; 379 return AppletMessage::NoMessage;
368 } 380 }
369 auto msg = messages.front(); 381 auto msg = messages.front();
370 messages.pop(); 382 messages.pop();
371 if (messages.empty()) { 383 if (messages.empty()) {
372 on_new_message->Clear(); 384 on_new_message.writable->Clear();
373 } 385 }
374 return msg; 386 return msg;
375} 387}
@@ -381,7 +393,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const {
381void AppletMessageQueue::OperationModeChanged() { 393void AppletMessageQueue::OperationModeChanged() {
382 PushMessage(AppletMessage::OperationModeChanged); 394 PushMessage(AppletMessage::OperationModeChanged);
383 PushMessage(AppletMessage::PerformanceModeChanged); 395 PushMessage(AppletMessage::PerformanceModeChanged);
384 on_operation_mode_changed->Signal(); 396 on_operation_mode_changed.writable->Signal();
385} 397}
386 398
387ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) 399ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
@@ -418,97 +430,131 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
418 // clang-format on 430 // clang-format on
419 431
420 RegisterHandlers(functions); 432 RegisterHandlers(functions);
421
422 auto& kernel = Core::System::GetInstance().Kernel();
423 event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
424} 433}
425 434
426ICommonStateGetter::~ICommonStateGetter() = default; 435ICommonStateGetter::~ICommonStateGetter() = default;
427 436
428void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { 437void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
438 LOG_DEBUG(Service_AM, "called");
439
429 IPC::ResponseBuilder rb{ctx, 3}; 440 IPC::ResponseBuilder rb{ctx, 3};
430 rb.Push(RESULT_SUCCESS); 441 rb.Push(RESULT_SUCCESS);
431 442
432 rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode 443 rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
433
434 LOG_DEBUG(Service_AM, "called");
435} 444}
436 445
437void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { 446void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
447 LOG_DEBUG(Service_AM, "called");
448
438 IPC::ResponseBuilder rb{ctx, 2, 1}; 449 IPC::ResponseBuilder rb{ctx, 2, 1};
439 rb.Push(RESULT_SUCCESS); 450 rb.Push(RESULT_SUCCESS);
440 rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); 451 rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent());
441
442 LOG_DEBUG(Service_AM, "called");
443} 452}
444 453
445void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { 454void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
455 LOG_DEBUG(Service_AM, "called");
456
446 IPC::ResponseBuilder rb{ctx, 3}; 457 IPC::ResponseBuilder rb{ctx, 3};
447 rb.Push(RESULT_SUCCESS); 458 rb.Push(RESULT_SUCCESS);
448 rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage()); 459 rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage());
449
450 LOG_DEBUG(Service_AM, "called");
451} 460}
452 461
453void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { 462void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
463 LOG_WARNING(Service_AM, "(STUBBED) called");
464
454 IPC::ResponseBuilder rb{ctx, 3}; 465 IPC::ResponseBuilder rb{ctx, 3};
455 rb.Push(RESULT_SUCCESS); 466 rb.Push(RESULT_SUCCESS);
456 rb.Push(static_cast<u8>(FocusState::InFocus)); 467 rb.Push(static_cast<u8>(FocusState::InFocus));
457
458 LOG_WARNING(Service_AM, "(STUBBED) called");
459} 468}
460 469
461void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { 470void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
471 LOG_DEBUG(Service_AM, "called");
472
462 IPC::ResponseBuilder rb{ctx, 2, 1}; 473 IPC::ResponseBuilder rb{ctx, 2, 1};
463 rb.Push(RESULT_SUCCESS); 474 rb.Push(RESULT_SUCCESS);
464 rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); 475 rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
465
466 LOG_DEBUG(Service_AM, "called");
467} 476}
468 477
469void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { 478void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
479 LOG_DEBUG(Service_AM, "called");
480
470 IPC::ResponseBuilder rb{ctx, 4}; 481 IPC::ResponseBuilder rb{ctx, 4};
471 rb.Push(RESULT_SUCCESS); 482 rb.Push(RESULT_SUCCESS);
472 483
473 if (Settings::values.use_docked_mode) { 484 if (Settings::values.use_docked_mode) {
474 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); 485 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
475 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); 486 static_cast<u32>(Settings::values.resolution_factor));
487 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
488 static_cast<u32>(Settings::values.resolution_factor));
476 } else { 489 } else {
477 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); 490 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
478 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); 491 static_cast<u32>(Settings::values.resolution_factor));
492 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
493 static_cast<u32>(Settings::values.resolution_factor));
479 } 494 }
495}
480 496
481 LOG_DEBUG(Service_AM, "called"); 497IStorage::IStorage(std::vector<u8> buffer)
498 : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
499 // clang-format off
500 static const FunctionInfo functions[] = {
501 {0, &IStorage::Open, "Open"},
502 {1, nullptr, "OpenTransferStorage"},
503 };
504 // clang-format on
505
506 RegisterHandlers(functions);
507}
508
509IStorage::~IStorage() = default;
510
511const std::vector<u8>& IStorage::GetData() const {
512 return buffer;
482} 513}
483 514
484void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { 515void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
485 const bool use_docked_mode{Settings::values.use_docked_mode}; 516 const bool use_docked_mode{Settings::values.use_docked_mode};
517 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
518
486 IPC::ResponseBuilder rb{ctx, 3}; 519 IPC::ResponseBuilder rb{ctx, 3};
487 rb.Push(RESULT_SUCCESS); 520 rb.Push(RESULT_SUCCESS);
488 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); 521 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
489
490 LOG_DEBUG(Service_AM, "called");
491} 522}
492 523
493void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { 524void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
494 const bool use_docked_mode{Settings::values.use_docked_mode}; 525 const bool use_docked_mode{Settings::values.use_docked_mode};
526 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
527
495 IPC::ResponseBuilder rb{ctx, 3}; 528 IPC::ResponseBuilder rb{ctx, 3};
496 rb.Push(RESULT_SUCCESS); 529 rb.Push(RESULT_SUCCESS);
497 rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked 530 rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
498 : APM::PerformanceMode::Handheld)); 531 : APM::PerformanceMode::Handheld));
499
500 LOG_DEBUG(Service_AM, "called");
501} 532}
502 533
503class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { 534class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
504public: 535public:
505 explicit IStorageAccessor(std::vector<u8> buffer) 536 explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet)
506 : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { 537 : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) {
507 // clang-format off 538 // clang-format off
508 static const FunctionInfo functions[] = { 539 static const FunctionInfo functions[] = {
509 {0, &IStorageAccessor::GetSize, "GetSize"}, 540 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
510 {10, &IStorageAccessor::Write, "Write"}, 541 {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
511 {11, &IStorageAccessor::Read, "Read"}, 542 {10, &ILibraryAppletAccessor::Start, "Start"},
543 {20, nullptr, "RequestExit"},
544 {25, nullptr, "Terminate"},
545 {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
546 {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
547 {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
548 {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
549 {102, nullptr, "PushExtraStorage"},
550 {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
551 {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
552 {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
553 {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
554 {110, nullptr, "NeedsToExitProcess"},
555 {120, nullptr, "GetLibraryAppletInfo"},
556 {150, nullptr, "RequestForAppletToGetForeground"},
557 {160, nullptr, "GetIndirectLayerConsumerHandle"},
512 }; 558 };
513 // clang-format on 559 // clang-format on
514 560
@@ -516,158 +562,200 @@ public:
516 } 562 }
517 563
518private: 564private:
519 std::vector<u8> buffer; 565 void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
566 LOG_DEBUG(Service_AM, "called");
520 567
521 void GetSize(Kernel::HLERequestContext& ctx) { 568 applet->GetBroker().SignalStateChanged();
522 IPC::ResponseBuilder rb{ctx, 4}; 569 const auto event = applet->GetBroker().GetStateChangedEvent();
523 570
571 IPC::ResponseBuilder rb{ctx, 2, 1};
524 rb.Push(RESULT_SUCCESS); 572 rb.Push(RESULT_SUCCESS);
525 rb.Push(static_cast<u64>(buffer.size())); 573 rb.PushCopyObjects(event);
574 }
526 575
576 void IsCompleted(Kernel::HLERequestContext& ctx) {
527 LOG_DEBUG(Service_AM, "called"); 577 LOG_DEBUG(Service_AM, "called");
578
579 IPC::ResponseBuilder rb{ctx, 3};
580 rb.Push(RESULT_SUCCESS);
581 rb.Push<u32>(applet->TransactionComplete());
528 } 582 }
529 583
530 void Write(Kernel::HLERequestContext& ctx) { 584 void GetResult(Kernel::HLERequestContext& ctx) {
531 IPC::RequestParser rp{ctx}; 585 LOG_DEBUG(Service_AM, "called");
532 586
533 const u64 offset{rp.Pop<u64>()}; 587 IPC::ResponseBuilder rb{ctx, 2};
534 const std::vector<u8> data{ctx.ReadBuffer()}; 588 rb.Push(applet->GetStatus());
589 }
535 590
536 ASSERT(offset + data.size() <= buffer.size()); 591 void Start(Kernel::HLERequestContext& ctx) {
592 LOG_DEBUG(Service_AM, "called");
537 593
538 std::memcpy(&buffer[offset], data.data(), data.size()); 594 ASSERT(applet != nullptr);
595
596 applet->Initialize();
597 applet->Execute();
539 598
540 IPC::ResponseBuilder rb{ctx, 2}; 599 IPC::ResponseBuilder rb{ctx, 2};
541 rb.Push(RESULT_SUCCESS); 600 rb.Push(RESULT_SUCCESS);
542
543 LOG_DEBUG(Service_AM, "called, offset={}", offset);
544 } 601 }
545 602
546 void Read(Kernel::HLERequestContext& ctx) { 603 void PushInData(Kernel::HLERequestContext& ctx) {
604 LOG_DEBUG(Service_AM, "called");
605
547 IPC::RequestParser rp{ctx}; 606 IPC::RequestParser rp{ctx};
607 applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
608
609 IPC::ResponseBuilder rb{ctx, 2};
610 rb.Push(RESULT_SUCCESS);
611 }
612
613 void PopOutData(Kernel::HLERequestContext& ctx) {
614 LOG_DEBUG(Service_AM, "called");
548 615
549 const u64 offset{rp.Pop<u64>()}; 616 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
550 const std::size_t size{ctx.GetWriteBufferSize()};
551 617
552 ASSERT(offset + size <= buffer.size()); 618 const auto storage = applet->GetBroker().PopNormalDataToGame();
619 if (storage == nullptr) {
620 LOG_ERROR(Service_AM,
621 "storage is a nullptr. There is no data in the current normal channel");
553 622
554 ctx.WriteBuffer(buffer.data() + offset, size); 623 rb.Push(ERR_NO_DATA_IN_CHANNEL);
624 return;
625 }
555 626
556 IPC::ResponseBuilder rb{ctx, 2};
557 rb.Push(RESULT_SUCCESS); 627 rb.Push(RESULT_SUCCESS);
558 628 rb.PushIpcInterface<IStorage>(std::move(*storage));
559 LOG_DEBUG(Service_AM, "called, offset={}", offset);
560 } 629 }
561};
562 630
563class IStorage final : public ServiceFramework<IStorage> { 631 void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
564public: 632 LOG_DEBUG(Service_AM, "called");
565 explicit IStorage(std::vector<u8> buffer)
566 : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
567 // clang-format off
568 static const FunctionInfo functions[] = {
569 {0, &IStorage::Open, "Open"},
570 {1, nullptr, "OpenTransferStorage"},
571 };
572 // clang-format on
573 633
574 RegisterHandlers(functions); 634 IPC::RequestParser rp{ctx};
635 applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
636
637 ASSERT(applet->IsInitialized());
638 applet->ExecuteInteractive();
639 applet->Execute();
640
641 IPC::ResponseBuilder rb{ctx, 2};
642 rb.Push(RESULT_SUCCESS);
575 } 643 }
576 644
577private: 645 void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
578 std::vector<u8> buffer; 646 LOG_DEBUG(Service_AM, "called");
579 647
580 void Open(Kernel::HLERequestContext& ctx) {
581 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 648 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
582 649
650 const auto storage = applet->GetBroker().PopInteractiveDataToGame();
651 if (storage == nullptr) {
652 LOG_ERROR(Service_AM,
653 "storage is a nullptr. There is no data in the current interactive channel");
654
655 rb.Push(ERR_NO_DATA_IN_CHANNEL);
656 return;
657 }
658
659 rb.Push(RESULT_SUCCESS);
660 rb.PushIpcInterface<IStorage>(std::move(*storage));
661 }
662
663 void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
664 LOG_DEBUG(Service_AM, "called");
665
666 IPC::ResponseBuilder rb{ctx, 2, 1};
583 rb.Push(RESULT_SUCCESS); 667 rb.Push(RESULT_SUCCESS);
584 rb.PushIpcInterface<AM::IStorageAccessor>(buffer); 668 rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent());
669 }
585 670
671 void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
586 LOG_DEBUG(Service_AM, "called"); 672 LOG_DEBUG(Service_AM, "called");
673
674 IPC::ResponseBuilder rb{ctx, 2, 1};
675 rb.Push(RESULT_SUCCESS);
676 rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent());
587 } 677 }
678
679 std::shared_ptr<Applets::Applet> applet;
588}; 680};
589 681
590class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { 682void IStorage::Open(Kernel::HLERequestContext& ctx) {
591public: 683 LOG_DEBUG(Service_AM, "called");
592 explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") { 684
593 // clang-format off 685 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
686
687 rb.Push(RESULT_SUCCESS);
688 rb.PushIpcInterface<IStorageAccessor>(*this);
689}
690
691IStorageAccessor::IStorageAccessor(IStorage& storage)
692 : ServiceFramework("IStorageAccessor"), backing(storage) {
693 // clang-format off
594 static const FunctionInfo functions[] = { 694 static const FunctionInfo functions[] = {
595 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, 695 {0, &IStorageAccessor::GetSize, "GetSize"},
596 {1, nullptr, "IsCompleted"}, 696 {10, &IStorageAccessor::Write, "Write"},
597 {10, &ILibraryAppletAccessor::Start, "Start"}, 697 {11, &IStorageAccessor::Read, "Read"},
598 {20, nullptr, "RequestExit"},
599 {25, nullptr, "Terminate"},
600 {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
601 {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
602 {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
603 {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
604 {102, nullptr, "PushExtraStorage"},
605 {103, nullptr, "PushInteractiveInData"},
606 {104, nullptr, "PopInteractiveOutData"},
607 {105, nullptr, "GetPopOutDataEvent"},
608 {106, nullptr, "GetPopInteractiveOutDataEvent"},
609 {110, nullptr, "NeedsToExitProcess"},
610 {120, nullptr, "GetLibraryAppletInfo"},
611 {150, nullptr, "RequestForAppletToGetForeground"},
612 {160, nullptr, "GetIndirectLayerConsumerHandle"},
613 }; 698 };
614 // clang-format on 699 // clang-format on
615 700
616 RegisterHandlers(functions); 701 RegisterHandlers(functions);
702}
617 703
618 auto& kernel = Core::System::GetInstance().Kernel(); 704IStorageAccessor::~IStorageAccessor() = default;
619 state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
620 "ILibraryAppletAccessor:StateChangedEvent");
621 }
622 705
623private: 706void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
624 void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { 707 LOG_DEBUG(Service_AM, "called");
625 state_changed_event->Signal();
626 708
627 IPC::ResponseBuilder rb{ctx, 2, 1}; 709 IPC::ResponseBuilder rb{ctx, 4};
628 rb.Push(RESULT_SUCCESS);
629 rb.PushCopyObjects(state_changed_event);
630 710
631 LOG_WARNING(Service_AM, "(STUBBED) called"); 711 rb.Push(RESULT_SUCCESS);
632 } 712 rb.Push(static_cast<u64>(backing.buffer.size()));
713}
633 714
634 void GetResult(Kernel::HLERequestContext& ctx) { 715void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
635 IPC::ResponseBuilder rb{ctx, 2}; 716 IPC::RequestParser rp{ctx};
636 rb.Push(RESULT_SUCCESS);
637 717
638 LOG_WARNING(Service_AM, "(STUBBED) called"); 718 const u64 offset{rp.Pop<u64>()};
639 } 719 LOG_DEBUG(Service_AM, "called, offset={}", offset);
640 720
641 void Start(Kernel::HLERequestContext& ctx) { 721 const std::vector<u8> data{ctx.ReadBuffer()};
642 IPC::ResponseBuilder rb{ctx, 2}; 722
643 rb.Push(RESULT_SUCCESS); 723 if (data.size() > backing.buffer.size() - offset) {
724 LOG_ERROR(Service_AM,
725 "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
726 backing.buffer.size(), data.size(), offset);
644 727
645 LOG_WARNING(Service_AM, "(STUBBED) called"); 728 IPC::ResponseBuilder rb{ctx, 2};
729 rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
646 } 730 }
647 731
648 void PushInData(Kernel::HLERequestContext& ctx) { 732 std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
649 IPC::RequestParser rp{ctx};
650 storage_stack.push(rp.PopIpcInterface<AM::IStorage>());
651 733
652 IPC::ResponseBuilder rb{ctx, 2}; 734 IPC::ResponseBuilder rb{ctx, 2};
653 rb.Push(RESULT_SUCCESS); 735 rb.Push(RESULT_SUCCESS);
736}
654 737
655 LOG_DEBUG(Service_AM, "called"); 738void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
656 } 739 IPC::RequestParser rp{ctx};
657 740
658 void PopOutData(Kernel::HLERequestContext& ctx) { 741 const u64 offset{rp.Pop<u64>()};
659 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 742 LOG_DEBUG(Service_AM, "called, offset={}", offset);
660 rb.Push(RESULT_SUCCESS);
661 rb.PushIpcInterface<AM::IStorage>(std::move(storage_stack.top()));
662 743
663 storage_stack.pop(); 744 const std::size_t size{ctx.GetWriteBufferSize()};
664 745
665 LOG_DEBUG(Service_AM, "called"); 746 if (size > backing.buffer.size() - offset) {
747 LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
748 backing.buffer.size(), size, offset);
749
750 IPC::ResponseBuilder rb{ctx, 2};
751 rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
666 } 752 }
667 753
668 std::stack<std::shared_ptr<AM::IStorage>> storage_stack; 754 ctx.WriteBuffer(backing.buffer.data() + offset, size);
669 Kernel::SharedPtr<Kernel::Event> state_changed_event; 755
670}; 756 IPC::ResponseBuilder rb{ctx, 2};
757 rb.Push(RESULT_SUCCESS);
758}
671 759
672ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { 760ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {
673 static const FunctionInfo functions[] = { 761 static const FunctionInfo functions[] = {
@@ -675,7 +763,7 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple
675 {1, nullptr, "TerminateAllLibraryApplets"}, 763 {1, nullptr, "TerminateAllLibraryApplets"},
676 {2, nullptr, "AreAnyLibraryAppletsLeft"}, 764 {2, nullptr, "AreAnyLibraryAppletsLeft"},
677 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, 765 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
678 {11, nullptr, "CreateTransferMemoryStorage"}, 766 {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
679 {12, nullptr, "CreateHandleStorage"}, 767 {12, nullptr, "CreateHandleStorage"},
680 }; 768 };
681 RegisterHandlers(functions); 769 RegisterHandlers(functions);
@@ -683,25 +771,79 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple
683 771
684ILibraryAppletCreator::~ILibraryAppletCreator() = default; 772ILibraryAppletCreator::~ILibraryAppletCreator() = default;
685 773
774static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
775 switch (id) {
776 case AppletId::SoftwareKeyboard:
777 return std::make_shared<Applets::SoftwareKeyboard>();
778 default:
779 LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!",
780 static_cast<u32>(id));
781 return std::make_shared<Applets::StubApplet>();
782 }
783}
784
686void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { 785void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
786 IPC::RequestParser rp{ctx};
787 const auto applet_id = rp.PopRaw<AppletId>();
788 const auto applet_mode = rp.PopRaw<u32>();
789
790 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}",
791 static_cast<u32>(applet_id), applet_mode);
792
793 const auto applet = GetAppletFromId(applet_id);
794
795 if (applet == nullptr) {
796 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
797
798 IPC::ResponseBuilder rb{ctx, 2};
799 rb.Push(ResultCode(-1));
800 return;
801 }
802
687 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 803 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
688 804
689 rb.Push(RESULT_SUCCESS); 805 rb.Push(RESULT_SUCCESS);
690 rb.PushIpcInterface<AM::ILibraryAppletAccessor>(); 806 rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet);
691
692 LOG_DEBUG(Service_AM, "called");
693} 807}
694 808
695void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { 809void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
696 IPC::RequestParser rp{ctx}; 810 IPC::RequestParser rp{ctx};
697 const u64 size{rp.Pop<u64>()}; 811 const u64 size{rp.Pop<u64>()};
812 LOG_DEBUG(Service_AM, "called, size={}", size);
813
698 std::vector<u8> buffer(size); 814 std::vector<u8> buffer(size);
699 815
700 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 816 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
701 rb.Push(RESULT_SUCCESS); 817 rb.Push(RESULT_SUCCESS);
702 rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); 818 rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
819}
703 820
704 LOG_DEBUG(Service_AM, "called, size={}", size); 821void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
822 LOG_DEBUG(Service_AM, "called");
823
824 IPC::RequestParser rp{ctx};
825
826 rp.SetCurrentOffset(3);
827 const auto handle{rp.Pop<Kernel::Handle>()};
828
829 const auto shared_mem =
830 Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::SharedMemory>(
831 handle);
832
833 if (shared_mem == nullptr) {
834 LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
835 IPC::ResponseBuilder rb{ctx, 2};
836 rb.Push(ResultCode(-1));
837 return;
838 }
839
840 const u8* mem_begin = shared_mem->GetPointer();
841 const u8* mem_end = mem_begin + shared_mem->GetSize();
842 std::vector<u8> memory{mem_begin, mem_end};
843
844 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
845 rb.Push(RESULT_SUCCESS);
846 rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory)));
705} 847}
706 848
707IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { 849IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
@@ -733,7 +875,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
733 {70, nullptr, "RequestToShutdown"}, 875 {70, nullptr, "RequestToShutdown"},
734 {71, nullptr, "RequestToReboot"}, 876 {71, nullptr, "RequestToReboot"},
735 {80, nullptr, "ExitAndRequestToShowThanksMessage"}, 877 {80, nullptr, "ExitAndRequestToShowThanksMessage"},
736 {90, nullptr, "EnableApplicationCrashReport"}, 878 {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
737 {100, nullptr, "InitializeApplicationCopyrightFrameBuffer"}, 879 {100, nullptr, "InitializeApplicationCopyrightFrameBuffer"},
738 {101, nullptr, "SetApplicationCopyrightImage"}, 880 {101, nullptr, "SetApplicationCopyrightImage"},
739 {102, nullptr, "SetApplicationCopyrightVisibility"}, 881 {102, nullptr, "SetApplicationCopyrightVisibility"},
@@ -752,33 +894,46 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
752 894
753IApplicationFunctions::~IApplicationFunctions() = default; 895IApplicationFunctions::~IApplicationFunctions() = default;
754 896
897void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) {
898 LOG_WARNING(Service_AM, "(STUBBED) called");
899
900 IPC::ResponseBuilder rb{ctx, 2};
901 rb.Push(RESULT_SUCCESS);
902}
903
755void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed( 904void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(
756 Kernel::HLERequestContext& ctx) { 905 Kernel::HLERequestContext& ctx) {
906 LOG_WARNING(Service_AM, "(STUBBED) called");
907
757 IPC::ResponseBuilder rb{ctx, 2}; 908 IPC::ResponseBuilder rb{ctx, 2};
758 rb.Push(RESULT_SUCCESS); 909 rb.Push(RESULT_SUCCESS);
759 LOG_WARNING(Service_AM, "(STUBBED) called");
760} 910}
761 911
762void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed( 912void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(
763 Kernel::HLERequestContext& ctx) { 913 Kernel::HLERequestContext& ctx) {
914 LOG_WARNING(Service_AM, "(STUBBED) called");
915
764 IPC::ResponseBuilder rb{ctx, 2}; 916 IPC::ResponseBuilder rb{ctx, 2};
765 rb.Push(RESULT_SUCCESS); 917 rb.Push(RESULT_SUCCESS);
766 LOG_WARNING(Service_AM, "(STUBBED) called");
767} 918}
768 919
769void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) { 920void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) {
921 LOG_WARNING(Service_AM, "(STUBBED) called");
922
770 IPC::ResponseBuilder rb{ctx, 2}; 923 IPC::ResponseBuilder rb{ctx, 2};
771 rb.Push(RESULT_SUCCESS); 924 rb.Push(RESULT_SUCCESS);
772 LOG_WARNING(Service_AM, "(STUBBED) called");
773} 925}
774 926
775void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) { 927void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) {
928 LOG_WARNING(Service_AM, "(STUBBED) called");
929
776 IPC::ResponseBuilder rb{ctx, 2}; 930 IPC::ResponseBuilder rb{ctx, 2};
777 rb.Push(RESULT_SUCCESS); 931 rb.Push(RESULT_SUCCESS);
778 LOG_WARNING(Service_AM, "(STUBBED) called");
779} 932}
780 933
781void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { 934void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
935 LOG_DEBUG(Service_AM, "called");
936
782 LaunchParameters params{}; 937 LaunchParameters params{};
783 938
784 params.magic = POP_LAUNCH_PARAMETER_MAGIC; 939 params.magic = POP_LAUNCH_PARAMETER_MAGIC;
@@ -797,21 +952,19 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
797 std::memcpy(buffer.data(), &params, buffer.size()); 952 std::memcpy(buffer.data(), &params, buffer.size());
798 953
799 rb.PushIpcInterface<AM::IStorage>(buffer); 954 rb.PushIpcInterface<AM::IStorage>(buffer);
800
801 LOG_DEBUG(Service_AM, "called");
802} 955}
803 956
804void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( 957void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
805 Kernel::HLERequestContext& ctx) { 958 Kernel::HLERequestContext& ctx) {
959 LOG_WARNING(Service_AM, "(STUBBED) called");
960
806 IPC::ResponseBuilder rb{ctx, 2}; 961 IPC::ResponseBuilder rb{ctx, 2};
807 rb.Push(RESULT_SUCCESS); 962 rb.Push(RESULT_SUCCESS);
808 LOG_WARNING(Service_AM, "(STUBBED) called");
809} 963}
810 964
811void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { 965void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
812 IPC::RequestParser rp{ctx}; 966 IPC::RequestParser rp{ctx};
813 u128 uid = rp.PopRaw<u128>(); // What does this do? 967 u128 uid = rp.PopRaw<u128>(); // What does this do?
814
815 LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); 968 LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
816 969
817 IPC::ResponseBuilder rb{ctx, 4}; 970 IPC::ResponseBuilder rb{ctx, 4};
@@ -821,71 +974,74 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
821 974
822void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { 975void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
823 // Takes an input u32 Result, no output. 976 // Takes an input u32 Result, no output.
824 // For example, in some cases official apps use this with error 0x2A2 then uses svcBreak. 977 // For example, in some cases official apps use this with error 0x2A2 then
978 // uses svcBreak.
825 979
826 IPC::RequestParser rp{ctx}; 980 IPC::RequestParser rp{ctx};
827 u32 result = rp.Pop<u32>(); 981 u32 result = rp.Pop<u32>();
982 LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
828 983
829 IPC::ResponseBuilder rb{ctx, 2}; 984 IPC::ResponseBuilder rb{ctx, 2};
830 rb.Push(RESULT_SUCCESS); 985 rb.Push(RESULT_SUCCESS);
831
832 LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
833} 986}
834 987
835void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { 988void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
989 LOG_WARNING(Service_AM, "(STUBBED) called");
990
836 IPC::ResponseBuilder rb{ctx, 6}; 991 IPC::ResponseBuilder rb{ctx, 6};
837 rb.Push(RESULT_SUCCESS); 992 rb.Push(RESULT_SUCCESS);
838 rb.Push<u64>(1); 993 rb.Push<u64>(1);
839 rb.Push<u64>(0); 994 rb.Push<u64>(0);
840 LOG_WARNING(Service_AM, "(STUBBED) called");
841} 995}
842 996
843void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { 997void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
844 // TODO(bunnei): This should be configurable 998 // TODO(bunnei): This should be configurable
999 LOG_DEBUG(Service_AM, "called");
1000
845 IPC::ResponseBuilder rb{ctx, 4}; 1001 IPC::ResponseBuilder rb{ctx, 4};
846 rb.Push(RESULT_SUCCESS); 1002 rb.Push(RESULT_SUCCESS);
847 rb.Push( 1003 rb.Push(
848 static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index))); 1004 static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index)));
849 LOG_DEBUG(Service_AM, "called");
850} 1005}
851 1006
852void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { 1007void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
1008 LOG_WARNING(Service_AM, "(STUBBED) called");
1009
853 IPC::ResponseBuilder rb{ctx, 2}; 1010 IPC::ResponseBuilder rb{ctx, 2};
854 rb.Push(RESULT_SUCCESS); 1011 rb.Push(RESULT_SUCCESS);
855 LOG_WARNING(Service_AM, "(STUBBED) called");
856} 1012}
857 1013
858void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { 1014void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) {
1015 LOG_WARNING(Service_AM, "(STUBBED) called");
1016
859 IPC::ResponseBuilder rb{ctx, 2}; 1017 IPC::ResponseBuilder rb{ctx, 2};
860 rb.Push(RESULT_SUCCESS); 1018 rb.Push(RESULT_SUCCESS);
861
862 LOG_WARNING(Service_AM, "(STUBBED) called");
863} 1019}
864 1020
865void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { 1021void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
1022 LOG_WARNING(Service_AM, "(STUBBED) called");
1023
866 IPC::ResponseBuilder rb{ctx, 3}; 1024 IPC::ResponseBuilder rb{ctx, 3};
867 rb.Push(RESULT_SUCCESS); 1025 rb.Push(RESULT_SUCCESS);
868 rb.Push<u8>(0); // Unknown, seems to be ignored by official processes 1026 rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
869
870 LOG_WARNING(Service_AM, "(STUBBED) called");
871} 1027}
872 1028
873void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { 1029void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
1030 LOG_WARNING(Service_AM, "(STUBBED) called");
1031
874 IPC::ResponseBuilder rb{ctx, 6}; 1032 IPC::ResponseBuilder rb{ctx, 6};
875 rb.Push(RESULT_SUCCESS); 1033 rb.Push(RESULT_SUCCESS);
876 1034
877 // Returns a 128-bit UUID 1035 // Returns a 128-bit UUID
878 rb.Push<u64>(0); 1036 rb.Push<u64>(0);
879 rb.Push<u64>(0); 1037 rb.Push<u64>(0);
880
881 LOG_WARNING(Service_AM, "(STUBBED) called");
882} 1038}
883 1039
884void InstallInterfaces(SM::ServiceManager& service_manager, 1040void InstallInterfaces(SM::ServiceManager& service_manager,
885 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { 1041 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
886 auto message_queue = std::make_shared<AppletMessageQueue>(); 1042 auto message_queue = std::make_shared<AppletMessageQueue>();
887 message_queue->PushMessage( 1043 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on
888 AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on game boot 1044 // game boot
889 1045
890 std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager); 1046 std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
891 std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager); 1047 std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
@@ -915,9 +1071,10 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
915IHomeMenuFunctions::~IHomeMenuFunctions() = default; 1071IHomeMenuFunctions::~IHomeMenuFunctions() = default;
916 1072
917void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { 1073void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
1074 LOG_WARNING(Service_AM, "(STUBBED) called");
1075
918 IPC::ResponseBuilder rb{ctx, 2}; 1076 IPC::ResponseBuilder rb{ctx, 2};
919 rb.Push(RESULT_SUCCESS); 1077 rb.Push(RESULT_SUCCESS);
920 LOG_WARNING(Service_AM, "(STUBBED) called");
921} 1078}
922 1079
923IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { 1080IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") {
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 2f1c20bce..34c45fadf 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -6,12 +6,9 @@
6 6
7#include <memory> 7#include <memory>
8#include <queue> 8#include <queue>
9#include "core/hle/kernel/writable_event.h"
9#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
10 11
11namespace Kernel {
12class Event;
13}
14
15namespace Service { 12namespace Service {
16namespace NVFlinger { 13namespace NVFlinger {
17class NVFlinger; 14class NVFlinger;
@@ -52,8 +49,8 @@ public:
52 AppletMessageQueue(); 49 AppletMessageQueue();
53 ~AppletMessageQueue(); 50 ~AppletMessageQueue();
54 51
55 const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const; 52 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
56 const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const; 53 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
57 void PushMessage(AppletMessage msg); 54 void PushMessage(AppletMessage msg);
58 AppletMessage PopMessage(); 55 AppletMessage PopMessage();
59 std::size_t GetMessageCount() const; 56 std::size_t GetMessageCount() const;
@@ -61,8 +58,8 @@ public:
61 58
62private: 59private:
63 std::queue<AppletMessage> messages; 60 std::queue<AppletMessage> messages;
64 Kernel::SharedPtr<Kernel::Event> on_new_message; 61 Kernel::EventPair on_new_message;
65 Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed; 62 Kernel::EventPair on_operation_mode_changed;
66}; 63};
67 64
68class IWindowController final : public ServiceFramework<IWindowController> { 65class IWindowController final : public ServiceFramework<IWindowController> {
@@ -122,7 +119,7 @@ private:
122 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); 119 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
123 120
124 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 121 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
125 Kernel::SharedPtr<Kernel::Event> launchable_event; 122 Kernel::EventPair launchable_event;
126 u32 idle_time_detection_extension = 0; 123 u32 idle_time_detection_extension = 0;
127}; 124};
128 125
@@ -151,10 +148,37 @@ private:
151 void GetBootMode(Kernel::HLERequestContext& ctx); 148 void GetBootMode(Kernel::HLERequestContext& ctx);
152 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); 149 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
153 150
154 Kernel::SharedPtr<Kernel::Event> event;
155 std::shared_ptr<AppletMessageQueue> msg_queue; 151 std::shared_ptr<AppletMessageQueue> msg_queue;
156}; 152};
157 153
154class IStorage final : public ServiceFramework<IStorage> {
155public:
156 explicit IStorage(std::vector<u8> buffer);
157 ~IStorage() override;
158
159 const std::vector<u8>& GetData() const;
160
161private:
162 void Open(Kernel::HLERequestContext& ctx);
163
164 std::vector<u8> buffer;
165
166 friend class IStorageAccessor;
167};
168
169class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
170public:
171 explicit IStorageAccessor(IStorage& backing);
172 ~IStorageAccessor() override;
173
174private:
175 void GetSize(Kernel::HLERequestContext& ctx);
176 void Write(Kernel::HLERequestContext& ctx);
177 void Read(Kernel::HLERequestContext& ctx);
178
179 IStorage& backing;
180};
181
158class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { 182class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
159public: 183public:
160 ILibraryAppletCreator(); 184 ILibraryAppletCreator();
@@ -163,6 +187,7 @@ public:
163private: 187private:
164 void CreateLibraryApplet(Kernel::HLERequestContext& ctx); 188 void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
165 void CreateStorage(Kernel::HLERequestContext& ctx); 189 void CreateStorage(Kernel::HLERequestContext& ctx);
190 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
166}; 191};
167 192
168class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { 193class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
@@ -185,6 +210,7 @@ private:
185 void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); 210 void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx);
186 void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); 211 void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx);
187 void EndBlockingHomeButton(Kernel::HLERequestContext& ctx); 212 void EndBlockingHomeButton(Kernel::HLERequestContext& ctx);
213 void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx);
188}; 214};
189 215
190class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { 216class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index ec93e3529..41a573a91 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -32,66 +32,75 @@ public:
32 32
33private: 33private:
34 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 34 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
35 LOG_DEBUG(Service_AM, "called");
36
35 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 37 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
36 rb.Push(RESULT_SUCCESS); 38 rb.Push(RESULT_SUCCESS);
37 rb.PushIpcInterface<ICommonStateGetter>(msg_queue); 39 rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
38 LOG_DEBUG(Service_AM, "called");
39 } 40 }
40 41
41 void GetSelfController(Kernel::HLERequestContext& ctx) { 42 void GetSelfController(Kernel::HLERequestContext& ctx) {
43 LOG_DEBUG(Service_AM, "called");
44
42 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 45 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
43 rb.Push(RESULT_SUCCESS); 46 rb.Push(RESULT_SUCCESS);
44 rb.PushIpcInterface<ISelfController>(nvflinger); 47 rb.PushIpcInterface<ISelfController>(nvflinger);
45 LOG_DEBUG(Service_AM, "called");
46 } 48 }
47 49
48 void GetWindowController(Kernel::HLERequestContext& ctx) { 50 void GetWindowController(Kernel::HLERequestContext& ctx) {
51 LOG_DEBUG(Service_AM, "called");
52
49 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 53 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
50 rb.Push(RESULT_SUCCESS); 54 rb.Push(RESULT_SUCCESS);
51 rb.PushIpcInterface<IWindowController>(); 55 rb.PushIpcInterface<IWindowController>();
52 LOG_DEBUG(Service_AM, "called");
53 } 56 }
54 57
55 void GetAudioController(Kernel::HLERequestContext& ctx) { 58 void GetAudioController(Kernel::HLERequestContext& ctx) {
59 LOG_DEBUG(Service_AM, "called");
60
56 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 61 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
57 rb.Push(RESULT_SUCCESS); 62 rb.Push(RESULT_SUCCESS);
58 rb.PushIpcInterface<IAudioController>(); 63 rb.PushIpcInterface<IAudioController>();
59 LOG_DEBUG(Service_AM, "called");
60 } 64 }
61 65
62 void GetDisplayController(Kernel::HLERequestContext& ctx) { 66 void GetDisplayController(Kernel::HLERequestContext& ctx) {
67 LOG_DEBUG(Service_AM, "called");
68
63 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 69 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
64 rb.Push(RESULT_SUCCESS); 70 rb.Push(RESULT_SUCCESS);
65 rb.PushIpcInterface<IDisplayController>(); 71 rb.PushIpcInterface<IDisplayController>();
66 LOG_DEBUG(Service_AM, "called");
67 } 72 }
68 73
69 void GetProcessWindingController(Kernel::HLERequestContext& ctx) { 74 void GetProcessWindingController(Kernel::HLERequestContext& ctx) {
75 LOG_DEBUG(Service_AM, "called");
76
70 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 77 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
71 rb.Push(RESULT_SUCCESS); 78 rb.Push(RESULT_SUCCESS);
72 rb.PushIpcInterface<IProcessWindingController>(); 79 rb.PushIpcInterface<IProcessWindingController>();
73 LOG_DEBUG(Service_AM, "called");
74 } 80 }
75 81
76 void GetDebugFunctions(Kernel::HLERequestContext& ctx) { 82 void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
83 LOG_DEBUG(Service_AM, "called");
84
77 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 85 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
78 rb.Push(RESULT_SUCCESS); 86 rb.Push(RESULT_SUCCESS);
79 rb.PushIpcInterface<IDebugFunctions>(); 87 rb.PushIpcInterface<IDebugFunctions>();
80 LOG_DEBUG(Service_AM, "called");
81 } 88 }
82 89
83 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { 90 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
91 LOG_DEBUG(Service_AM, "called");
92
84 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 93 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
85 rb.Push(RESULT_SUCCESS); 94 rb.Push(RESULT_SUCCESS);
86 rb.PushIpcInterface<ILibraryAppletCreator>(); 95 rb.PushIpcInterface<ILibraryAppletCreator>();
87 LOG_DEBUG(Service_AM, "called");
88 } 96 }
89 97
90 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { 98 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
99 LOG_DEBUG(Service_AM, "called");
100
91 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 101 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
92 rb.Push(RESULT_SUCCESS); 102 rb.Push(RESULT_SUCCESS);
93 rb.PushIpcInterface<IApplicationFunctions>(); 103 rb.PushIpcInterface<IApplicationFunctions>();
94 LOG_DEBUG(Service_AM, "called");
95 } 104 }
96 105
97 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 106 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -122,97 +131,110 @@ public:
122 131
123private: 132private:
124 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 133 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
134 LOG_DEBUG(Service_AM, "called");
135
125 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 136 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
126 rb.Push(RESULT_SUCCESS); 137 rb.Push(RESULT_SUCCESS);
127 rb.PushIpcInterface<ICommonStateGetter>(msg_queue); 138 rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
128 LOG_DEBUG(Service_AM, "called");
129 } 139 }
130 140
131 void GetSelfController(Kernel::HLERequestContext& ctx) { 141 void GetSelfController(Kernel::HLERequestContext& ctx) {
142 LOG_DEBUG(Service_AM, "called");
143
132 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 144 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
133 rb.Push(RESULT_SUCCESS); 145 rb.Push(RESULT_SUCCESS);
134 rb.PushIpcInterface<ISelfController>(nvflinger); 146 rb.PushIpcInterface<ISelfController>(nvflinger);
135 LOG_DEBUG(Service_AM, "called");
136 } 147 }
137 148
138 void GetWindowController(Kernel::HLERequestContext& ctx) { 149 void GetWindowController(Kernel::HLERequestContext& ctx) {
150 LOG_DEBUG(Service_AM, "called");
151
139 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 152 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
140 rb.Push(RESULT_SUCCESS); 153 rb.Push(RESULT_SUCCESS);
141 rb.PushIpcInterface<IWindowController>(); 154 rb.PushIpcInterface<IWindowController>();
142 LOG_DEBUG(Service_AM, "called");
143 } 155 }
144 156
145 void GetAudioController(Kernel::HLERequestContext& ctx) { 157 void GetAudioController(Kernel::HLERequestContext& ctx) {
158 LOG_DEBUG(Service_AM, "called");
159
146 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 160 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
147 rb.Push(RESULT_SUCCESS); 161 rb.Push(RESULT_SUCCESS);
148 rb.PushIpcInterface<IAudioController>(); 162 rb.PushIpcInterface<IAudioController>();
149 LOG_DEBUG(Service_AM, "called");
150 } 163 }
151 164
152 void GetDisplayController(Kernel::HLERequestContext& ctx) { 165 void GetDisplayController(Kernel::HLERequestContext& ctx) {
166 LOG_DEBUG(Service_AM, "called");
167
153 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 168 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
154 rb.Push(RESULT_SUCCESS); 169 rb.Push(RESULT_SUCCESS);
155 rb.PushIpcInterface<IDisplayController>(); 170 rb.PushIpcInterface<IDisplayController>();
156 LOG_DEBUG(Service_AM, "called");
157 } 171 }
158 172
159 void GetDebugFunctions(Kernel::HLERequestContext& ctx) { 173 void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
174 LOG_DEBUG(Service_AM, "called");
175
160 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 176 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
161 rb.Push(RESULT_SUCCESS); 177 rb.Push(RESULT_SUCCESS);
162 rb.PushIpcInterface<IDebugFunctions>(); 178 rb.PushIpcInterface<IDebugFunctions>();
163 LOG_DEBUG(Service_AM, "called");
164 } 179 }
165 180
166 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { 181 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
182 LOG_DEBUG(Service_AM, "called");
183
167 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 184 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
168 rb.Push(RESULT_SUCCESS); 185 rb.Push(RESULT_SUCCESS);
169 rb.PushIpcInterface<ILibraryAppletCreator>(); 186 rb.PushIpcInterface<ILibraryAppletCreator>();
170 LOG_DEBUG(Service_AM, "called");
171 } 187 }
172 188
173 void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { 189 void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
190 LOG_DEBUG(Service_AM, "called");
191
174 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 192 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
175 rb.Push(RESULT_SUCCESS); 193 rb.Push(RESULT_SUCCESS);
176 rb.PushIpcInterface<IHomeMenuFunctions>(); 194 rb.PushIpcInterface<IHomeMenuFunctions>();
177 LOG_DEBUG(Service_AM, "called");
178 } 195 }
179 196
180 void GetGlobalStateController(Kernel::HLERequestContext& ctx) { 197 void GetGlobalStateController(Kernel::HLERequestContext& ctx) {
198 LOG_DEBUG(Service_AM, "called");
199
181 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 200 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
182 rb.Push(RESULT_SUCCESS); 201 rb.Push(RESULT_SUCCESS);
183 rb.PushIpcInterface<IGlobalStateController>(); 202 rb.PushIpcInterface<IGlobalStateController>();
184 LOG_DEBUG(Service_AM, "called");
185 } 203 }
186 204
187 void GetApplicationCreator(Kernel::HLERequestContext& ctx) { 205 void GetApplicationCreator(Kernel::HLERequestContext& ctx) {
206 LOG_DEBUG(Service_AM, "called");
207
188 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 208 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
189 rb.Push(RESULT_SUCCESS); 209 rb.Push(RESULT_SUCCESS);
190 rb.PushIpcInterface<IApplicationCreator>(); 210 rb.PushIpcInterface<IApplicationCreator>();
191 LOG_DEBUG(Service_AM, "called");
192 } 211 }
193 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 212 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
194 std::shared_ptr<AppletMessageQueue> msg_queue; 213 std::shared_ptr<AppletMessageQueue> msg_queue;
195}; 214};
196 215
197void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { 216void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
217 LOG_DEBUG(Service_AM, "called");
218
198 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 219 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
199 rb.Push(RESULT_SUCCESS); 220 rb.Push(RESULT_SUCCESS);
200 rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue); 221 rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
201 LOG_DEBUG(Service_AM, "called");
202} 222}
203 223
204void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { 224void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
225 LOG_DEBUG(Service_AM, "called");
226
205 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 227 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
206 rb.Push(RESULT_SUCCESS); 228 rb.Push(RESULT_SUCCESS);
207 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); 229 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
208 LOG_DEBUG(Service_AM, "called");
209} 230}
210 231
211void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { 232void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
233 LOG_DEBUG(Service_AM, "called");
234
212 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 235 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
213 rb.Push(RESULT_SUCCESS); 236 rb.Push(RESULT_SUCCESS);
214 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); 237 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
215 LOG_DEBUG(Service_AM, "called");
216} 238}
217 239
218AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 240AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index 20c8d5fff..d3a0a1568 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -35,59 +35,67 @@ public:
35 35
36private: 36private:
37 void GetAudioController(Kernel::HLERequestContext& ctx) { 37 void GetAudioController(Kernel::HLERequestContext& ctx) {
38 LOG_DEBUG(Service_AM, "called");
39
38 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 40 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
39 rb.Push(RESULT_SUCCESS); 41 rb.Push(RESULT_SUCCESS);
40 rb.PushIpcInterface<IAudioController>(); 42 rb.PushIpcInterface<IAudioController>();
41 LOG_DEBUG(Service_AM, "called");
42 } 43 }
43 44
44 void GetDisplayController(Kernel::HLERequestContext& ctx) { 45 void GetDisplayController(Kernel::HLERequestContext& ctx) {
46 LOG_DEBUG(Service_AM, "called");
47
45 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 48 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
46 rb.Push(RESULT_SUCCESS); 49 rb.Push(RESULT_SUCCESS);
47 rb.PushIpcInterface<IDisplayController>(); 50 rb.PushIpcInterface<IDisplayController>();
48 LOG_DEBUG(Service_AM, "called");
49 } 51 }
50 52
51 void GetDebugFunctions(Kernel::HLERequestContext& ctx) { 53 void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
54 LOG_DEBUG(Service_AM, "called");
55
52 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 56 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
53 rb.Push(RESULT_SUCCESS); 57 rb.Push(RESULT_SUCCESS);
54 rb.PushIpcInterface<IDebugFunctions>(); 58 rb.PushIpcInterface<IDebugFunctions>();
55 LOG_DEBUG(Service_AM, "called");
56 } 59 }
57 60
58 void GetWindowController(Kernel::HLERequestContext& ctx) { 61 void GetWindowController(Kernel::HLERequestContext& ctx) {
62 LOG_DEBUG(Service_AM, "called");
63
59 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 64 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
60 rb.Push(RESULT_SUCCESS); 65 rb.Push(RESULT_SUCCESS);
61 rb.PushIpcInterface<IWindowController>(); 66 rb.PushIpcInterface<IWindowController>();
62 LOG_DEBUG(Service_AM, "called");
63 } 67 }
64 68
65 void GetSelfController(Kernel::HLERequestContext& ctx) { 69 void GetSelfController(Kernel::HLERequestContext& ctx) {
70 LOG_DEBUG(Service_AM, "called");
71
66 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 72 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
67 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
68 rb.PushIpcInterface<ISelfController>(nvflinger); 74 rb.PushIpcInterface<ISelfController>(nvflinger);
69 LOG_DEBUG(Service_AM, "called");
70 } 75 }
71 76
72 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 77 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
78 LOG_DEBUG(Service_AM, "called");
79
73 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 80 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
74 rb.Push(RESULT_SUCCESS); 81 rb.Push(RESULT_SUCCESS);
75 rb.PushIpcInterface<ICommonStateGetter>(msg_queue); 82 rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
76 LOG_DEBUG(Service_AM, "called");
77 } 83 }
78 84
79 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { 85 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
86 LOG_DEBUG(Service_AM, "called");
87
80 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 88 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
81 rb.Push(RESULT_SUCCESS); 89 rb.Push(RESULT_SUCCESS);
82 rb.PushIpcInterface<ILibraryAppletCreator>(); 90 rb.PushIpcInterface<ILibraryAppletCreator>();
83 LOG_DEBUG(Service_AM, "called");
84 } 91 }
85 92
86 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { 93 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
94 LOG_DEBUG(Service_AM, "called");
95
87 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 96 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
88 rb.Push(RESULT_SUCCESS); 97 rb.Push(RESULT_SUCCESS);
89 rb.PushIpcInterface<IApplicationFunctions>(); 98 rb.PushIpcInterface<IApplicationFunctions>();
90 LOG_DEBUG(Service_AM, "called");
91 } 99 }
92 100
93 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 101 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -95,10 +103,11 @@ private:
95}; 103};
96 104
97void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { 105void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
106 LOG_DEBUG(Service_AM, "called");
107
98 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 108 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
99 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
100 rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue); 110 rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
101 LOG_DEBUG(Service_AM, "called");
102} 111}
103 112
104AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 113AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
new file mode 100644
index 000000000..47da35537
--- /dev/null
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -0,0 +1,114 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/assert.h"
7#include "core/core.h"
8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/kernel/server_port.h"
10#include "core/hle/kernel/writable_event.h"
11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applets.h"
13
14namespace Service::AM::Applets {
15
16AppletDataBroker::AppletDataBroker() {
17 auto& kernel = Core::System::GetInstance().Kernel();
18 state_changed_event = Kernel::WritableEvent::CreateEventPair(
19 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:StateChangedEvent");
20 pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
21 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopDataOutEvent");
22 pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
23 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
24}
25
26AppletDataBroker::~AppletDataBroker() = default;
27
28std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
29 if (out_channel.empty())
30 return nullptr;
31
32 auto out = std::move(out_channel.front());
33 out_channel.pop();
34 return out;
35}
36
37std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
38 if (in_channel.empty())
39 return nullptr;
40
41 auto out = std::move(in_channel.front());
42 in_channel.pop();
43 return out;
44}
45
46std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
47 if (out_interactive_channel.empty())
48 return nullptr;
49
50 auto out = std::move(out_interactive_channel.front());
51 out_interactive_channel.pop();
52 return out;
53}
54
55std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
56 if (in_interactive_channel.empty())
57 return nullptr;
58
59 auto out = std::move(in_interactive_channel.front());
60 in_interactive_channel.pop();
61 return out;
62}
63
64void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
65 in_channel.push(std::make_unique<IStorage>(storage));
66}
67
68void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
69 out_channel.push(std::make_unique<IStorage>(storage));
70 pop_out_data_event.writable->Signal();
71}
72
73void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
74 in_interactive_channel.push(std::make_unique<IStorage>(storage));
75}
76
77void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
78 out_interactive_channel.push(std::make_unique<IStorage>(storage));
79 pop_interactive_out_data_event.writable->Signal();
80}
81
82void AppletDataBroker::SignalStateChanged() const {
83 state_changed_event.writable->Signal();
84}
85
86Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
87 return pop_out_data_event.readable;
88}
89
90Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
91 return pop_interactive_out_data_event.readable;
92}
93
94Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
95 return state_changed_event.readable;
96}
97
98Applet::Applet() = default;
99
100Applet::~Applet() = default;
101
102void Applet::Initialize() {
103 const auto common = broker.PopNormalDataToApplet();
104 ASSERT(common != nullptr);
105
106 const auto common_data = common->GetData();
107
108 ASSERT(common_data.size() >= sizeof(CommonArguments));
109 std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
110
111 initialized = true;
112}
113
114} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
new file mode 100644
index 000000000..b0a8913c3
--- /dev/null
+++ b/src/core/hle/service/am/applets/applets.h
@@ -0,0 +1,109 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <queue>
9#include "common/swap.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/writable_event.h"
12
13union ResultCode;
14
15namespace Service::AM {
16
17class IStorage;
18
19namespace Applets {
20
21class AppletDataBroker final {
22public:
23 AppletDataBroker();
24 ~AppletDataBroker();
25
26 std::unique_ptr<IStorage> PopNormalDataToGame();
27 std::unique_ptr<IStorage> PopNormalDataToApplet();
28
29 std::unique_ptr<IStorage> PopInteractiveDataToGame();
30 std::unique_ptr<IStorage> PopInteractiveDataToApplet();
31
32 void PushNormalDataFromGame(IStorage storage);
33 void PushNormalDataFromApplet(IStorage storage);
34
35 void PushInteractiveDataFromGame(IStorage storage);
36 void PushInteractiveDataFromApplet(IStorage storage);
37
38 void SignalStateChanged() const;
39
40 Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const;
41 Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const;
42 Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const;
43
44private:
45 // Queues are named from applet's perspective
46
47 // PopNormalDataToApplet and PushNormalDataFromGame
48 std::queue<std::unique_ptr<IStorage>> in_channel;
49
50 // PopNormalDataToGame and PushNormalDataFromApplet
51 std::queue<std::unique_ptr<IStorage>> out_channel;
52
53 // PopInteractiveDataToApplet and PushInteractiveDataFromGame
54 std::queue<std::unique_ptr<IStorage>> in_interactive_channel;
55
56 // PopInteractiveDataToGame and PushInteractiveDataFromApplet
57 std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
58
59 Kernel::EventPair state_changed_event;
60
61 // Signaled on PushNormalDataFromApplet
62 Kernel::EventPair pop_out_data_event;
63
64 // Signaled on PushInteractiveDataFromApplet
65 Kernel::EventPair pop_interactive_out_data_event;
66};
67
68class Applet {
69public:
70 Applet();
71 virtual ~Applet();
72
73 virtual void Initialize();
74
75 virtual bool TransactionComplete() const = 0;
76 virtual ResultCode GetStatus() const = 0;
77 virtual void ExecuteInteractive() = 0;
78 virtual void Execute() = 0;
79
80 bool IsInitialized() const {
81 return initialized;
82 }
83
84 AppletDataBroker& GetBroker() {
85 return broker;
86 }
87
88 const AppletDataBroker& GetBroker() const {
89 return broker;
90 }
91
92protected:
93 struct CommonArguments {
94 u32_le arguments_version;
95 u32_le size;
96 u32_le library_version;
97 u32_le theme_color;
98 u8 play_startup_sound;
99 u64_le system_tick;
100 };
101 static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
102
103 CommonArguments common_args{};
104 AppletDataBroker broker;
105 bool initialized = false;
106};
107
108} // namespace Applets
109} // namespace Service::AM
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
new file mode 100644
index 000000000..981bdec51
--- /dev/null
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -0,0 +1,161 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/assert.h"
7#include "common/string_util.h"
8#include "core/core.h"
9#include "core/frontend/applets/software_keyboard.h"
10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/software_keyboard.h"
12
13namespace Service::AM::Applets {
14
15constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8;
16constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4;
17constexpr std::size_t DEFAULT_MAX_LENGTH = 500;
18constexpr bool INTERACTIVE_STATUS_OK = false;
19
20static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
21 KeyboardConfig config, std::u16string initial_text) {
22 Core::Frontend::SoftwareKeyboardParameters params{};
23
24 params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
25 config.submit_text.data(), config.submit_text.size());
26 params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
27 config.header_text.data(), config.header_text.size());
28 params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(),
29 config.sub_text.size());
30 params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(),
31 config.guide_text.size());
32 params.initial_text = initial_text;
33 params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit;
34 params.password = static_cast<bool>(config.is_password);
35 params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position);
36 params.value = static_cast<u8>(config.keyset_disable_bitmask);
37
38 return params;
39}
40
41SoftwareKeyboard::SoftwareKeyboard() = default;
42
43SoftwareKeyboard::~SoftwareKeyboard() = default;
44
45void SoftwareKeyboard::Initialize() {
46 complete = false;
47 initial_text.clear();
48 final_data.clear();
49
50 Applet::Initialize();
51
52 const auto keyboard_config_storage = broker.PopNormalDataToApplet();
53 ASSERT(keyboard_config_storage != nullptr);
54 const auto& keyboard_config = keyboard_config_storage->GetData();
55
56 ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
57 std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
58
59 const auto work_buffer_storage = broker.PopNormalDataToApplet();
60 ASSERT(work_buffer_storage != nullptr);
61 const auto& work_buffer = work_buffer_storage->GetData();
62
63 if (config.initial_string_size == 0)
64 return;
65
66 std::vector<char16_t> string(config.initial_string_size);
67 std::memcpy(string.data(), work_buffer.data() + config.initial_string_offset,
68 string.size() * 2);
69 initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size());
70}
71
72bool SoftwareKeyboard::TransactionComplete() const {
73 return complete;
74}
75
76ResultCode SoftwareKeyboard::GetStatus() const {
77 return RESULT_SUCCESS;
78}
79
80void SoftwareKeyboard::ExecuteInteractive() {
81 if (complete)
82 return;
83
84 const auto storage = broker.PopInteractiveDataToApplet();
85 ASSERT(storage != nullptr);
86 const auto data = storage->GetData();
87 const auto status = static_cast<bool>(data[0]);
88
89 if (status == INTERACTIVE_STATUS_OK) {
90 complete = true;
91 } else {
92 const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
93
94 std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
95 std::memcpy(string.data(), data.data() + 4, string.size() * 2);
96 frontend.SendTextCheckDialog(
97 Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
98 [this] { broker.SignalStateChanged(); });
99 }
100}
101
102void SoftwareKeyboard::Execute() {
103 if (complete) {
104 broker.PushNormalDataFromApplet(IStorage{final_data});
105 return;
106 }
107
108 const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
109
110 const auto parameters = ConvertToFrontendParameters(config, initial_text);
111
112 frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); },
113 parameters);
114}
115
116void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
117 std::vector<u8> output_main(SWKBD_OUTPUT_BUFFER_SIZE);
118
119 if (text.has_value()) {
120 std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE);
121
122 if (config.utf_8) {
123 const u64 size = text->size() + 8;
124 const auto new_text = Common::UTF16ToUTF8(*text);
125
126 std::memcpy(output_sub.data(), &size, sizeof(u64));
127 std::memcpy(output_sub.data() + 8, new_text.data(),
128 std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 8));
129
130 output_main[0] = INTERACTIVE_STATUS_OK;
131 std::memcpy(output_main.data() + 4, new_text.data(),
132 std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4));
133 } else {
134 const u64 size = text->size() * 2 + 8;
135 std::memcpy(output_sub.data(), &size, sizeof(u64));
136 std::memcpy(output_sub.data() + 8, text->data(),
137 std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8));
138
139 output_main[0] = INTERACTIVE_STATUS_OK;
140 std::memcpy(output_main.data() + 4, text->data(),
141 std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4));
142 }
143
144 complete = !config.text_check;
145 final_data = output_main;
146
147 if (complete) {
148 broker.PushNormalDataFromApplet(IStorage{output_main});
149 } else {
150 broker.PushInteractiveDataFromApplet(IStorage{output_sub});
151 }
152
153 broker.SignalStateChanged();
154 } else {
155 output_main[0] = 1;
156 complete = true;
157 broker.PushNormalDataFromApplet(IStorage{output_main});
158 broker.SignalStateChanged();
159 }
160}
161} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
new file mode 100644
index 000000000..efd5753a1
--- /dev/null
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -0,0 +1,74 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <string>
9#include <vector>
10
11#include "common/common_funcs.h"
12#include "common/swap.h"
13#include "core/hle/service/am/am.h"
14#include "core/hle/service/am/applets/applets.h"
15
16namespace Service::AM::Applets {
17
18enum class KeysetDisable : u32 {
19 Space = 0x02,
20 Address = 0x04,
21 Percent = 0x08,
22 Slashes = 0x10,
23 Numbers = 0x40,
24 DownloadCode = 0x80,
25};
26
27struct KeyboardConfig {
28 INSERT_PADDING_BYTES(4);
29 std::array<char16_t, 9> submit_text;
30 u16_le left_symbol_key;
31 u16_le right_symbol_key;
32 INSERT_PADDING_BYTES(1);
33 KeysetDisable keyset_disable_bitmask;
34 u32_le initial_cursor_position;
35 std::array<char16_t, 65> header_text;
36 std::array<char16_t, 129> sub_text;
37 std::array<char16_t, 257> guide_text;
38 u32_le length_limit;
39 INSERT_PADDING_BYTES(4);
40 u32_le is_password;
41 INSERT_PADDING_BYTES(5);
42 bool utf_8;
43 bool draw_background;
44 u32_le initial_string_offset;
45 u32_le initial_string_size;
46 u32_le user_dictionary_offset;
47 u32_le user_dictionary_size;
48 bool text_check;
49 u64_le text_check_callback;
50};
51static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size.");
52
53class SoftwareKeyboard final : public Applet {
54public:
55 SoftwareKeyboard();
56 ~SoftwareKeyboard() override;
57
58 void Initialize() override;
59
60 bool TransactionComplete() const override;
61 ResultCode GetStatus() const override;
62 void ExecuteInteractive() override;
63 void Execute() override;
64
65 void WriteText(std::optional<std::u16string> text);
66
67private:
68 KeyboardConfig config;
69 std::u16string initial_text;
70 bool complete = false;
71 std::vector<u8> final_data;
72};
73
74} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/stub_applet.cpp b/src/core/hle/service/am/applets/stub_applet.cpp
new file mode 100644
index 000000000..ed166b87d
--- /dev/null
+++ b/src/core/hle/service/am/applets/stub_applet.cpp
@@ -0,0 +1,70 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <string>
6
7#include "common/hex_util.h"
8#include "common/logging/log.h"
9#include "core/hle/result.h"
10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/stub_applet.h"
12
13namespace Service::AM::Applets {
14
15static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) {
16 std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
17 for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
18 const auto data = storage->GetData();
19 LOG_INFO(Service_AM,
20 "called (STUBBED), during {} recieved normal data with size={:08X}, data={}",
21 prefix, data.size(), Common::HexVectorToString(data));
22 }
23
24 storage = broker.PopInteractiveDataToApplet();
25 for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
26 const auto data = storage->GetData();
27 LOG_INFO(Service_AM,
28 "called (STUBBED), during {} recieved interactive data with size={:08X}, data={}",
29 prefix, data.size(), Common::HexVectorToString(data));
30 }
31}
32
33StubApplet::StubApplet() = default;
34
35StubApplet::~StubApplet() = default;
36
37void StubApplet::Initialize() {
38 LOG_WARNING(Service_AM, "called (STUBBED)");
39 Applet::Initialize();
40 LogCurrentStorage(broker, "Initialize");
41}
42
43bool StubApplet::TransactionComplete() const {
44 LOG_WARNING(Service_AM, "called (STUBBED)");
45 return true;
46}
47
48ResultCode StubApplet::GetStatus() const {
49 LOG_WARNING(Service_AM, "called (STUBBED)");
50 return RESULT_SUCCESS;
51}
52
53void StubApplet::ExecuteInteractive() {
54 LOG_WARNING(Service_AM, "called (STUBBED)");
55 LogCurrentStorage(broker, "ExecuteInteractive");
56
57 broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
58 broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
59 broker.SignalStateChanged();
60}
61
62void StubApplet::Execute() {
63 LOG_WARNING(Service_AM, "called (STUBBED)");
64 LogCurrentStorage(broker, "Execute");
65
66 broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
67 broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
68 broker.SignalStateChanged();
69}
70} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/stub_applet.h b/src/core/hle/service/am/applets/stub_applet.h
new file mode 100644
index 000000000..7d8dc968d
--- /dev/null
+++ b/src/core/hle/service/am/applets/stub_applet.h
@@ -0,0 +1,24 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/am/applets/applets.h"
8
9namespace Service::AM::Applets {
10
11class StubApplet final : public Applet {
12public:
13 StubApplet();
14 ~StubApplet() override;
15
16 void Initialize() override;
17
18 bool TransactionComplete() const override;
19 ResultCode GetStatus() const override;
20 void ExecuteInteractive() override;
21 void Execute() override;
22};
23
24} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 54305cf05..0417fdb92 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -13,8 +13,10 @@
13#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/registered_cache.h" 14#include "core/file_sys/registered_cache.h"
15#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/readable_event.h"
19#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/aoc/aoc_u.h" 20#include "core/hle/service/aoc/aoc_u.h"
19#include "core/hle/service/filesystem/filesystem.h" 21#include "core/hle/service/filesystem/filesystem.h"
20#include "core/loader/loader.h" 22#include "core/loader/loader.h"
@@ -32,14 +34,14 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
32 std::vector<u64> add_on_content; 34 std::vector<u64> add_on_content;
33 const auto rcu = FileSystem::GetUnionContents(); 35 const auto rcu = FileSystem::GetUnionContents();
34 const auto list = 36 const auto list =
35 rcu->ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); 37 rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
36 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content), 38 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
37 [](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; }); 39 [](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; });
38 add_on_content.erase( 40 add_on_content.erase(
39 std::remove_if( 41 std::remove_if(
40 add_on_content.begin(), add_on_content.end(), 42 add_on_content.begin(), add_on_content.end(),
41 [&rcu](u64 tid) { 43 [&rcu](u64 tid) {
42 return rcu->GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() != 44 return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
43 Loader::ResultStatus::Success; 45 Loader::ResultStatus::Success;
44 }), 46 }),
45 add_on_content.end()); 47 add_on_content.end());
@@ -61,13 +63,15 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
61 RegisterHandlers(functions); 63 RegisterHandlers(functions);
62 64
63 auto& kernel = Core::System::GetInstance().Kernel(); 65 auto& kernel = Core::System::GetInstance().Kernel();
64 aoc_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, 66 aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
65 "GetAddOnContentListChanged:Event"); 67 "GetAddOnContentListChanged:Event");
66} 68}
67 69
68AOC_U::~AOC_U() = default; 70AOC_U::~AOC_U() = default;
69 71
70void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { 72void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
73 LOG_DEBUG(Service_AOC, "called");
74
71 IPC::ResponseBuilder rb{ctx, 3}; 75 IPC::ResponseBuilder rb{ctx, 3};
72 rb.Push(RESULT_SUCCESS); 76 rb.Push(RESULT_SUCCESS);
73 77
@@ -82,6 +86,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
82 86
83 const auto offset = rp.PopRaw<u32>(); 87 const auto offset = rp.PopRaw<u32>();
84 auto count = rp.PopRaw<u32>(); 88 auto count = rp.PopRaw<u32>();
89 LOG_DEBUG(Service_AOC, "called with offset={}, count={}", offset, count);
85 90
86 const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 91 const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
87 92
@@ -110,6 +115,8 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
110} 115}
111 116
112void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { 117void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
118 LOG_DEBUG(Service_AOC, "called");
119
113 IPC::ResponseBuilder rb{ctx, 4}; 120 IPC::ResponseBuilder rb{ctx, 4};
114 rb.Push(RESULT_SUCCESS); 121 rb.Push(RESULT_SUCCESS);
115 const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 122 const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
@@ -128,7 +135,6 @@ void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
128 IPC::RequestParser rp{ctx}; 135 IPC::RequestParser rp{ctx};
129 136
130 const auto aoc_id = rp.PopRaw<u32>(); 137 const auto aoc_id = rp.PopRaw<u32>();
131
132 LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id); 138 LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id);
133 139
134 IPC::ResponseBuilder rb{ctx, 2}; 140 IPC::ResponseBuilder rb{ctx, 2};
@@ -140,7 +146,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
140 146
141 IPC::ResponseBuilder rb{ctx, 2, 1}; 147 IPC::ResponseBuilder rb{ctx, 2, 1};
142 rb.Push(RESULT_SUCCESS); 148 rb.Push(RESULT_SUCCESS);
143 rb.PushCopyObjects(aoc_change_event); 149 rb.PushCopyObjects(aoc_change_event.readable);
144} 150}
145 151
146void InstallInterfaces(SM::ServiceManager& service_manager) { 152void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 68d94fdaa..5effea730 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Kernel {
10class WritableEvent;
11}
12
9namespace Service::AOC { 13namespace Service::AOC {
10 14
11class AOC_U final : public ServiceFramework<AOC_U> { 15class AOC_U final : public ServiceFramework<AOC_U> {
@@ -21,7 +25,7 @@ private:
21 void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx); 25 void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
22 26
23 std::vector<u64> add_on_content; 27 std::vector<u64> add_on_content;
24 Kernel::SharedPtr<Kernel::Event> aoc_change_event; 28 Kernel::EventPair aoc_change_event;
25}; 29};
26 30
27/// Registers all AOC services with the specified service manager. 31/// Registers all AOC services with the specified service manager.
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index c22bd3859..fcacbab72 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -40,24 +40,22 @@ private:
40 40
41 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); 41 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
42 u32 config = rp.Pop<u32>(); 42 u32 config = rp.Pop<u32>();
43 LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
44 config);
43 45
44 IPC::ResponseBuilder rb{ctx, 2}; 46 IPC::ResponseBuilder rb{ctx, 2};
45 rb.Push(RESULT_SUCCESS); 47 rb.Push(RESULT_SUCCESS);
46
47 LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
48 config);
49 } 48 }
50 49
51 void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { 50 void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
52 IPC::RequestParser rp{ctx}; 51 IPC::RequestParser rp{ctx};
53 52
54 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); 53 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
54 LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
55 55
56 IPC::ResponseBuilder rb{ctx, 3}; 56 IPC::ResponseBuilder rb{ctx, 3};
57 rb.Push(RESULT_SUCCESS); 57 rb.Push(RESULT_SUCCESS);
58 rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1)); 58 rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
59
60 LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
61 } 59 }
62}; 60};
63 61
@@ -73,11 +71,11 @@ APM::APM(std::shared_ptr<Module> apm, const char* name)
73APM::~APM() = default; 71APM::~APM() = default;
74 72
75void APM::OpenSession(Kernel::HLERequestContext& ctx) { 73void APM::OpenSession(Kernel::HLERequestContext& ctx) {
74 LOG_DEBUG(Service_APM, "called");
75
76 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 76 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
77 rb.Push(RESULT_SUCCESS); 77 rb.Push(RESULT_SUCCESS);
78 rb.PushIpcInterface<ISession>(); 78 rb.PushIpcInterface<ISession>();
79
80 LOG_DEBUG(Service_APM, "called");
81} 79}
82 80
83APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { 81APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
@@ -98,11 +96,11 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
98APM_Sys::~APM_Sys() = default; 96APM_Sys::~APM_Sys() = default;
99 97
100void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { 98void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
99 LOG_DEBUG(Service_APM, "called");
100
101 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 101 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
102 rb.Push(RESULT_SUCCESS); 102 rb.Push(RESULT_SUCCESS);
103 rb.PushIpcInterface<ISession>(); 103 rb.PushIpcInterface<ISession>();
104
105 LOG_DEBUG(Service_APM, "called");
106} 104}
107 105
108} // namespace Service::APM 106} // namespace Service::APM
diff --git a/src/core/hle/service/arp/arp.cpp b/src/core/hle/service/arp/arp.cpp
index 358ef2576..e675b0188 100644
--- a/src/core/hle/service/arp/arp.cpp
+++ b/src/core/hle/service/arp/arp.cpp
@@ -59,11 +59,11 @@ public:
59 59
60private: 60private:
61 void AcquireRegistrar(Kernel::HLERequestContext& ctx) { 61 void AcquireRegistrar(Kernel::HLERequestContext& ctx) {
62 LOG_DEBUG(Service_ARP, "called");
63
62 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 64 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
63 rb.Push(RESULT_SUCCESS); 65 rb.Push(RESULT_SUCCESS);
64 rb.PushIpcInterface<IRegistrar>(); 66 rb.PushIpcInterface<IRegistrar>();
65
66 LOG_DEBUG(Service_ARP, "called");
67 } 67 }
68}; 68};
69 69
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index ff1edefbb..dc6a6b188 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -13,8 +13,10 @@
13#include "common/swap.h" 13#include "common/swap.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/event.h"
17#include "core/hle/kernel/hle_ipc.h" 16#include "core/hle/kernel/hle_ipc.h"
17#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/readable_event.h"
19#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/audio/audout_u.h" 20#include "core/hle/service/audio/audout_u.h"
19#include "core/memory.h" 21#include "core/memory.h"
20 22
@@ -44,8 +46,10 @@ enum class AudioState : u32 {
44 46
45class IAudioOut final : public ServiceFramework<IAudioOut> { 47class IAudioOut final : public ServiceFramework<IAudioOut> {
46public: 48public:
47 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) 49 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
48 : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) { 50 std::string&& unique_name)
51 : ServiceFramework("IAudioOut"), audio_core(audio_core),
52 device_name(std::move(device_name)), audio_params(audio_params) {
49 53
50 static const FunctionInfo functions[] = { 54 static const FunctionInfo functions[] = {
51 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 55 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -65,11 +69,12 @@ public:
65 69
66 // This is the event handle used to check if the audio buffer was released 70 // This is the event handle used to check if the audio buffer was released
67 auto& kernel = Core::System::GetInstance().Kernel(); 71 auto& kernel = Core::System::GetInstance().Kernel();
68 buffer_event = 72 buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
69 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); 73 "IAudioOutBufferReleased");
70 74
71 stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, 75 stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
72 "IAudioOut", [=]() { buffer_event->Signal(); }); 76 std::move(unique_name),
77 [=]() { buffer_event.writable->Signal(); });
73 } 78 }
74 79
75private: 80private:
@@ -84,6 +89,7 @@ private:
84 89
85 void GetAudioOutState(Kernel::HLERequestContext& ctx) { 90 void GetAudioOutState(Kernel::HLERequestContext& ctx) {
86 LOG_DEBUG(Service_Audio, "called"); 91 LOG_DEBUG(Service_Audio, "called");
92
87 IPC::ResponseBuilder rb{ctx, 3}; 93 IPC::ResponseBuilder rb{ctx, 3};
88 rb.Push(RESULT_SUCCESS); 94 rb.Push(RESULT_SUCCESS);
89 rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped)); 95 rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped));
@@ -118,7 +124,7 @@ private:
118 124
119 IPC::ResponseBuilder rb{ctx, 2, 1}; 125 IPC::ResponseBuilder rb{ctx, 2, 1};
120 rb.Push(RESULT_SUCCESS); 126 rb.Push(RESULT_SUCCESS);
121 rb.PushCopyObjects(buffer_event); 127 rb.PushCopyObjects(buffer_event.readable);
122 } 128 }
123 129
124 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 130 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
@@ -146,6 +152,7 @@ private:
146 152
147 void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 153 void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
148 LOG_DEBUG(Service_Audio, "called {}", ctx.Description()); 154 LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
155
149 IPC::RequestParser rp{ctx}; 156 IPC::RequestParser rp{ctx};
150 const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)}; 157 const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
151 const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)}; 158 const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
@@ -161,6 +168,7 @@ private:
161 168
162 void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) { 169 void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
163 LOG_DEBUG(Service_Audio, "called"); 170 LOG_DEBUG(Service_Audio, "called");
171
164 IPC::RequestParser rp{ctx}; 172 IPC::RequestParser rp{ctx};
165 const u64 tag{rp.Pop<u64>()}; 173 const u64 tag{rp.Pop<u64>()};
166 IPC::ResponseBuilder rb{ctx, 3}; 174 IPC::ResponseBuilder rb{ctx, 3};
@@ -170,6 +178,7 @@ private:
170 178
171 void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) { 179 void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
172 LOG_DEBUG(Service_Audio, "called"); 180 LOG_DEBUG(Service_Audio, "called");
181
173 IPC::ResponseBuilder rb{ctx, 3}; 182 IPC::ResponseBuilder rb{ctx, 3};
174 rb.Push(RESULT_SUCCESS); 183 rb.Push(RESULT_SUCCESS);
175 rb.Push(static_cast<u32>(stream->GetQueueSize())); 184 rb.Push(static_cast<u32>(stream->GetQueueSize()));
@@ -177,15 +186,17 @@ private:
177 186
178 AudioCore::AudioOut& audio_core; 187 AudioCore::AudioOut& audio_core;
179 AudioCore::StreamPtr stream; 188 AudioCore::StreamPtr stream;
189 std::string device_name;
180 190
181 AudoutParams audio_params{}; 191 AudoutParams audio_params{};
182 192
183 /// This is the evend handle used to check if the audio buffer was released 193 /// This is the event handle used to check if the audio buffer was released
184 Kernel::SharedPtr<Kernel::Event> buffer_event; 194 Kernel::EventPair buffer_event;
185}; 195};
186 196
187void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { 197void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
188 LOG_DEBUG(Service_Audio, "called"); 198 LOG_DEBUG(Service_Audio, "called");
199
189 IPC::RequestParser rp{ctx}; 200 IPC::RequestParser rp{ctx};
190 201
191 ctx.WriteBuffer(DefaultDevice); 202 ctx.WriteBuffer(DefaultDevice);
@@ -199,7 +210,15 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
199void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { 210void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
200 LOG_DEBUG(Service_Audio, "called"); 211 LOG_DEBUG(Service_Audio, "called");
201 212
202 ctx.WriteBuffer(DefaultDevice); 213 const auto device_name_data{ctx.ReadBuffer()};
214 std::string device_name;
215 if (device_name_data[0] != '\0') {
216 device_name.assign(device_name_data.begin(), device_name_data.end());
217 } else {
218 device_name.assign(DefaultDevice.begin(), DefaultDevice.end());
219 }
220 ctx.WriteBuffer(device_name);
221
203 IPC::RequestParser rp{ctx}; 222 IPC::RequestParser rp{ctx};
204 auto params{rp.PopRaw<AudoutParams>()}; 223 auto params{rp.PopRaw<AudoutParams>()};
205 if (params.channel_count <= 2) { 224 if (params.channel_count <= 2) {
@@ -212,10 +231,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
212 params.sample_rate = DefaultSampleRate; 231 params.sample_rate = DefaultSampleRate;
213 } 232 }
214 233
215 // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl 234 std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())};
216 // will likely need to be updated as well. 235 auto audio_out_interface = std::make_shared<IAudioOut>(
217 ASSERT_MSG(!audio_out_interface, "Unimplemented"); 236 params, *audio_core, std::move(device_name), std::move(unique_name));
218 audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core);
219 237
220 IPC::ResponseBuilder rb{ctx, 6, 0, 1}; 238 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
221 rb.Push(RESULT_SUCCESS); 239 rb.Push(RESULT_SUCCESS);
@@ -224,6 +242,8 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
224 rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16)); 242 rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
225 rb.Push<u32>(static_cast<u32>(AudioState::Stopped)); 243 rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
226 rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface); 244 rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
245
246 audio_out_interfaces.push_back(std::move(audio_out_interface));
227} 247}
228 248
229AudOutU::AudOutU() : ServiceFramework("audout:u") { 249AudOutU::AudOutU() : ServiceFramework("audout:u") {
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index dcaf64708..aed4c43b2 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector>
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace AudioCore { 10namespace AudioCore {
@@ -24,7 +25,7 @@ public:
24 ~AudOutU() override; 25 ~AudOutU() override;
25 26
26private: 27private:
27 std::shared_ptr<IAudioOut> audio_out_interface; 28 std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces;
28 std::unique_ptr<AudioCore::AudioOut> audio_core; 29 std::unique_ptr<AudioCore::AudioOut> audio_core;
29 30
30 void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); 31 void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index fac6785a5..945259c7d 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -12,8 +12,10 @@
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "core/core.h" 13#include "core/core.h"
14#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
15#include "core/hle/kernel/event.h"
16#include "core/hle/kernel/hle_ipc.h" 15#include "core/hle/kernel/hle_ipc.h"
16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/readable_event.h"
18#include "core/hle/kernel/writable_event.h"
17#include "core/hle/service/audio/audren_u.h" 19#include "core/hle/service/audio/audren_u.h"
18 20
19namespace Service::Audio { 21namespace Service::Audio {
@@ -28,90 +30,116 @@ public:
28 {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"}, 30 {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
29 {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"}, 31 {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
30 {3, &IAudioRenderer::GetState, "GetState"}, 32 {3, &IAudioRenderer::GetState, "GetState"},
31 {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"}, 33 {4, &IAudioRenderer::RequestUpdateImpl, "RequestUpdate"},
32 {5, &IAudioRenderer::Start, "Start"}, 34 {5, &IAudioRenderer::Start, "Start"},
33 {6, &IAudioRenderer::Stop, "Stop"}, 35 {6, &IAudioRenderer::Stop, "Stop"},
34 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, 36 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
35 {8, nullptr, "SetRenderingTimeLimit"}, 37 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
36 {9, nullptr, "GetRenderingTimeLimit"}, 38 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
37 {10, nullptr, "RequestUpdateAuto"}, 39 {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"},
38 {11, nullptr, "ExecuteAudioRendererRendering"}, 40 {11, nullptr, "ExecuteAudioRendererRendering"},
39 }; 41 };
40 // clang-format on 42 // clang-format on
41 RegisterHandlers(functions); 43 RegisterHandlers(functions);
42 44
43 auto& kernel = Core::System::GetInstance().Kernel(); 45 auto& kernel = Core::System::GetInstance().Kernel();
44 system_event = 46 system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
45 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent"); 47 "IAudioRenderer:SystemEvent");
46 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event); 48 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable);
47 } 49 }
48 50
49private: 51private:
50 void UpdateAudioCallback() { 52 void UpdateAudioCallback() {
51 system_event->Signal(); 53 system_event.writable->Signal();
52 } 54 }
53 55
54 void GetSampleRate(Kernel::HLERequestContext& ctx) { 56 void GetSampleRate(Kernel::HLERequestContext& ctx) {
57 LOG_DEBUG(Service_Audio, "called");
58
55 IPC::ResponseBuilder rb{ctx, 3}; 59 IPC::ResponseBuilder rb{ctx, 3};
56 rb.Push(RESULT_SUCCESS); 60 rb.Push(RESULT_SUCCESS);
57 rb.Push<u32>(renderer->GetSampleRate()); 61 rb.Push<u32>(renderer->GetSampleRate());
58 LOG_DEBUG(Service_Audio, "called");
59 } 62 }
60 63
61 void GetSampleCount(Kernel::HLERequestContext& ctx) { 64 void GetSampleCount(Kernel::HLERequestContext& ctx) {
65 LOG_DEBUG(Service_Audio, "called");
66
62 IPC::ResponseBuilder rb{ctx, 3}; 67 IPC::ResponseBuilder rb{ctx, 3};
63 rb.Push(RESULT_SUCCESS); 68 rb.Push(RESULT_SUCCESS);
64 rb.Push<u32>(renderer->GetSampleCount()); 69 rb.Push<u32>(renderer->GetSampleCount());
65 LOG_DEBUG(Service_Audio, "called");
66 } 70 }
67 71
68 void GetState(Kernel::HLERequestContext& ctx) { 72 void GetState(Kernel::HLERequestContext& ctx) {
73 LOG_DEBUG(Service_Audio, "called");
74
69 IPC::ResponseBuilder rb{ctx, 3}; 75 IPC::ResponseBuilder rb{ctx, 3};
70 rb.Push(RESULT_SUCCESS); 76 rb.Push(RESULT_SUCCESS);
71 rb.Push<u32>(static_cast<u32>(renderer->GetStreamState())); 77 rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
72 LOG_DEBUG(Service_Audio, "called");
73 } 78 }
74 79
75 void GetMixBufferCount(Kernel::HLERequestContext& ctx) { 80 void GetMixBufferCount(Kernel::HLERequestContext& ctx) {
81 LOG_DEBUG(Service_Audio, "called");
82
76 IPC::ResponseBuilder rb{ctx, 3}; 83 IPC::ResponseBuilder rb{ctx, 3};
77 rb.Push(RESULT_SUCCESS); 84 rb.Push(RESULT_SUCCESS);
78 rb.Push<u32>(renderer->GetMixBufferCount()); 85 rb.Push<u32>(renderer->GetMixBufferCount());
79 LOG_DEBUG(Service_Audio, "called");
80 } 86 }
81 87
82 void RequestUpdate(Kernel::HLERequestContext& ctx) { 88 void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
89 LOG_WARNING(Service_Audio, "(STUBBED) called");
90
83 ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); 91 ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
84 IPC::ResponseBuilder rb{ctx, 2}; 92 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(RESULT_SUCCESS); 93 rb.Push(RESULT_SUCCESS);
86 LOG_WARNING(Service_Audio, "(STUBBED) called");
87 } 94 }
88 95
89 void Start(Kernel::HLERequestContext& ctx) { 96 void Start(Kernel::HLERequestContext& ctx) {
97 LOG_WARNING(Service_Audio, "(STUBBED) called");
98
90 IPC::ResponseBuilder rb{ctx, 2}; 99 IPC::ResponseBuilder rb{ctx, 2};
91 100
92 rb.Push(RESULT_SUCCESS); 101 rb.Push(RESULT_SUCCESS);
93
94 LOG_WARNING(Service_Audio, "(STUBBED) called");
95 } 102 }
96 103
97 void Stop(Kernel::HLERequestContext& ctx) { 104 void Stop(Kernel::HLERequestContext& ctx) {
105 LOG_WARNING(Service_Audio, "(STUBBED) called");
106
98 IPC::ResponseBuilder rb{ctx, 2}; 107 IPC::ResponseBuilder rb{ctx, 2};
99 108
100 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
101
102 LOG_WARNING(Service_Audio, "(STUBBED) called");
103 } 110 }
104 111
105 void QuerySystemEvent(Kernel::HLERequestContext& ctx) { 112 void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
113 LOG_WARNING(Service_Audio, "(STUBBED) called");
114
106 IPC::ResponseBuilder rb{ctx, 2, 1}; 115 IPC::ResponseBuilder rb{ctx, 2, 1};
107 rb.Push(RESULT_SUCCESS); 116 rb.Push(RESULT_SUCCESS);
108 rb.PushCopyObjects(system_event); 117 rb.PushCopyObjects(system_event.readable);
118 }
109 119
110 LOG_WARNING(Service_Audio, "(STUBBED) called"); 120 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
121 IPC::RequestParser rp{ctx};
122 rendering_time_limit_percent = rp.Pop<u32>();
123 LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}",
124 rendering_time_limit_percent);
125
126 ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100);
127
128 IPC::ResponseBuilder rb{ctx, 2};
129 rb.Push(RESULT_SUCCESS);
111 } 130 }
112 131
113 Kernel::SharedPtr<Kernel::Event> system_event; 132 void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
133 LOG_DEBUG(Service_Audio, "called");
134
135 IPC::ResponseBuilder rb{ctx, 3};
136 rb.Push(RESULT_SUCCESS);
137 rb.Push(rendering_time_limit_percent);
138 }
139
140 Kernel::EventPair system_event;
114 std::unique_ptr<AudioCore::AudioRenderer> renderer; 141 std::unique_ptr<AudioCore::AudioRenderer> renderer;
142 u32 rendering_time_limit_percent = 100;
115}; 143};
116 144
117class IAudioDevice final : public ServiceFramework<IAudioDevice> { 145class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -136,8 +164,8 @@ public:
136 RegisterHandlers(functions); 164 RegisterHandlers(functions);
137 165
138 auto& kernel = Core::System::GetInstance().Kernel(); 166 auto& kernel = Core::System::GetInstance().Kernel();
139 buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 167 buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
140 "IAudioOutBufferReleasedEvent"); 168 "IAudioOutBufferReleasedEvent");
141 } 169 }
142 170
143private: 171private:
@@ -181,21 +209,22 @@ private:
181 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { 209 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
182 LOG_WARNING(Service_Audio, "(STUBBED) called"); 210 LOG_WARNING(Service_Audio, "(STUBBED) called");
183 211
184 buffer_event->Signal(); 212 buffer_event.writable->Signal();
185 213
186 IPC::ResponseBuilder rb{ctx, 2, 1}; 214 IPC::ResponseBuilder rb{ctx, 2, 1};
187 rb.Push(RESULT_SUCCESS); 215 rb.Push(RESULT_SUCCESS);
188 rb.PushCopyObjects(buffer_event); 216 rb.PushCopyObjects(buffer_event.readable);
189 } 217 }
190 218
191 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { 219 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
192 LOG_WARNING(Service_Audio, "(STUBBED) called"); 220 LOG_WARNING(Service_Audio, "(STUBBED) called");
221
193 IPC::ResponseBuilder rb{ctx, 3}; 222 IPC::ResponseBuilder rb{ctx, 3};
194 rb.Push(RESULT_SUCCESS); 223 rb.Push(RESULT_SUCCESS);
195 rb.Push<u32>(1); 224 rb.Push<u32>(1);
196 } 225 }
197 226
198 Kernel::SharedPtr<Kernel::Event> buffer_event; 227 Kernel::EventPair buffer_event;
199 228
200}; // namespace Audio 229}; // namespace Audio
201 230
@@ -214,19 +243,20 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
214AudRenU::~AudRenU() = default; 243AudRenU::~AudRenU() = default;
215 244
216void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { 245void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
246 LOG_DEBUG(Service_Audio, "called");
247
217 IPC::RequestParser rp{ctx}; 248 IPC::RequestParser rp{ctx};
218 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); 249 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
219 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 250 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
220 251
221 rb.Push(RESULT_SUCCESS); 252 rb.Push(RESULT_SUCCESS);
222 rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params)); 253 rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
223
224 LOG_DEBUG(Service_Audio, "called");
225} 254}
226 255
227void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { 256void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
228 IPC::RequestParser rp{ctx}; 257 IPC::RequestParser rp{ctx};
229 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); 258 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
259 LOG_DEBUG(Service_Audio, "called");
230 260
231 u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40); 261 u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40);
232 buffer_sz += params.unknown_c * 1024; 262 buffer_sz += params.unknown_c * 1024;
@@ -280,26 +310,26 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
280 rb.Push(RESULT_SUCCESS); 310 rb.Push(RESULT_SUCCESS);
281 rb.Push<u64>(output_sz); 311 rb.Push<u64>(output_sz);
282 312
283 LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz); 313 LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", output_sz);
284} 314}
285 315
286void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { 316void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
317 LOG_DEBUG(Service_Audio, "called");
318
287 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 319 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
288 320
289 rb.Push(RESULT_SUCCESS); 321 rb.Push(RESULT_SUCCESS);
290 rb.PushIpcInterface<Audio::IAudioDevice>(); 322 rb.PushIpcInterface<Audio::IAudioDevice>();
291
292 LOG_DEBUG(Service_Audio, "called");
293} 323}
294 324
295void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { 325void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
326 LOG_WARNING(Service_Audio, "(STUBBED) called");
327
296 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 328 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
297 329
298 rb.Push(RESULT_SUCCESS); 330 rb.Push(RESULT_SUCCESS);
299 rb.PushIpcInterface<Audio::IAudioDevice>(); 331 rb.PushIpcInterface<Audio::IAudioDevice>(); // TODO(ogniK): Figure out what is different
300 332 // based on the current revision
301 LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different
302 // based on the current revision
303} 333}
304 334
305bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { 335bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 783c39503..a850cadc8 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -46,10 +46,13 @@ public:
46 46
47private: 47private:
48 void DecodeInterleaved(Kernel::HLERequestContext& ctx) { 48 void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
49 LOG_DEBUG(Audio, "called");
50
49 u32 consumed = 0; 51 u32 consumed = 0;
50 u32 sample_count = 0; 52 u32 sample_count = 0;
51 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); 53 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
52 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) { 54 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) {
55 LOG_ERROR(Audio, "Failed to decode opus data");
53 IPC::ResponseBuilder rb{ctx, 2}; 56 IPC::ResponseBuilder rb{ctx, 2};
54 // TODO(ogniK): Use correct error code 57 // TODO(ogniK): Use correct error code
55 rb.Push(ResultCode(-1)); 58 rb.Push(ResultCode(-1));
@@ -63,12 +66,15 @@ private:
63 } 66 }
64 67
65 void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) { 68 void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) {
69 LOG_DEBUG(Audio, "called");
70
66 u32 consumed = 0; 71 u32 consumed = 0;
67 u32 sample_count = 0; 72 u32 sample_count = 0;
68 u64 performance = 0; 73 u64 performance = 0;
69 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); 74 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
70 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples, 75 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples,
71 performance)) { 76 performance)) {
77 LOG_ERROR(Audio, "Failed to decode opus data");
72 IPC::ResponseBuilder rb{ctx, 2}; 78 IPC::ResponseBuilder rb{ctx, 2};
73 // TODO(ogniK): Use correct error code 79 // TODO(ogniK): Use correct error code
74 rb.Push(ResultCode(-1)); 80 rb.Push(ResultCode(-1));
@@ -77,8 +83,8 @@ private:
77 IPC::ResponseBuilder rb{ctx, 6}; 83 IPC::ResponseBuilder rb{ctx, 6};
78 rb.Push(RESULT_SUCCESS); 84 rb.Push(RESULT_SUCCESS);
79 rb.Push<u32>(consumed); 85 rb.Push<u32>(consumed);
80 rb.Push<u64>(performance);
81 rb.Push<u32>(sample_count); 86 rb.Push<u32>(sample_count);
87 rb.Push<u64>(performance);
82 ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); 88 ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
83 } 89 }
84 90
@@ -88,24 +94,39 @@ private:
88 std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) { 94 std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) {
89 const auto start_time = std::chrono::high_resolution_clock::now(); 95 const auto start_time = std::chrono::high_resolution_clock::now();
90 std::size_t raw_output_sz = output.size() * sizeof(opus_int16); 96 std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
91 if (sizeof(OpusHeader) > input.size()) 97 if (sizeof(OpusHeader) > input.size()) {
98 LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}",
99 sizeof(OpusHeader), input.size());
92 return false; 100 return false;
101 }
93 OpusHeader hdr{}; 102 OpusHeader hdr{};
94 std::memcpy(&hdr, input.data(), sizeof(OpusHeader)); 103 std::memcpy(&hdr, input.data(), sizeof(OpusHeader));
95 if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) { 104 if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) {
105 LOG_ERROR(Audio, "Input does not fit in the opus header size. data_sz={}, input_sz={}",
106 sizeof(OpusHeader) + static_cast<u32>(hdr.sz), input.size());
96 return false; 107 return false;
97 } 108 }
98 auto frame = input.data() + sizeof(OpusHeader); 109 auto frame = input.data() + sizeof(OpusHeader);
99 auto decoded_sample_count = opus_packet_get_nb_samples( 110 auto decoded_sample_count = opus_packet_get_nb_samples(
100 frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)), 111 frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)),
101 static_cast<opus_int32>(sample_rate)); 112 static_cast<opus_int32>(sample_rate));
102 if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) 113 if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) {
114 LOG_ERROR(
115 Audio,
116 "Decoded data does not fit into the output data, decoded_sz={}, raw_output_sz={}",
117 decoded_sample_count * channel_count * sizeof(u16), raw_output_sz);
103 return false; 118 return false;
119 }
120 const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count));
104 auto out_sample_count = 121 auto out_sample_count =
105 opus_decode(decoder.get(), frame, hdr.sz, output.data(), 122 opus_decode(decoder.get(), frame, hdr.sz, output.data(), frame_size, 0);
106 (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0); 123 if (out_sample_count < 0) {
107 if (out_sample_count < 0) 124 LOG_ERROR(Audio,
125 "Incorrect sample count received from opus_decode, "
126 "output_sample_count={}, frame_size={}, data_sz_from_hdr={}",
127 out_sample_count, frame_size, static_cast<u32>(hdr.sz));
108 return false; 128 return false;
129 }
109 const auto end_time = std::chrono::high_resolution_clock::now() - start_time; 130 const auto end_time = std::chrono::high_resolution_clock::now() - start_time;
110 sample_count = out_sample_count; 131 sample_count = out_sample_count;
111 consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); 132 consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz);
@@ -134,14 +155,17 @@ static std::size_t WorkerBufferSize(u32 channel_count) {
134 155
135void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { 156void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
136 IPC::RequestParser rp{ctx}; 157 IPC::RequestParser rp{ctx};
137 auto sample_rate = rp.Pop<u32>(); 158 const auto sample_rate = rp.Pop<u32>();
138 auto channel_count = rp.Pop<u32>(); 159 const auto channel_count = rp.Pop<u32>();
160 LOG_DEBUG(Audio, "called with sample_rate={}, channel_count={}", sample_rate, channel_count);
161
139 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || 162 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
140 sample_rate == 12000 || sample_rate == 8000, 163 sample_rate == 12000 || sample_rate == 8000,
141 "Invalid sample rate"); 164 "Invalid sample rate");
142 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); 165 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
143 u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count)); 166
144 LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz); 167 const u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
168 LOG_DEBUG(Audio, "worker_buffer_sz={}", worker_buffer_sz);
145 169
146 IPC::ResponseBuilder rb{ctx, 3}; 170 IPC::ResponseBuilder rb{ctx, 3};
147 rb.Push(RESULT_SUCCESS); 171 rb.Push(RESULT_SUCCESS);
@@ -155,6 +179,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
155 auto buffer_sz = rp.Pop<u32>(); 179 auto buffer_sz = rp.Pop<u32>();
156 LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate, 180 LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate,
157 channel_count, buffer_sz); 181 channel_count, buffer_sz);
182
158 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || 183 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
159 sample_rate == 12000 || sample_rate == 8000, 184 sample_rate == 12000 || sample_rate == 8000,
160 "Invalid sample rate"); 185 "Invalid sample rate");
@@ -164,7 +189,8 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
164 ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); 189 ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
165 std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ 190 std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
166 static_cast<OpusDecoder*>(operator new(worker_sz))}; 191 static_cast<OpusDecoder*>(operator new(worker_sz))};
167 if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) { 192 if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
193 LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err);
168 IPC::ResponseBuilder rb{ctx, 2}; 194 IPC::ResponseBuilder rb{ctx, 2};
169 // TODO(ogniK): Use correct error code 195 // TODO(ogniK): Use correct error code
170 rb.Push(ResultCode(-1)); 196 rb.Push(ResultCode(-1));
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 6e7b795fb..b7bd738fc 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -33,10 +33,11 @@ public:
33}; 33};
34 34
35void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { 35void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
36 LOG_DEBUG(Service_BCAT, "called");
37
36 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 38 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
37 rb.Push(RESULT_SUCCESS); 39 rb.Push(RESULT_SUCCESS);
38 rb.PushIpcInterface<IBcatService>(); 40 rb.PushIpcInterface<IBcatService>();
39 LOG_DEBUG(Service_BCAT, "called");
40} 41}
41 42
42Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 43Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index d0a15cc4c..5704ca0ab 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -2,12 +2,54 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/writable_event.h"
5#include "core/hle/service/btdrv/btdrv.h" 11#include "core/hle/service/btdrv/btdrv.h"
6#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
7#include "core/hle/service/sm/sm.h" 13#include "core/hle/service/sm/sm.h"
8 14
9namespace Service::BtDrv { 15namespace Service::BtDrv {
10 16
17class Bt final : public ServiceFramework<Bt> {
18public:
19 explicit Bt() : ServiceFramework{"bt"} {
20 // clang-format off
21 static const FunctionInfo functions[] = {
22 {0, nullptr, "Unknown0"},
23 {1, nullptr, "Unknown1"},
24 {2, nullptr, "Unknown2"},
25 {3, nullptr, "Unknown3"},
26 {4, nullptr, "Unknown4"},
27 {5, nullptr, "Unknown5"},
28 {6, nullptr, "Unknown6"},
29 {7, nullptr, "Unknown7"},
30 {8, nullptr, "Unknown8"},
31 {9, &Bt::RegisterEvent, "RegisterEvent"},
32 };
33 // clang-format on
34 RegisterHandlers(functions);
35
36 auto& kernel = Core::System::GetInstance().Kernel();
37 register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
38 "BT:RegisterEvent");
39 }
40
41private:
42 void RegisterEvent(Kernel::HLERequestContext& ctx) {
43 LOG_WARNING(Service_BTM, "(STUBBED) called");
44
45 IPC::ResponseBuilder rb{ctx, 2, 1};
46 rb.Push(RESULT_SUCCESS);
47 rb.PushCopyObjects(register_event.readable);
48 }
49
50 Kernel::EventPair register_event;
51};
52
11class BtDrv final : public ServiceFramework<BtDrv> { 53class BtDrv final : public ServiceFramework<BtDrv> {
12public: 54public:
13 explicit BtDrv() : ServiceFramework{"btdrv"} { 55 explicit BtDrv() : ServiceFramework{"btdrv"} {
@@ -67,6 +109,7 @@ public:
67 109
68void InstallInterfaces(SM::ServiceManager& sm) { 110void InstallInterfaces(SM::ServiceManager& sm) {
69 std::make_shared<BtDrv>()->InstallAsService(sm); 111 std::make_shared<BtDrv>()->InstallAsService(sm);
112 std::make_shared<Bt>()->InstallAsService(sm);
70} 113}
71 114
72} // namespace Service::BtDrv 115} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index b949bfabd..ef7398a23 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -7,12 +7,126 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h" 9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/btm/btm.h" 13#include "core/hle/service/btm/btm.h"
11#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h"
13 15
14namespace Service::BTM { 16namespace Service::BTM {
15 17
18class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
19public:
20 explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, &IBtmUserCore::GetScanEvent, "GetScanEvent"},
24 {1, nullptr, "Unknown1"},
25 {2, nullptr, "Unknown2"},
26 {3, nullptr, "Unknown3"},
27 {4, nullptr, "Unknown4"},
28 {5, nullptr, "Unknown5"},
29 {6, nullptr, "Unknown6"},
30 {7, nullptr, "Unknown7"},
31 {8, nullptr, "Unknown8"},
32 {9, nullptr, "Unknown9"},
33 {10, nullptr, "Unknown10"},
34 {17, &IBtmUserCore::GetConnectionEvent, "GetConnectionEvent"},
35 {18, nullptr, "Unknown18"},
36 {19, nullptr, "Unknown19"},
37 {20, nullptr, "Unknown20"},
38 {21, nullptr, "Unknown21"},
39 {22, nullptr, "Unknown22"},
40 {23, nullptr, "Unknown23"},
41 {24, nullptr, "Unknown24"},
42 {25, nullptr, "Unknown25"},
43 {26, &IBtmUserCore::GetDiscoveryEvent, "AcquireBleServiceDiscoveryEventImpl"},
44 {27, nullptr, "Unknown27"},
45 {28, nullptr, "Unknown28"},
46 {29, nullptr, "Unknown29"},
47 {30, nullptr, "Unknown30"},
48 {31, nullptr, "Unknown31"},
49 {32, nullptr, "Unknown32"},
50 {33, &IBtmUserCore::GetConfigEvent, "GetConfigEvent"},
51 {34, nullptr, "Unknown34"},
52 {35, nullptr, "Unknown35"},
53 {36, nullptr, "Unknown36"},
54 {37, nullptr, "Unknown37"},
55 };
56 // clang-format on
57 RegisterHandlers(functions);
58
59 auto& kernel = Core::System::GetInstance().Kernel();
60 scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
61 "IBtmUserCore:ScanEvent");
62 connection_event = Kernel::WritableEvent::CreateEventPair(
63 kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent");
64 service_discovery = Kernel::WritableEvent::CreateEventPair(
65 kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
66 config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
67 "IBtmUserCore:ConfigEvent");
68 }
69
70private:
71 void GetScanEvent(Kernel::HLERequestContext& ctx) {
72 LOG_WARNING(Service_BTM, "(STUBBED) called");
73
74 IPC::ResponseBuilder rb{ctx, 2, 1};
75 rb.Push(RESULT_SUCCESS);
76 rb.PushCopyObjects(scan_event.readable);
77 }
78
79 void GetConnectionEvent(Kernel::HLERequestContext& ctx) {
80 LOG_WARNING(Service_BTM, "(STUBBED) called");
81
82 IPC::ResponseBuilder rb{ctx, 2, 1};
83 rb.Push(RESULT_SUCCESS);
84 rb.PushCopyObjects(connection_event.readable);
85 }
86
87 void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) {
88 LOG_WARNING(Service_BTM, "(STUBBED) called");
89
90 IPC::ResponseBuilder rb{ctx, 2, 1};
91 rb.Push(RESULT_SUCCESS);
92 rb.PushCopyObjects(service_discovery.readable);
93 }
94
95 void GetConfigEvent(Kernel::HLERequestContext& ctx) {
96 LOG_WARNING(Service_BTM, "(STUBBED) called");
97
98 IPC::ResponseBuilder rb{ctx, 2, 1};
99 rb.Push(RESULT_SUCCESS);
100 rb.PushCopyObjects(config_event.readable);
101 }
102
103 Kernel::EventPair scan_event;
104 Kernel::EventPair connection_event;
105 Kernel::EventPair service_discovery;
106 Kernel::EventPair config_event;
107};
108
109class BTM_USR final : public ServiceFramework<BTM_USR> {
110public:
111 explicit BTM_USR() : ServiceFramework{"btm:u"} {
112 // clang-format off
113 static const FunctionInfo functions[] = {
114 {0, &BTM_USR::GetCoreImpl, "GetCoreImpl"},
115 };
116 // clang-format on
117 RegisterHandlers(functions);
118 }
119
120private:
121 void GetCoreImpl(Kernel::HLERequestContext& ctx) {
122 LOG_DEBUG(Service_BTM, "called");
123
124 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
125 rb.Push(RESULT_SUCCESS);
126 rb.PushIpcInterface<IBtmUserCore>();
127 }
128};
129
16class BTM final : public ServiceFramework<BTM> { 130class BTM final : public ServiceFramework<BTM> {
17public: 131public:
18 explicit BTM() : ServiceFramework{"btm"} { 132 explicit BTM() : ServiceFramework{"btm"} {
@@ -104,11 +218,11 @@ public:
104 218
105private: 219private:
106 void GetCoreImpl(Kernel::HLERequestContext& ctx) { 220 void GetCoreImpl(Kernel::HLERequestContext& ctx) {
221 LOG_DEBUG(Service_BTM, "called");
222
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 223 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(RESULT_SUCCESS); 224 rb.Push(RESULT_SUCCESS);
109 rb.PushIpcInterface<IBtmSystemCore>(); 225 rb.PushIpcInterface<IBtmSystemCore>();
110
111 LOG_DEBUG(Service_BTM, "called");
112 } 226 }
113}; 227};
114 228
@@ -116,6 +230,7 @@ void InstallInterfaces(SM::ServiceManager& sm) {
116 std::make_shared<BTM>()->InstallAsService(sm); 230 std::make_shared<BTM>()->InstallAsService(sm);
117 std::make_shared<BTM_DBG>()->InstallAsService(sm); 231 std::make_shared<BTM_DBG>()->InstallAsService(sm);
118 std::make_shared<BTM_SYS>()->InstallAsService(sm); 232 std::make_shared<BTM_SYS>()->InstallAsService(sm);
233 std::make_shared<BTM_USR>()->InstallAsService(sm);
119} 234}
120 235
121} // namespace Service::BTM 236} // namespace Service::BTM
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index ee11cd78e..d9b32954e 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -17,11 +17,13 @@ public:
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SubmitContext"}, 18 {0, nullptr, "SubmitContext"},
19 {1, nullptr, "CreateReport"}, 19 {1, nullptr, "CreateReport"},
20 {2, nullptr, "Unknown1"}, 20 {2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
21 {3, nullptr, "Unknown2"}, 21 {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
22 {4, nullptr, "Unknown3"}, 22 {4, nullptr, "UpdatePowerOnTime"},
23 {5, nullptr, "Unknown4"}, 23 {5, nullptr, "UpdateAwakeTime"},
24 {6, nullptr, "Unknown5"}, 24 {6, nullptr, "SubmitMultipleCategoryContext"},
25 {7, nullptr, "UpdateApplicationLaunchTime"},
26 {8, nullptr, "ClearApplicationLaunchTime"},
25 }; 27 };
26 // clang-format on 28 // clang-format on
27 29
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp
index 566fbf924..e461274c1 100644
--- a/src/core/hle/service/fgm/fgm.cpp
+++ b/src/core/hle/service/fgm/fgm.cpp
@@ -42,11 +42,11 @@ public:
42 42
43private: 43private:
44 void Initialize(Kernel::HLERequestContext& ctx) { 44 void Initialize(Kernel::HLERequestContext& ctx) {
45 LOG_DEBUG(Service_FGM, "called");
46
45 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 47 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
46 rb.Push(RESULT_SUCCESS); 48 rb.Push(RESULT_SUCCESS);
47 rb.PushIpcInterface<IRequest>(); 49 rb.PushIpcInterface<IRequest>();
48
49 LOG_DEBUG(Service_FGM, "called");
50 } 50 }
51}; 51};
52 52
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index e32a7c48e..b1490e6fa 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -113,6 +113,18 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str
113 return RESULT_SUCCESS; 113 return RESULT_SUCCESS;
114} 114}
115 115
116ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
117 const std::string sanitized_path(FileUtil::SanitizePath(path));
118 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path));
119
120 if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) {
121 // TODO(DarkLordZach): Find a better error code for this
122 return ResultCode(-1);
123 }
124
125 return RESULT_SUCCESS;
126}
127
116ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, 128ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
117 const std::string& dest_path_) const { 129 const std::string& dest_path_) const {
118 std::string src_path(FileUtil::SanitizePath(src_path_)); 130 std::string src_path(FileUtil::SanitizePath(src_path_));
@@ -303,25 +315,35 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
303 static_cast<u8>(space), save_struct.DebugInfo()); 315 static_cast<u8>(space), save_struct.DebugInfo());
304 316
305 if (save_data_factory == nullptr) { 317 if (save_data_factory == nullptr) {
306 return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound); 318 return FileSys::ERROR_ENTITY_NOT_FOUND;
307 } 319 }
308 320
309 return save_data_factory->Open(space, save_struct); 321 return save_data_factory->Open(space, save_struct);
310} 322}
311 323
324ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
325 LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
326
327 if (save_data_factory == nullptr) {
328 return FileSys::ERROR_ENTITY_NOT_FOUND;
329 }
330
331 return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
332}
333
312ResultVal<FileSys::VirtualDir> OpenSDMC() { 334ResultVal<FileSys::VirtualDir> OpenSDMC() {
313 LOG_TRACE(Service_FS, "Opening SDMC"); 335 LOG_TRACE(Service_FS, "Opening SDMC");
314 336
315 if (sdmc_factory == nullptr) { 337 if (sdmc_factory == nullptr) {
316 return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SdCardNotFound); 338 return FileSys::ERROR_SD_CARD_NOT_FOUND;
317 } 339 }
318 340
319 return sdmc_factory->Open(); 341 return sdmc_factory->Open();
320} 342}
321 343
322std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { 344FileSys::RegisteredCacheUnion GetUnionContents() {
323 return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{ 345 return FileSys::RegisteredCacheUnion{
324 GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}); 346 {GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
325} 347}
326 348
327FileSys::RegisteredCache* GetSystemNANDContents() { 349FileSys::RegisteredCache* GetSystemNANDContents() {
@@ -360,6 +382,15 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
360 return bis_factory->GetModificationLoadRoot(title_id); 382 return bis_factory->GetModificationLoadRoot(title_id);
361} 383}
362 384
385FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
386 LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
387
388 if (bis_factory == nullptr)
389 return nullptr;
390
391 return bis_factory->GetModificationDumpRoot(title_id);
392}
393
363void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { 394void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
364 if (overwrite) { 395 if (overwrite) {
365 bis_factory = nullptr; 396 bis_factory = nullptr;
@@ -373,13 +404,21 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
373 FileSys::Mode::ReadWrite); 404 FileSys::Mode::ReadWrite);
374 auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), 405 auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
375 FileSys::Mode::ReadWrite); 406 FileSys::Mode::ReadWrite);
407 auto dump_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
408 FileSys::Mode::ReadWrite);
376 409
377 if (bis_factory == nullptr) 410 if (bis_factory == nullptr) {
378 bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory); 411 bis_factory =
379 if (save_data_factory == nullptr) 412 std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory);
413 }
414
415 if (save_data_factory == nullptr) {
380 save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); 416 save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
381 if (sdmc_factory == nullptr) 417 }
418
419 if (sdmc_factory == nullptr) {
382 sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); 420 sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
421 }
383} 422}
384 423
385void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) { 424void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) {
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6ca5c5636..965414be0 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -45,15 +45,17 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
45 FileSys::ContentRecordType type); 45 FileSys::ContentRecordType type);
46ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, 46ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
47 FileSys::SaveDataDescriptor save_struct); 47 FileSys::SaveDataDescriptor save_struct);
48ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
48ResultVal<FileSys::VirtualDir> OpenSDMC(); 49ResultVal<FileSys::VirtualDir> OpenSDMC();
49 50
50std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); 51FileSys::RegisteredCacheUnion GetUnionContents();
51 52
52FileSys::RegisteredCache* GetSystemNANDContents(); 53FileSys::RegisteredCache* GetSystemNANDContents();
53FileSys::RegisteredCache* GetUserNANDContents(); 54FileSys::RegisteredCache* GetUserNANDContents();
54FileSys::RegisteredCache* GetSDMCContents(); 55FileSys::RegisteredCache* GetSDMCContents();
55 56
56FileSys::VirtualDir GetModificationLoadRoot(u64 title_id); 57FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
58FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
57 59
58// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function 60// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
59// above is called. 61// above is called.
@@ -111,6 +113,18 @@ public:
111 ResultCode DeleteDirectoryRecursively(const std::string& path) const; 113 ResultCode DeleteDirectoryRecursively(const std::string& path) const;
112 114
113 /** 115 /**
116 * Cleans the specified directory. This is similar to DeleteDirectoryRecursively,
117 * in that it deletes all the contents of the specified directory, however, this
118 * function does *not* delete the directory itself. It only deletes everything
119 * within it.
120 *
121 * @param path Path relative to the archive.
122 *
123 * @return Result of the operation.
124 */
125 ResultCode CleanDirectoryRecursively(const std::string& path) const;
126
127 /**
114 * Rename a File specified by its path 128 * Rename a File specified by its path
115 * @param src_path Source path relative to the archive 129 * @param src_path Source path relative to the archive
116 * @param dest_path Destination path relative to the archive 130 * @param dest_path Destination path relative to the archive
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index f06bb33ae..d2ffd5776 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -11,6 +11,7 @@
11 11
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/hex_util.h"
14#include "common/logging/log.h" 15#include "common/logging/log.h"
15#include "common/string_util.h" 16#include "common/string_util.h"
16#include "core/file_sys/directory.h" 17#include "core/file_sys/directory.h"
@@ -62,13 +63,15 @@ private:
62 63
63 // Error checking 64 // Error checking
64 if (length < 0) { 65 if (length < 0) {
66 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
65 IPC::ResponseBuilder rb{ctx, 2}; 67 IPC::ResponseBuilder rb{ctx, 2};
66 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); 68 rb.Push(FileSys::ERROR_INVALID_SIZE);
67 return; 69 return;
68 } 70 }
69 if (offset < 0) { 71 if (offset < 0) {
72 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
70 IPC::ResponseBuilder rb{ctx, 2}; 73 IPC::ResponseBuilder rb{ctx, 2};
71 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); 74 rb.Push(FileSys::ERROR_INVALID_OFFSET);
72 return; 75 return;
73 } 76 }
74 77
@@ -107,13 +110,15 @@ private:
107 110
108 // Error checking 111 // Error checking
109 if (length < 0) { 112 if (length < 0) {
113 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
110 IPC::ResponseBuilder rb{ctx, 2}; 114 IPC::ResponseBuilder rb{ctx, 2};
111 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); 115 rb.Push(FileSys::ERROR_INVALID_SIZE);
112 return; 116 return;
113 } 117 }
114 if (offset < 0) { 118 if (offset < 0) {
119 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
115 IPC::ResponseBuilder rb{ctx, 2}; 120 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); 121 rb.Push(FileSys::ERROR_INVALID_OFFSET);
117 return; 122 return;
118 } 123 }
119 124
@@ -138,13 +143,15 @@ private:
138 143
139 // Error checking 144 // Error checking
140 if (length < 0) { 145 if (length < 0) {
146 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
141 IPC::ResponseBuilder rb{ctx, 2}; 147 IPC::ResponseBuilder rb{ctx, 2};
142 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); 148 rb.Push(FileSys::ERROR_INVALID_SIZE);
143 return; 149 return;
144 } 150 }
145 if (offset < 0) { 151 if (offset < 0) {
152 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
146 IPC::ResponseBuilder rb{ctx, 2}; 153 IPC::ResponseBuilder rb{ctx, 2};
147 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); 154 rb.Push(FileSys::ERROR_INVALID_OFFSET);
148 return; 155 return;
149 } 156 }
150 157
@@ -180,9 +187,10 @@ private:
180 void SetSize(Kernel::HLERequestContext& ctx) { 187 void SetSize(Kernel::HLERequestContext& ctx) {
181 IPC::RequestParser rp{ctx}; 188 IPC::RequestParser rp{ctx};
182 const u64 size = rp.Pop<u64>(); 189 const u64 size = rp.Pop<u64>();
183 backend->Resize(size);
184 LOG_DEBUG(Service_FS, "called, size={}", size); 190 LOG_DEBUG(Service_FS, "called, size={}", size);
185 191
192 backend->Resize(size);
193
186 IPC::ResponseBuilder rb{ctx, 2}; 194 IPC::ResponseBuilder rb{ctx, 2};
187 rb.Push(RESULT_SUCCESS); 195 rb.Push(RESULT_SUCCESS);
188 } 196 }
@@ -284,7 +292,7 @@ public:
284 {10, &IFileSystem::Commit, "Commit"}, 292 {10, &IFileSystem::Commit, "Commit"},
285 {11, nullptr, "GetFreeSpaceSize"}, 293 {11, nullptr, "GetFreeSpaceSize"},
286 {12, nullptr, "GetTotalSpaceSize"}, 294 {12, nullptr, "GetTotalSpaceSize"},
287 {13, nullptr, "CleanDirectoryRecursively"}, 295 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
288 {14, nullptr, "GetFileTimeStampRaw"}, 296 {14, nullptr, "GetFileTimeStampRaw"},
289 {15, nullptr, "QueryEntry"}, 297 {15, nullptr, "QueryEntry"},
290 }; 298 };
@@ -354,6 +362,16 @@ public:
354 rb.Push(backend.DeleteDirectoryRecursively(name)); 362 rb.Push(backend.DeleteDirectoryRecursively(name));
355 } 363 }
356 364
365 void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) {
366 const auto file_buffer = ctx.ReadBuffer();
367 const std::string name = Common::StringFromBuffer(file_buffer);
368
369 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
370
371 IPC::ResponseBuilder rb{ctx, 2};
372 rb.Push(backend.CleanDirectoryRecursively(name));
373 }
374
357 void RenameFile(Kernel::HLERequestContext& ctx) { 375 void RenameFile(Kernel::HLERequestContext& ctx) {
358 IPC::RequestParser rp{ctx}; 376 IPC::RequestParser rp{ctx};
359 377
@@ -452,7 +470,149 @@ private:
452 VfsDirectoryServiceWrapper backend; 470 VfsDirectoryServiceWrapper backend;
453}; 471};
454 472
473class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
474public:
475 explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
476 : ServiceFramework("ISaveDataInfoReader") {
477 static const FunctionInfo functions[] = {
478 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
479 };
480 RegisterHandlers(functions);
481
482 FindAllSaves(space);
483 }
484
485 void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
486 LOG_DEBUG(Service_FS, "called");
487
488 // Calculate how many entries we can fit in the output buffer
489 const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
490
491 // Cap at total number of entries.
492 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
493
494 // Determine data start and end
495 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
496 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
497 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
498
499 next_entry_index += actual_entries;
500
501 // Write the data to memory
502 ctx.WriteBuffer(begin, range_size);
503
504 IPC::ResponseBuilder rb{ctx, 3};
505 rb.Push(RESULT_SUCCESS);
506 rb.Push<u32>(static_cast<u32>(actual_entries));
507 }
508
509private:
510 static u64 stoull_be(std::string_view str) {
511 if (str.size() != 16)
512 return 0;
513
514 const auto bytes = Common::HexStringToArray<0x8>(str);
515 u64 out{};
516 std::memcpy(&out, bytes.data(), sizeof(u64));
517
518 return Common::swap64(out);
519 }
520
521 void FindAllSaves(FileSys::SaveDataSpaceId space) {
522 const auto save_root = OpenSaveDataSpace(space);
523 ASSERT(save_root.Succeeded());
524
525 for (const auto& type : (*save_root)->GetSubdirectories()) {
526 if (type->GetName() == "save") {
527 for (const auto& save_id : type->GetSubdirectories()) {
528 for (const auto& user_id : save_id->GetSubdirectories()) {
529 const auto save_id_numeric = stoull_be(save_id->GetName());
530 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
531 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
532
533 if (save_id_numeric != 0) {
534 // System Save Data
535 info.emplace_back(SaveDataInfo{
536 0,
537 space,
538 FileSys::SaveDataType::SystemSaveData,
539 {},
540 user_id_numeric,
541 save_id_numeric,
542 0,
543 user_id->GetSize(),
544 {},
545 });
546
547 continue;
548 }
549
550 for (const auto& title_id : user_id->GetSubdirectories()) {
551 const auto device =
552 std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
553 [](u8 val) { return val == 0; });
554 info.emplace_back(SaveDataInfo{
555 0,
556 space,
557 device ? FileSys::SaveDataType::DeviceSaveData
558 : FileSys::SaveDataType::SaveData,
559 {},
560 user_id_numeric,
561 save_id_numeric,
562 stoull_be(title_id->GetName()),
563 title_id->GetSize(),
564 {},
565 });
566 }
567 }
568 }
569 } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
570 // Temporary Storage
571 for (const auto& user_id : type->GetSubdirectories()) {
572 for (const auto& title_id : user_id->GetSubdirectories()) {
573 if (!title_id->GetFiles().empty() ||
574 !title_id->GetSubdirectories().empty()) {
575 auto user_id_numeric =
576 Common::HexStringToArray<0x10>(user_id->GetName());
577 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
578
579 info.emplace_back(SaveDataInfo{
580 0,
581 space,
582 FileSys::SaveDataType::TemporaryStorage,
583 {},
584 user_id_numeric,
585 stoull_be(type->GetName()),
586 stoull_be(title_id->GetName()),
587 title_id->GetSize(),
588 {},
589 });
590 }
591 }
592 }
593 }
594 }
595 }
596
597 struct SaveDataInfo {
598 u64_le save_id_unknown;
599 FileSys::SaveDataSpaceId space;
600 FileSys::SaveDataType type;
601 INSERT_PADDING_BYTES(0x6);
602 std::array<u8, 0x10> user_id;
603 u64_le save_id;
604 u64_le title_id;
605 u64_le save_image_size;
606 INSERT_PADDING_BYTES(0x28);
607 };
608 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
609
610 std::vector<SaveDataInfo> info;
611 u64 next_entry_index = 0;
612};
613
455FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { 614FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
615 // clang-format off
456 static const FunctionInfo functions[] = { 616 static const FunctionInfo functions[] = {
457 {0, nullptr, "MountContent"}, 617 {0, nullptr, "MountContent"},
458 {1, &FSP_SRV::Initialize, "Initialize"}, 618 {1, &FSP_SRV::Initialize, "Initialize"},
@@ -486,7 +646,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
486 {58, nullptr, "ReadSaveDataFileSystemExtraData"}, 646 {58, nullptr, "ReadSaveDataFileSystemExtraData"},
487 {59, nullptr, "WriteSaveDataFileSystemExtraData"}, 647 {59, nullptr, "WriteSaveDataFileSystemExtraData"},
488 {60, nullptr, "OpenSaveDataInfoReader"}, 648 {60, nullptr, "OpenSaveDataInfoReader"},
489 {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, 649 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
490 {62, nullptr, "OpenCacheStorageList"}, 650 {62, nullptr, "OpenCacheStorageList"},
491 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, 651 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
492 {65, nullptr, "UpdateSaveDataMacForDebug"}, 652 {65, nullptr, "UpdateSaveDataMacForDebug"},
@@ -545,6 +705,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
545 {1009, nullptr, "GetAndClearMemoryReportInfo"}, 705 {1009, nullptr, "GetAndClearMemoryReportInfo"},
546 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, 706 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
547 }; 707 };
708 // clang-format on
548 RegisterHandlers(functions); 709 RegisterHandlers(functions);
549} 710}
550 711
@@ -562,6 +723,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
562 723
563 const auto type = rp.PopRaw<FileSystemType>(); 724 const auto type = rp.PopRaw<FileSystemType>();
564 const auto title_id = rp.PopRaw<u64>(); 725 const auto title_id = rp.PopRaw<u64>();
726 LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}",
727 static_cast<u8>(type), title_id);
565 728
566 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 729 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
567 rb.Push(ResultCode(-1)); 730 rb.Push(ResultCode(-1));
@@ -597,13 +760,14 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
597 auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>(); 760 auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
598 auto unk = rp.Pop<u32>(); 761 auto unk = rp.Pop<u32>();
599 LOG_INFO(Service_FS, "called with unknown={:08X}", unk); 762 LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
763
600 auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); 764 auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
601 765
602 auto dir = OpenSaveData(space_id, save_struct); 766 auto dir = OpenSaveData(space_id, save_struct);
603 767
604 if (dir.Failed()) { 768 if (dir.Failed()) {
605 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 769 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
606 rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); 770 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
607 return; 771 return;
608 } 772 }
609 773
@@ -619,6 +783,16 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
619 MountSaveData(ctx); 783 MountSaveData(ctx);
620} 784}
621 785
786void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
787 IPC::RequestParser rp{ctx};
788 const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
789 LOG_INFO(Service_FS, "called, space={}", static_cast<u8>(space));
790
791 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
792 rb.Push(RESULT_SUCCESS);
793 rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
794}
795
622void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { 796void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
623 LOG_WARNING(Service_FS, "(STUBBED) called"); 797 LOG_WARNING(Service_FS, "(STUBBED) called");
624 798
@@ -695,7 +869,7 @@ void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
695 static_cast<u8>(storage_id), title_id); 869 static_cast<u8>(storage_id), title_id);
696 870
697 IPC::ResponseBuilder rb{ctx, 2}; 871 IPC::ResponseBuilder rb{ctx, 2};
698 rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); 872 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
699} 873}
700 874
701} // namespace Service::FileSystem 875} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 4aa0358cb..e7abec0a3 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -25,6 +25,7 @@ private:
25 void CreateSaveData(Kernel::HLERequestContext& ctx); 25 void CreateSaveData(Kernel::HLERequestContext& ctx);
26 void MountSaveData(Kernel::HLERequestContext& ctx); 26 void MountSaveData(Kernel::HLERequestContext& ctx);
27 void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx); 27 void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
28 void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
28 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 29 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
29 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); 30 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
30 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); 31 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index 3d100763f..c22357d8c 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -6,9 +6,14 @@
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/hle/service/hid/controllers/debug_pad.h" 8#include "core/hle/service/hid/controllers/debug_pad.h"
9#include "core/settings.h"
9 10
10namespace Service::HID { 11namespace Service::HID {
11 12
13constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
14constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
15enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
16
12Controller_DebugPad::Controller_DebugPad() = default; 17Controller_DebugPad::Controller_DebugPad() = default;
13Controller_DebugPad::~Controller_DebugPad() = default; 18Controller_DebugPad::~Controller_DebugPad() = default;
14 19
@@ -33,10 +38,44 @@ void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) {
33 38
34 cur_entry.sampling_number = last_entry.sampling_number + 1; 39 cur_entry.sampling_number = last_entry.sampling_number + 1;
35 cur_entry.sampling_number2 = cur_entry.sampling_number; 40 cur_entry.sampling_number2 = cur_entry.sampling_number;
36 // TODO(ogniK): Update debug pad states 41 cur_entry.attribute.connected.Assign(1);
42 auto& pad = cur_entry.pad_state;
43
44 using namespace Settings::NativeButton;
45 pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
46 pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
47 pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
48 pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
49 pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
50 pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
51 pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
52 pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
53 pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
54 pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
55 pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
56 pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
57 pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
58 pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
59
60 const auto [stick_l_x_f, stick_l_y_f] =
61 analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
62 const auto [stick_r_x_f, stick_r_y_f] =
63 analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
64 cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
65 cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
66 cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
67 cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
37 68
38 std::memcpy(data, &shared_memory, sizeof(SharedMemory)); 69 std::memcpy(data, &shared_memory, sizeof(SharedMemory));
39} 70}
40 71
41void Controller_DebugPad::OnLoadInputDevices() {} 72void Controller_DebugPad::OnLoadInputDevices() {
73 std::transform(Settings::values.debug_pad_buttons.begin(),
74 Settings::values.debug_pad_buttons.begin() +
75 Settings::NativeButton::NUM_BUTTONS_HID,
76 buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
77 std::transform(Settings::values.debug_pad_analogs.begin(),
78 Settings::values.debug_pad_analogs.end(), analogs.begin(),
79 Input::CreateDevice<Input::AnalogDevice>);
80}
42} // namespace Service::HID 81} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 62b4f2682..68b734248 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -5,10 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/bit_field.h"
8#include "common/common_funcs.h" 9#include "common/common_funcs.h"
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "common/swap.h" 11#include "common/swap.h"
12#include "core/frontend/input.h"
11#include "core/hle/service/hid/controllers/controller_base.h" 13#include "core/hle/service/hid/controllers/controller_base.h"
14#include "core/settings.h"
12 15
13namespace Service::HID { 16namespace Service::HID {
14class Controller_DebugPad final : public ControllerBase { 17class Controller_DebugPad final : public ControllerBase {
@@ -35,11 +38,40 @@ private:
35 }; 38 };
36 static_assert(sizeof(AnalogStick) == 0x8); 39 static_assert(sizeof(AnalogStick) == 0x8);
37 40
41 struct PadState {
42 union {
43 u32_le raw{};
44 BitField<0, 1, u32_le> a;
45 BitField<1, 1, u32_le> b;
46 BitField<2, 1, u32_le> x;
47 BitField<3, 1, u32_le> y;
48 BitField<4, 1, u32_le> l;
49 BitField<5, 1, u32_le> r;
50 BitField<6, 1, u32_le> zl;
51 BitField<7, 1, u32_le> zr;
52 BitField<8, 1, u32_le> plus;
53 BitField<9, 1, u32_le> minus;
54 BitField<10, 1, u32_le> d_left;
55 BitField<11, 1, u32_le> d_up;
56 BitField<12, 1, u32_le> d_right;
57 BitField<13, 1, u32_le> d_down;
58 };
59 };
60 static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size");
61
62 struct Attributes {
63 union {
64 u32_le raw{};
65 BitField<0, 1, u32_le> connected;
66 };
67 };
68 static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
69
38 struct PadStates { 70 struct PadStates {
39 s64_le sampling_number; 71 s64_le sampling_number;
40 s64_le sampling_number2; 72 s64_le sampling_number2;
41 u32_le attribute; 73 Attributes attribute;
42 u32_le button_state; 74 PadState pad_state;
43 AnalogStick r_stick; 75 AnalogStick r_stick;
44 AnalogStick l_stick; 76 AnalogStick l_stick;
45 }; 77 };
@@ -52,5 +84,10 @@ private:
52 }; 84 };
53 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); 85 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
54 SharedMemory shared_memory{}; 86 SharedMemory shared_memory{};
87
88 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
89 buttons;
90 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>
91 analogs;
55}; 92};
56} // namespace Service::HID 93} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index ccfbce9ac..ca75adc2b 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -6,9 +6,11 @@
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/hle/service/hid/controllers/keyboard.h" 8#include "core/hle/service/hid/controllers/keyboard.h"
9#include "core/settings.h"
9 10
10namespace Service::HID { 11namespace Service::HID {
11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; 12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
13constexpr u8 KEYS_PER_BYTE = 8;
12 14
13Controller_Keyboard::Controller_Keyboard() = default; 15Controller_Keyboard::Controller_Keyboard() = default;
14Controller_Keyboard::~Controller_Keyboard() = default; 16Controller_Keyboard::~Controller_Keyboard() = default;
@@ -34,10 +36,24 @@ void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) {
34 36
35 cur_entry.sampling_number = last_entry.sampling_number + 1; 37 cur_entry.sampling_number = last_entry.sampling_number + 1;
36 cur_entry.sampling_number2 = cur_entry.sampling_number; 38 cur_entry.sampling_number2 = cur_entry.sampling_number;
37 // TODO(ogniK): Update keyboard states 39
40 for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
41 for (std::size_t k = 0; k < KEYS_PER_BYTE; ++k) {
42 cur_entry.key[i / KEYS_PER_BYTE] |= (keyboard_keys[i]->GetStatus() << k);
43 }
44 }
45
46 for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
47 cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i);
48 }
38 49
39 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); 50 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
40} 51}
41 52
42void Controller_Keyboard::OnLoadInputDevices() {} 53void Controller_Keyboard::OnLoadInputDevices() {
54 std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(),
55 keyboard_keys.begin(), Input::CreateDevice<Input::ButtonDevice>);
56 std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(),
57 keyboard_mods.begin(), Input::CreateDevice<Input::ButtonDevice>);
58}
43} // namespace Service::HID 59} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 493e68fce..f52775456 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -8,7 +8,9 @@
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/swap.h" 10#include "common/swap.h"
11#include "core/frontend/input.h"
11#include "core/hle/service/hid/controllers/controller_base.h" 12#include "core/hle/service/hid/controllers/controller_base.h"
13#include "core/settings.h"
12 14
13namespace Service::HID { 15namespace Service::HID {
14class Controller_Keyboard final : public ControllerBase { 16class Controller_Keyboard final : public ControllerBase {
@@ -46,5 +48,10 @@ private:
46 }; 48 };
47 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); 49 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
48 SharedMemory shared_memory{}; 50 SharedMemory shared_memory{};
51
52 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardKeys>
53 keyboard_keys;
54 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods>
55 keyboard_mods;
49}; 56};
50} // namespace Service::HID 57} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 4e246a57d..63391dbe9 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -5,6 +5,7 @@
5#include <cstring> 5#include <cstring>
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/frontend/emu_window.h"
8#include "core/hle/service/hid/controllers/mouse.h" 9#include "core/hle/service/hid/controllers/mouse.h"
9 10
10namespace Service::HID { 11namespace Service::HID {
@@ -14,7 +15,6 @@ Controller_Mouse::Controller_Mouse() = default;
14Controller_Mouse::~Controller_Mouse() = default; 15Controller_Mouse::~Controller_Mouse() = default;
15 16
16void Controller_Mouse::OnInit() {} 17void Controller_Mouse::OnInit() {}
17
18void Controller_Mouse::OnRelease() {} 18void Controller_Mouse::OnRelease() {}
19 19
20void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { 20void Controller_Mouse::OnUpdate(u8* data, std::size_t size) {
@@ -34,10 +34,29 @@ void Controller_Mouse::OnUpdate(u8* data, std::size_t size) {
34 34
35 cur_entry.sampling_number = last_entry.sampling_number + 1; 35 cur_entry.sampling_number = last_entry.sampling_number + 1;
36 cur_entry.sampling_number2 = cur_entry.sampling_number; 36 cur_entry.sampling_number2 = cur_entry.sampling_number;
37 // TODO(ogniK): Update mouse states 37
38 if (Settings::values.mouse_enabled) {
39 const auto [px, py, sx, sy] = mouse_device->GetStatus();
40 const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width);
41 const auto y = static_cast<s32>(py * Layout::ScreenUndocked::Height);
42 cur_entry.x = x;
43 cur_entry.y = y;
44 cur_entry.delta_x = x - last_entry.x;
45 cur_entry.delta_y = y - last_entry.y;
46 cur_entry.mouse_wheel_x = sx;
47 cur_entry.mouse_wheel_y = sy;
48
49 for (std::size_t i = 0; i < mouse_button_devices.size(); ++i) {
50 cur_entry.button |= (mouse_button_devices[i]->GetStatus() << i);
51 }
52 }
38 53
39 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); 54 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
40} 55}
41 56
42void Controller_Mouse::OnLoadInputDevices() {} 57void Controller_Mouse::OnLoadInputDevices() {
58 mouse_device = Input::CreateDevice<Input::MouseDevice>(Settings::values.mouse_device);
59 std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
60 mouse_button_devices.begin(), Input::CreateDevice<Input::ButtonDevice>);
61}
43} // namespace Service::HID 62} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 543b0b71f..70b654d07 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -7,7 +7,9 @@
7#include <array> 7#include <array>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/swap.h" 9#include "common/swap.h"
10#include "core/frontend/input.h"
10#include "core/hle/service/hid/controllers/controller_base.h" 11#include "core/hle/service/hid/controllers/controller_base.h"
12#include "core/settings.h"
11 13
12namespace Service::HID { 14namespace Service::HID {
13class Controller_Mouse final : public ControllerBase { 15class Controller_Mouse final : public ControllerBase {
@@ -35,7 +37,8 @@ private:
35 s32_le y; 37 s32_le y;
36 s32_le delta_x; 38 s32_le delta_x;
37 s32_le delta_y; 39 s32_le delta_y;
38 s32_le mouse_wheel; 40 s32_le mouse_wheel_x;
41 s32_le mouse_wheel_y;
39 s32_le button; 42 s32_le button;
40 s32_le attribute; 43 s32_le attribute;
41 }; 44 };
@@ -46,5 +49,9 @@ private:
46 std::array<MouseState, 17> mouse_states; 49 std::array<MouseState, 17> mouse_states;
47 }; 50 };
48 SharedMemory shared_memory{}; 51 SharedMemory shared_memory{};
52
53 std::unique_ptr<Input::MouseDevice> mouse_device;
54 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons>
55 mouse_button_devices;
49}; 56};
50} // namespace Service::HID 57} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ff9b64be4..d6829d0b8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -12,27 +12,20 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/core_timing.h" 13#include "core/core_timing.h"
14#include "core/frontend/input.h" 14#include "core/frontend/input.h"
15#include "core/hle/kernel/event.h" 15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/readable_event.h"
17#include "core/hle/kernel/writable_event.h"
16#include "core/hle/service/hid/controllers/npad.h" 18#include "core/hle/service/hid/controllers/npad.h"
17#include "core/settings.h" 19#include "core/settings.h"
18 20
19namespace Service::HID { 21namespace Service::HID {
20
21constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
22constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
23constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
24constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
25constexpr s32 HID_JOYSTICK_MAX = 0x7fff; 22constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
26constexpr s32 HID_JOYSTICK_MIN = -0x7fff; 23constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
27constexpr std::size_t NPAD_OFFSET = 0x9A00; 24constexpr std::size_t NPAD_OFFSET = 0x9A00;
28constexpr u32 BATTERY_FULL = 2; 25constexpr u32 BATTERY_FULL = 2;
29constexpr u32 NPAD_HANDHELD = 32;
30constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
31constexpr u32 MAX_NPAD_ID = 7; 26constexpr u32 MAX_NPAD_ID = 7;
32constexpr Controller_NPad::NPadControllerType PREFERRED_CONTROLLER =
33 Controller_NPad::NPadControllerType::JoyDual;
34constexpr std::array<u32, 10> npad_id_list{ 27constexpr std::array<u32, 10> npad_id_list{
35 0, 1, 2, 3, 4, 5, 6, 7, 32, 16, 28 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN,
36}; 29};
37 30
38enum class JoystickId : std::size_t { 31enum class JoystickId : std::size_t {
@@ -40,6 +33,66 @@ enum class JoystickId : std::size_t {
40 Joystick_Right, 33 Joystick_Right,
41}; 34};
42 35
36static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type) {
37 switch (type) {
38 case Settings::ControllerType::ProController:
39 return Controller_NPad::NPadControllerType::ProController;
40 case Settings::ControllerType::DualJoycon:
41 return Controller_NPad::NPadControllerType::JoyDual;
42 case Settings::ControllerType::LeftJoycon:
43 return Controller_NPad::NPadControllerType::JoyLeft;
44 case Settings::ControllerType::RightJoycon:
45 return Controller_NPad::NPadControllerType::JoyRight;
46 default:
47 UNREACHABLE();
48 return Controller_NPad::NPadControllerType::JoyDual;
49 }
50}
51
52std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
53 switch (npad_id) {
54 case 0:
55 case 1:
56 case 2:
57 case 3:
58 case 4:
59 case 5:
60 case 6:
61 case 7:
62 return npad_id;
63 case 8:
64 case NPAD_HANDHELD:
65 return 8;
66 case 9:
67 case NPAD_UNKNOWN:
68 return 9;
69 default:
70 UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id);
71 return 0;
72 }
73}
74
75u32 Controller_NPad::IndexToNPad(std::size_t index) {
76 switch (index) {
77 case 0:
78 case 1:
79 case 2:
80 case 3:
81 case 4:
82 case 5:
83 case 6:
84 case 7:
85 return static_cast<u32>(index);
86 case 8:
87 return NPAD_HANDHELD;
88 case 9:
89 return NPAD_UNKNOWN;
90 default:
91 UNIMPLEMENTED_MSG("Unknown npad index {}", index);
92 return 0;
93 };
94}
95
43Controller_NPad::Controller_NPad() = default; 96Controller_NPad::Controller_NPad() = default;
44Controller_NPad::~Controller_NPad() = default; 97Controller_NPad::~Controller_NPad() = default;
45 98
@@ -56,22 +109,32 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
56 controller.joy_styles.handheld.Assign(1); 109 controller.joy_styles.handheld.Assign(1);
57 controller.device_type.handheld.Assign(1); 110 controller.device_type.handheld.Assign(1);
58 controller.pad_assignment = NPadAssignments::Dual; 111 controller.pad_assignment = NPadAssignments::Dual;
112 controller.properties.is_vertical.Assign(1);
113 controller.properties.use_plus.Assign(1);
114 controller.properties.use_minus.Assign(1);
59 break; 115 break;
60 case NPadControllerType::JoyDual: 116 case NPadControllerType::JoyDual:
61 controller.joy_styles.joycon_dual.Assign(1); 117 controller.joy_styles.joycon_dual.Assign(1);
62 controller.device_type.joycon_left.Assign(1); 118 controller.device_type.joycon_left.Assign(1);
63 controller.device_type.joycon_right.Assign(1); 119 controller.device_type.joycon_right.Assign(1);
120 controller.properties.is_vertical.Assign(1);
121 controller.properties.use_plus.Assign(1);
122 controller.properties.use_minus.Assign(1);
64 controller.pad_assignment = NPadAssignments::Dual; 123 controller.pad_assignment = NPadAssignments::Dual;
65 break; 124 break;
66 case NPadControllerType::JoyLeft: 125 case NPadControllerType::JoyLeft:
67 controller.joy_styles.joycon_left.Assign(1); 126 controller.joy_styles.joycon_left.Assign(1);
68 controller.device_type.joycon_left.Assign(1); 127 controller.device_type.joycon_left.Assign(1);
69 controller.pad_assignment = NPadAssignments::Dual; 128 controller.properties.is_horizontal.Assign(1);
129 controller.properties.use_minus.Assign(1);
130 controller.pad_assignment = NPadAssignments::Single;
70 break; 131 break;
71 case NPadControllerType::JoyRight: 132 case NPadControllerType::JoyRight:
72 controller.joy_styles.joycon_right.Assign(1); 133 controller.joy_styles.joycon_right.Assign(1);
73 controller.device_type.joycon_right.Assign(1); 134 controller.device_type.joycon_right.Assign(1);
74 controller.pad_assignment = NPadAssignments::Dual; 135 controller.properties.is_horizontal.Assign(1);
136 controller.properties.use_plus.Assign(1);
137 controller.pad_assignment = NPadAssignments::Single;
75 break; 138 break;
76 case NPadControllerType::Pokeball: 139 case NPadControllerType::Pokeball:
77 controller.joy_styles.pokeball.Assign(1); 140 controller.joy_styles.pokeball.Assign(1);
@@ -81,6 +144,9 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
81 case NPadControllerType::ProController: 144 case NPadControllerType::ProController:
82 controller.joy_styles.pro_controller.Assign(1); 145 controller.joy_styles.pro_controller.Assign(1);
83 controller.device_type.pro_controller.Assign(1); 146 controller.device_type.pro_controller.Assign(1);
147 controller.properties.is_vertical.Assign(1);
148 controller.properties.use_plus.Assign(1);
149 controller.properties.use_minus.Assign(1);
84 controller.pad_assignment = NPadAssignments::Single; 150 controller.pad_assignment = NPadAssignments::Single;
85 break; 151 break;
86 } 152 }
@@ -90,14 +156,12 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
90 controller.single_color.button_color = 0; 156 controller.single_color.button_color = 0;
91 157
92 controller.dual_color_error = ColorReadError::ReadOk; 158 controller.dual_color_error = ColorReadError::ReadOk;
93 controller.left_color.body_color = JOYCON_BODY_NEON_BLUE; 159 controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left;
94 controller.left_color.button_color = JOYCON_BUTTONS_NEON_BLUE; 160 controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left;
95 controller.right_color.body_color = JOYCON_BODY_NEON_RED; 161 controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right;
96 controller.right_color.button_color = JOYCON_BUTTONS_NEON_RED; 162 controller.right_color.button_color =
97 163 Settings::values.players[controller_idx].button_color_right;
98 controller.properties.is_vertical.Assign(1); // TODO(ogniK): Swap joycons orientations 164
99 controller.properties.use_plus.Assign(1);
100 controller.properties.use_minus.Assign(1);
101 controller.battery_level[0] = BATTERY_FULL; 165 controller.battery_level[0] = BATTERY_FULL;
102 controller.battery_level[1] = BATTERY_FULL; 166 controller.battery_level[1] = BATTERY_FULL;
103 controller.battery_level[2] = BATTERY_FULL; 167 controller.battery_level[2] = BATTERY_FULL;
@@ -105,8 +169,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
105 169
106void Controller_NPad::OnInit() { 170void Controller_NPad::OnInit() {
107 auto& kernel = Core::System::GetInstance().Kernel(); 171 auto& kernel = Core::System::GetInstance().Kernel();
108 styleset_changed_event = 172 styleset_changed_event = Kernel::WritableEvent::CreateEventPair(
109 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); 173 kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
110 174
111 if (!IsControllerActivated()) { 175 if (!IsControllerActivated()) {
112 return; 176 return;
@@ -121,26 +185,109 @@ void Controller_NPad::OnInit() {
121 style.pro_controller.Assign(1); 185 style.pro_controller.Assign(1);
122 style.pokeball.Assign(1); 186 style.pokeball.Assign(1);
123 } 187 }
188
189 std::transform(
190 Settings::values.players.begin(), Settings::values.players.end(),
191 connected_controllers.begin(), [](const Settings::PlayerInput& player) {
192 return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected};
193 });
194
195 std::stable_partition(connected_controllers.begin(), connected_controllers.begin() + 8,
196 [](const ControllerHolder& holder) { return holder.is_connected; });
197
198 // Account for handheld
199 if (connected_controllers[8].is_connected)
200 connected_controllers[8].type = NPadControllerType::Handheld;
201
202 supported_npad_id_types.resize(npad_id_list.size());
203 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
204 npad_id_list.size() * sizeof(u32));
205
206 // Add a default dual joycon controller if none are present.
124 if (std::none_of(connected_controllers.begin(), connected_controllers.end(), 207 if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
125 [](const ControllerHolder& controller) { return controller.is_connected; })) { 208 [](const ControllerHolder& controller) { return controller.is_connected; })) {
126 supported_npad_id_types.resize(npad_id_list.size()); 209 supported_npad_id_types.resize(npad_id_list.size());
127 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), 210 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
128 npad_id_list.size() * sizeof(u32)); 211 npad_id_list.size() * sizeof(u32));
129 AddNewController(PREFERRED_CONTROLLER); 212 AddNewController(NPadControllerType::JoyDual);
213 }
214
215 for (std::size_t i = 0; i < connected_controllers.size(); ++i) {
216 const auto& controller = connected_controllers[i];
217 if (controller.is_connected) {
218 AddNewControllerAt(controller.type, IndexToNPad(i));
219 }
130 } 220 }
131} 221}
132 222
133void Controller_NPad::OnLoadInputDevices() { 223void Controller_NPad::OnLoadInputDevices() {
134 std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, 224 const auto& players = Settings::values.players;
135 Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, 225 for (std::size_t i = 0; i < players.size(); ++i) {
136 buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); 226 std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
137 std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, 227 players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
138 Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END, 228 buttons[i].begin(), Input::CreateDevice<Input::ButtonDevice>);
139 sticks.begin(), Input::CreateDevice<Input::AnalogDevice>); 229 std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
230 players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
231 sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
232 }
140} 233}
141 234
142void Controller_NPad::OnRelease() {} 235void Controller_NPad::OnRelease() {}
143 236
237void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
238 const auto controller_idx = NPadIdToIndex(npad_id);
239 const auto controller_type = connected_controllers[controller_idx].type;
240 if (!connected_controllers[controller_idx].is_connected) {
241 return;
242 }
243 auto& pad_state = npad_pad_states[controller_idx].pad_states;
244 auto& lstick_entry = npad_pad_states[controller_idx].l_stick;
245 auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
246 const auto& button_state = buttons[controller_idx];
247 const auto& analog_state = sticks[controller_idx];
248
249 using namespace Settings::NativeButton;
250 pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
251 pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
252 pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
253 pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
254 pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
255 pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
256 pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
257 pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
258 pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
259 pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
260 pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
261 pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
262
263 pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
264 pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
265 pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
266 pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
267
268 pad_state.l_stick_left.Assign(button_state[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
269 pad_state.l_stick_up.Assign(button_state[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
270 pad_state.l_stick_right.Assign(button_state[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
271 pad_state.l_stick_down.Assign(button_state[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
272
273 pad_state.r_stick_left.Assign(button_state[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
274 pad_state.r_stick_up.Assign(button_state[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
275 pad_state.r_stick_right.Assign(button_state[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
276 pad_state.r_stick_down.Assign(button_state[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
277
278 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
279 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
280
281 const auto [stick_l_x_f, stick_l_y_f] =
282 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
283 const auto [stick_r_x_f, stick_r_y_f] =
284 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
285 lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
286 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
287 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
288 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
289}
290
144void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { 291void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
145 if (!IsControllerActivated()) 292 if (!IsControllerActivated())
146 return; 293 return;
@@ -176,97 +323,9 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
176 if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { 323 if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
177 continue; 324 continue;
178 } 325 }
179 326 const u32 npad_index = static_cast<u32>(i);
180 // Pad states 327 RequestPadStateUpdate(npad_index);
181 ControllerPadState pad_state{}; 328 auto& pad_state = npad_pad_states[npad_index];
182 using namespace Settings::NativeButton;
183 pad_state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
184 pad_state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
185 pad_state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
186 pad_state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
187 pad_state.l_stick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
188 pad_state.r_stick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
189 pad_state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
190 pad_state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
191 pad_state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
192 pad_state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
193 pad_state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
194 pad_state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
195
196 pad_state.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
197 pad_state.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
198 pad_state.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
199 pad_state.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
200
201 pad_state.l_stick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
202 pad_state.l_stick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
203 pad_state.l_stick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
204 pad_state.l_stick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
205
206 pad_state.r_stick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
207 pad_state.r_stick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
208 pad_state.r_stick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
209 pad_state.r_stick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
210
211 pad_state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
212 pad_state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
213
214 AnalogPosition lstick_entry{};
215 AnalogPosition rstick_entry{};
216
217 const auto [stick_l_x_f, stick_l_y_f] =
218 sticks[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
219 const auto [stick_r_x_f, stick_r_y_f] =
220 sticks[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
221 lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
222 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
223 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
224 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
225
226 if (controller_type == NPadControllerType::JoyLeft ||
227 controller_type == NPadControllerType::JoyRight) {
228 if (npad.properties.is_horizontal) {
229 ControllerPadState state{};
230 AnalogPosition temp_lstick_entry{};
231 AnalogPosition temp_rstick_entry{};
232 if (controller_type == NPadControllerType::JoyLeft) {
233 state.d_down.Assign(pad_state.d_left.Value());
234 state.d_left.Assign(pad_state.d_up.Value());
235 state.d_right.Assign(pad_state.d_down.Value());
236 state.d_up.Assign(pad_state.d_right.Value());
237 state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
238 state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
239
240 state.zl.Assign(pad_state.zl.Value());
241 state.plus.Assign(pad_state.minus.Value());
242
243 temp_lstick_entry = lstick_entry;
244 temp_rstick_entry = rstick_entry;
245 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
246 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
247 temp_lstick_entry.y *= -1;
248 } else if (controller_type == NPadControllerType::JoyRight) {
249 state.x.Assign(pad_state.a.Value());
250 state.a.Assign(pad_state.b.Value());
251 state.b.Assign(pad_state.y.Value());
252 state.y.Assign(pad_state.b.Value());
253
254 state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
255 state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
256 state.zr.Assign(pad_state.zr.Value());
257 state.plus.Assign(pad_state.plus.Value());
258
259 temp_lstick_entry = lstick_entry;
260 temp_rstick_entry = rstick_entry;
261 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
262 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
263 temp_rstick_entry.x *= -1;
264 }
265 pad_state.raw = state.raw;
266 lstick_entry = temp_lstick_entry;
267 rstick_entry = temp_rstick_entry;
268 }
269 }
270 329
271 auto& main_controller = 330 auto& main_controller =
272 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; 331 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
@@ -281,20 +340,64 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
281 auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; 340 auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
282 341
283 if (hold_type == NpadHoldType::Horizontal) { 342 if (hold_type == NpadHoldType::Horizontal) {
284 // TODO(ogniK): Remap buttons for different orientations 343 ControllerPadState state{};
344 AnalogPosition temp_lstick_entry{};
345 AnalogPosition temp_rstick_entry{};
346 if (controller_type == NPadControllerType::JoyLeft) {
347 state.d_down.Assign(pad_state.pad_states.d_left.Value());
348 state.d_left.Assign(pad_state.pad_states.d_up.Value());
349 state.d_right.Assign(pad_state.pad_states.d_down.Value());
350 state.d_up.Assign(pad_state.pad_states.d_right.Value());
351 state.l.Assign(pad_state.pad_states.l.Value() |
352 pad_state.pad_states.left_sl.Value());
353 state.r.Assign(pad_state.pad_states.r.Value() |
354 pad_state.pad_states.left_sr.Value());
355
356 state.zl.Assign(pad_state.pad_states.zl.Value());
357 state.plus.Assign(pad_state.pad_states.minus.Value());
358
359 temp_lstick_entry = pad_state.l_stick;
360 temp_rstick_entry = pad_state.r_stick;
361 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
362 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
363 temp_lstick_entry.y *= -1;
364 } else if (controller_type == NPadControllerType::JoyRight) {
365 state.x.Assign(pad_state.pad_states.a.Value());
366 state.a.Assign(pad_state.pad_states.b.Value());
367 state.b.Assign(pad_state.pad_states.y.Value());
368 state.y.Assign(pad_state.pad_states.b.Value());
369
370 state.l.Assign(pad_state.pad_states.l.Value() |
371 pad_state.pad_states.right_sl.Value());
372 state.r.Assign(pad_state.pad_states.r.Value() |
373 pad_state.pad_states.right_sr.Value());
374 state.zr.Assign(pad_state.pad_states.zr.Value());
375 state.plus.Assign(pad_state.pad_states.plus.Value());
376
377 temp_lstick_entry = pad_state.l_stick;
378 temp_rstick_entry = pad_state.r_stick;
379 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
380 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
381 temp_rstick_entry.x *= -1;
382 }
383 pad_state.pad_states.raw = state.raw;
384 pad_state.l_stick = temp_lstick_entry;
385 pad_state.r_stick = temp_rstick_entry;
285 } 386 }
387
286 libnx_entry.connection_status.raw = 0; 388 libnx_entry.connection_status.raw = 0;
287 389
288 switch (controller_type) { 390 switch (controller_type) {
289 case NPadControllerType::Handheld: 391 case NPadControllerType::Handheld:
290 handheld_entry.connection_status.raw = 0; 392 handheld_entry.connection_status.raw = 0;
291 handheld_entry.connection_status.IsConnected.Assign(1); 393 handheld_entry.connection_status.IsWired.Assign(1);
292 if (!Settings::values.use_docked_mode) { 394 handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
293 handheld_entry.connection_status.IsWired.Assign(1); 395 handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
294 } 396 handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
295 handheld_entry.pad_states.raw = pad_state.raw; 397 handheld_entry.connection_status.IsRightJoyWired.Assign(1);
296 handheld_entry.l_stick = lstick_entry; 398 handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
297 handheld_entry.r_stick = rstick_entry; 399 handheld_entry.pad.l_stick = pad_state.l_stick;
400 handheld_entry.pad.r_stick = pad_state.r_stick;
298 break; 401 break;
299 case NPadControllerType::JoyDual: 402 case NPadControllerType::JoyDual:
300 dual_entry.connection_status.raw = 0; 403 dual_entry.connection_status.raw = 0;
@@ -307,24 +410,25 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
307 libnx_entry.connection_status.IsRightJoyConnected.Assign(1); 410 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
308 libnx_entry.connection_status.IsConnected.Assign(1); 411 libnx_entry.connection_status.IsConnected.Assign(1);
309 412
310 dual_entry.pad_states.raw = pad_state.raw; 413 dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
311 dual_entry.l_stick = lstick_entry; 414 dual_entry.pad.l_stick = pad_state.l_stick;
312 dual_entry.r_stick = rstick_entry; 415 dual_entry.pad.r_stick = pad_state.r_stick;
416 break;
313 case NPadControllerType::JoyLeft: 417 case NPadControllerType::JoyLeft:
314 left_entry.connection_status.raw = 0; 418 left_entry.connection_status.raw = 0;
315 419
316 left_entry.connection_status.IsConnected.Assign(1); 420 left_entry.connection_status.IsConnected.Assign(1);
317 left_entry.pad_states.raw = pad_state.raw; 421 left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
318 left_entry.l_stick = lstick_entry; 422 left_entry.pad.l_stick = pad_state.l_stick;
319 left_entry.r_stick = rstick_entry; 423 left_entry.pad.r_stick = pad_state.r_stick;
320 break; 424 break;
321 case NPadControllerType::JoyRight: 425 case NPadControllerType::JoyRight:
322 right_entry.connection_status.raw = 0; 426 right_entry.connection_status.raw = 0;
323 427
324 right_entry.connection_status.IsConnected.Assign(1); 428 right_entry.connection_status.IsConnected.Assign(1);
325 right_entry.pad_states.raw = pad_state.raw; 429 right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
326 right_entry.l_stick = lstick_entry; 430 right_entry.pad.l_stick = pad_state.l_stick;
327 right_entry.r_stick = rstick_entry; 431 right_entry.pad.r_stick = pad_state.r_stick;
328 break; 432 break;
329 case NPadControllerType::Pokeball: 433 case NPadControllerType::Pokeball:
330 pokeball_entry.connection_status.raw = 0; 434 pokeball_entry.connection_status.raw = 0;
@@ -332,30 +436,30 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
332 pokeball_entry.connection_status.IsConnected.Assign(1); 436 pokeball_entry.connection_status.IsConnected.Assign(1);
333 pokeball_entry.connection_status.IsWired.Assign(1); 437 pokeball_entry.connection_status.IsWired.Assign(1);
334 438
335 pokeball_entry.pad_states.raw = pad_state.raw; 439 pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
336 pokeball_entry.l_stick = lstick_entry; 440 pokeball_entry.pad.l_stick = pad_state.l_stick;
337 pokeball_entry.r_stick = rstick_entry; 441 pokeball_entry.pad.r_stick = pad_state.r_stick;
338 break; 442 break;
339 case NPadControllerType::ProController: 443 case NPadControllerType::ProController:
340 main_controller.connection_status.raw = 0; 444 main_controller.connection_status.raw = 0;
341 445
342 main_controller.connection_status.IsConnected.Assign(1); 446 main_controller.connection_status.IsConnected.Assign(1);
343 main_controller.connection_status.IsWired.Assign(1); 447 main_controller.connection_status.IsWired.Assign(1);
344 main_controller.pad_states.raw = pad_state.raw; 448 main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
345 main_controller.l_stick = lstick_entry; 449 main_controller.pad.l_stick = pad_state.l_stick;
346 main_controller.r_stick = rstick_entry; 450 main_controller.pad.r_stick = pad_state.r_stick;
347 break; 451 break;
348 } 452 }
349 453
350 // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate 454 // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
351 // any controllers. 455 // any controllers.
352 libnx_entry.pad_states.raw = pad_state.raw; 456 libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
353 libnx_entry.l_stick = lstick_entry; 457 libnx_entry.pad.l_stick = pad_state.l_stick;
354 libnx_entry.r_stick = rstick_entry; 458 libnx_entry.pad.r_stick = pad_state.r_stick;
355 } 459 }
356 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), 460 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
357 shared_memory_entries.size() * sizeof(NPadEntry)); 461 shared_memory_entries.size() * sizeof(NPadEntry));
358} // namespace Service::HID 462}
359 463
360void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { 464void Controller_NPad::SetSupportedStyleSet(NPadType style_set) {
361 style.raw = style_set.raw; 465 style.raw = style_set.raw;
@@ -370,14 +474,29 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
370 supported_npad_id_types.clear(); 474 supported_npad_id_types.clear();
371 supported_npad_id_types.resize(length / sizeof(u32)); 475 supported_npad_id_types.resize(length / sizeof(u32));
372 std::memcpy(supported_npad_id_types.data(), data, length); 476 std::memcpy(supported_npad_id_types.data(), data, length);
477 bool had_controller_update = false;
373 for (std::size_t i = 0; i < connected_controllers.size(); i++) { 478 for (std::size_t i = 0; i < connected_controllers.size(); i++) {
374 auto& controller = connected_controllers[i]; 479 auto& controller = connected_controllers[i];
375 if (!controller.is_connected) { 480 if (!controller.is_connected) {
376 continue; 481 continue;
377 } 482 }
378 if (!IsControllerSupported(PREFERRED_CONTROLLER)) { 483 const auto requested_controller =
379 controller.type = DecideBestController(PREFERRED_CONTROLLER); 484 i <= MAX_NPAD_ID ? MapSettingsTypeToNPad(Settings::values.players[i].type)
380 InitNewlyAddedControler(i); 485 : NPadControllerType::Handheld;
486 if (!IsControllerSupported(requested_controller)) {
487 const auto is_handheld = requested_controller == NPadControllerType::Handheld;
488 if (is_handheld) {
489 controller.type = NPadControllerType::None;
490 controller.is_connected = false;
491 AddNewController(requested_controller);
492 } else {
493 controller.type = requested_controller;
494 InitNewlyAddedControler(i);
495 }
496 had_controller_update = true;
497 }
498 if (had_controller_update) {
499 styleset_changed_event.writable->Signal();
381 } 500 }
382 } 501 }
383} 502}
@@ -392,7 +511,7 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
392} 511}
393 512
394void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { 513void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
395 styleset_changed_event->Signal(); 514 styleset_changed_event.writable->Signal();
396 hold_type = joy_hold_type; 515 hold_type = joy_hold_type;
397} 516}
398 517
@@ -401,44 +520,40 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
401} 520}
402 521
403void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { 522void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
404 ASSERT(npad_id < shared_memory_entries.size()); 523 const std::size_t npad_index = NPadIdToIndex(npad_id);
405 shared_memory_entries[npad_id].pad_assignment = assignment_mode; 524 ASSERT(npad_index < shared_memory_entries.size());
525 shared_memory_entries[npad_index].pad_assignment = assignment_mode;
406} 526}
407 527
408void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, 528void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
409 const std::vector<Vibration>& vibrations) { 529 const std::vector<Vibration>& vibrations) {
530 LOG_WARNING(Service_HID, "(STUBBED) called");
531
410 if (!can_controllers_vibrate) { 532 if (!can_controllers_vibrate) {
411 return; 533 return;
412 } 534 }
413 for (std::size_t i = 0; i < controller_ids.size(); i++) { 535 for (std::size_t i = 0; i < controller_ids.size(); i++) {
414 std::size_t controller_pos = i; 536 std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i));
415 // Handheld controller conversion
416 if (controller_pos == NPAD_HANDHELD) {
417 controller_pos = 8;
418 }
419 // Unknown controller conversion
420 if (controller_pos == NPAD_UNKNOWN) {
421 controller_pos = 9;
422 }
423 if (connected_controllers[controller_pos].is_connected) { 537 if (connected_controllers[controller_pos].is_connected) {
424 // TODO(ogniK): Vibrate the physical controller 538 // TODO(ogniK): Vibrate the physical controller
425 } 539 }
426 } 540 }
427 LOG_WARNING(Service_HID, "(STUBBED) called");
428 last_processed_vibration = vibrations.back(); 541 last_processed_vibration = vibrations.back();
429} 542}
430 543
431Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { 544Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const {
432 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should 545 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
433 // be signalled at least once, and signaled after a new controller is connected? 546 // be signalled at least once, and signaled after a new controller is connected?
434 styleset_changed_event->Signal(); 547 styleset_changed_event.writable->Signal();
435 return styleset_changed_event; 548 return styleset_changed_event.readable;
436} 549}
437 550
438Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { 551Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
439 return last_processed_vibration; 552 return last_processed_vibration;
440} 553}
554
441void Controller_NPad::AddNewController(NPadControllerType controller) { 555void Controller_NPad::AddNewController(NPadControllerType controller) {
556 controller = DecideBestController(controller);
442 if (controller == NPadControllerType::Handheld) { 557 if (controller == NPadControllerType::Handheld) {
443 connected_controllers[8] = {controller, true}; 558 connected_controllers[8] = {controller, true};
444 InitNewlyAddedControler(8); 559 InitNewlyAddedControler(8);
@@ -456,16 +571,54 @@ void Controller_NPad::AddNewController(NPadControllerType controller) {
456 InitNewlyAddedControler(controller_id); 571 InitNewlyAddedControler(controller_id);
457} 572}
458 573
459void Controller_NPad::ConnectNPad(u32 npad_id) { 574void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) {
460 if (npad_id >= connected_controllers.size()) 575 controller = DecideBestController(controller);
576 if (controller == NPadControllerType::Handheld) {
577 connected_controllers[NPadIdToIndex(NPAD_HANDHELD)] = {controller, true};
578 InitNewlyAddedControler(NPadIdToIndex(NPAD_HANDHELD));
461 return; 579 return;
462 connected_controllers[npad_id].is_connected = true; 580 }
581
582 connected_controllers[NPadIdToIndex(npad_id)] = {controller, true};
583 InitNewlyAddedControler(NPadIdToIndex(npad_id));
584}
585
586void Controller_NPad::ConnectNPad(u32 npad_id) {
587 connected_controllers[NPadIdToIndex(npad_id)].is_connected = true;
463} 588}
464 589
465void Controller_NPad::DisconnectNPad(u32 npad_id) { 590void Controller_NPad::DisconnectNPad(u32 npad_id) {
466 if (npad_id >= connected_controllers.size()) 591 connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
467 return; 592}
468 connected_controllers[npad_id].is_connected = false; 593
594bool Controller_NPad::IsControllerSupported(NPadControllerType controller) {
595 if (controller == NPadControllerType::Handheld) {
596 // Handheld is not even a supported type, lets stop here
597 if (std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(),
598 NPAD_HANDHELD) == supported_npad_id_types.end()) {
599 return false;
600 }
601 // Handheld should not be supported in docked mode
602 if (Settings::values.use_docked_mode) {
603 return false;
604 }
605 }
606 switch (controller) {
607 case NPadControllerType::ProController:
608 return style.pro_controller;
609 case NPadControllerType::Handheld:
610 return style.handheld;
611 case NPadControllerType::JoyDual:
612 return style.joycon_dual;
613 case NPadControllerType::JoyLeft:
614 return style.joycon_left;
615 case NPadControllerType::JoyRight:
616 return style.joycon_right;
617 case NPadControllerType::Pokeball:
618 return style.pokeball;
619 default:
620 return false;
621 }
469} 622}
470 623
471Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { 624Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
@@ -499,6 +652,36 @@ void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
499 can_controllers_vibrate = can_vibrate; 652 can_controllers_vibrate = can_vibrate;
500} 653}
501 654
655void Controller_NPad::ClearAllConnectedControllers() {
656 for (auto& controller : connected_controllers) {
657 if (controller.is_connected && controller.type != NPadControllerType::None) {
658 controller.type = NPadControllerType::None;
659 controller.is_connected = false;
660 }
661 }
662}
663void Controller_NPad::DisconnectAllConnectedControllers() {
664 std::for_each(connected_controllers.begin(), connected_controllers.end(),
665 [](ControllerHolder& controller) { controller.is_connected = false; });
666}
667
668void Controller_NPad::ConnectAllDisconnectedControllers() {
669 std::for_each(connected_controllers.begin(), connected_controllers.end(),
670 [](ControllerHolder& controller) {
671 if (controller.type != NPadControllerType::None && !controller.is_connected) {
672 controller.is_connected = false;
673 }
674 });
675}
676
677void Controller_NPad::ClearAllControllers() {
678 std::for_each(connected_controllers.begin(), connected_controllers.end(),
679 [](ControllerHolder& controller) {
680 controller.type = NPadControllerType::None;
681 controller.is_connected = false;
682 });
683}
684
502bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { 685bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
503 const bool support_handheld = 686 const bool support_handheld =
504 std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != 687 std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) !=
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index ac86985ff..29851f16a 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -5,13 +5,19 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/bit_field.h"
8#include "common/common_types.h" 9#include "common/common_types.h"
9#include "core/frontend/input.h" 10#include "core/frontend/input.h"
11#include "core/hle/kernel/object.h"
12#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/hid/controllers/controller_base.h" 13#include "core/hle/service/hid/controllers/controller_base.h"
11#include "core/settings.h" 14#include "core/settings.h"
12 15
13namespace Service::HID { 16namespace Service::HID {
14 17
18constexpr u32 NPAD_HANDHELD = 32;
19constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
20
15class Controller_NPad final : public ControllerBase { 21class Controller_NPad final : public ControllerBase {
16public: 22public:
17 Controller_NPad(); 23 Controller_NPad();
@@ -75,9 +81,9 @@ public:
75 struct LedPattern { 81 struct LedPattern {
76 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { 82 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
77 position1.Assign(light1); 83 position1.Assign(light1);
78 position1.Assign(light2); 84 position2.Assign(light2);
79 position1.Assign(light3); 85 position3.Assign(light3);
80 position1.Assign(light4); 86 position4.Assign(light4);
81 } 87 }
82 union { 88 union {
83 u64 raw{}; 89 u64 raw{};
@@ -103,15 +109,23 @@ public:
103 void VibrateController(const std::vector<u32>& controller_ids, 109 void VibrateController(const std::vector<u32>& controller_ids,
104 const std::vector<Vibration>& vibrations); 110 const std::vector<Vibration>& vibrations);
105 111
106 Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const; 112 Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const;
107 Vibration GetLastVibration() const; 113 Vibration GetLastVibration() const;
108 114
109 void AddNewController(NPadControllerType controller); 115 void AddNewController(NPadControllerType controller);
116 void AddNewControllerAt(NPadControllerType controller, u32 npad_id);
110 117
111 void ConnectNPad(u32 npad_id); 118 void ConnectNPad(u32 npad_id);
112 void DisconnectNPad(u32 npad_id); 119 void DisconnectNPad(u32 npad_id);
113 LedPattern GetLedPattern(u32 npad_id); 120 LedPattern GetLedPattern(u32 npad_id);
114 void SetVibrationEnabled(bool can_vibrate); 121 void SetVibrationEnabled(bool can_vibrate);
122 void ClearAllConnectedControllers();
123 void DisconnectAllConnectedControllers();
124 void ConnectAllDisconnectedControllers();
125 void ClearAllControllers();
126
127 static std::size_t NPadIdToIndex(u32 npad_id);
128 static u32 IndexToNPad(std::size_t index);
115 129
116private: 130private:
117 struct CommonHeader { 131 struct CommonHeader {
@@ -164,8 +178,11 @@ private:
164 BitField<23, 1, u64_le> r_stick_down; 178 BitField<23, 1, u64_le> r_stick_down;
165 179
166 // Not always active? 180 // Not always active?
167 BitField<24, 1, u64_le> sl; 181 BitField<24, 1, u64_le> left_sl;
168 BitField<25, 1, u64_le> sr; 182 BitField<25, 1, u64_le> left_sr;
183
184 BitField<26, 1, u64_le> right_sl;
185 BitField<27, 1, u64_le> right_sr;
169 }; 186 };
170 }; 187 };
171 static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); 188 static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size");
@@ -189,12 +206,17 @@ private:
189 }; 206 };
190 static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); 207 static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
191 208
192 struct GenericStates { 209 struct ControllerPad {
193 s64_le timestamp;
194 s64_le timestamp2;
195 ControllerPadState pad_states; 210 ControllerPadState pad_states;
196 AnalogPosition l_stick; 211 AnalogPosition l_stick;
197 AnalogPosition r_stick; 212 AnalogPosition r_stick;
213 };
214 static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size");
215
216 struct GenericStates {
217 s64_le timestamp;
218 s64_le timestamp2;
219 ControllerPad pad;
198 ConnectionState connection_status; 220 ConnectionState connection_status;
199 }; 221 };
200 static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size"); 222 static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size");
@@ -266,18 +288,23 @@ private:
266 static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); 288 static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
267 289
268 struct ControllerHolder { 290 struct ControllerHolder {
269 Controller_NPad::NPadControllerType type; 291 NPadControllerType type;
270 bool is_connected; 292 bool is_connected;
271 }; 293 };
272 294
273 NPadType style{}; 295 NPadType style{};
274 std::array<NPadEntry, 10> shared_memory_entries{}; 296 std::array<NPadEntry, 10> shared_memory_entries{};
275 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> 297 std::array<
298 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
299 10>
276 buttons; 300 buttons;
277 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; 301 std::array<
302 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
303 10>
304 sticks;
278 std::vector<u32> supported_npad_id_types{}; 305 std::vector<u32> supported_npad_id_types{};
279 NpadHoldType hold_type{NpadHoldType::Vertical}; 306 NpadHoldType hold_type{NpadHoldType::Vertical};
280 Kernel::SharedPtr<Kernel::Event> styleset_changed_event; 307 Kernel::EventPair styleset_changed_event;
281 Vibration last_processed_vibration{}; 308 Vibration last_processed_vibration{};
282 std::array<ControllerHolder, 10> connected_controllers{}; 309 std::array<ControllerHolder, 10> connected_controllers{};
283 bool can_controllers_vibrate{true}; 310 bool can_controllers_vibrate{true};
@@ -285,5 +312,8 @@ private:
285 void InitNewlyAddedControler(std::size_t controller_idx); 312 void InitNewlyAddedControler(std::size_t controller_idx);
286 bool IsControllerSupported(NPadControllerType controller) const; 313 bool IsControllerSupported(NPadControllerType controller) const;
287 NPadControllerType DecideBestController(NPadControllerType priority) const; 314 NPadControllerType DecideBestController(NPadControllerType priority) const;
315 void RequestPadStateUpdate(u32 npad_id);
316 std::array<ControllerPad, 10> npad_pad_states{};
317 bool IsControllerSupported(NPadControllerType controller);
288}; 318};
289} // namespace Service::HID 319} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index 43efef803..f666b1bd8 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -41,16 +41,17 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
41 41
42 const auto [x, y, pressed] = touch_device->GetStatus(); 42 const auto [x, y, pressed] = touch_device->GetStatus();
43 auto& touch_entry = cur_entry.states[0]; 43 auto& touch_entry = cur_entry.states[0];
44 if (pressed) { 44 touch_entry.attribute.raw = 0;
45 if (pressed && Settings::values.touchscreen.enabled) {
45 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); 46 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width);
46 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); 47 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height);
47 touch_entry.diameter_x = 15; 48 touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
48 touch_entry.diameter_y = 15; 49 touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
49 touch_entry.rotation_angle = 0; 50 touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
50 const u64 tick = CoreTiming::GetTicks(); 51 const u64 tick = CoreTiming::GetTicks();
51 touch_entry.delta_time = tick - last_touch; 52 touch_entry.delta_time = tick - last_touch;
52 last_touch = tick; 53 last_touch = tick;
53 touch_entry.finger = 0; 54 touch_entry.finger = Settings::values.touchscreen.finger;
54 cur_entry.entry_count = 1; 55 cur_entry.entry_count = 1;
55 } else { 56 } else {
56 cur_entry.entry_count = 0; 57 cur_entry.entry_count = 0;
@@ -60,6 +61,6 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
60} 61}
61 62
62void Controller_Touchscreen::OnLoadInputDevices() { 63void Controller_Touchscreen::OnLoadInputDevices() {
63 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device); 64 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device);
64} 65}
65} // namespace Service::HID 66} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index e5db6e6ba..94cd0eba9 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/bit_field.h"
7#include "common/common_funcs.h" 8#include "common/common_funcs.h"
8#include "common/common_types.h" 9#include "common/common_types.h"
9#include "common/swap.h" 10#include "common/swap.h"
@@ -29,9 +30,18 @@ public:
29 void OnLoadInputDevices() override; 30 void OnLoadInputDevices() override;
30 31
31private: 32private:
33 struct Attributes {
34 union {
35 u32 raw{};
36 BitField<0, 1, u32_le> start_touch;
37 BitField<1, 1, u32_le> end_touch;
38 };
39 };
40 static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
41
32 struct TouchState { 42 struct TouchState {
33 u64_le delta_time; 43 u64_le delta_time;
34 u32_le attribute; 44 Attributes attribute;
35 u32_le finger; 45 u32_le finger;
36 u32_le x; 46 u32_le x;
37 u32_le y; 47 u32_le y;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a45fd4954..2ec38c726 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -13,8 +13,9 @@
13#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/client_port.h" 14#include "core/hle/kernel/client_port.h"
15#include "core/hle/kernel/client_session.h" 15#include "core/hle/kernel/client_session.h"
16#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/readable_event.h"
17#include "core/hle/kernel/shared_memory.h" 17#include "core/hle/kernel/shared_memory.h"
18#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/hid/hid.h" 19#include "core/hle/service/hid/hid.h"
19#include "core/hle/service/hid/irs.h" 20#include "core/hle/service/hid/irs.h"
20#include "core/hle/service/hid/xcd.h" 21#include "core/hle/service/hid/xcd.h"
@@ -34,8 +35,8 @@
34namespace Service::HID { 35namespace Service::HID {
35 36
36// Updating period for each HID device. 37// Updating period for each HID device.
37// TODO(shinyquagsire23): These need better values. 38// TODO(ogniK): Find actual polling rate of hid
38constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 39constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 66;
39constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 40constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
40constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 41constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
41constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 42constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
@@ -124,10 +125,11 @@ public:
124 125
125private: 126private:
126 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 127 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
128 LOG_DEBUG(Service_HID, "called");
129
127 IPC::ResponseBuilder rb{ctx, 2, 1}; 130 IPC::ResponseBuilder rb{ctx, 2, 1};
128 rb.Push(RESULT_SUCCESS); 131 rb.Push(RESULT_SUCCESS);
129 rb.PushCopyObjects(shared_mem); 132 rb.PushCopyObjects(shared_mem);
130 LOG_DEBUG(Service_HID, "called");
131 } 133 }
132 134
133 void UpdateControllers(u64 userdata, int cycles_late) { 135 void UpdateControllers(u64 userdata, int cycles_late) {
@@ -163,9 +165,10 @@ public:
163 165
164private: 166private:
165 void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { 167 void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) {
168 LOG_WARNING(Service_HID, "(STUBBED) called");
169
166 IPC::ResponseBuilder rb{ctx, 2}; 170 IPC::ResponseBuilder rb{ctx, 2};
167 rb.Push(RESULT_SUCCESS); 171 rb.Push(RESULT_SUCCESS);
168 LOG_WARNING(Service_HID, "(STUBBED) called");
169 } 172 }
170}; 173};
171 174
@@ -286,10 +289,10 @@ public:
286 {519, nullptr, "GetPalmaOperationResult"}, 289 {519, nullptr, "GetPalmaOperationResult"},
287 {520, nullptr, "ReadPalmaPlayLog"}, 290 {520, nullptr, "ReadPalmaPlayLog"},
288 {521, nullptr, "ResetPalmaPlayLog"}, 291 {521, nullptr, "ResetPalmaPlayLog"},
289 {522, nullptr, "SetIsPalmaAllConnectable"}, 292 {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
290 {523, nullptr, "SetIsPalmaPairedConnectable"}, 293 {523, nullptr, "SetIsPalmaPairedConnectable"},
291 {524, nullptr, "PairPalma"}, 294 {524, nullptr, "PairPalma"},
292 {525, nullptr, "SetPalmaBoostMode"}, 295 {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
293 {1000, nullptr, "SetNpadCommunicationMode"}, 296 {1000, nullptr, "SetNpadCommunicationMode"},
294 {1001, nullptr, "GetNpadCommunicationMode"}, 297 {1001, nullptr, "GetNpadCommunicationMode"},
295 }; 298 };
@@ -303,6 +306,8 @@ private:
303 std::shared_ptr<IAppletResource> applet_resource; 306 std::shared_ptr<IAppletResource> applet_resource;
304 307
305 void CreateAppletResource(Kernel::HLERequestContext& ctx) { 308 void CreateAppletResource(Kernel::HLERequestContext& ctx) {
309 LOG_DEBUG(Service_HID, "called");
310
306 if (applet_resource == nullptr) { 311 if (applet_resource == nullptr) {
307 applet_resource = std::make_shared<IAppletResource>(); 312 applet_resource = std::make_shared<IAppletResource>();
308 } 313 }
@@ -310,206 +315,228 @@ private:
310 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 315 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
311 rb.Push(RESULT_SUCCESS); 316 rb.Push(RESULT_SUCCESS);
312 rb.PushIpcInterface<IAppletResource>(applet_resource); 317 rb.PushIpcInterface<IAppletResource>(applet_resource);
313 LOG_DEBUG(Service_HID, "called");
314 } 318 }
315 319
316 void ActivateXpad(Kernel::HLERequestContext& ctx) { 320 void ActivateXpad(Kernel::HLERequestContext& ctx) {
321 LOG_DEBUG(Service_HID, "called");
322
317 applet_resource->ActivateController(HidController::XPad); 323 applet_resource->ActivateController(HidController::XPad);
318 IPC::ResponseBuilder rb{ctx, 2}; 324 IPC::ResponseBuilder rb{ctx, 2};
319 rb.Push(RESULT_SUCCESS); 325 rb.Push(RESULT_SUCCESS);
320 LOG_DEBUG(Service_HID, "called");
321 } 326 }
322 327
323 void ActivateDebugPad(Kernel::HLERequestContext& ctx) { 328 void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
329 LOG_DEBUG(Service_HID, "called");
330
324 applet_resource->ActivateController(HidController::DebugPad); 331 applet_resource->ActivateController(HidController::DebugPad);
325 IPC::ResponseBuilder rb{ctx, 2}; 332 IPC::ResponseBuilder rb{ctx, 2};
326 rb.Push(RESULT_SUCCESS); 333 rb.Push(RESULT_SUCCESS);
327 LOG_DEBUG(Service_HID, "called");
328 } 334 }
329 335
330 void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { 336 void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
337 LOG_DEBUG(Service_HID, "called");
338
331 applet_resource->ActivateController(HidController::Touchscreen); 339 applet_resource->ActivateController(HidController::Touchscreen);
332 IPC::ResponseBuilder rb{ctx, 2}; 340 IPC::ResponseBuilder rb{ctx, 2};
333 rb.Push(RESULT_SUCCESS); 341 rb.Push(RESULT_SUCCESS);
334 LOG_DEBUG(Service_HID, "called");
335 } 342 }
336 343
337 void ActivateMouse(Kernel::HLERequestContext& ctx) { 344 void ActivateMouse(Kernel::HLERequestContext& ctx) {
345 LOG_DEBUG(Service_HID, "called");
346
338 applet_resource->ActivateController(HidController::Mouse); 347 applet_resource->ActivateController(HidController::Mouse);
339 IPC::ResponseBuilder rb{ctx, 2}; 348 IPC::ResponseBuilder rb{ctx, 2};
340 rb.Push(RESULT_SUCCESS); 349 rb.Push(RESULT_SUCCESS);
341 LOG_DEBUG(Service_HID, "called");
342 } 350 }
343 351
344 void ActivateKeyboard(Kernel::HLERequestContext& ctx) { 352 void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
353 LOG_DEBUG(Service_HID, "called");
354
345 applet_resource->ActivateController(HidController::Keyboard); 355 applet_resource->ActivateController(HidController::Keyboard);
346 IPC::ResponseBuilder rb{ctx, 2}; 356 IPC::ResponseBuilder rb{ctx, 2};
347 rb.Push(RESULT_SUCCESS); 357 rb.Push(RESULT_SUCCESS);
348 LOG_DEBUG(Service_HID, "called");
349 } 358 }
350 359
351 void ActivateGesture(Kernel::HLERequestContext& ctx) { 360 void ActivateGesture(Kernel::HLERequestContext& ctx) {
361 LOG_DEBUG(Service_HID, "called");
362
352 applet_resource->ActivateController(HidController::Gesture); 363 applet_resource->ActivateController(HidController::Gesture);
353 IPC::ResponseBuilder rb{ctx, 2}; 364 IPC::ResponseBuilder rb{ctx, 2};
354 rb.Push(RESULT_SUCCESS); 365 rb.Push(RESULT_SUCCESS);
355 LOG_DEBUG(Service_HID, "called");
356 } 366 }
357 367
358 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { 368 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
359 // Should have no effect with how our npad sets up the data 369 // Should have no effect with how our npad sets up the data
370 LOG_DEBUG(Service_HID, "called");
371
360 applet_resource->ActivateController(HidController::NPad); 372 applet_resource->ActivateController(HidController::NPad);
361 IPC::ResponseBuilder rb{ctx, 2}; 373 IPC::ResponseBuilder rb{ctx, 2};
362 rb.Push(RESULT_SUCCESS); 374 rb.Push(RESULT_SUCCESS);
363 LOG_DEBUG(Service_HID, "called");
364 } 375 }
365 376
366 void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { 377 void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
367 IPC::RequestParser rp{ctx}; 378 IPC::RequestParser rp{ctx};
368 auto handle = rp.PopRaw<u32>(); 379 auto handle = rp.PopRaw<u32>();
380 LOG_WARNING(Service_HID, "(STUBBED) called with handle={}", handle);
381
369 IPC::ResponseBuilder rb{ctx, 2}; 382 IPC::ResponseBuilder rb{ctx, 2};
370 rb.Push(RESULT_SUCCESS); 383 rb.Push(RESULT_SUCCESS);
371 LOG_WARNING(Service_HID, "(STUBBED) called");
372 } 384 }
373 385
374 void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 386 void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
387 LOG_WARNING(Service_HID, "(STUBBED) called");
388
375 IPC::ResponseBuilder rb{ctx, 2}; 389 IPC::ResponseBuilder rb{ctx, 2};
376 rb.Push(RESULT_SUCCESS); 390 rb.Push(RESULT_SUCCESS);
377 LOG_WARNING(Service_HID, "(STUBBED) called");
378 } 391 }
379 392
380 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { 393 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
394 LOG_WARNING(Service_HID, "(STUBBED) called");
395
381 IPC::ResponseBuilder rb{ctx, 3}; 396 IPC::ResponseBuilder rb{ctx, 3};
382 rb.Push(RESULT_SUCCESS); 397 rb.Push(RESULT_SUCCESS);
383 // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. 398 // TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
384 rb.Push(true); 399 rb.Push(true);
385 LOG_WARNING(Service_HID, "(STUBBED) called");
386 } 400 }
387 401
388 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 402 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
389 IPC::RequestParser rp{ctx}; 403 IPC::RequestParser rp{ctx};
390 auto supported_styleset = rp.PopRaw<u32>(); 404 auto supported_styleset = rp.PopRaw<u32>();
405 LOG_DEBUG(Service_HID, "called with supported_styleset={}", supported_styleset);
406
391 applet_resource->GetController<Controller_NPad>(HidController::NPad) 407 applet_resource->GetController<Controller_NPad>(HidController::NPad)
392 .SetSupportedStyleSet({supported_styleset}); 408 .SetSupportedStyleSet({supported_styleset});
393 409
394 IPC::ResponseBuilder rb{ctx, 2}; 410 IPC::ResponseBuilder rb{ctx, 2};
395 rb.Push(RESULT_SUCCESS); 411 rb.Push(RESULT_SUCCESS);
396
397 LOG_DEBUG(Service_HID, "called");
398 } 412 }
399 413
400 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 414 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
415 LOG_DEBUG(Service_HID, "called");
416
401 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 417 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
402 418
403 IPC::ResponseBuilder rb{ctx, 3}; 419 IPC::ResponseBuilder rb{ctx, 3};
404 rb.Push(RESULT_SUCCESS); 420 rb.Push(RESULT_SUCCESS);
405 rb.Push<u32>(controller.GetSupportedStyleSet().raw); 421 rb.Push<u32>(controller.GetSupportedStyleSet().raw);
406 LOG_DEBUG(Service_HID, "called");
407 } 422 }
408 423
409 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { 424 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
425 LOG_DEBUG(Service_HID, "called");
426
410 applet_resource->GetController<Controller_NPad>(HidController::NPad) 427 applet_resource->GetController<Controller_NPad>(HidController::NPad)
411 .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); 428 .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
412 IPC::ResponseBuilder rb{ctx, 2}; 429 IPC::ResponseBuilder rb{ctx, 2};
413 rb.Push(RESULT_SUCCESS); 430 rb.Push(RESULT_SUCCESS);
414 LOG_DEBUG(Service_HID, "called");
415 } 431 }
416 432
417 void ActivateNpad(Kernel::HLERequestContext& ctx) { 433 void ActivateNpad(Kernel::HLERequestContext& ctx) {
434 LOG_DEBUG(Service_HID, "called");
435
418 IPC::ResponseBuilder rb{ctx, 2}; 436 IPC::ResponseBuilder rb{ctx, 2};
419 rb.Push(RESULT_SUCCESS); 437 rb.Push(RESULT_SUCCESS);
420 applet_resource->ActivateController(HidController::NPad); 438 applet_resource->ActivateController(HidController::NPad);
421 LOG_DEBUG(Service_HID, "called");
422 } 439 }
423 440
424 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { 441 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
425 IPC::RequestParser rp{ctx}; 442 IPC::RequestParser rp{ctx};
426 auto npad_id = rp.PopRaw<u32>(); 443 auto npad_id = rp.PopRaw<u32>();
444 LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
445
427 IPC::ResponseBuilder rb{ctx, 2, 1}; 446 IPC::ResponseBuilder rb{ctx, 2, 1};
428 rb.Push(RESULT_SUCCESS); 447 rb.Push(RESULT_SUCCESS);
429 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) 448 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
430 .GetStyleSetChangedEvent()); 449 .GetStyleSetChangedEvent());
431 LOG_DEBUG(Service_HID, "called");
432 } 450 }
433 451
434 void DisconnectNpad(Kernel::HLERequestContext& ctx) { 452 void DisconnectNpad(Kernel::HLERequestContext& ctx) {
435 IPC::RequestParser rp{ctx}; 453 IPC::RequestParser rp{ctx};
436 auto npad_id = rp.PopRaw<u32>(); 454 auto npad_id = rp.PopRaw<u32>();
455 LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
456
437 applet_resource->GetController<Controller_NPad>(HidController::NPad) 457 applet_resource->GetController<Controller_NPad>(HidController::NPad)
438 .DisconnectNPad(npad_id); 458 .DisconnectNPad(npad_id);
439 IPC::ResponseBuilder rb{ctx, 2}; 459 IPC::ResponseBuilder rb{ctx, 2};
440 rb.Push(RESULT_SUCCESS); 460 rb.Push(RESULT_SUCCESS);
441 LOG_DEBUG(Service_HID, "called");
442 } 461 }
443 462
444 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { 463 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
445 IPC::RequestParser rp{ctx}; 464 IPC::RequestParser rp{ctx};
446 auto npad_id = rp.PopRaw<u32>(); 465 auto npad_id = rp.PopRaw<u32>();
466 LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
467
447 IPC::ResponseBuilder rb{ctx, 4}; 468 IPC::ResponseBuilder rb{ctx, 4};
448 rb.Push(RESULT_SUCCESS); 469 rb.Push(RESULT_SUCCESS);
449 rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) 470 rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
450 .GetLedPattern(npad_id) 471 .GetLedPattern(npad_id)
451 .raw); 472 .raw);
452 LOG_DEBUG(Service_HID, "called");
453 } 473 }
454 474
455 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 475 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
456 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
457 IPC::RequestParser rp{ctx}; 476 IPC::RequestParser rp{ctx};
458 const auto hold_type = rp.PopRaw<u64>(); 477 const auto hold_type = rp.PopRaw<u64>();
478 LOG_DEBUG(Service_HID, "called with hold_type={}", hold_type);
479
480 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
459 controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); 481 controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
460 482
461 IPC::ResponseBuilder rb{ctx, 2}; 483 IPC::ResponseBuilder rb{ctx, 2};
462 rb.Push(RESULT_SUCCESS); 484 rb.Push(RESULT_SUCCESS);
463 LOG_DEBUG(Service_HID, "called");
464 } 485 }
465 486
466 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 487 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
488 LOG_DEBUG(Service_HID, "called");
489
467 const auto& controller = 490 const auto& controller =
468 applet_resource->GetController<Controller_NPad>(HidController::NPad); 491 applet_resource->GetController<Controller_NPad>(HidController::NPad);
469 IPC::ResponseBuilder rb{ctx, 4}; 492 IPC::ResponseBuilder rb{ctx, 4};
470 rb.Push(RESULT_SUCCESS); 493 rb.Push(RESULT_SUCCESS);
471 rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); 494 rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
472 LOG_DEBUG(Service_HID, "called");
473 } 495 }
474 496
475 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { 497 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
476 IPC::RequestParser rp{ctx}; 498 IPC::RequestParser rp{ctx};
477 auto npad_id = rp.PopRaw<u32>(); 499 auto npad_id = rp.PopRaw<u32>();
500 LOG_WARNING(Service_HID, "(STUBBED) called with npad_id={}", npad_id);
501
478 IPC::ResponseBuilder rb{ctx, 2}; 502 IPC::ResponseBuilder rb{ctx, 2};
479 rb.Push(RESULT_SUCCESS); 503 rb.Push(RESULT_SUCCESS);
480 LOG_WARNING(Service_HID, "(STUBBED) called");
481 } 504 }
482 505
483 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { 506 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
507 LOG_DEBUG(Service_HID, "called");
508
484 applet_resource->GetController<Controller_NPad>(HidController::NPad) 509 applet_resource->GetController<Controller_NPad>(HidController::NPad)
485 .SetVibrationEnabled(true); 510 .SetVibrationEnabled(true);
486 IPC::ResponseBuilder rb{ctx, 2}; 511 IPC::ResponseBuilder rb{ctx, 2};
487 rb.Push(RESULT_SUCCESS); 512 rb.Push(RESULT_SUCCESS);
488 LOG_DEBUG(Service_HID, "called");
489 } 513 }
490 514
491 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { 515 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
516 LOG_DEBUG(Service_HID, "called");
517
492 applet_resource->GetController<Controller_NPad>(HidController::NPad) 518 applet_resource->GetController<Controller_NPad>(HidController::NPad)
493 .SetVibrationEnabled(false); 519 .SetVibrationEnabled(false);
494 IPC::ResponseBuilder rb{ctx, 2}; 520 IPC::ResponseBuilder rb{ctx, 2};
495 rb.Push(RESULT_SUCCESS); 521 rb.Push(RESULT_SUCCESS);
496 LOG_DEBUG(Service_HID, "called");
497 } 522 }
498 523
499 void SendVibrationValue(Kernel::HLERequestContext& ctx) { 524 void SendVibrationValue(Kernel::HLERequestContext& ctx) {
500 IPC::RequestParser rp{ctx}; 525 IPC::RequestParser rp{ctx};
501 const auto controller_id = rp.PopRaw<u32>(); 526 const auto controller_id = rp.PopRaw<u32>();
502 const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); 527 const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>();
528 LOG_DEBUG(Service_HID, "called with controller_id={}", controller_id);
503 529
504 IPC::ResponseBuilder rb{ctx, 2}; 530 IPC::ResponseBuilder rb{ctx, 2};
505 rb.Push(RESULT_SUCCESS); 531 rb.Push(RESULT_SUCCESS);
506 532
507 applet_resource->GetController<Controller_NPad>(HidController::NPad) 533 applet_resource->GetController<Controller_NPad>(HidController::NPad)
508 .VibrateController({controller_id}, {vibration_values}); 534 .VibrateController({controller_id}, {vibration_values});
509 LOG_DEBUG(Service_HID, "called");
510 } 535 }
511 536
512 void SendVibrationValues(Kernel::HLERequestContext& ctx) { 537 void SendVibrationValues(Kernel::HLERequestContext& ctx) {
538 LOG_DEBUG(Service_HID, "called");
539
513 const auto controllers = ctx.ReadBuffer(0); 540 const auto controllers = ctx.ReadBuffer(0);
514 const auto vibrations = ctx.ReadBuffer(1); 541 const auto vibrations = ctx.ReadBuffer(1);
515 542
@@ -527,74 +554,96 @@ private:
527 554
528 IPC::ResponseBuilder rb{ctx, 2}; 555 IPC::ResponseBuilder rb{ctx, 2};
529 rb.Push(RESULT_SUCCESS); 556 rb.Push(RESULT_SUCCESS);
530 LOG_DEBUG(Service_HID, "called");
531 } 557 }
532 558
533 void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { 559 void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
560 LOG_DEBUG(Service_HID, "called");
561
534 IPC::ResponseBuilder rb{ctx, 6}; 562 IPC::ResponseBuilder rb{ctx, 6};
535 rb.Push(RESULT_SUCCESS); 563 rb.Push(RESULT_SUCCESS);
536 rb.PushRaw<Controller_NPad::Vibration>( 564 rb.PushRaw<Controller_NPad::Vibration>(
537 applet_resource->GetController<Controller_NPad>(HidController::NPad) 565 applet_resource->GetController<Controller_NPad>(HidController::NPad)
538 .GetLastVibration()); 566 .GetLastVibration());
539 LOG_DEBUG(Service_HID, "called");
540 } 567 }
541 568
542 void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { 569 void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
543 IPC::RequestParser rp{ctx}; 570 IPC::RequestParser rp{ctx};
544 const auto npad_id = rp.PopRaw<u32>(); 571 const auto npad_id = rp.PopRaw<u32>();
572 LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
573
545 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 574 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
546 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); 575 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual);
547 576
548 IPC::ResponseBuilder rb{ctx, 2}; 577 IPC::ResponseBuilder rb{ctx, 2};
549 rb.Push(RESULT_SUCCESS); 578 rb.Push(RESULT_SUCCESS);
550 LOG_DEBUG(Service_HID, "called");
551 } 579 }
552 580
553 void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { 581 void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
582 LOG_WARNING(Service_HID, "(STUBBED) called");
583
554 IPC::ResponseBuilder rb{ctx, 2}; 584 IPC::ResponseBuilder rb{ctx, 2};
555 rb.Push(RESULT_SUCCESS); 585 rb.Push(RESULT_SUCCESS);
556 LOG_WARNING(Service_HID, "(STUBBED) called");
557 } 586 }
558 587
559 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { 588 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
560 IPC::RequestParser rp{ctx}; 589 IPC::RequestParser rp{ctx};
561 auto mode = rp.PopRaw<u32>(); 590 auto mode = rp.PopRaw<u32>();
591 LOG_WARNING(Service_HID, "(STUBBED) called with mode={}", mode);
592
562 IPC::ResponseBuilder rb{ctx, 2}; 593 IPC::ResponseBuilder rb{ctx, 2};
563 rb.Push(RESULT_SUCCESS); 594 rb.Push(RESULT_SUCCESS);
564 LOG_WARNING(Service_HID, "(STUBBED) called");
565 } 595 }
566 596
567 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { 597 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
598 LOG_DEBUG(Service_HID, "called");
599
568 IPC::ResponseBuilder rb{ctx, 4}; 600 IPC::ResponseBuilder rb{ctx, 4};
569 rb.Push(RESULT_SUCCESS); 601 rb.Push(RESULT_SUCCESS);
570 rb.Push<u32>(1); 602 rb.Push<u32>(1);
571 rb.Push<u32>(0); 603 rb.Push<u32>(0);
572 LOG_DEBUG(Service_HID, "called");
573 } 604 }
574 605
575 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { 606 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
607 LOG_DEBUG(Service_HID, "called");
608
576 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 609 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
577 rb.Push(RESULT_SUCCESS); 610 rb.Push(RESULT_SUCCESS);
578 rb.PushIpcInterface<IActiveVibrationDeviceList>(); 611 rb.PushIpcInterface<IActiveVibrationDeviceList>();
579 LOG_DEBUG(Service_HID, "called");
580 } 612 }
581 613
582 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 614 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
615 LOG_WARNING(Service_HID, "(STUBBED) called");
616
583 IPC::ResponseBuilder rb{ctx, 2}; 617 IPC::ResponseBuilder rb{ctx, 2};
584 rb.Push(RESULT_SUCCESS); 618 rb.Push(RESULT_SUCCESS);
585 LOG_WARNING(Service_HID, "(STUBBED) called");
586 } 619 }
587 620
588 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 621 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
622 LOG_WARNING(Service_HID, "(STUBBED) called");
623
589 IPC::ResponseBuilder rb{ctx, 2}; 624 IPC::ResponseBuilder rb{ctx, 2};
590 rb.Push(RESULT_SUCCESS); 625 rb.Push(RESULT_SUCCESS);
591 LOG_WARNING(Service_HID, "(STUBBED) called");
592 } 626 }
593 627
594 void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { 628 void StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
629 LOG_WARNING(Service_HID, "(STUBBED) called");
630
595 IPC::ResponseBuilder rb{ctx, 2}; 631 IPC::ResponseBuilder rb{ctx, 2};
596 rb.Push(RESULT_SUCCESS); 632 rb.Push(RESULT_SUCCESS);
633 }
634
635 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
597 LOG_WARNING(Service_HID, "(STUBBED) called"); 636 LOG_WARNING(Service_HID, "(STUBBED) called");
637
638 IPC::ResponseBuilder rb{ctx, 2};
639 rb.Push(RESULT_SUCCESS);
640 }
641
642 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
643 LOG_WARNING(Service_HID, "(STUBBED) called");
644
645 IPC::ResponseBuilder rb{ctx, 2};
646 rb.Push(RESULT_SUCCESS);
598 } 647 }
599}; 648};
600 649
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 872e3c344..3c7f8b1ee 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -44,115 +44,133 @@ IRS::IRS() : ServiceFramework{"irs"} {
44} 44}
45 45
46void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { 46void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
47 LOG_WARNING(Service_IRS, "(STUBBED) called");
48
47 IPC::ResponseBuilder rb{ctx, 2}; 49 IPC::ResponseBuilder rb{ctx, 2};
48 rb.Push(RESULT_SUCCESS); 50 rb.Push(RESULT_SUCCESS);
49 LOG_WARNING(Service_IRS, "(STUBBED) called");
50} 51}
51 52
52void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { 53void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
54 LOG_WARNING(Service_IRS, "(STUBBED) called");
55
53 IPC::ResponseBuilder rb{ctx, 2}; 56 IPC::ResponseBuilder rb{ctx, 2};
54 rb.Push(RESULT_SUCCESS); 57 rb.Push(RESULT_SUCCESS);
55 LOG_WARNING(Service_IRS, "(STUBBED) called");
56} 58}
57 59
58void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 60void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
61 LOG_DEBUG(Service_IRS, "called");
62
59 IPC::ResponseBuilder rb{ctx, 2, 1}; 63 IPC::ResponseBuilder rb{ctx, 2, 1};
60 rb.Push(RESULT_SUCCESS); 64 rb.Push(RESULT_SUCCESS);
61 rb.PushCopyObjects(shared_mem); 65 rb.PushCopyObjects(shared_mem);
62 LOG_DEBUG(Service_IRS, "called");
63} 66}
64 67
65void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { 68void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
69 LOG_WARNING(Service_IRS, "(STUBBED) called");
70
66 IPC::ResponseBuilder rb{ctx, 2}; 71 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(RESULT_SUCCESS); 72 rb.Push(RESULT_SUCCESS);
68 LOG_WARNING(Service_IRS, "(STUBBED) called");
69} 73}
70 74
71void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { 75void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
76 LOG_WARNING(Service_IRS, "(STUBBED) called");
77
72 IPC::ResponseBuilder rb{ctx, 2}; 78 IPC::ResponseBuilder rb{ctx, 2};
73 rb.Push(RESULT_SUCCESS); 79 rb.Push(RESULT_SUCCESS);
74 LOG_WARNING(Service_IRS, "(STUBBED) called");
75} 80}
76 81
77void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { 82void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
83 LOG_WARNING(Service_IRS, "(STUBBED) called");
84
78 IPC::ResponseBuilder rb{ctx, 2}; 85 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(RESULT_SUCCESS); 86 rb.Push(RESULT_SUCCESS);
80 LOG_WARNING(Service_IRS, "(STUBBED) called");
81} 87}
82 88
83void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { 89void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
90 LOG_WARNING(Service_IRS, "(STUBBED) called");
91
84 IPC::ResponseBuilder rb{ctx, 2}; 92 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(RESULT_SUCCESS); 93 rb.Push(RESULT_SUCCESS);
86 LOG_WARNING(Service_IRS, "(STUBBED) called");
87} 94}
88 95
89void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { 96void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
97 LOG_WARNING(Service_IRS, "(STUBBED) called");
98
90 IPC::ResponseBuilder rb{ctx, 5}; 99 IPC::ResponseBuilder rb{ctx, 5};
91 rb.Push(RESULT_SUCCESS); 100 rb.Push(RESULT_SUCCESS);
92 rb.PushRaw<u64>(CoreTiming::GetTicks()); 101 rb.PushRaw<u64>(CoreTiming::GetTicks());
93 rb.PushRaw<u32>(0); 102 rb.PushRaw<u32>(0);
94 LOG_WARNING(Service_IRS, "(STUBBED) called");
95} 103}
96 104
97void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { 105void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
106 LOG_WARNING(Service_IRS, "(STUBBED) called");
107
98 IPC::ResponseBuilder rb{ctx, 2}; 108 IPC::ResponseBuilder rb{ctx, 2};
99 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
100 LOG_WARNING(Service_IRS, "(STUBBED) called");
101} 110}
102 111
103void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { 112void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
113 LOG_WARNING(Service_IRS, "(STUBBED) called");
114
104 IPC::ResponseBuilder rb{ctx, 3}; 115 IPC::ResponseBuilder rb{ctx, 3};
105 rb.Push(RESULT_SUCCESS); 116 rb.Push(RESULT_SUCCESS);
106 rb.PushRaw<u32>(device_handle); 117 rb.PushRaw<u32>(device_handle);
107 LOG_WARNING(Service_IRS, "(STUBBED) called");
108} 118}
109 119
110void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { 120void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
121 LOG_WARNING(Service_IRS, "(STUBBED) called");
122
111 IPC::ResponseBuilder rb{ctx, 2}; 123 IPC::ResponseBuilder rb{ctx, 2};
112 rb.Push(RESULT_SUCCESS); 124 rb.Push(RESULT_SUCCESS);
113 LOG_WARNING(Service_IRS, "(STUBBED) called");
114} 125}
115 126
116void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { 127void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
128 LOG_WARNING(Service_IRS, "(STUBBED) called");
129
117 IPC::ResponseBuilder rb{ctx, 2}; 130 IPC::ResponseBuilder rb{ctx, 2};
118 rb.Push(RESULT_SUCCESS); 131 rb.Push(RESULT_SUCCESS);
119 LOG_WARNING(Service_IRS, "(STUBBED) called");
120} 132}
121 133
122void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { 134void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
135 LOG_WARNING(Service_IRS, "(STUBBED) called");
136
123 IPC::ResponseBuilder rb{ctx, 2}; 137 IPC::ResponseBuilder rb{ctx, 2};
124 rb.Push(RESULT_SUCCESS); 138 rb.Push(RESULT_SUCCESS);
125 LOG_WARNING(Service_IRS, "(STUBBED) called");
126} 139}
127 140
128void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { 141void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
142 LOG_WARNING(Service_IRS, "(STUBBED) called");
143
129 IPC::ResponseBuilder rb{ctx, 2}; 144 IPC::ResponseBuilder rb{ctx, 2};
130 rb.Push(RESULT_SUCCESS); 145 rb.Push(RESULT_SUCCESS);
131 LOG_WARNING(Service_IRS, "(STUBBED) called");
132} 146}
133 147
134void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { 148void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
149 LOG_WARNING(Service_IRS, "(STUBBED) called");
150
135 IPC::ResponseBuilder rb{ctx, 2}; 151 IPC::ResponseBuilder rb{ctx, 2};
136 rb.Push(RESULT_SUCCESS); 152 rb.Push(RESULT_SUCCESS);
137 LOG_WARNING(Service_IRS, "(STUBBED) called");
138} 153}
139 154
140void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { 155void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
156 LOG_WARNING(Service_IRS, "(STUBBED) called");
157
141 IPC::ResponseBuilder rb{ctx, 2}; 158 IPC::ResponseBuilder rb{ctx, 2};
142 rb.Push(RESULT_SUCCESS); 159 rb.Push(RESULT_SUCCESS);
143 LOG_WARNING(Service_IRS, "(STUBBED) called");
144} 160}
145 161
146void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { 162void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
163 LOG_WARNING(Service_IRS, "(STUBBED) called");
164
147 IPC::ResponseBuilder rb{ctx, 2}; 165 IPC::ResponseBuilder rb{ctx, 2};
148 rb.Push(RESULT_SUCCESS); 166 rb.Push(RESULT_SUCCESS);
149 LOG_WARNING(Service_IRS, "(STUBBED) called");
150} 167}
151 168
152void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { 169void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
170 LOG_WARNING(Service_IRS, "(STUBBED) called");
171
153 IPC::ResponseBuilder rb{ctx, 2}; 172 IPC::ResponseBuilder rb{ctx, 2};
154 rb.Push(RESULT_SUCCESS); 173 rb.Push(RESULT_SUCCESS);
155 LOG_WARNING(Service_IRS, "(STUBBED) called");
156} 174}
157 175
158IRS::~IRS() = default; 176IRS::~IRS() = default;
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index 164c57e18..e8f9f2d29 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -55,29 +55,29 @@ public:
55 55
56private: 56private:
57 void EnableVrMode(Kernel::HLERequestContext& ctx) { 57 void EnableVrMode(Kernel::HLERequestContext& ctx) {
58 LOG_DEBUG(Service_LBL, "called");
59
58 IPC::ResponseBuilder rb{ctx, 2}; 60 IPC::ResponseBuilder rb{ctx, 2};
59 rb.Push(RESULT_SUCCESS); 61 rb.Push(RESULT_SUCCESS);
60 62
61 vr_mode_enabled = true; 63 vr_mode_enabled = true;
62
63 LOG_DEBUG(Service_LBL, "called");
64 } 64 }
65 65
66 void DisableVrMode(Kernel::HLERequestContext& ctx) { 66 void DisableVrMode(Kernel::HLERequestContext& ctx) {
67 LOG_DEBUG(Service_LBL, "called");
68
67 IPC::ResponseBuilder rb{ctx, 2}; 69 IPC::ResponseBuilder rb{ctx, 2};
68 rb.Push(RESULT_SUCCESS); 70 rb.Push(RESULT_SUCCESS);
69 71
70 vr_mode_enabled = false; 72 vr_mode_enabled = false;
71
72 LOG_DEBUG(Service_LBL, "called");
73 } 73 }
74 74
75 void IsVrModeEnabled(Kernel::HLERequestContext& ctx) { 75 void IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
76 LOG_DEBUG(Service_LBL, "called");
77
76 IPC::ResponseBuilder rb{ctx, 3}; 78 IPC::ResponseBuilder rb{ctx, 3};
77 rb.Push(RESULT_SUCCESS); 79 rb.Push(RESULT_SUCCESS);
78 rb.Push(vr_mode_enabled); 80 rb.Push(vr_mode_enabled);
79
80 LOG_DEBUG(Service_LBL, "called");
81 } 81 }
82 82
83 bool vr_mode_enabled = false; 83 bool vr_mode_enabled = false;
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 167f2c66a..e250595e3 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -44,11 +44,11 @@ public:
44 } 44 }
45 45
46 void CreateMonitorService(Kernel::HLERequestContext& ctx) { 46 void CreateMonitorService(Kernel::HLERequestContext& ctx) {
47 LOG_DEBUG(Service_LDN, "called");
48
47 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 49 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
48 rb.Push(RESULT_SUCCESS); 50 rb.Push(RESULT_SUCCESS);
49 rb.PushIpcInterface<IMonitorService>(); 51 rb.PushIpcInterface<IMonitorService>();
50
51 LOG_DEBUG(Service_LDN, "called");
52 } 52 }
53}; 53};
54 54
@@ -104,11 +104,11 @@ public:
104 } 104 }
105 105
106 void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) { 106 void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) {
107 LOG_DEBUG(Service_LDN, "called");
108
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 109 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(RESULT_SUCCESS); 110 rb.Push(RESULT_SUCCESS);
109 rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService"); 111 rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService");
110
111 LOG_DEBUG(Service_LDN, "called");
112 } 112 }
113}; 113};
114 114
@@ -125,11 +125,11 @@ public:
125 } 125 }
126 126
127 void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) { 127 void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) {
128 LOG_DEBUG(Service_LDN, "called");
129
128 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 130 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
129 rb.Push(RESULT_SUCCESS); 131 rb.Push(RESULT_SUCCESS);
130 rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService"); 132 rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService");
131
132 LOG_DEBUG(Service_LDN, "called");
133 } 133 }
134}; 134};
135 135
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index d607d985e..ca119dd3a 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -4,7 +4,10 @@
4 4
5#include <memory> 5#include <memory>
6#include <fmt/format.h> 6#include <fmt/format.h>
7#include <mbedtls/sha256.h>
7 8
9#include "common/alignment.h"
10#include "common/hex_util.h"
8#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
10#include "core/hle/service/ldr/ldr.h" 13#include "core/hle/service/ldr/ldr.h"
@@ -13,6 +16,21 @@
13 16
14namespace Service::LDR { 17namespace Service::LDR {
15 18
19constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51};
20constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52};
21constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53};
22constexpr ResultCode ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54};
23constexpr ResultCode ERROR_MAXIMUM_NRO{ErrorModule::Loader, 55};
24constexpr ResultCode ERROR_MAXIMUM_NRR{ErrorModule::Loader, 56};
25constexpr ResultCode ERROR_ALREADY_LOADED{ErrorModule::Loader, 57};
26constexpr ResultCode ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81};
27constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::Loader, 82};
28constexpr ResultCode ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84};
29constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85};
30constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
31
32constexpr u64 MAXIMUM_LOADED_RO = 0x40;
33
16class DebugMonitor final : public ServiceFramework<DebugMonitor> { 34class DebugMonitor final : public ServiceFramework<DebugMonitor> {
17public: 35public:
18 explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} { 36 explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} {
@@ -64,9 +82,9 @@ public:
64 // clang-format off 82 // clang-format off
65 static const FunctionInfo functions[] = { 83 static const FunctionInfo functions[] = {
66 {0, &RelocatableObject::LoadNro, "LoadNro"}, 84 {0, &RelocatableObject::LoadNro, "LoadNro"},
67 {1, nullptr, "UnloadNro"}, 85 {1, &RelocatableObject::UnloadNro, "UnloadNro"},
68 {2, &RelocatableObject::LoadNrr, "LoadNrr"}, 86 {2, &RelocatableObject::LoadNrr, "LoadNrr"},
69 {3, nullptr, "UnloadNrr"}, 87 {3, &RelocatableObject::UnloadNrr, "UnloadNrr"},
70 {4, &RelocatableObject::Initialize, "Initialize"}, 88 {4, &RelocatableObject::Initialize, "Initialize"},
71 }; 89 };
72 // clang-format on 90 // clang-format on
@@ -75,9 +93,126 @@ public:
75 } 93 }
76 94
77 void LoadNrr(Kernel::HLERequestContext& ctx) { 95 void LoadNrr(Kernel::HLERequestContext& ctx) {
96 IPC::RequestParser rp{ctx};
97 rp.Skip(2, false);
98 const VAddr nrr_addr{rp.Pop<VAddr>()};
99 const u64 nrr_size{rp.Pop<u64>()};
100 LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}, nrr_size={:016X}", nrr_addr,
101 nrr_size);
102
103 if (!initialized) {
104 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
105 IPC::ResponseBuilder rb{ctx, 2};
106 rb.Push(ERROR_NOT_INITIALIZED);
107 return;
108 }
109
110 if (nrr.size() >= MAXIMUM_LOADED_RO) {
111 LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs "
112 "(0x40)! Failing...");
113 IPC::ResponseBuilder rb{ctx, 2};
114 rb.Push(ERROR_MAXIMUM_NRR);
115 return;
116 }
117
118 // NRR Address does not fall on 0x1000 byte boundary
119 if (!Common::Is4KBAligned(nrr_addr)) {
120 LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
121 IPC::ResponseBuilder rb{ctx, 2};
122 rb.Push(ERROR_INVALID_ALIGNMENT);
123 return;
124 }
125
126 // NRR Size is zero or causes overflow
127 if (nrr_addr + nrr_size <= nrr_addr || nrr_size == 0 || !Common::Is4KBAligned(nrr_size)) {
128 LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})",
129 nrr_addr, nrr_size);
130 IPC::ResponseBuilder rb{ctx, 2};
131 rb.Push(ERROR_INVALID_SIZE);
132 return;
133 }
134 // Read NRR data from memory
135 std::vector<u8> nrr_data(nrr_size);
136 Memory::ReadBlock(nrr_addr, nrr_data.data(), nrr_size);
137 NRRHeader header;
138 std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
139
140 if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) {
141 LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic);
142 IPC::ResponseBuilder rb{ctx, 2};
143 rb.Push(ERROR_INVALID_NRR);
144 return;
145 }
146
147 if (header.size != nrr_size) {
148 LOG_ERROR(Service_LDR,
149 "NRR header reported size did not match LoadNrr parameter size! "
150 "(header_size={:016X}, loadnrr_size={:016X})",
151 header.size, nrr_size);
152 IPC::ResponseBuilder rb{ctx, 2};
153 rb.Push(ERROR_INVALID_SIZE);
154 return;
155 }
156
157 if (Core::CurrentProcess()->GetTitleID() != header.title_id) {
158 LOG_ERROR(Service_LDR,
159 "Attempting to load NRR with title ID other than current process. (actual "
160 "{:016X})!",
161 header.title_id);
162 IPC::ResponseBuilder rb{ctx, 2};
163 rb.Push(ERROR_INVALID_NRR);
164 return;
165 }
166
167 std::vector<SHA256Hash> hashes;
168
169 // Copy all hashes in the NRR (specified by hash count/hash offset) into vector.
170 for (std::size_t i = header.hash_offset;
171 i < (header.hash_offset + (header.hash_count * sizeof(SHA256Hash))); i += 8) {
172 SHA256Hash hash;
173 std::memcpy(hash.data(), nrr_data.data() + i, sizeof(SHA256Hash));
174 hashes.emplace_back(hash);
175 }
176
177 nrr.insert_or_assign(nrr_addr, std::move(hashes));
178
179 IPC::ResponseBuilder rb{ctx, 2};
180 rb.Push(RESULT_SUCCESS);
181 }
182
183 void UnloadNrr(Kernel::HLERequestContext& ctx) {
184 if (!initialized) {
185 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
186 IPC::ResponseBuilder rb{ctx, 2};
187 rb.Push(ERROR_NOT_INITIALIZED);
188 return;
189 }
190
191 IPC::RequestParser rp{ctx};
192 rp.Skip(2, false);
193 const auto nrr_addr{rp.Pop<VAddr>()};
194 LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}", nrr_addr);
195
196 if (!Common::Is4KBAligned(nrr_addr)) {
197 LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
198 IPC::ResponseBuilder rb{ctx, 2};
199 rb.Push(ERROR_INVALID_ALIGNMENT);
200 return;
201 }
202
203 const auto iter = nrr.find(nrr_addr);
204 if (iter == nrr.end()) {
205 LOG_ERROR(Service_LDR,
206 "Attempting to unload NRR which has not been loaded! (addr={:016X})",
207 nrr_addr);
208 IPC::ResponseBuilder rb{ctx, 2};
209 rb.Push(ERROR_INVALID_NRR_ADDRESS);
210 return;
211 }
212
213 nrr.erase(iter);
78 IPC::ResponseBuilder rb{ctx, 2}; 214 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(RESULT_SUCCESS); 215 rb.Push(RESULT_SUCCESS);
80 LOG_WARNING(Service_LDR, "(STUBBED) called");
81 } 216 }
82 217
83 void LoadNro(Kernel::HLERequestContext& ctx) { 218 void LoadNro(Kernel::HLERequestContext& ctx) {
@@ -87,33 +222,260 @@ public:
87 const u64 nro_size{rp.Pop<u64>()}; 222 const u64 nro_size{rp.Pop<u64>()};
88 const VAddr bss_addr{rp.Pop<VAddr>()}; 223 const VAddr bss_addr{rp.Pop<VAddr>()};
89 const u64 bss_size{rp.Pop<u64>()}; 224 const u64 bss_size{rp.Pop<u64>()};
225 LOG_DEBUG(
226 Service_LDR,
227 "called with nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, bss_size={:016X}",
228 nro_addr, nro_size, bss_addr, bss_size);
229
230 if (!initialized) {
231 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
232 IPC::ResponseBuilder rb{ctx, 2};
233 rb.Push(ERROR_NOT_INITIALIZED);
234 return;
235 }
236
237 if (nro.size() >= MAXIMUM_LOADED_RO) {
238 LOG_ERROR(Service_LDR, "Loading new NRO would exceed the maximum number of loaded NROs "
239 "(0x40)! Failing...");
240 IPC::ResponseBuilder rb{ctx, 2};
241 rb.Push(ERROR_MAXIMUM_NRO);
242 return;
243 }
244
245 // NRO Address does not fall on 0x1000 byte boundary
246 if (!Common::Is4KBAligned(nro_addr)) {
247 LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!", nro_addr);
248 IPC::ResponseBuilder rb{ctx, 2};
249 rb.Push(ERROR_INVALID_ALIGNMENT);
250 return;
251 }
252
253 // NRO Size or BSS Size is zero or causes overflow
254 const auto nro_size_valid =
255 nro_size != 0 && nro_addr + nro_size > nro_addr && Common::Is4KBAligned(nro_size);
256 const auto bss_size_valid =
257 nro_size + bss_size >= nro_size && (bss_size == 0 || bss_addr + bss_size > bss_addr);
258
259 if (!nro_size_valid || !bss_size_valid) {
260 LOG_ERROR(Service_LDR,
261 "NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, "
262 "bss_address={:016X}, bss_size={:016X})",
263 nro_addr, nro_size, bss_addr, bss_size);
264 IPC::ResponseBuilder rb{ctx, 2};
265 rb.Push(ERROR_INVALID_SIZE);
266 return;
267 }
90 268
91 // Read NRO data from memory 269 // Read NRO data from memory
92 std::vector<u8> nro_data(nro_size); 270 std::vector<u8> nro_data(nro_size);
93 Memory::ReadBlock(nro_addr, nro_data.data(), nro_size); 271 Memory::ReadBlock(nro_addr, nro_data.data(), nro_size);
94 272
273 SHA256Hash hash{};
274 mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0);
275
276 // NRO Hash is already loaded
277 if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) {
278 return info.second.hash == hash;
279 })) {
280 LOG_ERROR(Service_LDR, "NRO is already loaded!");
281 IPC::ResponseBuilder rb{ctx, 2};
282 rb.Push(ERROR_ALREADY_LOADED);
283 return;
284 }
285
286 // NRO Hash is not in any loaded NRR
287 if (!IsValidNROHash(hash)) {
288 LOG_ERROR(Service_LDR,
289 "NRO hash is not present in any currently loaded NRRs (hash={})!",
290 Common::HexArrayToString(hash));
291 IPC::ResponseBuilder rb{ctx, 2};
292 rb.Push(ERROR_MISSING_NRR_HASH);
293 return;
294 }
295
296 NROHeader header;
297 std::memcpy(&header, nro_data.data(), sizeof(NROHeader));
298
299 if (!IsValidNRO(header, nro_size, bss_size)) {
300 LOG_ERROR(Service_LDR, "NRO was invalid!");
301 IPC::ResponseBuilder rb{ctx, 2};
302 rb.Push(ERROR_INVALID_NRO);
303 return;
304 }
305
95 // Load NRO as new executable module 306 // Load NRO as new executable module
96 const VAddr addr{*Core::CurrentProcess()->VMManager().FindFreeRegion(nro_size + bss_size)}; 307 auto* process = Core::CurrentProcess();
97 Loader::AppLoader_NRO::LoadNro(nro_data, fmt::format("nro-{:08x}", addr), addr); 308 auto& vm_manager = process->VMManager();
309 auto map_address = vm_manager.FindFreeRegion(nro_size + bss_size);
310
311 if (!map_address.Succeeded() ||
312 *map_address + nro_size + bss_size > vm_manager.GetAddressSpaceEndAddress()) {
313
314 LOG_ERROR(Service_LDR,
315 "General error while allocation memory or no available memory to allocate!");
316 IPC::ResponseBuilder rb{ctx, 2};
317 rb.Push(ERROR_INVALID_MEMORY_STATE);
318 return;
319 }
320
321 ASSERT(process->MirrorMemory(*map_address, nro_addr, nro_size,
322 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
323 ASSERT(process->UnmapMemory(nro_addr, 0, nro_size) == RESULT_SUCCESS);
324
325 if (bss_size > 0) {
326 ASSERT(process->MirrorMemory(*map_address + nro_size, bss_addr, bss_size,
327 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
328 ASSERT(process->UnmapMemory(bss_addr, 0, bss_size) == RESULT_SUCCESS);
329 }
98 330
99 // TODO(bunnei): This is an incomplete implementation. It was tested with Super Mario Party. 331 vm_manager.ReprotectRange(*map_address, header.text_size,
100 // It is currently missing: 332 Kernel::VMAPermission::ReadExecute);
101 // - Signature checks with LoadNRR 333 vm_manager.ReprotectRange(*map_address + header.ro_offset, header.ro_size,
102 // - Checking if a module has already been loaded 334 Kernel::VMAPermission::Read);
103 // - Using/validating BSS, etc. params (these are used from NRO header instead) 335 vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
104 // - Error checking 336 Kernel::VMAPermission::ReadWrite);
105 // - ...Probably other things 337
338 Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
339 Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
340 Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
341 Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
342
343 nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size});
106 344
107 IPC::ResponseBuilder rb{ctx, 4}; 345 IPC::ResponseBuilder rb{ctx, 4};
108 rb.Push(RESULT_SUCCESS); 346 rb.Push(RESULT_SUCCESS);
109 rb.Push(addr); 347 rb.Push(*map_address);
110 LOG_WARNING(Service_LDR, "(STUBBED) called");
111 } 348 }
112 349
113 void Initialize(Kernel::HLERequestContext& ctx) { 350 void UnloadNro(Kernel::HLERequestContext& ctx) {
351 IPC::RequestParser rp{ctx};
352 rp.Skip(2, false);
353 const VAddr mapped_addr{rp.PopRaw<VAddr>()};
354 const VAddr heap_addr{rp.PopRaw<VAddr>()};
355 LOG_DEBUG(Service_LDR, "called with mapped_addr={:016X}, heap_addr={:016X}", mapped_addr,
356 heap_addr);
357
358 if (!initialized) {
359 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
360 IPC::ResponseBuilder rb{ctx, 2};
361 rb.Push(ERROR_NOT_INITIALIZED);
362 return;
363 }
364
365 if (!Common::Is4KBAligned(mapped_addr) || !Common::Is4KBAligned(heap_addr)) {
366 LOG_ERROR(Service_LDR,
367 "NRO/BSS Address has invalid alignment (actual nro_addr={:016X}, "
368 "bss_addr={:016X})!",
369 mapped_addr, heap_addr);
370 IPC::ResponseBuilder rb{ctx, 2};
371 rb.Push(ERROR_INVALID_ALIGNMENT);
372 return;
373 }
374
375 const auto iter = nro.find(mapped_addr);
376 if (iter == nro.end()) {
377 LOG_ERROR(Service_LDR,
378 "The NRO attempting to unmap was not mapped or has an invalid address "
379 "(actual {:016X})!",
380 mapped_addr);
381 IPC::ResponseBuilder rb{ctx, 2};
382 rb.Push(ERROR_INVALID_NRO_ADDRESS);
383 return;
384 }
385
386 auto* process = Core::CurrentProcess();
387 auto& vm_manager = process->VMManager();
388 const auto& nro_size = iter->second.size;
389
390 ASSERT(process->MirrorMemory(heap_addr, mapped_addr, nro_size,
391 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
392 ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS);
393
394 Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
395 Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
396 Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
397 Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
398
399 nro.erase(iter);
114 IPC::ResponseBuilder rb{ctx, 2}; 400 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(RESULT_SUCCESS); 401 rb.Push(RESULT_SUCCESS);
402 }
403
404 void Initialize(Kernel::HLERequestContext& ctx) {
116 LOG_WARNING(Service_LDR, "(STUBBED) called"); 405 LOG_WARNING(Service_LDR, "(STUBBED) called");
406
407 initialized = true;
408
409 IPC::ResponseBuilder rb{ctx, 2};
410 rb.Push(RESULT_SUCCESS);
411 }
412
413private:
414 using SHA256Hash = std::array<u8, 0x20>;
415
416 struct NROHeader {
417 u32_le entrypoint_insn;
418 u32_le mod_offset;
419 INSERT_PADDING_WORDS(2);
420 u32_le magic;
421 INSERT_PADDING_WORDS(1);
422 u32_le nro_size;
423 INSERT_PADDING_WORDS(1);
424 u32_le text_offset;
425 u32_le text_size;
426 u32_le ro_offset;
427 u32_le ro_size;
428 u32_le rw_offset;
429 u32_le rw_size;
430 u32_le bss_size;
431 INSERT_PADDING_WORDS(1);
432 std::array<u8, 0x20> build_id;
433 INSERT_PADDING_BYTES(0x20);
434 };
435 static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
436
437 struct NRRHeader {
438 u32_le magic;
439 INSERT_PADDING_BYTES(0x1C);
440 u64_le title_id_mask;
441 u64_le title_id_pattern;
442 std::array<u8, 0x100> modulus;
443 std::array<u8, 0x100> signature_1;
444 std::array<u8, 0x100> signature_2;
445 u64_le title_id;
446 u32_le size;
447 INSERT_PADDING_BYTES(4);
448 u32_le hash_offset;
449 u32_le hash_count;
450 INSERT_PADDING_BYTES(8);
451 };
452 static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has incorrect size.");
453
454 struct NROInfo {
455 SHA256Hash hash;
456 u64 size;
457 };
458
459 bool initialized = false;
460
461 std::map<VAddr, NROInfo> nro;
462 std::map<VAddr, std::vector<SHA256Hash>> nrr;
463
464 bool IsValidNROHash(const SHA256Hash& hash) {
465 return std::any_of(
466 nrr.begin(), nrr.end(), [&hash](const std::pair<VAddr, std::vector<SHA256Hash>>& p) {
467 return std::find(p.second.begin(), p.second.end(), hash) != p.second.end();
468 });
469 }
470
471 static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
472 return header.magic == Common::MakeMagic('N', 'R', 'O', '0') &&
473 header.nro_size == nro_size && header.bss_size == bss_size &&
474 header.ro_offset == header.text_offset + header.text_size &&
475 header.rw_offset == header.ro_offset + header.ro_size &&
476 nro_size == header.rw_offset + header.rw_size &&
477 Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) &&
478 Common::Is4KBAligned(header.rw_size);
117 } 479 }
118}; 480};
119 481
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index c89157a4d..1f462e087 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -18,7 +18,7 @@ public:
18 ILogger() : ServiceFramework("ILogger") { 18 ILogger() : ServiceFramework("ILogger") {
19 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
20 {0x00000000, &ILogger::Initialize, "Initialize"}, 20 {0x00000000, &ILogger::Initialize, "Initialize"},
21 {0x00000001, nullptr, "SetDestination"}, 21 {0x00000001, &ILogger::SetDestination, "SetDestination"},
22 }; 22 };
23 RegisterHandlers(functions); 23 RegisterHandlers(functions);
24 } 24 }
@@ -178,6 +178,17 @@ private:
178 } 178 }
179 } 179 }
180 180
181 // This service function is intended to be used as a way to
182 // redirect logging output to different destinations, however,
183 // given we always want to see the logging output, it's sufficient
184 // to do nothing and return success here.
185 void SetDestination(Kernel::HLERequestContext& ctx) {
186 LOG_DEBUG(Service_LM, "called");
187
188 IPC::ResponseBuilder rb{ctx, 2};
189 rb.Push(RESULT_SUCCESS);
190 }
191
181 std::ostringstream log_stream; 192 std::ostringstream log_stream;
182}; 193};
183 194
@@ -198,11 +209,11 @@ public:
198 * 0: ResultCode 209 * 0: ResultCode
199 */ 210 */
200 void OpenLogger(Kernel::HLERequestContext& ctx) { 211 void OpenLogger(Kernel::HLERequestContext& ctx) {
212 LOG_DEBUG(Service_LM, "called");
213
201 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 214 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
202 rb.Push(RESULT_SUCCESS); 215 rb.Push(RESULT_SUCCESS);
203 rb.PushIpcInterface<ILogger>(); 216 rb.PushIpcInterface<ILogger>();
204
205 LOG_DEBUG(Service_LM, "called");
206 } 217 }
207}; 218};
208 219
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index e1f17a926..def63dc8a 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -31,12 +31,14 @@ public:
31private: 31private:
32 void Initialize(Kernel::HLERequestContext& ctx) { 32 void Initialize(Kernel::HLERequestContext& ctx) {
33 LOG_WARNING(Service_MM, "(STUBBED) called"); 33 LOG_WARNING(Service_MM, "(STUBBED) called");
34
34 IPC::ResponseBuilder rb{ctx, 2}; 35 IPC::ResponseBuilder rb{ctx, 2};
35 rb.Push(RESULT_SUCCESS); 36 rb.Push(RESULT_SUCCESS);
36 } 37 }
37 38
38 void Finalize(Kernel::HLERequestContext& ctx) { 39 void Finalize(Kernel::HLERequestContext& ctx) {
39 LOG_WARNING(Service_MM, "(STUBBED) called"); 40 LOG_WARNING(Service_MM, "(STUBBED) called");
41
40 IPC::ResponseBuilder rb{ctx, 2}; 42 IPC::ResponseBuilder rb{ctx, 2};
41 rb.Push(RESULT_SUCCESS); 43 rb.Push(RESULT_SUCCESS);
42 } 44 }
@@ -45,15 +47,16 @@ private:
45 IPC::RequestParser rp{ctx}; 47 IPC::RequestParser rp{ctx};
46 min = rp.Pop<u32>(); 48 min = rp.Pop<u32>();
47 max = rp.Pop<u32>(); 49 max = rp.Pop<u32>();
48 current = min;
49
50 LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); 50 LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
51
52 current = min;
51 IPC::ResponseBuilder rb{ctx, 2}; 53 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(RESULT_SUCCESS); 54 rb.Push(RESULT_SUCCESS);
53 } 55 }
54 56
55 void Get(Kernel::HLERequestContext& ctx) { 57 void Get(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service_MM, "(STUBBED) called"); 58 LOG_WARNING(Service_MM, "(STUBBED) called");
59
57 IPC::ResponseBuilder rb{ctx, 3}; 60 IPC::ResponseBuilder rb{ctx, 3};
58 rb.Push(RESULT_SUCCESS); 61 rb.Push(RESULT_SUCCESS);
59 rb.Push(current); 62 rb.Push(current);
@@ -61,6 +64,7 @@ private:
61 64
62 void InitializeWithId(Kernel::HLERequestContext& ctx) { 65 void InitializeWithId(Kernel::HLERequestContext& ctx) {
63 LOG_WARNING(Service_MM, "(STUBBED) called"); 66 LOG_WARNING(Service_MM, "(STUBBED) called");
67
64 IPC::ResponseBuilder rb{ctx, 3}; 68 IPC::ResponseBuilder rb{ctx, 3};
65 rb.Push(RESULT_SUCCESS); 69 rb.Push(RESULT_SUCCESS);
66 rb.Push<u32>(id); // Any non zero value 70 rb.Push<u32>(id); // Any non zero value
@@ -68,6 +72,7 @@ private:
68 72
69 void FinalizeWithId(Kernel::HLERequestContext& ctx) { 73 void FinalizeWithId(Kernel::HLERequestContext& ctx) {
70 LOG_WARNING(Service_MM, "(STUBBED) called"); 74 LOG_WARNING(Service_MM, "(STUBBED) called");
75
71 IPC::ResponseBuilder rb{ctx, 2}; 76 IPC::ResponseBuilder rb{ctx, 2};
72 rb.Push(RESULT_SUCCESS); 77 rb.Push(RESULT_SUCCESS);
73 } 78 }
@@ -77,16 +82,17 @@ private:
77 u32 input_id = rp.Pop<u32>(); 82 u32 input_id = rp.Pop<u32>();
78 min = rp.Pop<u32>(); 83 min = rp.Pop<u32>();
79 max = rp.Pop<u32>(); 84 max = rp.Pop<u32>();
80 current = min;
81
82 LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", 85 LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}",
83 input_id, min, max); 86 input_id, min, max);
87
88 current = min;
84 IPC::ResponseBuilder rb{ctx, 2}; 89 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(RESULT_SUCCESS); 90 rb.Push(RESULT_SUCCESS);
86 } 91 }
87 92
88 void GetWithId(Kernel::HLERequestContext& ctx) { 93 void GetWithId(Kernel::HLERequestContext& ctx) {
89 LOG_WARNING(Service_MM, "(STUBBED) called"); 94 LOG_WARNING(Service_MM, "(STUBBED) called");
95
90 IPC::ResponseBuilder rb{ctx, 3}; 96 IPC::ResponseBuilder rb{ctx, 3};
91 rb.Push(RESULT_SUCCESS); 97 rb.Push(RESULT_SUCCESS);
92 rb.Push(current); 98 rb.Push(current);
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 30e542542..5c62d42ba 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -43,11 +43,11 @@ public:
43 43
44private: 44private:
45 void CreateAmInterface(Kernel::HLERequestContext& ctx) { 45 void CreateAmInterface(Kernel::HLERequestContext& ctx) {
46 LOG_DEBUG(Service_NFC, "called");
47
46 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 48 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
47 rb.Push(RESULT_SUCCESS); 49 rb.Push(RESULT_SUCCESS);
48 rb.PushIpcInterface<IAm>(); 50 rb.PushIpcInterface<IAm>();
49
50 LOG_DEBUG(Service_NFC, "called");
51 } 51 }
52}; 52};
53 53
@@ -91,11 +91,11 @@ public:
91 91
92private: 92private:
93 void CreateUserInterface(Kernel::HLERequestContext& ctx) { 93 void CreateUserInterface(Kernel::HLERequestContext& ctx) {
94 LOG_DEBUG(Service_NFC, "called");
95
94 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 96 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
95 rb.Push(RESULT_SUCCESS); 97 rb.Push(RESULT_SUCCESS);
96 rb.PushIpcInterface<MFIUser>(); 98 rb.PushIpcInterface<MFIUser>();
97
98 LOG_DEBUG(Service_NFC, "called");
99 } 99 }
100}; 100};
101 101
@@ -138,19 +138,19 @@ private:
138 }; 138 };
139 139
140 void InitializeOld(Kernel::HLERequestContext& ctx) { 140 void InitializeOld(Kernel::HLERequestContext& ctx) {
141 LOG_DEBUG(Service_NFC, "called");
142
141 IPC::ResponseBuilder rb{ctx, 2, 0}; 143 IPC::ResponseBuilder rb{ctx, 2, 0};
142 rb.Push(RESULT_SUCCESS); 144 rb.Push(RESULT_SUCCESS);
143
144 // We don't deal with hardware initialization so we can just stub this. 145 // We don't deal with hardware initialization so we can just stub this.
145 LOG_DEBUG(Service_NFC, "called");
146 } 146 }
147 147
148 void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) { 148 void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) {
149 LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
150
149 IPC::ResponseBuilder rb{ctx, 3}; 151 IPC::ResponseBuilder rb{ctx, 3};
150 rb.Push(RESULT_SUCCESS); 152 rb.Push(RESULT_SUCCESS);
151 rb.PushRaw<u8>(Settings::values.enable_nfc); 153 rb.PushRaw<u8>(Settings::values.enable_nfc);
152
153 LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
154 } 154 }
155 155
156 void GetStateOld(Kernel::HLERequestContext& ctx) { 156 void GetStateOld(Kernel::HLERequestContext& ctx) {
@@ -183,11 +183,11 @@ public:
183 183
184private: 184private:
185 void CreateUserInterface(Kernel::HLERequestContext& ctx) { 185 void CreateUserInterface(Kernel::HLERequestContext& ctx) {
186 LOG_DEBUG(Service_NFC, "called");
187
186 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 188 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
187 rb.Push(RESULT_SUCCESS); 189 rb.Push(RESULT_SUCCESS);
188 rb.PushIpcInterface<IUser>(); 190 rb.PushIpcInterface<IUser>();
189
190 LOG_DEBUG(Service_NFC, "called");
191 } 191 }
192}; 192};
193 193
@@ -241,11 +241,11 @@ public:
241 241
242private: 242private:
243 void CreateSystemInterface(Kernel::HLERequestContext& ctx) { 243 void CreateSystemInterface(Kernel::HLERequestContext& ctx) {
244 LOG_DEBUG(Service_NFC, "called");
245
244 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 246 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
245 rb.Push(RESULT_SUCCESS); 247 rb.Push(RESULT_SUCCESS);
246 rb.PushIpcInterface<ISystem>(); 248 rb.PushIpcInterface<ISystem>();
247
248 LOG_DEBUG(Service_NFC, "called");
249 } 249 }
250}; 250};
251 251
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index c1af878fe..d5df112a0 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -7,7 +7,9 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
11#include "core/hle/lock.h" 13#include "core/hle/lock.h"
12#include "core/hle/service/hid/hid.h" 14#include "core/hle/service/hid/hid.h"
13#include "core/hle/service/nfp/nfp.h" 15#include "core/hle/service/nfp/nfp.h"
@@ -23,8 +25,8 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
23Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 25Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
24 : ServiceFramework(name), module(std::move(module)) { 26 : ServiceFramework(name), module(std::move(module)) {
25 auto& kernel = Core::System::GetInstance().Kernel(); 27 auto& kernel = Core::System::GetInstance().Kernel();
26 nfc_tag_load = 28 nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
27 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected"); 29 "IUser:NFCTagDetected");
28} 30}
29 31
30Module::Interface::~Interface() = default; 32Module::Interface::~Interface() = default;
@@ -63,10 +65,10 @@ public:
63 RegisterHandlers(functions); 65 RegisterHandlers(functions);
64 66
65 auto& kernel = Core::System::GetInstance().Kernel(); 67 auto& kernel = Core::System::GetInstance().Kernel();
66 deactivate_event = 68 deactivate_event = Kernel::WritableEvent::CreateEventPair(
67 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); 69 kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
68 availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 70 availability_change_event = Kernel::WritableEvent::CreateEventPair(
69 "IUser:AvailabilityChangeEvent"); 71 kernel, Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
70 } 72 }
71 73
72private: 74private:
@@ -108,30 +110,29 @@ private:
108 static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); 110 static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
109 111
110 void Initialize(Kernel::HLERequestContext& ctx) { 112 void Initialize(Kernel::HLERequestContext& ctx) {
113 LOG_DEBUG(Service_NFC, "called");
114
111 IPC::ResponseBuilder rb{ctx, 2, 0}; 115 IPC::ResponseBuilder rb{ctx, 2, 0};
112 rb.Push(RESULT_SUCCESS); 116 rb.Push(RESULT_SUCCESS);
113 117
114 state = State::Initialized; 118 state = State::Initialized;
115
116 LOG_DEBUG(Service_NFC, "called");
117 } 119 }
118 120
119 void GetState(Kernel::HLERequestContext& ctx) { 121 void GetState(Kernel::HLERequestContext& ctx) {
122 LOG_DEBUG(Service_NFC, "called");
123
120 IPC::ResponseBuilder rb{ctx, 3, 0}; 124 IPC::ResponseBuilder rb{ctx, 3, 0};
121 rb.Push(RESULT_SUCCESS); 125 rb.Push(RESULT_SUCCESS);
122 rb.PushRaw<u32>(static_cast<u32>(state)); 126 rb.PushRaw<u32>(static_cast<u32>(state));
123
124 LOG_DEBUG(Service_NFC, "called");
125 } 127 }
126 128
127 void ListDevices(Kernel::HLERequestContext& ctx) { 129 void ListDevices(Kernel::HLERequestContext& ctx) {
128 IPC::RequestParser rp{ctx}; 130 IPC::RequestParser rp{ctx};
129 const u32 array_size = rp.Pop<u32>(); 131 const u32 array_size = rp.Pop<u32>();
132 LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
130 133
131 ctx.WriteBuffer(&device_handle, sizeof(device_handle)); 134 ctx.WriteBuffer(&device_handle, sizeof(device_handle));
132 135
133 LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
134
135 IPC::ResponseBuilder rb{ctx, 3}; 136 IPC::ResponseBuilder rb{ctx, 3};
136 rb.Push(RESULT_SUCCESS); 137 rb.Push(RESULT_SUCCESS);
137 rb.Push<u32>(1); 138 rb.Push<u32>(1);
@@ -141,6 +142,7 @@ private:
141 IPC::RequestParser rp{ctx}; 142 IPC::RequestParser rp{ctx};
142 const u64 dev_handle = rp.Pop<u64>(); 143 const u64 dev_handle = rp.Pop<u64>();
143 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); 144 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
145
144 IPC::ResponseBuilder rb{ctx, 3}; 146 IPC::ResponseBuilder rb{ctx, 3};
145 rb.Push(RESULT_SUCCESS); 147 rb.Push(RESULT_SUCCESS);
146 rb.Push<u32>(npad_id); 148 rb.Push<u32>(npad_id);
@@ -150,6 +152,7 @@ private:
150 IPC::RequestParser rp{ctx}; 152 IPC::RequestParser rp{ctx};
151 const u64 dev_handle = rp.Pop<u64>(); 153 const u64 dev_handle = rp.Pop<u64>();
152 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); 154 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
155
153 IPC::ResponseBuilder rb{ctx, 2, 1}; 156 IPC::ResponseBuilder rb{ctx, 2, 1};
154 rb.Push(RESULT_SUCCESS); 157 rb.Push(RESULT_SUCCESS);
155 rb.PushCopyObjects(nfp_interface.GetNFCEvent()); 158 rb.PushCopyObjects(nfp_interface.GetNFCEvent());
@@ -163,15 +166,16 @@ private:
163 166
164 IPC::ResponseBuilder rb{ctx, 2, 1}; 167 IPC::ResponseBuilder rb{ctx, 2, 1};
165 rb.Push(RESULT_SUCCESS); 168 rb.Push(RESULT_SUCCESS);
166 rb.PushCopyObjects(deactivate_event); 169 rb.PushCopyObjects(deactivate_event.readable);
167 } 170 }
168 171
169 void StopDetection(Kernel::HLERequestContext& ctx) { 172 void StopDetection(Kernel::HLERequestContext& ctx) {
170 LOG_DEBUG(Service_NFP, "called"); 173 LOG_DEBUG(Service_NFP, "called");
174
171 switch (device_state) { 175 switch (device_state) {
172 case DeviceState::TagFound: 176 case DeviceState::TagFound:
173 case DeviceState::TagNearby: 177 case DeviceState::TagNearby:
174 deactivate_event->Signal(); 178 deactivate_event.writable->Signal();
175 device_state = DeviceState::Initialized; 179 device_state = DeviceState::Initialized;
176 break; 180 break;
177 case DeviceState::SearchingForTag: 181 case DeviceState::SearchingForTag:
@@ -185,6 +189,7 @@ private:
185 189
186 void GetDeviceState(Kernel::HLERequestContext& ctx) { 190 void GetDeviceState(Kernel::HLERequestContext& ctx) {
187 LOG_DEBUG(Service_NFP, "called"); 191 LOG_DEBUG(Service_NFP, "called");
192
188 auto nfc_event = nfp_interface.GetNFCEvent(); 193 auto nfc_event = nfp_interface.GetNFCEvent();
189 if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) { 194 if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) {
190 device_state = DeviceState::TagFound; 195 device_state = DeviceState::TagFound;
@@ -212,7 +217,7 @@ private:
212 IPC::ResponseBuilder rb{ctx, 2}; 217 IPC::ResponseBuilder rb{ctx, 2};
213 auto amiibo = nfp_interface.GetAmiiboBuffer(); 218 auto amiibo = nfp_interface.GetAmiiboBuffer();
214 TagInfo tag_info{}; 219 TagInfo tag_info{};
215 std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size())); 220 tag_info.uuid = amiibo.uuid;
216 tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size()); 221 tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size());
217 222
218 tag_info.protocol = 1; // TODO(ogniK): Figure out actual values 223 tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
@@ -261,7 +266,7 @@ private:
261 266
262 IPC::ResponseBuilder rb{ctx, 2, 1}; 267 IPC::ResponseBuilder rb{ctx, 2, 1};
263 rb.Push(RESULT_SUCCESS); 268 rb.Push(RESULT_SUCCESS);
264 rb.PushCopyObjects(availability_change_event); 269 rb.PushCopyObjects(availability_change_event.readable);
265 } 270 }
266 271
267 void GetRegisterInfo(Kernel::HLERequestContext& ctx) { 272 void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
@@ -316,13 +321,14 @@ private:
316 const u32 npad_id{0}; // Player 1 controller 321 const u32 npad_id{0}; // Player 1 controller
317 State state{State::NonInitialized}; 322 State state{State::NonInitialized};
318 DeviceState device_state{DeviceState::Initialized}; 323 DeviceState device_state{DeviceState::Initialized};
319 Kernel::SharedPtr<Kernel::Event> deactivate_event; 324 Kernel::EventPair deactivate_event;
320 Kernel::SharedPtr<Kernel::Event> availability_change_event; 325 Kernel::EventPair availability_change_event;
321 const Module::Interface& nfp_interface; 326 const Module::Interface& nfp_interface;
322}; 327};
323 328
324void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { 329void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
325 LOG_DEBUG(Service_NFP, "called"); 330 LOG_DEBUG(Service_NFP, "called");
331
326 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 332 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
327 rb.Push(RESULT_SUCCESS); 333 rb.Push(RESULT_SUCCESS);
328 rb.PushIpcInterface<IUser>(*this); 334 rb.PushIpcInterface<IUser>(*this);
@@ -335,12 +341,14 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
335 } 341 }
336 342
337 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); 343 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
338 nfc_tag_load->Signal(); 344 nfc_tag_load.writable->Signal();
339 return true; 345 return true;
340} 346}
341const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { 347
342 return nfc_tag_load; 348const Kernel::SharedPtr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const {
349 return nfc_tag_load.readable;
343} 350}
351
344const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { 352const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
345 return amiibo; 353 return amiibo;
346} 354}
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 5c0ae8a54..a1817e991 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -6,7 +6,8 @@
6 6
7#include <array> 7#include <array>
8#include <vector> 8#include <vector>
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11 12
12namespace Service::NFP { 13namespace Service::NFP {
@@ -33,11 +34,11 @@ public:
33 34
34 void CreateUserInterface(Kernel::HLERequestContext& ctx); 35 void CreateUserInterface(Kernel::HLERequestContext& ctx);
35 bool LoadAmiibo(const std::vector<u8>& buffer); 36 bool LoadAmiibo(const std::vector<u8>& buffer);
36 const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; 37 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetNFCEvent() const;
37 const AmiiboFile& GetAmiiboBuffer() const; 38 const AmiiboFile& GetAmiiboBuffer() const;
38 39
39 private: 40 private:
40 Kernel::SharedPtr<Kernel::Event> nfc_tag_load{}; 41 Kernel::EventPair nfc_tag_load{};
41 AmiiboFile amiibo{}; 42 AmiiboFile amiibo{};
42 43
43 protected: 44 protected:
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 75dcd94a3..60479bb45 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -4,7 +4,9 @@
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/event.h" 7#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/kernel/writable_event.h"
8#include "core/hle/service/nifm/nifm.h" 10#include "core/hle/service/nifm/nifm.h"
9#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
10 12
@@ -56,19 +58,23 @@ public:
56 RegisterHandlers(functions); 58 RegisterHandlers(functions);
57 59
58 auto& kernel = Core::System::GetInstance().Kernel(); 60 auto& kernel = Core::System::GetInstance().Kernel();
59 event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1"); 61 event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
60 event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2"); 62 "IRequest:Event1");
63 event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
64 "IRequest:Event2");
61 } 65 }
62 66
63private: 67private:
64 void Submit(Kernel::HLERequestContext& ctx) { 68 void Submit(Kernel::HLERequestContext& ctx) {
65 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 69 LOG_WARNING(Service_NIFM, "(STUBBED) called");
70
66 IPC::ResponseBuilder rb{ctx, 2}; 71 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(RESULT_SUCCESS); 72 rb.Push(RESULT_SUCCESS);
68 } 73 }
69 74
70 void GetRequestState(Kernel::HLERequestContext& ctx) { 75 void GetRequestState(Kernel::HLERequestContext& ctx) {
71 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 76 LOG_WARNING(Service_NIFM, "(STUBBED) called");
77
72 IPC::ResponseBuilder rb{ctx, 3}; 78 IPC::ResponseBuilder rb{ctx, 3};
73 rb.Push(RESULT_SUCCESS); 79 rb.Push(RESULT_SUCCESS);
74 rb.Push<u32>(0); 80 rb.Push<u32>(0);
@@ -76,30 +82,34 @@ private:
76 82
77 void GetResult(Kernel::HLERequestContext& ctx) { 83 void GetResult(Kernel::HLERequestContext& ctx) {
78 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 84 LOG_WARNING(Service_NIFM, "(STUBBED) called");
85
79 IPC::ResponseBuilder rb{ctx, 2}; 86 IPC::ResponseBuilder rb{ctx, 2};
80 rb.Push(RESULT_SUCCESS); 87 rb.Push(RESULT_SUCCESS);
81 } 88 }
82 89
83 void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { 90 void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
84 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 91 LOG_WARNING(Service_NIFM, "(STUBBED) called");
92
85 IPC::ResponseBuilder rb{ctx, 2, 2}; 93 IPC::ResponseBuilder rb{ctx, 2, 2};
86 rb.Push(RESULT_SUCCESS); 94 rb.Push(RESULT_SUCCESS);
87 rb.PushCopyObjects(event1, event2); 95 rb.PushCopyObjects(event1.readable, event2.readable);
88 } 96 }
89 97
90 void Cancel(Kernel::HLERequestContext& ctx) { 98 void Cancel(Kernel::HLERequestContext& ctx) {
91 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 99 LOG_WARNING(Service_NIFM, "(STUBBED) called");
100
92 IPC::ResponseBuilder rb{ctx, 2}; 101 IPC::ResponseBuilder rb{ctx, 2};
93 rb.Push(RESULT_SUCCESS); 102 rb.Push(RESULT_SUCCESS);
94 } 103 }
95 104
96 void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { 105 void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) {
97 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 106 LOG_WARNING(Service_NIFM, "(STUBBED) called");
107
98 IPC::ResponseBuilder rb{ctx, 2}; 108 IPC::ResponseBuilder rb{ctx, 2};
99 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
100 } 110 }
101 111
102 Kernel::SharedPtr<Kernel::Event> event1, event2; 112 Kernel::EventPair event1, event2;
103}; 113};
104 114
105class INetworkProfile final : public ServiceFramework<INetworkProfile> { 115class INetworkProfile final : public ServiceFramework<INetworkProfile> {
@@ -122,32 +132,36 @@ private:
122 void GetClientId(Kernel::HLERequestContext& ctx) { 132 void GetClientId(Kernel::HLERequestContext& ctx) {
123 static constexpr u32 client_id = 1; 133 static constexpr u32 client_id = 1;
124 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 134 LOG_WARNING(Service_NIFM, "(STUBBED) called");
135
125 IPC::ResponseBuilder rb{ctx, 4}; 136 IPC::ResponseBuilder rb{ctx, 4};
126 rb.Push(RESULT_SUCCESS); 137 rb.Push(RESULT_SUCCESS);
127 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid 138 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
128 } 139 }
129 void CreateScanRequest(Kernel::HLERequestContext& ctx) { 140 void CreateScanRequest(Kernel::HLERequestContext& ctx) {
141 LOG_DEBUG(Service_NIFM, "called");
142
130 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 143 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
131 144
132 rb.Push(RESULT_SUCCESS); 145 rb.Push(RESULT_SUCCESS);
133 rb.PushIpcInterface<IScanRequest>(); 146 rb.PushIpcInterface<IScanRequest>();
134
135 LOG_DEBUG(Service_NIFM, "called");
136 } 147 }
137 void CreateRequest(Kernel::HLERequestContext& ctx) { 148 void CreateRequest(Kernel::HLERequestContext& ctx) {
149 LOG_DEBUG(Service_NIFM, "called");
150
138 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 151 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
139 152
140 rb.Push(RESULT_SUCCESS); 153 rb.Push(RESULT_SUCCESS);
141 rb.PushIpcInterface<IRequest>(); 154 rb.PushIpcInterface<IRequest>();
142
143 LOG_DEBUG(Service_NIFM, "called");
144 } 155 }
145 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { 156 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
146 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 157 LOG_WARNING(Service_NIFM, "(STUBBED) called");
158
147 IPC::ResponseBuilder rb{ctx, 2}; 159 IPC::ResponseBuilder rb{ctx, 2};
148 rb.Push(RESULT_SUCCESS); 160 rb.Push(RESULT_SUCCESS);
149 } 161 }
150 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { 162 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
163 LOG_DEBUG(Service_NIFM, "called");
164
151 ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size"); 165 ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size");
152 u128 uuid{}; 166 u128 uuid{};
153 auto buffer = ctx.ReadBuffer(); 167 auto buffer = ctx.ReadBuffer();
@@ -158,23 +172,24 @@ private:
158 rb.Push(RESULT_SUCCESS); 172 rb.Push(RESULT_SUCCESS);
159 rb.PushIpcInterface<INetworkProfile>(); 173 rb.PushIpcInterface<INetworkProfile>();
160 rb.PushRaw<u128>(uuid); 174 rb.PushRaw<u128>(uuid);
161
162 LOG_DEBUG(Service_NIFM, "called");
163 } 175 }
164 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { 176 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
165 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 177 LOG_WARNING(Service_NIFM, "(STUBBED) called");
178
166 IPC::ResponseBuilder rb{ctx, 3}; 179 IPC::ResponseBuilder rb{ctx, 3};
167 rb.Push(RESULT_SUCCESS); 180 rb.Push(RESULT_SUCCESS);
168 rb.Push<u8>(0); 181 rb.Push<u8>(0);
169 } 182 }
170 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { 183 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
171 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 184 LOG_WARNING(Service_NIFM, "(STUBBED) called");
185
172 IPC::ResponseBuilder rb{ctx, 3}; 186 IPC::ResponseBuilder rb{ctx, 3};
173 rb.Push(RESULT_SUCCESS); 187 rb.Push(RESULT_SUCCESS);
174 rb.Push<u8>(0); 188 rb.Push<u8>(0);
175 } 189 }
176 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { 190 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
177 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 191 LOG_WARNING(Service_NIFM, "(STUBBED) called");
192
178 IPC::ResponseBuilder rb{ctx, 3}; 193 IPC::ResponseBuilder rb{ctx, 3};
179 rb.Push(RESULT_SUCCESS); 194 rb.Push(RESULT_SUCCESS);
180 rb.Push<u8>(0); 195 rb.Push<u8>(0);
@@ -235,17 +250,19 @@ public:
235 } 250 }
236 251
237 void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { 252 void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) {
253 LOG_DEBUG(Service_NIFM, "called");
254
238 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 255 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
239 rb.Push(RESULT_SUCCESS); 256 rb.Push(RESULT_SUCCESS);
240 rb.PushIpcInterface<IGeneralService>(); 257 rb.PushIpcInterface<IGeneralService>();
241 LOG_DEBUG(Service_NIFM, "called");
242 } 258 }
243 259
244 void CreateGeneralService(Kernel::HLERequestContext& ctx) { 260 void CreateGeneralService(Kernel::HLERequestContext& ctx) {
261 LOG_DEBUG(Service_NIFM, "called");
262
245 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 263 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
246 rb.Push(RESULT_SUCCESS); 264 rb.Push(RESULT_SUCCESS);
247 rb.PushIpcInterface<IGeneralService>(); 265 rb.PushIpcInterface<IGeneralService>();
248 LOG_DEBUG(Service_NIFM, "called");
249 } 266 }
250}; 267};
251 268
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 18091c9bb..0dabcd23b 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -6,7 +6,9 @@
6#include <ctime> 6#include <ctime>
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/readable_event.h"
11#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nim/nim.h" 12#include "core/hle/service/nim/nim.h"
11#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h" 14#include "core/hle/service/sm/sm.h"
@@ -138,57 +140,61 @@ public:
138 RegisterHandlers(functions); 140 RegisterHandlers(functions);
139 141
140 auto& kernel = Core::System::GetInstance().Kernel(); 142 auto& kernel = Core::System::GetInstance().Kernel();
141 finished_event = 143 finished_event = Kernel::WritableEvent::CreateEventPair(
142 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 144 kernel, Kernel::ResetType::OneShot,
143 "IEnsureNetworkClockAvailabilityService:FinishEvent"); 145 "IEnsureNetworkClockAvailabilityService:FinishEvent");
144 } 146 }
145 147
146private: 148private:
147 Kernel::SharedPtr<Kernel::Event> finished_event; 149 Kernel::EventPair finished_event;
148 150
149 void StartTask(Kernel::HLERequestContext& ctx) { 151 void StartTask(Kernel::HLERequestContext& ctx) {
150 // No need to connect to the internet, just finish the task straight away. 152 // No need to connect to the internet, just finish the task straight away.
151 finished_event->Signal(); 153 LOG_DEBUG(Service_NIM, "called");
154 finished_event.writable->Signal();
152 IPC::ResponseBuilder rb{ctx, 2}; 155 IPC::ResponseBuilder rb{ctx, 2};
153 rb.Push(RESULT_SUCCESS); 156 rb.Push(RESULT_SUCCESS);
154 LOG_DEBUG(Service_NIM, "called");
155 } 157 }
156 158
157 void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) { 159 void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) {
160 LOG_DEBUG(Service_NIM, "called");
161
158 IPC::ResponseBuilder rb{ctx, 2, 1}; 162 IPC::ResponseBuilder rb{ctx, 2, 1};
159 rb.Push(RESULT_SUCCESS); 163 rb.Push(RESULT_SUCCESS);
160 rb.PushCopyObjects(finished_event); 164 rb.PushCopyObjects(finished_event.readable);
161 LOG_DEBUG(Service_NIM, "called");
162 } 165 }
163 166
164 void GetResult(Kernel::HLERequestContext& ctx) { 167 void GetResult(Kernel::HLERequestContext& ctx) {
168 LOG_DEBUG(Service_NIM, "called");
169
165 IPC::ResponseBuilder rb{ctx, 2}; 170 IPC::ResponseBuilder rb{ctx, 2};
166 rb.Push(RESULT_SUCCESS); 171 rb.Push(RESULT_SUCCESS);
167 LOG_DEBUG(Service_NIM, "called");
168 } 172 }
169 173
170 void Cancel(Kernel::HLERequestContext& ctx) { 174 void Cancel(Kernel::HLERequestContext& ctx) {
171 finished_event->Clear(); 175 LOG_DEBUG(Service_NIM, "called");
176 finished_event.writable->Clear();
172 IPC::ResponseBuilder rb{ctx, 2}; 177 IPC::ResponseBuilder rb{ctx, 2};
173 rb.Push(RESULT_SUCCESS); 178 rb.Push(RESULT_SUCCESS);
174 LOG_DEBUG(Service_NIM, "called");
175 } 179 }
176 180
177 void IsProcessing(Kernel::HLERequestContext& ctx) { 181 void IsProcessing(Kernel::HLERequestContext& ctx) {
182 LOG_DEBUG(Service_NIM, "called");
183
178 IPC::ResponseBuilder rb{ctx, 3}; 184 IPC::ResponseBuilder rb{ctx, 3};
179 rb.Push(RESULT_SUCCESS); 185 rb.Push(RESULT_SUCCESS);
180 rb.PushRaw<u32>(0); // We instantly process the request 186 rb.PushRaw<u32>(0); // We instantly process the request
181 LOG_DEBUG(Service_NIM, "called");
182 } 187 }
183 188
184 void GetServerTime(Kernel::HLERequestContext& ctx) { 189 void GetServerTime(Kernel::HLERequestContext& ctx) {
190 LOG_DEBUG(Service_NIM, "called");
191
185 const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>( 192 const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>(
186 std::chrono::system_clock::now().time_since_epoch()) 193 std::chrono::system_clock::now().time_since_epoch())
187 .count()}; 194 .count()};
188 IPC::ResponseBuilder rb{ctx, 4}; 195 IPC::ResponseBuilder rb{ctx, 4};
189 rb.Push(RESULT_SUCCESS); 196 rb.Push(RESULT_SUCCESS);
190 rb.PushRaw<s64>(server_time); 197 rb.PushRaw<s64>(server_time);
191 LOG_DEBUG(Service_NIM, "called");
192 } 198 }
193}; 199};
194 200
@@ -208,23 +214,26 @@ public:
208 214
209private: 215private:
210 void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) { 216 void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) {
217 LOG_DEBUG(Service_NIM, "called");
218
211 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 219 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
212 rb.Push(RESULT_SUCCESS); 220 rb.Push(RESULT_SUCCESS);
213 rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); 221 rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>();
214 LOG_DEBUG(Service_NIM, "called");
215 } 222 }
216 223
217 // TODO(ogniK): Do we need these? 224 // TODO(ogniK): Do we need these?
218 void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { 225 void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
226 LOG_WARNING(Service_NIM, "(STUBBED) called");
227
219 IPC::ResponseBuilder rb{ctx, 2}; 228 IPC::ResponseBuilder rb{ctx, 2};
220 rb.Push(RESULT_SUCCESS); 229 rb.Push(RESULT_SUCCESS);
221 LOG_WARNING(Service_NIM, "(STUBBED) called");
222 } 230 }
223 231
224 void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { 232 void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
233 LOG_WARNING(Service_NIM, "(STUBBED) called");
234
225 IPC::ResponseBuilder rb{ctx, 2}; 235 IPC::ResponseBuilder rb{ctx, 2};
226 rb.Push(RESULT_SUCCESS); 236 rb.Push(RESULT_SUCCESS);
227 LOG_WARNING(Service_NIM, "(STUBBED) called");
228 } 237 }
229}; 238};
230 239
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 07c1381fe..2663f56b1 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -2,6 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h"
5#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
6#include "core/hle/kernel/hle_ipc.h" 9#include "core/hle/kernel/hle_ipc.h"
7#include "core/hle/service/ns/ns.h" 10#include "core/hle/service/ns/ns.h"
@@ -118,7 +121,7 @@ public:
118 {305, nullptr, "TerminateSystemApplet"}, 121 {305, nullptr, "TerminateSystemApplet"},
119 {306, nullptr, "LaunchOverlayApplet"}, 122 {306, nullptr, "LaunchOverlayApplet"},
120 {307, nullptr, "TerminateOverlayApplet"}, 123 {307, nullptr, "TerminateOverlayApplet"},
121 {400, nullptr, "GetApplicationControlData"}, 124 {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
122 {401, nullptr, "InvalidateAllApplicationControlCache"}, 125 {401, nullptr, "InvalidateAllApplicationControlCache"},
123 {402, nullptr, "RequestDownloadApplicationControlData"}, 126 {402, nullptr, "RequestDownloadApplicationControlData"},
124 {403, nullptr, "GetMaxApplicationControlCacheCount"}, 127 {403, nullptr, "GetMaxApplicationControlCacheCount"},
@@ -243,6 +246,65 @@ public:
243 246
244 RegisterHandlers(functions); 247 RegisterHandlers(functions);
245 } 248 }
249
250 void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
251 IPC::RequestParser rp{ctx};
252 const auto flag = rp.PopRaw<u64>();
253 LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
254
255 const auto title_id = rp.PopRaw<u64>();
256
257 const auto size = ctx.GetWriteBufferSize();
258
259 const FileSys::PatchManager pm{title_id};
260 const auto control = pm.GetControlMetadata();
261
262 std::vector<u8> out;
263
264 if (control.first != nullptr) {
265 if (size < 0x4000) {
266 LOG_ERROR(Service_NS,
267 "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
268 size);
269 IPC::ResponseBuilder rb{ctx, 2};
270 // TODO(DarkLordZach): Find a better error code for this.
271 rb.Push(ResultCode(-1));
272 return;
273 }
274
275 out.resize(0x4000);
276 const auto bytes = control.first->GetRawBytes();
277 std::memcpy(out.data(), bytes.data(), bytes.size());
278 } else {
279 LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
280 title_id);
281 out.resize(std::min<u64>(0x4000, size));
282 }
283
284 if (control.second != nullptr) {
285 if (size < 0x4000 + control.second->GetSize()) {
286 LOG_ERROR(Service_NS,
287 "output buffer is too small! (actual={:016X}, expected_min={:016X})",
288 size, 0x4000 + control.second->GetSize());
289 IPC::ResponseBuilder rb{ctx, 2};
290 // TODO(DarkLordZach): Find a better error code for this.
291 rb.Push(ResultCode(-1));
292 return;
293 }
294
295 out.resize(0x4000 + control.second->GetSize());
296 control.second->Read(out.data() + 0x4000, control.second->GetSize());
297 } else {
298 LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
299 title_id);
300 }
301
302 ctx.WriteBuffer(out);
303
304 IPC::ResponseBuilder rb{ctx, 3};
305 rb.Push(RESULT_SUCCESS);
306 rb.Push<u32>(static_cast<u32>(out.size()));
307 }
246}; 308};
247 309
248class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { 310class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
@@ -371,11 +433,11 @@ public:
371private: 433private:
372 template <typename T> 434 template <typename T>
373 void PushInterface(Kernel::HLERequestContext& ctx) { 435 void PushInterface(Kernel::HLERequestContext& ctx) {
436 LOG_DEBUG(Service_NS, "called");
437
374 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 438 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
375 rb.Push(RESULT_SUCCESS); 439 rb.Push(RESULT_SUCCESS);
376 rb.PushIpcInterface<T>(); 440 rb.PushIpcInterface<T>();
377
378 LOG_DEBUG(Service_NS, "called");
379 } 441 }
380}; 442};
381 443
@@ -464,11 +526,11 @@ public:
464 526
465private: 527private:
466 void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) { 528 void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) {
529 LOG_DEBUG(Service_NS, "called");
530
467 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 531 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
468 rb.Push(RESULT_SUCCESS); 532 rb.Push(RESULT_SUCCESS);
469 rb.PushIpcInterface<ISystemUpdateControl>(); 533 rb.PushIpcInterface<ISystemUpdateControl>();
470
471 LOG_DEBUG(Service_NS, "called");
472 } 534 }
473}; 535};
474 536
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 44accecb7..ad176f89d 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -281,6 +281,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
281 const u32 shared_font_type{rp.Pop<u32>()}; 281 const u32 shared_font_type{rp.Pop<u32>()};
282 // Games don't call this so all fonts should be loaded 282 // Games don't call this so all fonts should be loaded
283 LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); 283 LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type);
284
284 IPC::ResponseBuilder rb{ctx, 2}; 285 IPC::ResponseBuilder rb{ctx, 2};
285 rb.Push(RESULT_SUCCESS); 286 rb.Push(RESULT_SUCCESS);
286} 287}
@@ -288,8 +289,8 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
288void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { 289void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
289 IPC::RequestParser rp{ctx}; 290 IPC::RequestParser rp{ctx};
290 const u32 font_id{rp.Pop<u32>()}; 291 const u32 font_id{rp.Pop<u32>()};
291
292 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 292 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
293
293 IPC::ResponseBuilder rb{ctx, 3}; 294 IPC::ResponseBuilder rb{ctx, 3};
294 rb.Push(RESULT_SUCCESS); 295 rb.Push(RESULT_SUCCESS);
295 rb.Push<u32>(static_cast<u32>(LoadState::Done)); 296 rb.Push<u32>(static_cast<u32>(LoadState::Done));
@@ -298,8 +299,8 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
298void PL_U::GetSize(Kernel::HLERequestContext& ctx) { 299void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
299 IPC::RequestParser rp{ctx}; 300 IPC::RequestParser rp{ctx};
300 const u32 font_id{rp.Pop<u32>()}; 301 const u32 font_id{rp.Pop<u32>()};
301
302 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 302 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
303
303 IPC::ResponseBuilder rb{ctx, 3}; 304 IPC::ResponseBuilder rb{ctx, 3};
304 rb.Push(RESULT_SUCCESS); 305 rb.Push(RESULT_SUCCESS);
305 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); 306 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
@@ -308,8 +309,8 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
308void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { 309void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
309 IPC::RequestParser rp{ctx}; 310 IPC::RequestParser rp{ctx};
310 const u32 font_id{rp.Pop<u32>()}; 311 const u32 font_id{rp.Pop<u32>()};
311
312 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 312 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
313
313 IPC::ResponseBuilder rb{ctx, 3}; 314 IPC::ResponseBuilder rb{ctx, 3};
314 rb.Push(RESULT_SUCCESS); 315 rb.Push(RESULT_SUCCESS);
315 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); 316 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
@@ -317,6 +318,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
317 318
318void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 319void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
319 // Map backing memory for the font data 320 // Map backing memory for the font data
321 LOG_DEBUG(Service_NS, "called");
320 Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, 322 Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
321 SHARED_FONT_MEM_SIZE, 323 SHARED_FONT_MEM_SIZE,
322 Kernel::MemoryState::Shared); 324 Kernel::MemoryState::Shared);
@@ -328,7 +330,6 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
328 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, 330 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
329 "PL_U:shared_font_mem"); 331 "PL_U:shared_font_mem");
330 332
331 LOG_DEBUG(Service_NS, "called");
332 IPC::ResponseBuilder rb{ctx, 2, 1}; 333 IPC::ResponseBuilder rb{ctx, 2, 1};
333 rb.Push(RESULT_SUCCESS); 334 rb.Push(RESULT_SUCCESS);
334 rb.PushCopyObjects(impl->shared_font_mem); 335 rb.PushCopyObjects(impl->shared_font_mem);
@@ -338,6 +339,7 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
338 IPC::RequestParser rp{ctx}; 339 IPC::RequestParser rp{ctx};
339 const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for 340 const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
340 LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); 341 LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code);
342
341 IPC::ResponseBuilder rb{ctx, 4}; 343 IPC::ResponseBuilder rb{ctx, 4};
342 std::vector<u32> font_codes; 344 std::vector<u32> font_codes;
343 std::vector<u32> font_offsets; 345 std::vector<u32> font_offsets;
@@ -351,6 +353,14 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
351 font_sizes.push_back(region.size); 353 font_sizes.push_back(region.size);
352 } 354 }
353 355
356 // Resize buffers if game requests smaller size output.
357 font_codes.resize(
358 std::min<std::size_t>(font_codes.size(), ctx.GetWriteBufferSize(0) / sizeof(u32)));
359 font_offsets.resize(
360 std::min<std::size_t>(font_offsets.size(), ctx.GetWriteBufferSize(1) / sizeof(u32)));
361 font_sizes.resize(
362 std::min<std::size_t>(font_sizes.size(), ctx.GetWriteBufferSize(2) / sizeof(u32)));
363
354 ctx.WriteBuffer(font_codes, 0); 364 ctx.WriteBuffer(font_codes, 0);
355 ctx.WriteBuffer(font_offsets, 1); 365 ctx.WriteBuffer(font_offsets, 1);
356 ctx.WriteBuffer(font_sizes, 2); 366 ctx.WriteBuffer(font_sizes, 2);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index c41ef7058..466db7ccd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -54,6 +54,7 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou
54 IoctlInitalizeEx params{}; 54 IoctlInitalizeEx params{};
55 std::memcpy(&params, input.data(), input.size()); 55 std::memcpy(&params, input.data(), input.size());
56 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); 56 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
57
57 return 0; 58 return 0;
58} 59}
59 60
@@ -191,6 +192,7 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou
191 IoctlBindChannel params{}; 192 IoctlBindChannel params{};
192 std::memcpy(&params, input.data(), input.size()); 193 std::memcpy(&params, input.data(), input.size());
193 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); 194 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
195
194 channel = params.fd; 196 channel = params.fd;
195 return 0; 197 return 0;
196} 198}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 7a88ae029..d57a54ee8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -5,6 +5,8 @@
5#include <cstring> 5#include <cstring>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core_timing.h"
9#include "core/core_timing_util.h"
8#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" 10#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
9 11
10namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
@@ -33,6 +35,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec
33 return ZBCQueryTable(input, output); 35 return ZBCQueryTable(input, output);
34 case IoctlCommand::IocFlushL2: 36 case IoctlCommand::IocFlushL2:
35 return FlushL2(input, output); 37 return FlushL2(input, output);
38 case IoctlCommand::IocGetGpuTime:
39 return GetGpuTime(input, output);
36 } 40 }
37 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 41 UNIMPLEMENTED_MSG("Unimplemented ioctl");
38 return 0; 42 return 0;
@@ -99,6 +103,7 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>&
99 103
100u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { 104u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
101 LOG_DEBUG(Service_NVDRV, "called"); 105 LOG_DEBUG(Service_NVDRV, "called");
106
102 IoctlActiveSlotMask params{}; 107 IoctlActiveSlotMask params{};
103 if (input.size() > 0) { 108 if (input.size() > 0) {
104 std::memcpy(&params, input.data(), input.size()); 109 std::memcpy(&params, input.data(), input.size());
@@ -111,6 +116,7 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
111 116
112u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { 117u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
113 LOG_DEBUG(Service_NVDRV, "called"); 118 LOG_DEBUG(Service_NVDRV, "called");
119
114 IoctlZcullGetCtxSize params{}; 120 IoctlZcullGetCtxSize params{};
115 if (input.size() > 0) { 121 if (input.size() > 0) {
116 std::memcpy(&params, input.data(), input.size()); 122 std::memcpy(&params, input.data(), input.size());
@@ -122,6 +128,7 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
122 128
123u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { 129u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
124 LOG_DEBUG(Service_NVDRV, "called"); 130 LOG_DEBUG(Service_NVDRV, "called");
131
125 IoctlNvgpuGpuZcullGetInfoArgs params{}; 132 IoctlNvgpuGpuZcullGetInfoArgs params{};
126 133
127 if (input.size() > 0) { 134 if (input.size() > 0) {
@@ -144,6 +151,7 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&
144 151
145u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { 152u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
146 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 153 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
154
147 IoctlZbcSetTable params{}; 155 IoctlZbcSetTable params{};
148 std::memcpy(&params, input.data(), input.size()); 156 std::memcpy(&params, input.data(), input.size());
149 // TODO(ogniK): What does this even actually do? 157 // TODO(ogniK): What does this even actually do?
@@ -153,6 +161,7 @@ u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>&
153 161
154u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { 162u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
155 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 163 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
164
156 IoctlZbcQueryTable params{}; 165 IoctlZbcQueryTable params{};
157 std::memcpy(&params, input.data(), input.size()); 166 std::memcpy(&params, input.data(), input.size());
158 // TODO : To implement properly 167 // TODO : To implement properly
@@ -162,6 +171,7 @@ u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>
162 171
163u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { 172u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
164 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 173 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
174
165 IoctlFlushL2 params{}; 175 IoctlFlushL2 params{};
166 std::memcpy(&params, input.data(), input.size()); 176 std::memcpy(&params, input.data(), input.size());
167 // TODO : To implement properly 177 // TODO : To implement properly
@@ -169,4 +179,14 @@ u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& outp
169 return 0; 179 return 0;
170} 180}
171 181
182u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
183 LOG_DEBUG(Service_NVDRV, "called");
184
185 IoctlGetGpuTime params{};
186 std::memcpy(&params, input.data(), input.size());
187 params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks());
188 std::memcpy(output.data(), &params, output.size());
189 return 0;
190}
191
172} // namespace Service::Nvidia::Devices 192} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index 3bbf028ad..240435eea 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -156,6 +156,11 @@ private:
156 }; 156 };
157 static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size"); 157 static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size");
158 158
159 struct IoctlGetGpuTime {
160 u64_le gpu_time;
161 };
162 static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size");
163
159 u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); 164 u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
160 u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); 165 u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
161 u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); 166 u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
@@ -164,6 +169,7 @@ private:
164 u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); 169 u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
165 u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); 170 u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
166 u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); 171 u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
172 u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
167}; 173};
168 174
169} // namespace Service::Nvidia::Devices 175} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 874d5e1c3..3bfce0110 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -8,7 +8,6 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_gpu.h" 9#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
10#include "core/memory.h" 10#include "core/memory.h"
11#include "video_core/command_processor.h"
12#include "video_core/gpu.h" 11#include "video_core/gpu.h"
13#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
14 13
@@ -61,12 +60,14 @@ u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output
61 IoctlSetNvmapFD params{}; 60 IoctlSetNvmapFD params{};
62 std::memcpy(&params, input.data(), input.size()); 61 std::memcpy(&params, input.data(), input.size());
63 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 62 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
63
64 nvmap_fd = params.nvmap_fd; 64 nvmap_fd = params.nvmap_fd;
65 return 0; 65 return 0;
66} 66}
67 67
68u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 68u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
69 LOG_DEBUG(Service_NVDRV, "called"); 69 LOG_DEBUG(Service_NVDRV, "called");
70
70 IoctlClientData params{}; 71 IoctlClientData params{};
71 std::memcpy(&params, input.data(), input.size()); 72 std::memcpy(&params, input.data(), input.size());
72 user_data = params.data; 73 user_data = params.data;
@@ -75,6 +76,7 @@ u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& out
75 76
76u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 77u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
77 LOG_DEBUG(Service_NVDRV, "called"); 78 LOG_DEBUG(Service_NVDRV, "called");
79
78 IoctlClientData params{}; 80 IoctlClientData params{};
79 std::memcpy(&params, input.data(), input.size()); 81 std::memcpy(&params, input.data(), input.size());
80 params.data = user_data; 82 params.data = user_data;
@@ -86,6 +88,7 @@ u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output)
86 std::memcpy(&zcull_params, input.data(), input.size()); 88 std::memcpy(&zcull_params, input.data(), input.size());
87 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, 89 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
88 zcull_params.mode); 90 zcull_params.mode);
91
89 std::memcpy(output.data(), &zcull_params, output.size()); 92 std::memcpy(output.data(), &zcull_params, output.size());
90 return 0; 93 return 0;
91} 94}
@@ -95,6 +98,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>&
95 std::memcpy(&params, input.data(), input.size()); 98 std::memcpy(&params, input.data(), input.size());
96 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, 99 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
97 params.size, params.mem); 100 params.size, params.mem);
101
98 std::memcpy(output.data(), &params, output.size()); 102 std::memcpy(output.data(), &params, output.size());
99 return 0; 103 return 0;
100} 104}
@@ -102,6 +106,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>&
102u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { 106u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
103 std::memcpy(&channel_priority, input.data(), input.size()); 107 std::memcpy(&channel_priority, input.data(), input.size());
104 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); 108 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
109
105 return 0; 110 return 0;
106} 111}
107 112
@@ -113,6 +118,7 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
113 "unk1={:X}, unk2={:X}, unk3={:X}", 118 "unk1={:X}, unk2={:X}, unk3={:X}",
114 params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, 119 params.num_entries, params.flags, params.unk0, params.unk1, params.unk2,
115 params.unk3); 120 params.unk3);
121
116 params.fence_out.id = 0; 122 params.fence_out.id = 0;
117 params.fence_out.value = 0; 123 params.fence_out.value = 0;
118 std::memcpy(output.data(), &params, output.size()); 124 std::memcpy(output.data(), &params, output.size());
@@ -124,11 +130,18 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
124 std::memcpy(&params, input.data(), input.size()); 130 std::memcpy(&params, input.data(), input.size());
125 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, 131 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
126 params.flags); 132 params.flags);
133
127 params.obj_id = 0x0; 134 params.obj_id = 0x0;
128 std::memcpy(output.data(), &params, output.size()); 135 std::memcpy(output.data(), &params, output.size());
129 return 0; 136 return 0;
130} 137}
131 138
139static void PushGPUEntries(Tegra::CommandList&& entries) {
140 auto& dma_pusher{Core::System::GetInstance().GPU().DmaPusher()};
141 dma_pusher.Push(std::move(entries));
142 dma_pusher.DispatchCalls();
143}
144
132u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { 145u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) {
133 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 146 if (input.size() < sizeof(IoctlSubmitGpfifo)) {
134 UNIMPLEMENTED(); 147 UNIMPLEMENTED();
@@ -142,11 +155,11 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
142 params.num_entries * sizeof(Tegra::CommandListHeader), 155 params.num_entries * sizeof(Tegra::CommandListHeader),
143 "Incorrect input size"); 156 "Incorrect input size");
144 157
145 std::vector<Tegra::CommandListHeader> entries(params.num_entries); 158 Tegra::CommandList entries(params.num_entries);
146 std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], 159 std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],
147 params.num_entries * sizeof(Tegra::CommandListHeader)); 160 params.num_entries * sizeof(Tegra::CommandListHeader));
148 161
149 Core::System::GetInstance().GPU().ProcessCommandLists(entries); 162 PushGPUEntries(std::move(entries));
150 163
151 params.fence_out.id = 0; 164 params.fence_out.id = 0;
152 params.fence_out.value = 0; 165 params.fence_out.value = 0;
@@ -163,11 +176,11 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output)
163 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", 176 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
164 params.address, params.num_entries, params.flags); 177 params.address, params.num_entries, params.flags);
165 178
166 std::vector<Tegra::CommandListHeader> entries(params.num_entries); 179 Tegra::CommandList entries(params.num_entries);
167 Memory::ReadBlock(params.address, entries.data(), 180 Memory::ReadBlock(params.address, entries.data(),
168 params.num_entries * sizeof(Tegra::CommandListHeader)); 181 params.num_entries * sizeof(Tegra::CommandListHeader));
169 182
170 Core::System::GetInstance().GPU().ProcessCommandLists(entries); 183 PushGPUEntries(std::move(entries));
171 184
172 params.fence_out.id = 0; 185 params.fence_out.id = 0;
173 params.fence_out.value = 0; 186 params.fence_out.value = 0;
@@ -179,6 +192,7 @@ u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& outpu
179 IoctlGetWaitbase params{}; 192 IoctlGetWaitbase params{};
180 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase)); 193 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
181 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); 194 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
195
182 params.value = 0; // Seems to be hard coded at 0 196 params.value = 0; // Seems to be hard coded at 0
183 std::memcpy(output.data(), &params, output.size()); 197 std::memcpy(output.data(), &params, output.size());
184 return 0; 198 return 0;
@@ -188,6 +202,7 @@ u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>&
188 IoctlChannelSetTimeout params{}; 202 IoctlChannelSetTimeout params{};
189 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout)); 203 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout));
190 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); 204 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
205
191 return 0; 206 return 0;
192} 207}
193 208
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 46dbbc37c..f5e8ea7c3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -30,6 +30,7 @@ u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp
30 IoctlSetNvmapFD params{}; 30 IoctlSetNvmapFD params{};
31 std::memcpy(&params, input.data(), input.size()); 31 std::memcpy(&params, input.data(), input.size());
32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
33
33 nvmap_fd = params.nvmap_fd; 34 nvmap_fd = params.nvmap_fd;
34 return 0; 35 return 0;
35} 36}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index c67f934f6..3e0951ab0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -30,6 +30,7 @@ u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp
30 IoctlSetNvmapFD params{}; 30 IoctlSetNvmapFD params{};
31 std::memcpy(&params, input.data(), input.size()); 31 std::memcpy(&params, input.data(), input.size());
32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
33
33 nvmap_fd = params.nvmap_fd; 34 nvmap_fd = params.nvmap_fd;
34 return 0; 35 return 0;
35} 36}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 727b9fee4..d544f0f31 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -30,6 +30,7 @@ u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output
30 IoctlSetNvmapFD params{}; 30 IoctlSetNvmapFD params{};
31 std::memcpy(&params, input.data(), input.size()); 31 std::memcpy(&params, input.data(), input.size());
32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
33
33 nvmap_fd = params.nvmap_fd; 34 nvmap_fd = params.nvmap_fd;
34 return 0; 35 return 0;
35} 36}
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 43651d8a6..1ec796fc6 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -54,6 +54,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
54 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); 54 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
55 55
56 if (!params.size) { 56 if (!params.size) {
57 LOG_ERROR(Service_NVDRV, "Size is 0");
57 return static_cast<u32>(NvErrCodes::InvalidValue); 58 return static_cast<u32>(NvErrCodes::InvalidValue);
58 } 59 }
59 // Create a new nvmap object and obtain a handle to it. 60 // Create a new nvmap object and obtain a handle to it.
@@ -78,10 +79,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
78 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); 79 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
79 80
80 if (!params.handle) { 81 if (!params.handle) {
82 LOG_ERROR(Service_NVDRV, "Handle is 0");
81 return static_cast<u32>(NvErrCodes::InvalidValue); 83 return static_cast<u32>(NvErrCodes::InvalidValue);
82 } 84 }
83 85
84 if ((params.align - 1) & params.align) { 86 if ((params.align - 1) & params.align) {
87 LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
85 return static_cast<u32>(NvErrCodes::InvalidValue); 88 return static_cast<u32>(NvErrCodes::InvalidValue);
86 } 89 }
87 90
@@ -92,10 +95,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
92 95
93 auto object = GetObject(params.handle); 96 auto object = GetObject(params.handle);
94 if (!object) { 97 if (!object) {
98 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
95 return static_cast<u32>(NvErrCodes::InvalidValue); 99 return static_cast<u32>(NvErrCodes::InvalidValue);
96 } 100 }
97 101
98 if (object->status == Object::Status::Allocated) { 102 if (object->status == Object::Status::Allocated) {
103 LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
99 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 104 return static_cast<u32>(NvErrCodes::OperationNotPermitted);
100 } 105 }
101 106
@@ -116,11 +121,13 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
116 LOG_WARNING(Service_NVDRV, "called"); 121 LOG_WARNING(Service_NVDRV, "called");
117 122
118 if (!params.handle) { 123 if (!params.handle) {
124 LOG_ERROR(Service_NVDRV, "Handle is zero");
119 return static_cast<u32>(NvErrCodes::InvalidValue); 125 return static_cast<u32>(NvErrCodes::InvalidValue);
120 } 126 }
121 127
122 auto object = GetObject(params.handle); 128 auto object = GetObject(params.handle);
123 if (!object) { 129 if (!object) {
130 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
124 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 131 return static_cast<u32>(NvErrCodes::OperationNotPermitted);
125 } 132 }
126 133
@@ -139,11 +146,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
139 auto itr = std::find_if(handles.begin(), handles.end(), 146 auto itr = std::find_if(handles.begin(), handles.end(),
140 [&](const auto& entry) { return entry.second->id == params.id; }); 147 [&](const auto& entry) { return entry.second->id == params.id; });
141 if (itr == handles.end()) { 148 if (itr == handles.end()) {
149 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
142 return static_cast<u32>(NvErrCodes::InvalidValue); 150 return static_cast<u32>(NvErrCodes::InvalidValue);
143 } 151 }
144 152
145 auto& object = itr->second; 153 auto& object = itr->second;
146 if (object->status != Object::Status::Allocated) { 154 if (object->status != Object::Status::Allocated) {
155 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
147 return static_cast<u32>(NvErrCodes::InvalidValue); 156 return static_cast<u32>(NvErrCodes::InvalidValue);
148 } 157 }
149 158
@@ -166,10 +175,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
166 175
167 auto object = GetObject(params.handle); 176 auto object = GetObject(params.handle);
168 if (!object) { 177 if (!object) {
178 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
169 return static_cast<u32>(NvErrCodes::InvalidValue); 179 return static_cast<u32>(NvErrCodes::InvalidValue);
170 } 180 }
171 181
172 if (object->status != Object::Status::Allocated) { 182 if (object->status != Object::Status::Allocated) {
183 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
173 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 184 return static_cast<u32>(NvErrCodes::OperationNotPermitted);
174 } 185 }
175 186
@@ -209,9 +220,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
209 220
210 auto itr = handles.find(params.handle); 221 auto itr = handles.find(params.handle);
211 if (itr == handles.end()) { 222 if (itr == handles.end()) {
223 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
212 return static_cast<u32>(NvErrCodes::InvalidValue); 224 return static_cast<u32>(NvErrCodes::InvalidValue);
213 } 225 }
214 if (!itr->second->refcount) { 226 if (!itr->second->refcount) {
227 LOG_ERROR(
228 Service_NVDRV,
229 "There is no references to this object. The object is already freed. handle={:08X}",
230 params.handle);
215 return static_cast<u32>(NvErrCodes::InvalidValue); 231 return static_cast<u32>(NvErrCodes::InvalidValue);
216 } 232 }
217 233
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index ac3859353..3b9ab4b14 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -6,7 +6,9 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/readable_event.h"
11#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nvdrv/interface.h" 12#include "core/hle/service/nvdrv/interface.h"
11#include "core/hle/service/nvdrv/nvdrv.h" 13#include "core/hle/service/nvdrv/nvdrv.h"
12 14
@@ -55,6 +57,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) {
55 57
56void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { 58void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
57 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 59 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
60
58 IPC::ResponseBuilder rb{ctx, 3}; 61 IPC::ResponseBuilder rb{ctx, 3};
59 rb.Push(RESULT_SUCCESS); 62 rb.Push(RESULT_SUCCESS);
60 rb.Push<u32>(0); 63 rb.Push<u32>(0);
@@ -68,15 +71,15 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
68 71
69 IPC::ResponseBuilder rb{ctx, 3, 1}; 72 IPC::ResponseBuilder rb{ctx, 3, 1};
70 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
71 rb.PushCopyObjects(query_event); 74 rb.PushCopyObjects(query_event.readable);
72 rb.Push<u32>(0); 75 rb.Push<u32>(0);
73} 76}
74 77
75void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { 78void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
76 IPC::RequestParser rp{ctx}; 79 IPC::RequestParser rp{ctx};
77 pid = rp.Pop<u64>(); 80 pid = rp.Pop<u64>();
78
79 LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); 81 LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
82
80 IPC::ResponseBuilder rb{ctx, 3}; 83 IPC::ResponseBuilder rb{ctx, 3};
81 rb.Push(RESULT_SUCCESS); 84 rb.Push(RESULT_SUCCESS);
82 rb.Push<u32>(0); 85 rb.Push<u32>(0);
@@ -84,6 +87,23 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
84 87
85void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { 88void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) {
86 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 89 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
90
91 IPC::ResponseBuilder rb{ctx, 2};
92 rb.Push(RESULT_SUCCESS);
93}
94
95void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
96 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
97
98 IPC::ResponseBuilder rb{ctx, 2};
99 rb.Push(RESULT_SUCCESS);
100}
101
102void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
103 // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on
104 // retail hardware.
105 LOG_DEBUG(Service_NVDRV, "called");
106
87 IPC::ResponseBuilder rb{ctx, 2}; 107 IPC::ResponseBuilder rb{ctx, 2};
88 rb.Push(RESULT_SUCCESS); 108 rb.Push(RESULT_SUCCESS);
89} 109}
@@ -97,10 +117,10 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
97 {3, &NVDRV::Initialize, "Initialize"}, 117 {3, &NVDRV::Initialize, "Initialize"},
98 {4, &NVDRV::QueryEvent, "QueryEvent"}, 118 {4, &NVDRV::QueryEvent, "QueryEvent"},
99 {5, nullptr, "MapSharedMem"}, 119 {5, nullptr, "MapSharedMem"},
100 {6, nullptr, "GetStatus"}, 120 {6, &NVDRV::GetStatus, "GetStatus"},
101 {7, nullptr, "ForceSetClientPID"}, 121 {7, nullptr, "ForceSetClientPID"},
102 {8, &NVDRV::SetClientPID, "SetClientPID"}, 122 {8, &NVDRV::SetClientPID, "SetClientPID"},
103 {9, nullptr, "DumpGraphicsMemoryInfo"}, 123 {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
104 {10, nullptr, "InitializeDevtools"}, 124 {10, nullptr, "InitializeDevtools"},
105 {11, &NVDRV::Ioctl, "Ioctl2"}, 125 {11, &NVDRV::Ioctl, "Ioctl2"},
106 {12, nullptr, "Ioctl3"}, 126 {12, nullptr, "Ioctl3"},
@@ -109,7 +129,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
109 RegisterHandlers(functions); 129 RegisterHandlers(functions);
110 130
111 auto& kernel = Core::System::GetInstance().Kernel(); 131 auto& kernel = Core::System::GetInstance().Kernel();
112 query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event"); 132 query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
133 "NVDRV::query_event");
113} 134}
114 135
115NVDRV::~NVDRV() = default; 136NVDRV::~NVDRV() = default;
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index d340893c2..fe311b069 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -5,10 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "core/hle/kernel/event.h"
9#include "core/hle/service/nvdrv/nvdrv.h" 8#include "core/hle/service/nvdrv/nvdrv.h"
10#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
11 10
11namespace Kernel {
12class WritableEvent;
13}
14
12namespace Service::Nvidia { 15namespace Service::Nvidia {
13 16
14class NVDRV final : public ServiceFramework<NVDRV> { 17class NVDRV final : public ServiceFramework<NVDRV> {
@@ -24,12 +27,14 @@ private:
24 void QueryEvent(Kernel::HLERequestContext& ctx); 27 void QueryEvent(Kernel::HLERequestContext& ctx);
25 void SetClientPID(Kernel::HLERequestContext& ctx); 28 void SetClientPID(Kernel::HLERequestContext& ctx);
26 void FinishInitialize(Kernel::HLERequestContext& ctx); 29 void FinishInitialize(Kernel::HLERequestContext& ctx);
30 void GetStatus(Kernel::HLERequestContext& ctx);
31 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
27 32
28 std::shared_ptr<Module> nvdrv; 33 std::shared_ptr<Module> nvdrv;
29 34
30 u64 pid{}; 35 u64 pid{};
31 36
32 Kernel::SharedPtr<Kernel::Event> query_event; 37 Kernel::EventPair query_event;
33}; 38};
34 39
35} // namespace Service::Nvidia 40} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 630ebbfc7..fc07d9bb8 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -7,28 +7,31 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nvflinger/buffer_queue.h" 13#include "core/hle/service/nvflinger/buffer_queue.h"
11 14
12namespace Service::NVFlinger { 15namespace Service::NVFlinger {
13 16
14BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { 17BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
15 auto& kernel = Core::System::GetInstance().Kernel(); 18 auto& kernel = Core::System::GetInstance().Kernel();
16 buffer_wait_event = 19 buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
17 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); 20 "BufferQueue NativeHandle");
18} 21}
19 22
20BufferQueue::~BufferQueue() = default; 23BufferQueue::~BufferQueue() = default;
21 24
22void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { 25void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
26 LOG_WARNING(Service, "Adding graphics buffer {}", slot);
27
23 Buffer buffer{}; 28 Buffer buffer{};
24 buffer.slot = slot; 29 buffer.slot = slot;
25 buffer.igbp_buffer = igbp_buffer; 30 buffer.igbp_buffer = igbp_buffer;
26 buffer.status = Buffer::Status::Free; 31 buffer.status = Buffer::Status::Free;
27 32
28 LOG_WARNING(Service, "Adding graphics buffer {}", slot);
29
30 queue.emplace_back(buffer); 33 queue.emplace_back(buffer);
31 buffer_wait_event->Signal(); 34 buffer_wait_event.writable->Signal();
32} 35}
33 36
34std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { 37std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
@@ -87,11 +90,12 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
87 ASSERT(itr->status == Buffer::Status::Acquired); 90 ASSERT(itr->status == Buffer::Status::Acquired);
88 itr->status = Buffer::Status::Free; 91 itr->status = Buffer::Status::Free;
89 92
90 buffer_wait_event->Signal(); 93 buffer_wait_event.writable->Signal();
91} 94}
92 95
93u32 BufferQueue::Query(QueryType type) { 96u32 BufferQueue::Query(QueryType type) {
94 LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); 97 LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type));
98
95 switch (type) { 99 switch (type) {
96 case QueryType::NativeWindowFormat: 100 case QueryType::NativeWindowFormat:
97 // TODO(Subv): Use an enum for this 101 // TODO(Subv): Use an enum for this
@@ -103,4 +107,12 @@ u32 BufferQueue::Query(QueryType type) {
103 return 0; 107 return 0;
104} 108}
105 109
110Kernel::SharedPtr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
111 return buffer_wait_event.writable;
112}
113
114Kernel::SharedPtr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const {
115 return buffer_wait_event.readable;
116}
117
106} // namespace Service::NVFlinger 118} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 8cff5eb71..b171f256c 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -10,7 +10,8 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/math_util.h" 11#include "common/math_util.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/object.h"
14#include "core/hle/kernel/writable_event.h"
14 15
15namespace CoreTiming { 16namespace CoreTiming {
16struct EventType; 17struct EventType;
@@ -86,16 +87,16 @@ public:
86 return id; 87 return id;
87 } 88 }
88 89
89 Kernel::SharedPtr<Kernel::Event> GetBufferWaitEvent() const { 90 Kernel::SharedPtr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const;
90 return buffer_wait_event; 91
91 } 92 Kernel::SharedPtr<Kernel::ReadableEvent> GetBufferWaitEvent() const;
92 93
93private: 94private:
94 u32 id; 95 u32 id;
95 u64 layer_id; 96 u64 layer_id;
96 97
97 std::vector<Buffer> queue; 98 std::vector<Buffer> queue;
98 Kernel::SharedPtr<Kernel::Event> buffer_wait_event; 99 Kernel::EventPair buffer_wait_event;
99}; 100};
100 101
101} // namespace Service::NVFlinger 102} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 214e6d1b3..05af2d593 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -13,6 +13,9 @@
13#include "core/core.h" 13#include "core/core.h"
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/core_timing_util.h" 15#include "core/core_timing_util.h"
16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/readable_event.h"
18#include "core/hle/kernel/writable_event.h"
16#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 19#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
17#include "core/hle/service/nvdrv/nvdrv.h" 20#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvflinger/buffer_queue.h" 21#include "core/hle/service/nvflinger/buffer_queue.h"
@@ -83,9 +86,8 @@ u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) {
83 return layer.buffer_queue->GetId(); 86 return layer.buffer_queue->GetId();
84} 87}
85 88
86Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) { 89Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id) {
87 const auto& display = GetDisplay(display_id); 90 return GetDisplay(display_id).vsync_event.readable;
88 return display.vsync_event;
89} 91}
90 92
91std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { 93std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const {
@@ -117,7 +119,7 @@ Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) {
117void NVFlinger::Compose() { 119void NVFlinger::Compose() {
118 for (auto& display : displays) { 120 for (auto& display : displays) {
119 // Trigger vsync for this display at the end of drawing 121 // Trigger vsync for this display at the end of drawing
120 SCOPE_EXIT({ display.vsync_event->Signal(); }); 122 SCOPE_EXIT({ display.vsync_event.writable->Signal(); });
121 123
122 // Don't do anything for displays without layers. 124 // Don't do anything for displays without layers.
123 if (display.layers.empty()) 125 if (display.layers.empty())
@@ -164,7 +166,8 @@ Layer::~Layer() = default;
164 166
165Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { 167Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
166 auto& kernel = Core::System::GetInstance().Kernel(); 168 auto& kernel = Core::System::GetInstance().Kernel();
167 vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event"); 169 vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse,
170 fmt::format("Display VSync Event {}", id));
168} 171}
169 172
170Display::~Display() = default; 173Display::~Display() = default;
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 3dc69e69b..9abba555b 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -10,12 +10,17 @@
10#include <vector> 10#include <vector>
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/object.h"
14 14
15namespace CoreTiming { 15namespace CoreTiming {
16struct EventType; 16struct EventType;
17} 17}
18 18
19namespace Kernel {
20class ReadableEvent;
21class WritableEvent;
22} // namespace Kernel
23
19namespace Service::Nvidia { 24namespace Service::Nvidia {
20class Module; 25class Module;
21} 26}
@@ -40,7 +45,7 @@ struct Display {
40 std::string name; 45 std::string name;
41 46
42 std::vector<Layer> layers; 47 std::vector<Layer> layers;
43 Kernel::SharedPtr<Kernel::Event> vsync_event; 48 Kernel::EventPair vsync_event;
44}; 49};
45 50
46class NVFlinger final { 51class NVFlinger final {
@@ -61,7 +66,7 @@ public:
61 u32 GetBufferQueueId(u64 display_id, u64 layer_id); 66 u32 GetBufferQueueId(u64 display_id, u64 layer_id);
62 67
63 /// Gets the vsync event for the specified display. 68 /// Gets the vsync event for the specified display.
64 Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id); 69 Kernel::SharedPtr<Kernel::ReadableEvent> GetVsyncEvent(u64 display_id);
65 70
66 /// Obtains a buffer queue identified by the id. 71 /// Obtains a buffer queue identified by the id.
67 std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; 72 std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const;
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index 4fd185f69..6081f41e1 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -114,29 +114,33 @@ public:
114private: 114private:
115 void Initialize(Kernel::HLERequestContext& ctx) { 115 void Initialize(Kernel::HLERequestContext& ctx) {
116 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 116 LOG_WARNING(Service_PCTL, "(STUBBED) called");
117
117 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 118 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
118 rb.Push(RESULT_SUCCESS); 119 rb.Push(RESULT_SUCCESS);
119 } 120 }
120 121
121 void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { 122 void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
122 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 123 LOG_WARNING(Service_PCTL, "(STUBBED) called");
124
123 IPC::ResponseBuilder rb{ctx, 2}; 125 IPC::ResponseBuilder rb{ctx, 2};
124 rb.Push(RESULT_SUCCESS); 126 rb.Push(RESULT_SUCCESS);
125 } 127 }
126}; 128};
127 129
128void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { 130void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
131 LOG_DEBUG(Service_PCTL, "called");
132
129 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 133 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
130 rb.Push(RESULT_SUCCESS); 134 rb.Push(RESULT_SUCCESS);
131 rb.PushIpcInterface<IParentalControlService>(); 135 rb.PushIpcInterface<IParentalControlService>();
132 LOG_DEBUG(Service_PCTL, "called");
133} 136}
134 137
135void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { 138void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
139 LOG_DEBUG(Service_PCTL, "called");
140
136 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 141 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
137 rb.Push(RESULT_SUCCESS); 142 rb.Push(RESULT_SUCCESS);
138 rb.PushIpcInterface<IParentalControlService>(); 143 rb.PushIpcInterface<IParentalControlService>();
139 LOG_DEBUG(Service_PCTL, "called");
140} 144}
141 145
142Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 146Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index 6ec35ca60..53e7da9c3 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -20,11 +20,11 @@ public:
20 20
21private: 21private:
22 void GetBootMode(Kernel::HLERequestContext& ctx) { 22 void GetBootMode(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_PM, "called");
24
23 IPC::ResponseBuilder rb{ctx, 3}; 25 IPC::ResponseBuilder rb{ctx, 3};
24 rb.Push(RESULT_SUCCESS); 26 rb.Push(RESULT_SUCCESS);
25 rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode 27 rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode
26
27 LOG_DEBUG(Service_PM, "called");
28 } 28 }
29}; 29};
30 30
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index bbad870a2..0ba0a4076 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -61,11 +61,11 @@ public:
61 61
62private: 62private:
63 void GetPmModule(Kernel::HLERequestContext& ctx) { 63 void GetPmModule(Kernel::HLERequestContext& ctx) {
64 LOG_DEBUG(Service_PSC, "called");
65
64 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 66 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
65 rb.Push(RESULT_SUCCESS); 67 rb.Push(RESULT_SUCCESS);
66 rb.PushIpcInterface<IPmModule>(); 68 rb.PushIpcInterface<IPmModule>();
67
68 LOG_DEBUG(Service_PSC, "called");
69 } 69 }
70}; 70};
71 71
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index a4cf45267..1ec340466 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -80,8 +80,8 @@ namespace Service {
80 * Creates a function string for logging, complete with the name (or header code, depending 80 * Creates a function string for logging, complete with the name (or header code, depending
81 * on what's passed in) the port name, and all the cmd_buff arguments. 81 * on what's passed in) the port name, and all the cmd_buff arguments.
82 */ 82 */
83static std::string MakeFunctionString(const char* name, const char* port_name, 83[[maybe_unused]] static std::string MakeFunctionString(const char* name, const char* port_name,
84 const u32* cmd_buff) { 84 const u32* cmd_buff) {
85 // Number of params == bits 0-5 + bits 6-11 85 // Number of params == bits 0-5 + bits 6-11
86 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); 86 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
87 87
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 9e5af7839..1afc43f75 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -35,6 +35,8 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
35constexpr std::size_t pre4_0_0_max_entries = 0xF; 35constexpr std::size_t pre4_0_0_max_entries = 0xF;
36constexpr std::size_t post4_0_0_max_entries = 0x40; 36constexpr std::size_t post4_0_0_max_entries = 0x40;
37 37
38constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625};
39
38LanguageCode GetLanguageCodeFromIndex(std::size_t index) { 40LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
39 return available_language_codes.at(index); 41 return available_language_codes.at(index);
40} 42}
@@ -49,38 +51,54 @@ static std::array<LanguageCode, size> MakeLanguageCodeSubset() {
49static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) { 51static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) {
50 IPC::ResponseBuilder rb{ctx, 3}; 52 IPC::ResponseBuilder rb{ctx, 3};
51 rb.Push(RESULT_SUCCESS); 53 rb.Push(RESULT_SUCCESS);
52 if (available_language_codes.size() > max_size) 54 if (available_language_codes.size() > max_size) {
53 rb.Push(static_cast<u32>(max_size)); 55 rb.Push(static_cast<u32>(max_size));
54 else 56 } else {
55 rb.Push(static_cast<u32>(available_language_codes.size())); 57 rb.Push(static_cast<u32>(available_language_codes.size()));
58 }
56} 59}
57 60
58void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { 61void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
59 if (available_language_codes.size() > pre4_0_0_max_entries) 62 LOG_DEBUG(Service_SET, "called");
63
64 if (available_language_codes.size() > pre4_0_0_max_entries) {
60 ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>()); 65 ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>());
61 else 66 } else {
62 ctx.WriteBuffer(available_language_codes); 67 ctx.WriteBuffer(available_language_codes);
63 68 }
64 PushResponseLanguageCode(ctx, pre4_0_0_max_entries); 69 PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
70}
65 71
66 LOG_DEBUG(Service_SET, "called"); 72void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
73 IPC::RequestParser rp{ctx};
74 const auto index = rp.Pop<u32>();
75
76 if (index >= available_language_codes.size()) {
77 IPC::ResponseBuilder rb{ctx, 2};
78 rb.Push(ERR_INVALID_LANGUAGE);
79 return;
80 }
81
82 IPC::ResponseBuilder rb{ctx, 4};
83 rb.Push(RESULT_SUCCESS);
84 rb.PushEnum(available_language_codes[index]);
67} 85}
68 86
69void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { 87void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
70 if (available_language_codes.size() > post4_0_0_max_entries) 88 LOG_DEBUG(Service_SET, "called");
89
90 if (available_language_codes.size() > post4_0_0_max_entries) {
71 ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>()); 91 ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>());
72 else 92 } else {
73 ctx.WriteBuffer(available_language_codes); 93 ctx.WriteBuffer(available_language_codes);
74 94 }
75 PushResponseLanguageCode(ctx, post4_0_0_max_entries); 95 PushResponseLanguageCode(ctx, post4_0_0_max_entries);
76
77 LOG_DEBUG(Service_SET, "called");
78} 96}
79 97
80void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { 98void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
81 PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
82
83 LOG_DEBUG(Service_SET, "called"); 99 LOG_DEBUG(Service_SET, "called");
100
101 PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
84} 102}
85 103
86void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { 104void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
@@ -90,18 +108,18 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
90} 108}
91 109
92void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { 110void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
111 LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
112
93 IPC::ResponseBuilder rb{ctx, 4}; 113 IPC::ResponseBuilder rb{ctx, 4};
94 rb.Push(RESULT_SUCCESS); 114 rb.Push(RESULT_SUCCESS);
95 rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index])); 115 rb.PushEnum(available_language_codes[Settings::values.language_index]);
96
97 LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
98} 116}
99 117
100SET::SET() : ServiceFramework("set") { 118SET::SET() : ServiceFramework("set") {
101 static const FunctionInfo functions[] = { 119 static const FunctionInfo functions[] = {
102 {0, &SET::GetLanguageCode, "GetLanguageCode"}, 120 {0, &SET::GetLanguageCode, "GetLanguageCode"},
103 {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, 121 {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"},
104 {2, nullptr, "MakeLanguageCode"}, 122 {2, &SET::MakeLanguageCode, "MakeLanguageCode"},
105 {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, 123 {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"},
106 {4, nullptr, "GetRegionCode"}, 124 {4, nullptr, "GetRegionCode"},
107 {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, 125 {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 266f13e46..31f9cb296 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -38,6 +38,7 @@ public:
38private: 38private:
39 void GetLanguageCode(Kernel::HLERequestContext& ctx); 39 void GetLanguageCode(Kernel::HLERequestContext& ctx);
40 void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); 40 void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx);
41 void MakeLanguageCode(Kernel::HLERequestContext& ctx);
41 void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx); 42 void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx);
42 void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx); 43 void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
43 void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); 44 void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 41efca31c..c9b4da5b0 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -10,22 +10,22 @@
10namespace Service::Set { 10namespace Service::Set {
11 11
12void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { 12void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) {
13 LOG_DEBUG(Service_SET, "called");
14
13 IPC::ResponseBuilder rb{ctx, 3}; 15 IPC::ResponseBuilder rb{ctx, 3};
14 16
15 rb.Push(RESULT_SUCCESS); 17 rb.Push(RESULT_SUCCESS);
16 rb.PushEnum(color_set); 18 rb.PushEnum(color_set);
17
18 LOG_DEBUG(Service_SET, "called");
19} 19}
20 20
21void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { 21void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) {
22 LOG_DEBUG(Service_SET, "called");
23
22 IPC::RequestParser rp{ctx}; 24 IPC::RequestParser rp{ctx};
23 color_set = rp.PopEnum<ColorSet>(); 25 color_set = rp.PopEnum<ColorSet>();
24 26
25 IPC::ResponseBuilder rb{ctx, 2}; 27 IPC::ResponseBuilder rb{ctx, 2};
26 rb.Push(RESULT_SUCCESS); 28 rb.Push(RESULT_SUCCESS);
27
28 LOG_DEBUG(Service_SET, "called");
29} 29}
30 30
31SET_SYS::SET_SYS() : ServiceFramework("set:sys") { 31SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 98f6e4111..74da4d5e6 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -14,25 +14,26 @@ namespace Service::SM {
14 14
15void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { 15void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
16 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); 16 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
17 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
17 ctx.Session()->ConvertToDomain(); 18 ctx.Session()->ConvertToDomain();
18 19
19 IPC::ResponseBuilder rb{ctx, 3}; 20 IPC::ResponseBuilder rb{ctx, 3};
20 rb.Push(RESULT_SUCCESS); 21 rb.Push(RESULT_SUCCESS);
21 rb.Push<u32>(1); // Converted sessions start with 1 request handler 22 rb.Push<u32>(1); // Converted sessions start with 1 request handler
22
23 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
24} 23}
25 24
26void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { 25void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
27 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong 26 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
28 // and that we probably want to actually make an entirely new Session, but we still need to 27 // and that we probably want to actually make an entirely new Session, but we still need to
29 // verify this on hardware. 28 // verify this on hardware.
29 LOG_DEBUG(Service, "called");
30
30 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 31 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
31 rb.Push(RESULT_SUCCESS); 32 rb.Push(RESULT_SUCCESS);
32 Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; 33 Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client};
33 rb.PushMoveObjects(session); 34 rb.PushMoveObjects(session);
34 35
35 LOG_DEBUG(Service, "called, session={}", session->GetObjectId()); 36 LOG_DEBUG(Service, "session={}", session->GetObjectId());
36} 37}
37 38
38void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { 39void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
@@ -42,11 +43,11 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
42} 43}
43 44
44void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { 45void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
46 LOG_WARNING(Service, "(STUBBED) called");
47
45 IPC::ResponseBuilder rb{ctx, 3}; 48 IPC::ResponseBuilder rb{ctx, 3};
46 rb.Push(RESULT_SUCCESS); 49 rb.Push(RESULT_SUCCESS);
47 rb.Push<u16>(0x500); 50 rb.Push<u16>(0x500);
48
49 LOG_WARNING(Service, "(STUBBED) called");
50} 51}
51 52
52Controller::Controller() : ServiceFramework("IpcController") { 53Controller::Controller() : ServiceFramework("IpcController") {
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 464e79d01..0d0f63a78 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -63,6 +63,17 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
63 return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); 63 return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
64} 64}
65 65
66ResultCode ServiceManager::UnregisterService(const std::string& name) {
67 CASCADE_CODE(ValidateServiceName(name));
68
69 const auto iter = registered_services.find(name);
70 if (iter == registered_services.end())
71 return ERR_SERVICE_NOT_REGISTERED;
72
73 registered_services.erase(iter);
74 return RESULT_SUCCESS;
75}
76
66ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( 77ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort(
67 const std::string& name) { 78 const std::string& name) {
68 79
@@ -92,9 +103,10 @@ SM::~SM() = default;
92 * 0: ResultCode 103 * 0: ResultCode
93 */ 104 */
94void SM::Initialize(Kernel::HLERequestContext& ctx) { 105void SM::Initialize(Kernel::HLERequestContext& ctx) {
106 LOG_DEBUG(Service_SM, "called");
107
95 IPC::ResponseBuilder rb{ctx, 2}; 108 IPC::ResponseBuilder rb{ctx, 2};
96 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
97 LOG_DEBUG(Service_SM, "called");
98} 110}
99 111
100void SM::GetService(Kernel::HLERequestContext& ctx) { 112void SM::GetService(Kernel::HLERequestContext& ctx) {
@@ -127,13 +139,53 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
127 } 139 }
128} 140}
129 141
142void SM::RegisterService(Kernel::HLERequestContext& ctx) {
143 IPC::RequestParser rp{ctx};
144
145 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
146 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
147
148 const std::string name(name_buf.begin(), end);
149
150 const auto unk_bool = static_cast<bool>(rp.PopRaw<u32>());
151 const auto session_count = rp.PopRaw<u32>();
152
153 LOG_DEBUG(Service_SM, "called with unk_bool={}", unk_bool);
154
155 auto handle = service_manager->RegisterService(name, session_count);
156 if (handle.Failed()) {
157 LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
158 handle.Code().raw);
159 IPC::ResponseBuilder rb{ctx, 2};
160 rb.Push(handle.Code());
161 return;
162 }
163
164 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
165 rb.Push(handle.Code());
166 rb.PushMoveObjects(std::move(handle).Unwrap());
167}
168
169void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
170 IPC::RequestParser rp{ctx};
171
172 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
173 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
174
175 const std::string name(name_buf.begin(), end);
176 LOG_DEBUG(Service_SM, "called with name={}", name);
177
178 IPC::ResponseBuilder rb{ctx, 2};
179 rb.Push(service_manager->UnregisterService(name));
180}
181
130SM::SM(std::shared_ptr<ServiceManager> service_manager) 182SM::SM(std::shared_ptr<ServiceManager> service_manager)
131 : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { 183 : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) {
132 static const FunctionInfo functions[] = { 184 static const FunctionInfo functions[] = {
133 {0x00000000, &SM::Initialize, "Initialize"}, 185 {0x00000000, &SM::Initialize, "Initialize"},
134 {0x00000001, &SM::GetService, "GetService"}, 186 {0x00000001, &SM::GetService, "GetService"},
135 {0x00000002, nullptr, "RegisterService"}, 187 {0x00000002, &SM::RegisterService, "RegisterService"},
136 {0x00000003, nullptr, "UnregisterService"}, 188 {0x00000003, &SM::UnregisterService, "UnregisterService"},
137 }; 189 };
138 RegisterHandlers(functions); 190 RegisterHandlers(functions);
139} 191}
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 4f8145dda..bef25433e 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -35,6 +35,8 @@ public:
35private: 35private:
36 void Initialize(Kernel::HLERequestContext& ctx); 36 void Initialize(Kernel::HLERequestContext& ctx);
37 void GetService(Kernel::HLERequestContext& ctx); 37 void GetService(Kernel::HLERequestContext& ctx);
38 void RegisterService(Kernel::HLERequestContext& ctx);
39 void UnregisterService(Kernel::HLERequestContext& ctx);
38 40
39 std::shared_ptr<ServiceManager> service_manager; 41 std::shared_ptr<ServiceManager> service_manager;
40}; 42};
@@ -48,6 +50,7 @@ public:
48 50
49 ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, 51 ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
50 unsigned int max_sessions); 52 unsigned int max_sessions);
53 ResultCode UnregisterService(const std::string& name);
51 ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); 54 ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
52 ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); 55 ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);
53 56
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 44a6717d0..8db0c2f13 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -3,34 +3,41 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <chrono>
6#include <cstdlib> 7#include <cstdlib>
8#include <ctime>
9#include <functional>
7#include <vector> 10#include <vector>
8#include "common/logging/log.h" 11#include "common/logging/log.h"
9#include "core/hle/ipc_helpers.h" 12#include "core/hle/ipc_helpers.h"
10#include "core/hle/service/spl/csrng.h" 13#include "core/hle/service/spl/csrng.h"
11#include "core/hle/service/spl/module.h" 14#include "core/hle/service/spl/module.h"
12#include "core/hle/service/spl/spl.h" 15#include "core/hle/service/spl/spl.h"
16#include "core/settings.h"
13 17
14namespace Service::SPL { 18namespace Service::SPL {
15 19
16Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 20Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
17 : ServiceFramework(name), module(std::move(module)) {} 21 : ServiceFramework(name), module(std::move(module)),
22 rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {}
18 23
19Module::Interface::~Interface() = default; 24Module::Interface::~Interface() = default;
20 25
21void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { 26void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
27 LOG_DEBUG(Service_SPL, "called");
28
22 IPC::RequestParser rp{ctx}; 29 IPC::RequestParser rp{ctx};
23 30
24 std::size_t size = ctx.GetWriteBufferSize(); 31 std::size_t size = ctx.GetWriteBufferSize();
25 32
33 std::uniform_int_distribution<u16> distribution(0, std::numeric_limits<u8>::max());
26 std::vector<u8> data(size); 34 std::vector<u8> data(size);
27 std::generate(data.begin(), data.end(), std::rand); 35 std::generate(data.begin(), data.end(), [&] { return static_cast<u8>(distribution(rng)); });
28 36
29 ctx.WriteBuffer(data); 37 ctx.WriteBuffer(data);
30 38
31 IPC::ResponseBuilder rb{ctx, 2}; 39 IPC::ResponseBuilder rb{ctx, 2};
32 rb.Push(RESULT_SUCCESS); 40 rb.Push(RESULT_SUCCESS);
33 LOG_DEBUG(Service_SPL, "called");
34} 41}
35 42
36void InstallInterfaces(SM::ServiceManager& service_manager) { 43void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h
index 48fda6099..afa1f0295 100644
--- a/src/core/hle/service/spl/module.h
+++ b/src/core/hle/service/spl/module.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <random>
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Service::SPL { 10namespace Service::SPL {
@@ -19,6 +20,9 @@ public:
19 20
20 protected: 21 protected:
21 std::shared_ptr<Module> module; 22 std::shared_ptr<Module> module;
23
24 private:
25 std::mt19937 rng;
22 }; 26 };
23}; 27};
24 28
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index bc4f7a437..af40a1815 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -69,6 +69,7 @@ public:
69private: 69private:
70 void SetOption(Kernel::HLERequestContext& ctx) { 70 void SetOption(Kernel::HLERequestContext& ctx) {
71 LOG_WARNING(Service_SSL, "(STUBBED) called"); 71 LOG_WARNING(Service_SSL, "(STUBBED) called");
72
72 IPC::RequestParser rp{ctx}; 73 IPC::RequestParser rp{ctx};
73 74
74 IPC::ResponseBuilder rb{ctx, 2}; 75 IPC::ResponseBuilder rb{ctx, 2};
@@ -114,6 +115,7 @@ private:
114 115
115 void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { 116 void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
116 LOG_DEBUG(Service_SSL, "called"); 117 LOG_DEBUG(Service_SSL, "called");
118
117 IPC::RequestParser rp{ctx}; 119 IPC::RequestParser rp{ctx};
118 ssl_version = rp.Pop<u32>(); 120 ssl_version = rp.Pop<u32>();
119 121
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 18a5d71d5..b3a196f65 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -21,9 +21,10 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
21 {102, nullptr, "GetStandardUserSystemClockInitialYear"}, 21 {102, nullptr, "GetStandardUserSystemClockInitialYear"},
22 {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, 22 {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
23 {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, 23 {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
24 {400, nullptr, "GetClockSnapshot"}, 24 {400, &Time::GetClockSnapshot, "GetClockSnapshot"},
25 {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, 25 {401, nullptr, "GetClockSnapshotFromSystemClockContext"},
26 {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"}, 26 {500, &Time::CalculateStandardUserSystemClockDifferenceByUser,
27 "CalculateStandardUserSystemClockDifferenceByUser"},
27 {501, nullptr, "CalculateSpanBetween"}, 28 {501, nullptr, "CalculateSpanBetween"},
28 }; 29 };
29 RegisterHandlers(functions); 30 RegisterHandlers(functions);
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 28fd8debc..60b201d06 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -15,6 +15,44 @@
15 15
16namespace Service::Time { 16namespace Service::Time {
17 17
18static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
19 CalendarAdditionalInfo& additional_info,
20 [[maybe_unused]] const TimeZoneRule& /*rule*/) {
21 const std::time_t time(posix_time);
22 const std::tm* tm = std::localtime(&time);
23 if (tm == nullptr) {
24 calendar_time = {};
25 additional_info = {};
26 return;
27 }
28 calendar_time.year = tm->tm_year + 1900;
29 calendar_time.month = tm->tm_mon + 1;
30 calendar_time.day = tm->tm_mday;
31 calendar_time.hour = tm->tm_hour;
32 calendar_time.minute = tm->tm_min;
33 calendar_time.second = tm->tm_sec;
34
35 additional_info.day_of_week = tm->tm_wday;
36 additional_info.day_of_year = tm->tm_yday;
37 std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
38 additional_info.utc_offset = 0;
39}
40
41static u64 CalendarToPosix(const CalendarTime& calendar_time,
42 [[maybe_unused]] const TimeZoneRule& /*rule*/) {
43 std::tm time{};
44 time.tm_year = calendar_time.year - 1900;
45 time.tm_mon = calendar_time.month - 1;
46 time.tm_mday = calendar_time.day;
47
48 time.tm_hour = calendar_time.hour;
49 time.tm_min = calendar_time.minute;
50 time.tm_sec = calendar_time.second;
51
52 std::time_t epoch_time = std::mktime(&time);
53 return static_cast<u64>(epoch_time);
54}
55
18class ISystemClock final : public ServiceFramework<ISystemClock> { 56class ISystemClock final : public ServiceFramework<ISystemClock> {
19public: 57public:
20 ISystemClock() : ServiceFramework("ISystemClock") { 58 ISystemClock() : ServiceFramework("ISystemClock") {
@@ -34,6 +72,7 @@ private:
34 std::chrono::system_clock::now().time_since_epoch()) 72 std::chrono::system_clock::now().time_since_epoch())
35 .count()}; 73 .count()};
36 LOG_DEBUG(Service_Time, "called"); 74 LOG_DEBUG(Service_Time, "called");
75
37 IPC::ResponseBuilder rb{ctx, 4}; 76 IPC::ResponseBuilder rb{ctx, 4};
38 rb.Push(RESULT_SUCCESS); 77 rb.Push(RESULT_SUCCESS);
39 rb.Push<u64>(time_since_epoch); 78 rb.Push<u64>(time_since_epoch);
@@ -41,6 +80,7 @@ private:
41 80
42 void GetSystemClockContext(Kernel::HLERequestContext& ctx) { 81 void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
43 LOG_WARNING(Service_Time, "(STUBBED) called"); 82 LOG_WARNING(Service_Time, "(STUBBED) called");
83
44 SystemClockContext system_clock_ontext{}; 84 SystemClockContext system_clock_ontext{};
45 IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; 85 IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
46 rb.Push(RESULT_SUCCESS); 86 rb.Push(RESULT_SUCCESS);
@@ -60,6 +100,7 @@ public:
60private: 100private:
61 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { 101 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
62 LOG_DEBUG(Service_Time, "called"); 102 LOG_DEBUG(Service_Time, "called");
103
63 SteadyClockTimePoint steady_clock_time_point{ 104 SteadyClockTimePoint steady_clock_time_point{
64 CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; 105 CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000};
65 IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; 106 IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
@@ -80,8 +121,8 @@ public:
80 {5, nullptr, "GetTimeZoneRuleVersion"}, 121 {5, nullptr, "GetTimeZoneRuleVersion"},
81 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, 122 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
82 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, 123 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
83 {201, nullptr, "ToPosixTime"}, 124 {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
84 {202, nullptr, "ToPosixTimeWithMyRule"}, 125 {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
85 }; 126 };
86 RegisterHandlers(functions); 127 RegisterHandlers(functions);
87 } 128 }
@@ -92,6 +133,7 @@ private:
92 133
93 void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { 134 void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
94 LOG_DEBUG(Service_Time, "called"); 135 LOG_DEBUG(Service_Time, "called");
136
95 IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; 137 IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
96 rb.Push(RESULT_SUCCESS); 138 rb.Push(RESULT_SUCCESS);
97 rb.PushRaw(location_name); 139 rb.PushRaw(location_name);
@@ -99,6 +141,7 @@ private:
99 141
100 void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { 142 void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) {
101 LOG_WARNING(Service_Time, "(STUBBED) called"); 143 LOG_WARNING(Service_Time, "(STUBBED) called");
144
102 IPC::ResponseBuilder rb{ctx, 3}; 145 IPC::ResponseBuilder rb{ctx, 3};
103 rb.Push(RESULT_SUCCESS); 146 rb.Push(RESULT_SUCCESS);
104 rb.Push<u32>(0); 147 rb.Push<u32>(0);
@@ -116,7 +159,6 @@ private:
116 void ToCalendarTime(Kernel::HLERequestContext& ctx) { 159 void ToCalendarTime(Kernel::HLERequestContext& ctx) {
117 IPC::RequestParser rp{ctx}; 160 IPC::RequestParser rp{ctx};
118 const u64 posix_time = rp.Pop<u64>(); 161 const u64 posix_time = rp.Pop<u64>();
119
120 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); 162 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
121 163
122 TimeZoneRule time_zone_rule{}; 164 TimeZoneRule time_zone_rule{};
@@ -137,7 +179,6 @@ private:
137 void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) { 179 void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
138 IPC::RequestParser rp{ctx}; 180 IPC::RequestParser rp{ctx};
139 const u64 posix_time = rp.Pop<u64>(); 181 const u64 posix_time = rp.Pop<u64>();
140
141 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); 182 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
142 183
143 CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; 184 CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
@@ -151,60 +192,137 @@ private:
151 rb.PushRaw(additional_info); 192 rb.PushRaw(additional_info);
152 } 193 }
153 194
154 void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, 195 void ToPosixTime(Kernel::HLERequestContext& ctx) {
155 CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) { 196 // TODO(ogniK): Figure out how to handle multiple times
156 std::time_t t(posix_time); 197 LOG_WARNING(Service_Time, "(STUBBED) called");
157 std::tm* tm = std::localtime(&t); 198
158 if (!tm) { 199 IPC::RequestParser rp{ctx};
159 return; 200 auto calendar_time = rp.PopRaw<CalendarTime>();
160 } 201 auto posix_time = CalendarToPosix(calendar_time, {});
161 calendar_time.year = tm->tm_year + 1900; 202
162 calendar_time.month = tm->tm_mon + 1; 203 IPC::ResponseBuilder rb{ctx, 3};
163 calendar_time.day = tm->tm_mday; 204 rb.Push(RESULT_SUCCESS);
164 calendar_time.hour = tm->tm_hour; 205 rb.PushRaw<u32>(1); // Amount of times we're returning
165 calendar_time.minute = tm->tm_min; 206 ctx.WriteBuffer(&posix_time, sizeof(u64));
166 calendar_time.second = tm->tm_sec; 207 }
167 208
168 additional_info.day_of_week = tm->tm_wday; 209 void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
169 additional_info.day_of_year = tm->tm_yday; 210 LOG_WARNING(Service_Time, "(STUBBED) called");
170 std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC")); 211
171 additional_info.utc_offset = 0; 212 IPC::RequestParser rp{ctx};
213 auto calendar_time = rp.PopRaw<CalendarTime>();
214 auto posix_time = CalendarToPosix(calendar_time, {});
215
216 IPC::ResponseBuilder rb{ctx, 3};
217 rb.Push(RESULT_SUCCESS);
218 rb.PushRaw<u32>(1); // Amount of times we're returning
219 ctx.WriteBuffer(&posix_time, sizeof(u64));
172 } 220 }
173}; 221};
174 222
175void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { 223void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
224 LOG_DEBUG(Service_Time, "called");
225
176 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 226 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
177 rb.Push(RESULT_SUCCESS); 227 rb.Push(RESULT_SUCCESS);
178 rb.PushIpcInterface<ISystemClock>(); 228 rb.PushIpcInterface<ISystemClock>();
179 LOG_DEBUG(Service_Time, "called");
180} 229}
181 230
182void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { 231void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
232 LOG_DEBUG(Service_Time, "called");
233
183 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 234 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
184 rb.Push(RESULT_SUCCESS); 235 rb.Push(RESULT_SUCCESS);
185 rb.PushIpcInterface<ISystemClock>(); 236 rb.PushIpcInterface<ISystemClock>();
186 LOG_DEBUG(Service_Time, "called");
187} 237}
188 238
189void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { 239void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
240 LOG_DEBUG(Service_Time, "called");
241
190 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 242 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
191 rb.Push(RESULT_SUCCESS); 243 rb.Push(RESULT_SUCCESS);
192 rb.PushIpcInterface<ISteadyClock>(); 244 rb.PushIpcInterface<ISteadyClock>();
193 LOG_DEBUG(Service_Time, "called");
194} 245}
195 246
196void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { 247void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
248 LOG_DEBUG(Service_Time, "called");
249
197 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 250 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
198 rb.Push(RESULT_SUCCESS); 251 rb.Push(RESULT_SUCCESS);
199 rb.PushIpcInterface<ITimeZoneService>(); 252 rb.PushIpcInterface<ITimeZoneService>();
200 LOG_DEBUG(Service_Time, "called");
201} 253}
202 254
203void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { 255void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
256 LOG_DEBUG(Service_Time, "called");
257
204 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 258 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
205 rb.Push(RESULT_SUCCESS); 259 rb.Push(RESULT_SUCCESS);
206 rb.PushIpcInterface<ISystemClock>(); 260 rb.PushIpcInterface<ISystemClock>();
261}
262
263void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
207 LOG_DEBUG(Service_Time, "called"); 264 LOG_DEBUG(Service_Time, "called");
265
266 IPC::RequestParser rp{ctx};
267 auto unknown_u8 = rp.PopRaw<u8>();
268
269 ClockSnapshot clock_snapshot{};
270
271 const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
272 std::chrono::system_clock::now().time_since_epoch())
273 .count()};
274 CalendarTime calendar_time{};
275 const std::time_t time(time_since_epoch);
276 const std::tm* tm = std::localtime(&time);
277 if (tm == nullptr) {
278 LOG_ERROR(Service_Time, "tm is a nullptr");
279 IPC::ResponseBuilder rb{ctx, 2};
280 rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code
281 return;
282 }
283 SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) /
284 1000};
285
286 LocationName location_name{"UTC"};
287 calendar_time.year = tm->tm_year + 1900;
288 calendar_time.month = tm->tm_mon + 1;
289 calendar_time.day = tm->tm_mday;
290 calendar_time.hour = tm->tm_hour;
291 calendar_time.minute = tm->tm_min;
292 calendar_time.second = tm->tm_sec;
293 clock_snapshot.system_posix_time = time_since_epoch;
294 clock_snapshot.network_posix_time = time_since_epoch;
295 clock_snapshot.system_calendar_time = calendar_time;
296 clock_snapshot.network_calendar_time = calendar_time;
297
298 CalendarAdditionalInfo additional_info{};
299 PosixToCalendar(time_since_epoch, calendar_time, additional_info, {});
300
301 clock_snapshot.system_calendar_info = additional_info;
302 clock_snapshot.network_calendar_info = additional_info;
303
304 clock_snapshot.steady_clock_timepoint = steady_clock_time_point;
305 clock_snapshot.location_name = location_name;
306 clock_snapshot.clock_auto_adjustment_enabled = 1;
307 clock_snapshot.ipc_u8 = unknown_u8;
308 IPC::ResponseBuilder rb{ctx, 2};
309 rb.Push(RESULT_SUCCESS);
310 ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
311}
312
313void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
314 Kernel::HLERequestContext& ctx) {
315 LOG_DEBUG(Service_Time, "called");
316
317 IPC::RequestParser rp{ctx};
318 const auto snapshot_a = rp.PopRaw<ClockSnapshot>();
319 const auto snapshot_b = rp.PopRaw<ClockSnapshot>();
320 const u64 difference =
321 snapshot_b.user_clock_context.offset - snapshot_a.user_clock_context.offset;
322
323 IPC::ResponseBuilder rb{ctx, 4};
324 rb.Push(RESULT_SUCCESS);
325 rb.PushRaw<u64>(difference);
208} 326}
209 327
210Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) 328Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 5659ecad3..ea43fbea7 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/common_funcs.h"
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
9 10
10namespace Service::Time { 11namespace Service::Time {
@@ -53,6 +54,23 @@ struct SystemClockContext {
53static_assert(sizeof(SystemClockContext) == 0x20, 54static_assert(sizeof(SystemClockContext) == 0x20,
54 "SystemClockContext structure has incorrect size"); 55 "SystemClockContext structure has incorrect size");
55 56
57struct ClockSnapshot {
58 SystemClockContext user_clock_context;
59 SystemClockContext network_clock_context;
60 s64_le system_posix_time;
61 s64_le network_posix_time;
62 CalendarTime system_calendar_time;
63 CalendarTime network_calendar_time;
64 CalendarAdditionalInfo system_calendar_info;
65 CalendarAdditionalInfo network_calendar_info;
66 SteadyClockTimePoint steady_clock_timepoint;
67 LocationName location_name;
68 u8 clock_auto_adjustment_enabled;
69 u8 ipc_u8;
70 INSERT_PADDING_BYTES(2);
71};
72static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size");
73
56class Module final { 74class Module final {
57public: 75public:
58 class Interface : public ServiceFramework<Interface> { 76 class Interface : public ServiceFramework<Interface> {
@@ -65,6 +83,8 @@ public:
65 void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); 83 void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
66 void GetTimeZoneService(Kernel::HLERequestContext& ctx); 84 void GetTimeZoneService(Kernel::HLERequestContext& ctx);
67 void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); 85 void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
86 void GetClockSnapshot(Kernel::HLERequestContext& ctx);
87 void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx);
68 88
69 protected: 89 protected:
70 std::shared_ptr<Module> time; 90 std::shared_ptr<Module> time;
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index f0a831d45..58a9845fc 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -73,7 +73,7 @@ public:
73 {3, nullptr, "Populate"}, 73 {3, nullptr, "Populate"},
74 {4, nullptr, "PostBufferAsync"}, 74 {4, nullptr, "PostBufferAsync"},
75 {5, nullptr, "GetXferReport"}, 75 {5, nullptr, "GetXferReport"},
76 {6, nullptr, "Unknown2"}, 76 {6, nullptr, "PostBufferMultiAsync"},
77 {7, nullptr, "Unknown3"}, 77 {7, nullptr, "Unknown3"},
78 {8, nullptr, "Unknown4"}, 78 {8, nullptr, "Unknown4"},
79 }; 79 };
@@ -159,11 +159,11 @@ public:
159 159
160private: 160private:
161 void GetPdSession(Kernel::HLERequestContext& ctx) { 161 void GetPdSession(Kernel::HLERequestContext& ctx) {
162 LOG_DEBUG(Service_USB, "called");
163
162 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 164 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
163 rb.Push(RESULT_SUCCESS); 165 rb.Push(RESULT_SUCCESS);
164 rb.PushIpcInterface<IPdSession>(); 166 rb.PushIpcInterface<IPdSession>();
165
166 LOG_DEBUG(Service_USB, "called");
167 } 167 }
168}; 168};
169 169
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index d764b2406..311b0c765 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -18,7 +18,8 @@
18#include "common/swap.h" 18#include "common/swap.h"
19#include "core/core_timing.h" 19#include "core/core_timing.h"
20#include "core/hle/ipc_helpers.h" 20#include "core/hle/ipc_helpers.h"
21#include "core/hle/kernel/event.h" 21#include "core/hle/kernel/readable_event.h"
22#include "core/hle/kernel/writable_event.h"
22#include "core/hle/service/nvdrv/nvdrv.h" 23#include "core/hle/service/nvdrv/nvdrv.h"
23#include "core/hle/service/nvflinger/buffer_queue.h" 24#include "core/hle/service/nvflinger/buffer_queue.h"
24#include "core/hle/service/nvflinger/nvflinger.h" 25#include "core/hle/service/nvflinger/nvflinger.h"
@@ -237,6 +238,22 @@ private:
237 Data data{}; 238 Data data{};
238}; 239};
239 240
241/// Represents a parcel containing one int '0' as its data
242/// Used by DetachBuffer and Disconnect
243class IGBPEmptyResponseParcel : public Parcel {
244protected:
245 void SerializeData() override {
246 Write(data);
247 }
248
249private:
250 struct Data {
251 u32_le unk_0;
252 };
253
254 Data data{};
255};
256
240class IGBPSetPreallocatedBufferRequestParcel : public Parcel { 257class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
241public: 258public:
242 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer) 259 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer)
@@ -488,13 +505,17 @@ private:
488 u32 id = rp.Pop<u32>(); 505 u32 id = rp.Pop<u32>();
489 auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); 506 auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
490 u32 flags = rp.Pop<u32>(); 507 u32 flags = rp.Pop<u32>();
491 auto buffer_queue = nv_flinger->GetBufferQueue(id);
492
493 LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); 508 LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction));
494 509
510 auto buffer_queue = nv_flinger->GetBufferQueue(id);
511
495 if (transaction == TransactionId::Connect) { 512 if (transaction == TransactionId::Connect) {
496 IGBPConnectRequestParcel request{ctx.ReadBuffer()}; 513 IGBPConnectRequestParcel request{ctx.ReadBuffer()};
497 IGBPConnectResponseParcel response{1280, 720}; 514 IGBPConnectResponseParcel response{
515 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) *
516 Settings::values.resolution_factor),
517 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
518 Settings::values.resolution_factor)};
498 ctx.WriteBuffer(response.Serialize()); 519 ctx.WriteBuffer(response.Serialize());
499 } else if (transaction == TransactionId::SetPreallocatedBuffer) { 520 } else if (transaction == TransactionId::SetPreallocatedBuffer) {
500 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; 521 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
@@ -522,12 +543,14 @@ private:
522 // Repeat TransactParcel DequeueBuffer when a buffer is available 543 // Repeat TransactParcel DequeueBuffer when a buffer is available
523 auto buffer_queue = nv_flinger->GetBufferQueue(id); 544 auto buffer_queue = nv_flinger->GetBufferQueue(id);
524 std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); 545 std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
546 ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer.");
547
525 IGBPDequeueBufferResponseParcel response{*slot}; 548 IGBPDequeueBufferResponseParcel response{*slot};
526 ctx.WriteBuffer(response.Serialize()); 549 ctx.WriteBuffer(response.Serialize());
527 IPC::ResponseBuilder rb{ctx, 2}; 550 IPC::ResponseBuilder rb{ctx, 2};
528 rb.Push(RESULT_SUCCESS); 551 rb.Push(RESULT_SUCCESS);
529 }, 552 },
530 buffer_queue->GetBufferWaitEvent()); 553 buffer_queue->GetWritableBufferWaitEvent());
531 } 554 }
532 } else if (transaction == TransactionId::RequestBuffer) { 555 } else if (transaction == TransactionId::RequestBuffer) {
533 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; 556 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
@@ -554,6 +577,12 @@ private:
554 ctx.WriteBuffer(response.Serialize()); 577 ctx.WriteBuffer(response.Serialize());
555 } else if (transaction == TransactionId::CancelBuffer) { 578 } else if (transaction == TransactionId::CancelBuffer) {
556 LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); 579 LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
580 } else if (transaction == TransactionId::Disconnect ||
581 transaction == TransactionId::DetachBuffer) {
582 const auto buffer = ctx.ReadBuffer();
583
584 IGBPEmptyResponseParcel response{};
585 ctx.WriteBuffer(response.Serialize());
557 } else { 586 } else {
558 ASSERT_MSG(false, "Unimplemented"); 587 ASSERT_MSG(false, "Unimplemented");
559 } 588 }
@@ -567,9 +596,9 @@ private:
567 u32 id = rp.Pop<u32>(); 596 u32 id = rp.Pop<u32>();
568 s32 addval = rp.PopRaw<s32>(); 597 s32 addval = rp.PopRaw<s32>();
569 u32 type = rp.Pop<u32>(); 598 u32 type = rp.Pop<u32>();
570
571 LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, 599 LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval,
572 type); 600 type);
601
573 IPC::ResponseBuilder rb{ctx, 2}; 602 IPC::ResponseBuilder rb{ctx, 2};
574 rb.Push(RESULT_SUCCESS); 603 rb.Push(RESULT_SUCCESS);
575 } 604 }
@@ -578,12 +607,11 @@ private:
578 IPC::RequestParser rp{ctx}; 607 IPC::RequestParser rp{ctx};
579 u32 id = rp.Pop<u32>(); 608 u32 id = rp.Pop<u32>();
580 u32 unknown = rp.Pop<u32>(); 609 u32 unknown = rp.Pop<u32>();
610 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
581 611
582 auto buffer_queue = nv_flinger->GetBufferQueue(id); 612 auto buffer_queue = nv_flinger->GetBufferQueue(id);
583 613
584 // TODO(Subv): Find out what this actually is. 614 // TODO(Subv): Find out what this actually is.
585
586 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
587 IPC::ResponseBuilder rb{ctx, 2, 1}; 615 IPC::ResponseBuilder rb{ctx, 2, 1};
588 rb.Push(RESULT_SUCCESS); 616 rb.Push(RESULT_SUCCESS);
589 rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent()); 617 rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent());
@@ -647,6 +675,7 @@ public:
647private: 675private:
648 void SetLayerZ(Kernel::HLERequestContext& ctx) { 676 void SetLayerZ(Kernel::HLERequestContext& ctx) {
649 LOG_WARNING(Service_VI, "(STUBBED) called"); 677 LOG_WARNING(Service_VI, "(STUBBED) called");
678
650 IPC::RequestParser rp{ctx}; 679 IPC::RequestParser rp{ctx};
651 u64 layer_id = rp.Pop<u64>(); 680 u64 layer_id = rp.Pop<u64>();
652 u64 z_value = rp.Pop<u64>(); 681 u64 z_value = rp.Pop<u64>();
@@ -659,28 +688,33 @@ private:
659 IPC::RequestParser rp{ctx}; 688 IPC::RequestParser rp{ctx};
660 u64 layer_id = rp.Pop<u64>(); 689 u64 layer_id = rp.Pop<u64>();
661 bool visibility = rp.Pop<bool>(); 690 bool visibility = rp.Pop<bool>();
662 IPC::ResponseBuilder rb{ctx, 2};
663 rb.Push(RESULT_SUCCESS);
664 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, 691 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
665 visibility); 692 visibility);
693
694 IPC::ResponseBuilder rb{ctx, 2};
695 rb.Push(RESULT_SUCCESS);
666 } 696 }
667 697
668 void GetDisplayMode(Kernel::HLERequestContext& ctx) { 698 void GetDisplayMode(Kernel::HLERequestContext& ctx) {
699 LOG_WARNING(Service_VI, "(STUBBED) called");
700
669 IPC::ResponseBuilder rb{ctx, 6}; 701 IPC::ResponseBuilder rb{ctx, 6};
670 rb.Push(RESULT_SUCCESS); 702 rb.Push(RESULT_SUCCESS);
671 703
672 if (Settings::values.use_docked_mode) { 704 if (Settings::values.use_docked_mode) {
673 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); 705 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
674 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); 706 static_cast<u32>(Settings::values.resolution_factor));
707 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
708 static_cast<u32>(Settings::values.resolution_factor));
675 } else { 709 } else {
676 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); 710 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
677 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); 711 static_cast<u32>(Settings::values.resolution_factor));
712 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
713 static_cast<u32>(Settings::values.resolution_factor));
678 } 714 }
679 715
680 rb.PushRaw<float>(60.0f); 716 rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
681 rb.Push<u32>(0); 717 rb.Push<u32>(0);
682
683 LOG_DEBUG(Service_VI, "called");
684 } 718 }
685}; 719};
686 720
@@ -763,6 +797,7 @@ public:
763private: 797private:
764 void CloseDisplay(Kernel::HLERequestContext& ctx) { 798 void CloseDisplay(Kernel::HLERequestContext& ctx) {
765 LOG_WARNING(Service_VI, "(STUBBED) called"); 799 LOG_WARNING(Service_VI, "(STUBBED) called");
800
766 IPC::RequestParser rp{ctx}; 801 IPC::RequestParser rp{ctx};
767 u64 display = rp.Pop<u64>(); 802 u64 display = rp.Pop<u64>();
768 803
@@ -772,6 +807,7 @@ private:
772 807
773 void CreateManagedLayer(Kernel::HLERequestContext& ctx) { 808 void CreateManagedLayer(Kernel::HLERequestContext& ctx) {
774 LOG_WARNING(Service_VI, "(STUBBED) called"); 809 LOG_WARNING(Service_VI, "(STUBBED) called");
810
775 IPC::RequestParser rp{ctx}; 811 IPC::RequestParser rp{ctx};
776 u32 unknown = rp.Pop<u32>(); 812 u32 unknown = rp.Pop<u32>();
777 rp.Skip(1, false); 813 rp.Skip(1, false);
@@ -787,6 +823,7 @@ private:
787 823
788 void AddToLayerStack(Kernel::HLERequestContext& ctx) { 824 void AddToLayerStack(Kernel::HLERequestContext& ctx) {
789 LOG_WARNING(Service_VI, "(STUBBED) called"); 825 LOG_WARNING(Service_VI, "(STUBBED) called");
826
790 IPC::RequestParser rp{ctx}; 827 IPC::RequestParser rp{ctx};
791 u32 stack = rp.Pop<u32>(); 828 u32 stack = rp.Pop<u32>();
792 u64 layer_id = rp.Pop<u64>(); 829 u64 layer_id = rp.Pop<u64>();
@@ -799,10 +836,11 @@ private:
799 IPC::RequestParser rp{ctx}; 836 IPC::RequestParser rp{ctx};
800 u64 layer_id = rp.Pop<u64>(); 837 u64 layer_id = rp.Pop<u64>();
801 bool visibility = rp.Pop<bool>(); 838 bool visibility = rp.Pop<bool>();
802 IPC::ResponseBuilder rb{ctx, 2};
803 rb.Push(RESULT_SUCCESS);
804 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, 839 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
805 visibility); 840 visibility);
841
842 IPC::ResponseBuilder rb{ctx, 2};
843 rb.Push(RESULT_SUCCESS);
806 } 844 }
807 845
808 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; 846 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
@@ -848,6 +886,7 @@ private:
848 886
849 void OpenDisplay(Kernel::HLERequestContext& ctx) { 887 void OpenDisplay(Kernel::HLERequestContext& ctx) {
850 LOG_WARNING(Service_VI, "(STUBBED) called"); 888 LOG_WARNING(Service_VI, "(STUBBED) called");
889
851 IPC::RequestParser rp{ctx}; 890 IPC::RequestParser rp{ctx};
852 auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); 891 auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
853 auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); 892 auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
@@ -863,6 +902,7 @@ private:
863 902
864 void CloseDisplay(Kernel::HLERequestContext& ctx) { 903 void CloseDisplay(Kernel::HLERequestContext& ctx) {
865 LOG_WARNING(Service_VI, "(STUBBED) called"); 904 LOG_WARNING(Service_VI, "(STUBBED) called");
905
866 IPC::RequestParser rp{ctx}; 906 IPC::RequestParser rp{ctx};
867 u64 display_id = rp.Pop<u64>(); 907 u64 display_id = rp.Pop<u64>();
868 908
@@ -872,6 +912,7 @@ private:
872 912
873 void GetDisplayResolution(Kernel::HLERequestContext& ctx) { 913 void GetDisplayResolution(Kernel::HLERequestContext& ctx) {
874 LOG_WARNING(Service_VI, "(STUBBED) called"); 914 LOG_WARNING(Service_VI, "(STUBBED) called");
915
875 IPC::RequestParser rp{ctx}; 916 IPC::RequestParser rp{ctx};
876 u64 display_id = rp.Pop<u64>(); 917 u64 display_id = rp.Pop<u64>();
877 918
@@ -879,16 +920,21 @@ private:
879 rb.Push(RESULT_SUCCESS); 920 rb.Push(RESULT_SUCCESS);
880 921
881 if (Settings::values.use_docked_mode) { 922 if (Settings::values.use_docked_mode) {
882 rb.Push(static_cast<u64>(DisplayResolution::DockedWidth)); 923 rb.Push(static_cast<u64>(DisplayResolution::DockedWidth) *
883 rb.Push(static_cast<u64>(DisplayResolution::DockedHeight)); 924 static_cast<u32>(Settings::values.resolution_factor));
925 rb.Push(static_cast<u64>(DisplayResolution::DockedHeight) *
926 static_cast<u32>(Settings::values.resolution_factor));
884 } else { 927 } else {
885 rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth)); 928 rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
886 rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight)); 929 static_cast<u32>(Settings::values.resolution_factor));
930 rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
931 static_cast<u32>(Settings::values.resolution_factor));
887 } 932 }
888 } 933 }
889 934
890 void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { 935 void SetLayerScalingMode(Kernel::HLERequestContext& ctx) {
891 LOG_WARNING(Service_VI, "(STUBBED) called"); 936 LOG_WARNING(Service_VI, "(STUBBED) called");
937
892 IPC::RequestParser rp{ctx}; 938 IPC::RequestParser rp{ctx};
893 u32 scaling_mode = rp.Pop<u32>(); 939 u32 scaling_mode = rp.Pop<u32>();
894 u64 unknown = rp.Pop<u64>(); 940 u64 unknown = rp.Pop<u64>();
@@ -898,17 +944,21 @@ private:
898 } 944 }
899 945
900 void ListDisplays(Kernel::HLERequestContext& ctx) { 946 void ListDisplays(Kernel::HLERequestContext& ctx) {
947 LOG_WARNING(Service_VI, "(STUBBED) called");
948
901 IPC::RequestParser rp{ctx}; 949 IPC::RequestParser rp{ctx};
902 DisplayInfo display_info; 950 DisplayInfo display_info;
951 display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
952 display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
903 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); 953 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
904 IPC::ResponseBuilder rb{ctx, 4}; 954 IPC::ResponseBuilder rb{ctx, 4};
905 rb.Push(RESULT_SUCCESS); 955 rb.Push(RESULT_SUCCESS);
906 rb.Push<u64>(1); 956 rb.Push<u64>(1);
907 LOG_WARNING(Service_VI, "(STUBBED) called");
908 } 957 }
909 958
910 void OpenLayer(Kernel::HLERequestContext& ctx) { 959 void OpenLayer(Kernel::HLERequestContext& ctx) {
911 LOG_DEBUG(Service_VI, "called"); 960 LOG_DEBUG(Service_VI, "called");
961
912 IPC::RequestParser rp{ctx}; 962 IPC::RequestParser rp{ctx};
913 auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); 963 auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
914 auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); 964 auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
@@ -959,6 +1009,7 @@ private:
959 1009
960 void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { 1010 void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) {
961 LOG_WARNING(Service_VI, "(STUBBED) called"); 1011 LOG_WARNING(Service_VI, "(STUBBED) called");
1012
962 IPC::RequestParser rp{ctx}; 1013 IPC::RequestParser rp{ctx};
963 u64 display_id = rp.Pop<u64>(); 1014 u64 display_id = rp.Pop<u64>();
964 1015
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 8518dddcb..ac04d72d7 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -7,7 +7,6 @@
7#include "common/common_funcs.h" 7#include "common/common_funcs.h"
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h"
11#include "core/file_sys/content_archive.h" 10#include "core/file_sys/content_archive.h"
12#include "core/file_sys/control_metadata.h" 11#include "core/file_sys/control_metadata.h"
13#include "core/file_sys/patch_manager.h" 12#include "core/file_sys/patch_manager.h"
@@ -146,7 +145,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
146 const VAddr load_addr = next_load_addr; 145 const VAddr load_addr = next_load_addr;
147 const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; 146 const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
148 const auto tentative_next_load_addr = 147 const auto tentative_next_load_addr =
149 AppLoader_NSO::LoadModule(*module_file, load_addr, should_pass_arguments, pm); 148 AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm);
150 if (!tentative_next_load_addr) { 149 if (!tentative_next_load_addr) {
151 return ResultStatus::ErrorLoadingNSO; 150 return ResultStatus::ErrorLoadingNSO;
152 } 151 }
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index bc8e402a8..4fad0c0dd 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -10,12 +10,13 @@
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/core.h"
14#include "core/file_sys/control_metadata.h" 13#include "core/file_sys/control_metadata.h"
14#include "core/file_sys/romfs_factory.h"
15#include "core/file_sys/vfs_offset.h" 15#include "core/file_sys/vfs_offset.h"
16#include "core/gdbstub/gdbstub.h" 16#include "core/gdbstub/gdbstub.h"
17#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
19#include "core/hle/service/filesystem/filesystem.h"
19#include "core/loader/nro.h" 20#include "core/loader/nro.h"
20#include "core/loader/nso.h" 21#include "core/loader/nso.h"
21#include "core/memory.h" 22#include "core/memory.h"
@@ -127,9 +128,8 @@ static constexpr u32 PageAlignSize(u32 size) {
127 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 128 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
128} 129}
129 130
130/*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name, 131static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
131 VAddr load_base) { 132 const std::string& name, VAddr load_base) {
132
133 if (data.size() < sizeof(NroHeader)) { 133 if (data.size() < sizeof(NroHeader)) {
134 return {}; 134 return {};
135 } 135 }
@@ -168,23 +168,26 @@ static constexpr u32 PageAlignSize(u32 size) {
168 arg_data.size()); 168 arg_data.size());
169 } 169 }
170 170
171 // Read MOD header
172 ModHeader mod_header{};
173 // Default .bss to NRO header bss size if MOD0 section doesn't exist 171 // Default .bss to NRO header bss size if MOD0 section doesn't exist
174 u32 bss_size{PageAlignSize(nro_header.bss_size)}; 172 u32 bss_size{PageAlignSize(nro_header.bss_size)};
173
174 // Read MOD header
175 ModHeader mod_header{};
175 std::memcpy(&mod_header, program_image.data() + nro_header.module_header_offset, 176 std::memcpy(&mod_header, program_image.data() + nro_header.module_header_offset,
176 sizeof(ModHeader)); 177 sizeof(ModHeader));
178
177 const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; 179 const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')};
178 if (has_mod_header) { 180 if (has_mod_header) {
179 // Resize program image to include .bss section and page align each section 181 // Resize program image to include .bss section and page align each section
180 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); 182 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
181 } 183 }
184
182 codeset.DataSegment().size += bss_size; 185 codeset.DataSegment().size += bss_size;
183 program_image.resize(static_cast<u32>(program_image.size()) + bss_size); 186 program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
184 187
185 // Load codeset for current process 188 // Load codeset for current process
186 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 189 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
187 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); 190 process.LoadModule(std::move(codeset), load_base);
188 191
189 // Register module with GDBStub 192 // Register module with GDBStub
190 GDBStub::RegisterModule(name, load_base, load_base); 193 GDBStub::RegisterModule(name, load_base, load_base);
@@ -192,8 +195,9 @@ static constexpr u32 PageAlignSize(u32 size) {
192 return true; 195 return true;
193} 196}
194 197
195bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { 198bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& file,
196 return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base); 199 VAddr load_base) {
200 return LoadNroImpl(process, file.ReadAllBytes(), file.GetName(), load_base);
197} 201}
198 202
199ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { 203ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
@@ -204,10 +208,13 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
204 // Load NRO 208 // Load NRO
205 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 209 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
206 210
207 if (!LoadNro(*file, base_address)) { 211 if (!LoadNro(process, *file, base_address)) {
208 return ResultStatus::ErrorLoadingNRO; 212 return ResultStatus::ErrorLoadingNRO;
209 } 213 }
210 214
215 if (romfs != nullptr)
216 Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
217
211 process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); 218 process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
212 219
213 is_loaded = true; 220 is_loaded = true;
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 3e6959302..6deff3a51 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -14,6 +14,10 @@ namespace FileSys {
14class NACP; 14class NACP;
15} 15}
16 16
17namespace Kernel {
18class Process;
19}
20
17namespace Loader { 21namespace Loader {
18 22
19/// Loads an NRO file 23/// Loads an NRO file
@@ -41,10 +45,8 @@ public:
41 ResultStatus ReadTitle(std::string& title) override; 45 ResultStatus ReadTitle(std::string& title) override;
42 bool IsRomFSUpdatable() const override; 46 bool IsRomFSUpdatable() const override;
43 47
44 static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base);
45
46private: 48private:
47 bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); 49 bool LoadNro(Kernel::Process& process, const FileSys::VfsFile& file, VAddr load_base);
48 50
49 std::vector<u8> icon_data; 51 std::vector<u8> icon_data;
50 std::unique_ptr<FileSys::NACP> nacp; 52 std::unique_ptr<FileSys::NACP> nacp;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 68efca5c0..6ded0b707 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -9,7 +9,6 @@
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/core.h"
13#include "core/file_sys/patch_manager.h" 12#include "core/file_sys/patch_manager.h"
14#include "core/gdbstub/gdbstub.h" 13#include "core/gdbstub/gdbstub.h"
15#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
@@ -93,7 +92,8 @@ static constexpr u32 PageAlignSize(u32 size) {
93 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 92 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
94} 93}
95 94
96std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base, 95std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
96 const FileSys::VfsFile& file, VAddr load_base,
97 bool should_pass_arguments, 97 bool should_pass_arguments,
98 std::optional<FileSys::PatchManager> pm) { 98 std::optional<FileSys::PatchManager> pm) {
99 if (file.GetSize() < sizeof(NsoHeader)) 99 if (file.GetSize() < sizeof(NsoHeader))
@@ -154,7 +154,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAd
154 program_image.resize(image_size); 154 program_image.resize(image_size);
155 155
156 // Apply patches if necessary 156 // Apply patches if necessary
157 if (pm && pm->HasNSOPatch(nso_header.build_id)) { 157 if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
158 std::vector<u8> pi_header(program_image.size() + 0x100); 158 std::vector<u8> pi_header(program_image.size() + 0x100);
159 std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader)); 159 std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader));
160 std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size()); 160 std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size());
@@ -166,7 +166,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAd
166 166
167 // Load codeset for current process 167 // Load codeset for current process
168 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 168 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
169 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); 169 process.LoadModule(std::move(codeset), load_base);
170 170
171 // Register module with GDBStub 171 // Register module with GDBStub
172 GDBStub::RegisterModule(file.GetName(), load_base, load_base); 172 GDBStub::RegisterModule(file.GetName(), load_base, load_base);
@@ -181,7 +181,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
181 181
182 // Load module 182 // Load module
183 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 183 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
184 if (!LoadModule(*file, base_address, true)) { 184 if (!LoadModule(process, *file, base_address, true)) {
185 return ResultStatus::ErrorLoadingNSO; 185 return ResultStatus::ErrorLoadingNSO;
186 } 186 }
187 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); 187 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 433306139..0c1defbb6 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -10,6 +10,10 @@
10#include "core/loader/linker.h" 10#include "core/loader/linker.h"
11#include "core/loader/loader.h" 11#include "core/loader/loader.h"
12 12
13namespace Kernel {
14class Process;
15}
16
13namespace Loader { 17namespace Loader {
14 18
15constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; 19constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
@@ -37,8 +41,8 @@ public:
37 return IdentifyType(file); 41 return IdentifyType(file);
38 } 42 }
39 43
40 static std::optional<VAddr> LoadModule(const FileSys::VfsFile& file, VAddr load_base, 44 static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file,
41 bool should_pass_arguments, 45 VAddr load_base, bool should_pass_arguments,
42 std::optional<FileSys::PatchManager> pm = {}); 46 std::optional<FileSys::PatchManager> pm = {});
43 47
44 ResultStatus Load(Kernel::Process& process) override; 48 ResultStatus Load(Kernel::Process& process) override;
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 0da159559..26fcd3405 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -10,6 +10,56 @@
10 10
11namespace Settings { 11namespace Settings {
12 12
13namespace NativeButton {
14const std::array<const char*, NumButtons> mapping = {{
15 "button_a",
16 "button_b",
17 "button_x",
18 "button_y",
19 "button_lstick",
20 "button_rstick",
21 "button_l",
22 "button_r",
23 "button_zl",
24 "button_zr",
25 "button_plus",
26 "button_minus",
27 "button_dleft",
28 "button_dup",
29 "button_dright",
30 "button_ddown",
31 "button_lstick_left",
32 "button_lstick_up",
33 "button_lstick_right",
34 "button_lstick_down",
35 "button_rstick_left",
36 "button_rstick_up",
37 "button_rstick_right",
38 "button_rstick_down",
39 "button_sl",
40 "button_sr",
41 "button_home",
42 "button_screenshot",
43}};
44}
45
46namespace NativeAnalog {
47const std::array<const char*, NumAnalogs> mapping = {{
48 "lstick",
49 "rstick",
50}};
51}
52
53namespace NativeMouseButton {
54const std::array<const char*, NumMouseButtons> mapping = {{
55 "left",
56 "right",
57 "middle",
58 "forward",
59 "back",
60}};
61}
62
13Values values = {}; 63Values values = {};
14 64
15void Apply() { 65void Apply() {
diff --git a/src/core/settings.h b/src/core/settings.h
index a8954647f..a0c5fd447 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <atomic> 8#include <atomic>
9#include <optional>
9#include <string> 10#include <string>
10#include "common/common_types.h" 11#include "common/common_types.h"
11 12
@@ -59,36 +60,7 @@ constexpr int BUTTON_NS_END = NumButtons;
59constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN; 60constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
60constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN; 61constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
61 62
62static const std::array<const char*, NumButtons> mapping = {{ 63extern const std::array<const char*, NumButtons> mapping;
63 "button_a",
64 "button_b",
65 "button_x",
66 "button_y",
67 "button_lstick",
68 "button_rstick",
69 "button_l",
70 "button_r",
71 "button_zl",
72 "button_zr",
73 "button_plus",
74 "button_minus",
75 "button_dleft",
76 "button_dup",
77 "button_dright",
78 "button_ddown",
79 "button_lstick_left",
80 "button_lstick_up",
81 "button_lstick_right",
82 "button_lstick_down",
83 "button_rstick_left",
84 "button_rstick_up",
85 "button_rstick_right",
86 "button_rstick_down",
87 "button_sl",
88 "button_sr",
89 "button_home",
90 "button_screenshot",
91}};
92 64
93} // namespace NativeButton 65} // namespace NativeButton
94 66
@@ -104,24 +76,298 @@ constexpr int STICK_HID_BEGIN = LStick;
104constexpr int STICK_HID_END = NumAnalogs; 76constexpr int STICK_HID_END = NumAnalogs;
105constexpr int NUM_STICKS_HID = NumAnalogs; 77constexpr int NUM_STICKS_HID = NumAnalogs;
106 78
107static const std::array<const char*, NumAnalogs> mapping = {{ 79extern const std::array<const char*, NumAnalogs> mapping;
108 "lstick",
109 "rstick",
110}};
111} // namespace NativeAnalog 80} // namespace NativeAnalog
112 81
82namespace NativeMouseButton {
83enum Values {
84 Left,
85 Right,
86 Middle,
87 Forward,
88 Back,
89
90 NumMouseButtons,
91};
92
93constexpr int MOUSE_HID_BEGIN = Left;
94constexpr int MOUSE_HID_END = NumMouseButtons;
95constexpr int NUM_MOUSE_HID = NumMouseButtons;
96
97extern const std::array<const char*, NumMouseButtons> mapping;
98} // namespace NativeMouseButton
99
100namespace NativeKeyboard {
101enum Keys {
102 None,
103 Error,
104
105 A = 4,
106 B,
107 C,
108 D,
109 E,
110 F,
111 G,
112 H,
113 I,
114 J,
115 K,
116 L,
117 M,
118 N,
119 O,
120 P,
121 Q,
122 R,
123 S,
124 T,
125 U,
126 V,
127 W,
128 X,
129 Y,
130 Z,
131 N1,
132 N2,
133 N3,
134 N4,
135 N5,
136 N6,
137 N7,
138 N8,
139 N9,
140 N0,
141 Enter,
142 Escape,
143 Backspace,
144 Tab,
145 Space,
146 Minus,
147 Equal,
148 LeftBrace,
149 RightBrace,
150 Backslash,
151 Tilde,
152 Semicolon,
153 Apostrophe,
154 Grave,
155 Comma,
156 Dot,
157 Slash,
158 CapsLockKey,
159
160 F1,
161 F2,
162 F3,
163 F4,
164 F5,
165 F6,
166 F7,
167 F8,
168 F9,
169 F10,
170 F11,
171 F12,
172
173 SystemRequest,
174 ScrollLockKey,
175 Pause,
176 Insert,
177 Home,
178 PageUp,
179 Delete,
180 End,
181 PageDown,
182 Right,
183 Left,
184 Down,
185 Up,
186
187 NumLockKey,
188 KPSlash,
189 KPAsterisk,
190 KPMinus,
191 KPPlus,
192 KPEnter,
193 KP1,
194 KP2,
195 KP3,
196 KP4,
197 KP5,
198 KP6,
199 KP7,
200 KP8,
201 KP9,
202 KP0,
203 KPDot,
204
205 Key102,
206 Compose,
207 Power,
208 KPEqual,
209
210 F13,
211 F14,
212 F15,
213 F16,
214 F17,
215 F18,
216 F19,
217 F20,
218 F21,
219 F22,
220 F23,
221 F24,
222
223 Open,
224 Help,
225 Properties,
226 Front,
227 Stop,
228 Repeat,
229 Undo,
230 Cut,
231 Copy,
232 Paste,
233 Find,
234 Mute,
235 VolumeUp,
236 VolumeDown,
237 CapsLockActive,
238 NumLockActive,
239 ScrollLockActive,
240 KPComma,
241
242 KPLeftParenthesis,
243 KPRightParenthesis,
244
245 LeftControlKey = 0xE0,
246 LeftShiftKey,
247 LeftAltKey,
248 LeftMetaKey,
249 RightControlKey,
250 RightShiftKey,
251 RightAltKey,
252 RightMetaKey,
253
254 MediaPlayPause,
255 MediaStopCD,
256 MediaPrevious,
257 MediaNext,
258 MediaEject,
259 MediaVolumeUp,
260 MediaVolumeDown,
261 MediaMute,
262 MediaWebsite,
263 MediaBack,
264 MediaForward,
265 MediaStop,
266 MediaFind,
267 MediaScrollUp,
268 MediaScrollDown,
269 MediaEdit,
270 MediaSleep,
271 MediaCoffee,
272 MediaRefresh,
273 MediaCalculator,
274
275 NumKeyboardKeys,
276};
277
278static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
279
280enum Modifiers {
281 LeftControl,
282 LeftShift,
283 LeftAlt,
284 LeftMeta,
285 RightControl,
286 RightShift,
287 RightAlt,
288 RightMeta,
289 CapsLock,
290 ScrollLock,
291 NumLock,
292
293 NumKeyboardMods,
294};
295
296constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
297constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
298constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
299
300constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
301constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
302constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
303
304} // namespace NativeKeyboard
305
306using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
307using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
308using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
309using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
310using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
311
312constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
313constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
314constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
315constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
316
317enum class ControllerType {
318 ProController,
319 DualJoycon,
320 RightJoycon,
321 LeftJoycon,
322};
323
324struct PlayerInput {
325 bool connected;
326 ControllerType type;
327 ButtonsRaw buttons;
328 AnalogsRaw analogs;
329
330 u32 body_color_right;
331 u32 button_color_right;
332 u32 body_color_left;
333 u32 button_color_left;
334};
335
336struct TouchscreenInput {
337 bool enabled;
338 std::string device;
339
340 u32 finger;
341 u32 diameter_x;
342 u32 diameter_y;
343 u32 rotation_angle;
344};
345
113struct Values { 346struct Values {
114 // System 347 // System
115 bool use_docked_mode; 348 bool use_docked_mode;
116 bool enable_nfc; 349 bool enable_nfc;
350 std::optional<u32> rng_seed;
117 s32 current_user; 351 s32 current_user;
118 s32 language_index; 352 s32 language_index;
119 353
120 // Controls 354 // Controls
121 std::array<std::string, NativeButton::NumButtons> buttons; 355 std::array<PlayerInput, 10> players;
122 std::array<std::string, NativeAnalog::NumAnalogs> analogs; 356
357 bool mouse_enabled;
358 std::string mouse_device;
359 MouseButtonsRaw mouse_buttons;
360
361 bool keyboard_enabled;
362 KeyboardKeysRaw keyboard_keys;
363 KeyboardModsRaw keyboard_mods;
364
365 bool debug_pad_enabled;
366 ButtonsRaw debug_pad_buttons;
367 AnalogsRaw debug_pad_analogs;
368
123 std::string motion_device; 369 std::string motion_device;
124 std::string touch_device; 370 TouchscreenInput touchscreen;
125 std::atomic_bool is_device_reload_pending{true}; 371 std::atomic_bool is_device_reload_pending{true};
126 372
127 // Core 373 // Core
@@ -157,6 +403,8 @@ struct Values {
157 bool use_gdbstub; 403 bool use_gdbstub;
158 u16 gdbstub_port; 404 u16 gdbstub_port;
159 std::string program_args; 405 std::string program_args;
406 bool dump_exefs;
407 bool dump_nso;
160 408
161 // WebService 409 // WebService
162 bool enable_telemetry; 410 bool enable_telemetry;
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index a780215c1..0406fbcd9 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -1,6 +1,6 @@
1add_library(video_core STATIC 1add_library(video_core STATIC
2 command_processor.cpp 2 dma_pusher.cpp
3 command_processor.h 3 dma_pusher.h
4 debug_utils/debug_utils.cpp 4 debug_utils/debug_utils.cpp
5 debug_utils/debug_utils.h 5 debug_utils/debug_utils.h
6 engines/fermi_2d.cpp 6 engines/fermi_2d.cpp
@@ -21,6 +21,8 @@ add_library(video_core STATIC
21 macro_interpreter.h 21 macro_interpreter.h
22 memory_manager.cpp 22 memory_manager.cpp
23 memory_manager.h 23 memory_manager.h
24 morton.cpp
25 morton.h
24 rasterizer_cache.cpp 26 rasterizer_cache.cpp
25 rasterizer_cache.h 27 rasterizer_cache.h
26 rasterizer_interface.h 28 rasterizer_interface.h
@@ -62,7 +64,6 @@ add_library(video_core STATIC
62 textures/decoders.cpp 64 textures/decoders.cpp
63 textures/decoders.h 65 textures/decoders.h
64 textures/texture.h 66 textures/texture.h
65 utils.h
66 video_core.cpp 67 video_core.cpp
67 video_core.h 68 video_core.h
68) 69)
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
deleted file mode 100644
index 28e8c13aa..000000000
--- a/src/video_core/command_processor.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <cstddef>
7#include <memory>
8#include <utility>
9#include "common/assert.h"
10#include "common/logging/log.h"
11#include "common/microprofile.h"
12#include "common/vector_math.h"
13#include "core/memory.h"
14#include "core/tracer/recorder.h"
15#include "video_core/command_processor.h"
16#include "video_core/engines/fermi_2d.h"
17#include "video_core/engines/kepler_memory.h"
18#include "video_core/engines/maxwell_3d.h"
19#include "video_core/engines/maxwell_compute.h"
20#include "video_core/engines/maxwell_dma.h"
21#include "video_core/gpu.h"
22#include "video_core/renderer_base.h"
23#include "video_core/video_core.h"
24
25namespace Tegra {
26
27enum class BufferMethods {
28 BindObject = 0,
29 CountBufferMethods = 0x40,
30};
31
32MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
33
34void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
35 MICROPROFILE_SCOPE(ProcessCommandLists);
36
37 auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) {
38 LOG_TRACE(HW_GPU,
39 "Processing method {:08X} on subchannel {} value "
40 "{:08X} remaining params {}",
41 method, subchannel, value, remaining_params);
42
43 ASSERT(subchannel < bound_engines.size());
44
45 if (method == static_cast<u32>(BufferMethods::BindObject)) {
46 // Bind the current subchannel to the desired engine id.
47 LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value);
48 bound_engines[subchannel] = static_cast<EngineID>(value);
49 return;
50 }
51
52 if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
53 // TODO(Subv): Research and implement these methods.
54 LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
55 return;
56 }
57
58 const EngineID engine = bound_engines[subchannel];
59
60 switch (engine) {
61 case EngineID::FERMI_TWOD_A:
62 fermi_2d->WriteReg(method, value);
63 break;
64 case EngineID::MAXWELL_B:
65 maxwell_3d->WriteReg(method, value, remaining_params);
66 break;
67 case EngineID::MAXWELL_COMPUTE_B:
68 maxwell_compute->WriteReg(method, value);
69 break;
70 case EngineID::MAXWELL_DMA_COPY_A:
71 maxwell_dma->WriteReg(method, value);
72 break;
73 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
74 kepler_memory->WriteReg(method, value);
75 break;
76 default:
77 UNIMPLEMENTED_MSG("Unimplemented engine");
78 }
79 };
80
81 for (auto entry : commands) {
82 Tegra::GPUVAddr address = entry.Address();
83 u32 size = entry.sz;
84 const std::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address);
85 VAddr current_addr = *head_address;
86 while (current_addr < *head_address + size * sizeof(CommandHeader)) {
87 const CommandHeader header = {Memory::Read32(current_addr)};
88 current_addr += sizeof(u32);
89
90 switch (header.mode.Value()) {
91 case SubmissionMode::IncreasingOld:
92 case SubmissionMode::Increasing: {
93 // Increase the method value with each argument.
94 for (unsigned i = 0; i < header.arg_count; ++i) {
95 WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr),
96 header.arg_count - i - 1);
97 current_addr += sizeof(u32);
98 }
99 break;
100 }
101 case SubmissionMode::NonIncreasingOld:
102 case SubmissionMode::NonIncreasing: {
103 // Use the same method value for all arguments.
104 for (unsigned i = 0; i < header.arg_count; ++i) {
105 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
106 header.arg_count - i - 1);
107 current_addr += sizeof(u32);
108 }
109 break;
110 }
111 case SubmissionMode::IncreaseOnce: {
112 ASSERT(header.arg_count.Value() >= 1);
113
114 // Use the original method for the first argument and then the next method for all
115 // other arguments.
116 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
117 header.arg_count - 1);
118 current_addr += sizeof(u32);
119
120 for (unsigned i = 1; i < header.arg_count; ++i) {
121 WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr),
122 header.arg_count - i - 1);
123 current_addr += sizeof(u32);
124 }
125 break;
126 }
127 case SubmissionMode::Inline: {
128 // The register value is stored in the bits 16-28 as an immediate
129 WriteReg(header.method, header.subchannel, header.inline_data, 0);
130 break;
131 }
132 default:
133 UNIMPLEMENTED();
134 }
135 }
136 }
137}
138
139} // namespace Tegra
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h
deleted file mode 100644
index bd766e77a..000000000
--- a/src/video_core/command_processor.h
+++ /dev/null
@@ -1,53 +0,0 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <type_traits>
8#include "common/bit_field.h"
9#include "common/common_types.h"
10#include "video_core/memory_manager.h"
11
12namespace Tegra {
13
14enum class SubmissionMode : u32 {
15 IncreasingOld = 0,
16 Increasing = 1,
17 NonIncreasingOld = 2,
18 NonIncreasing = 3,
19 Inline = 4,
20 IncreaseOnce = 5
21};
22
23struct CommandListHeader {
24 u32 entry0; // gpu_va_lo
25 union {
26 u32 entry1; // gpu_va_hi | (unk_0x02 << 0x08) | (size << 0x0A) | (unk_0x01 << 0x1F)
27 BitField<0, 8, u32> gpu_va_hi;
28 BitField<8, 2, u32> unk1;
29 BitField<10, 21, u32> sz;
30 BitField<31, 1, u32> unk2;
31 };
32
33 GPUVAddr Address() const {
34 return (static_cast<GPUVAddr>(gpu_va_hi) << 32) | entry0;
35 }
36};
37static_assert(sizeof(CommandListHeader) == 8, "CommandListHeader is incorrect size");
38
39union CommandHeader {
40 u32 hex;
41
42 BitField<0, 13, u32> method;
43 BitField<13, 3, u32> subchannel;
44
45 BitField<16, 13, u32> arg_count;
46 BitField<16, 13, u32> inline_data;
47
48 BitField<29, 3, SubmissionMode> mode;
49};
50static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout");
51static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
52
53} // namespace Tegra
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
new file mode 100644
index 000000000..63a958f11
--- /dev/null
+++ b/src/video_core/dma_pusher.cpp
@@ -0,0 +1,123 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/microprofile.h"
6#include "core/core.h"
7#include "core/memory.h"
8#include "video_core/dma_pusher.h"
9#include "video_core/engines/maxwell_3d.h"
10#include "video_core/gpu.h"
11
12namespace Tegra {
13
14DmaPusher::DmaPusher(GPU& gpu) : gpu(gpu) {}
15
16DmaPusher::~DmaPusher() = default;
17
18MICROPROFILE_DEFINE(DispatchCalls, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
19
20void DmaPusher::DispatchCalls() {
21 MICROPROFILE_SCOPE(DispatchCalls);
22
23 // On entering GPU code, assume all memory may be touched by the ARM core.
24 gpu.Maxwell3D().dirty_flags.OnMemoryWrite();
25
26 dma_pushbuffer_subindex = 0;
27
28 while (Core::System::GetInstance().IsPoweredOn()) {
29 if (!Step()) {
30 break;
31 }
32 }
33}
34
35bool DmaPusher::Step() {
36 if (dma_get != dma_put) {
37 // Push buffer non-empty, read a word
38 const CommandHeader command_header{
39 Memory::Read32(*gpu.MemoryManager().GpuToCpuAddress(dma_get))};
40
41 dma_get += sizeof(u32);
42
43 if (!non_main) {
44 dma_mget = dma_get;
45 }
46
47 // now, see if we're in the middle of a command
48 if (dma_state.length_pending) {
49 // Second word of long non-inc methods command - method count
50 dma_state.length_pending = 0;
51 dma_state.method_count = command_header.method_count_;
52 } else if (dma_state.method_count) {
53 // Data word of methods command
54 CallMethod(command_header.argument);
55
56 if (!dma_state.non_incrementing) {
57 dma_state.method++;
58 }
59
60 if (dma_increment_once) {
61 dma_state.non_incrementing = true;
62 }
63
64 dma_state.method_count--;
65 } else {
66 // No command active - this is the first word of a new one
67 switch (command_header.mode) {
68 case SubmissionMode::Increasing:
69 SetState(command_header);
70 dma_state.non_incrementing = false;
71 dma_increment_once = false;
72 break;
73 case SubmissionMode::NonIncreasing:
74 SetState(command_header);
75 dma_state.non_incrementing = true;
76 dma_increment_once = false;
77 break;
78 case SubmissionMode::Inline:
79 dma_state.method = command_header.method;
80 dma_state.subchannel = command_header.subchannel;
81 CallMethod(command_header.arg_count);
82 dma_state.non_incrementing = true;
83 dma_increment_once = false;
84 break;
85 case SubmissionMode::IncreaseOnce:
86 SetState(command_header);
87 dma_state.non_incrementing = false;
88 dma_increment_once = true;
89 break;
90 }
91 }
92 } else if (ib_enable && !dma_pushbuffer.empty()) {
93 // Current pushbuffer empty, but we have more IB entries to read
94 const CommandList& command_list{dma_pushbuffer.front()};
95 const CommandListHeader& command_list_header{command_list[dma_pushbuffer_subindex++]};
96 dma_get = command_list_header.addr;
97 dma_put = dma_get + command_list_header.size * sizeof(u32);
98 non_main = command_list_header.is_non_main;
99
100 if (dma_pushbuffer_subindex >= command_list.size()) {
101 // We've gone through the current list, remove it from the queue
102 dma_pushbuffer.pop();
103 dma_pushbuffer_subindex = 0;
104 }
105 } else {
106 // Otherwise, pushbuffer empty and IB empty or nonexistent - nothing to do
107 return {};
108 }
109
110 return true;
111}
112
113void DmaPusher::SetState(const CommandHeader& command_header) {
114 dma_state.method = command_header.method;
115 dma_state.subchannel = command_header.subchannel;
116 dma_state.method_count = command_header.method_count;
117}
118
119void DmaPusher::CallMethod(u32 argument) const {
120 gpu.CallMethod({dma_state.method, argument, dma_state.subchannel, dma_state.method_count});
121}
122
123} // namespace Tegra
diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h
new file mode 100644
index 000000000..16e0697c4
--- /dev/null
+++ b/src/video_core/dma_pusher.h
@@ -0,0 +1,99 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include <queue>
9
10#include "common/bit_field.h"
11#include "common/common_types.h"
12#include "video_core/memory_manager.h"
13
14namespace Tegra {
15
16enum class SubmissionMode : u32 {
17 IncreasingOld = 0,
18 Increasing = 1,
19 NonIncreasingOld = 2,
20 NonIncreasing = 3,
21 Inline = 4,
22 IncreaseOnce = 5
23};
24
25struct CommandListHeader {
26 union {
27 u64 raw;
28 BitField<0, 40, GPUVAddr> addr;
29 BitField<41, 1, u64> is_non_main;
30 BitField<42, 21, u64> size;
31 };
32};
33static_assert(sizeof(CommandListHeader) == sizeof(u64), "CommandListHeader is incorrect size");
34
35union CommandHeader {
36 u32 argument;
37 BitField<0, 13, u32> method;
38 BitField<0, 24, u32> method_count_;
39 BitField<13, 3, u32> subchannel;
40 BitField<16, 13, u32> arg_count;
41 BitField<16, 13, u32> method_count;
42 BitField<29, 3, SubmissionMode> mode;
43};
44static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout");
45static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
46
47class GPU;
48
49using CommandList = std::vector<Tegra::CommandListHeader>;
50
51/**
52 * The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the
53 * emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled
54 * into a "command stream" consisting of 32-bit words that make up "commands".
55 * See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for
56 * details on this implementation.
57 */
58class DmaPusher {
59public:
60 explicit DmaPusher(GPU& gpu);
61 ~DmaPusher();
62
63 void Push(CommandList&& entries) {
64 dma_pushbuffer.push(std::move(entries));
65 }
66
67 void DispatchCalls();
68
69private:
70 bool Step();
71
72 void SetState(const CommandHeader& command_header);
73
74 void CallMethod(u32 argument) const;
75
76 GPU& gpu;
77
78 std::queue<CommandList> dma_pushbuffer; ///< Queue of command lists to be processed
79 std::size_t dma_pushbuffer_subindex{}; ///< Index within a command list within the pushbuffer
80
81 struct DmaState {
82 u32 method; ///< Current method
83 u32 subchannel; ///< Current subchannel
84 u32 method_count; ///< Current method count
85 u32 length_pending; ///< Large NI command length pending
86 bool non_incrementing; ///< Current command’s NI flag
87 };
88
89 DmaState dma_state{};
90 bool dma_increment_once{};
91
92 GPUVAddr dma_put{}; ///< pushbuffer current end address
93 GPUVAddr dma_get{}; ///< pushbuffer current read address
94 GPUVAddr dma_mget{}; ///< main pushbuffer last read address
95 bool ib_enable{true}; ///< IB mode enabled
96 bool non_main{}; ///< non-main pushbuffer active
97};
98
99} // namespace Tegra
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index 74e44c7fe..80f70e332 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -2,8 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h"
5#include "core/memory.h" 6#include "core/memory.h"
6#include "video_core/engines/fermi_2d.h" 7#include "video_core/engines/fermi_2d.h"
8#include "video_core/engines/maxwell_3d.h"
7#include "video_core/rasterizer_interface.h" 9#include "video_core/rasterizer_interface.h"
8#include "video_core/textures/decoders.h" 10#include "video_core/textures/decoders.h"
9 11
@@ -12,13 +14,13 @@ namespace Tegra::Engines {
12Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) 14Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
13 : memory_manager(memory_manager), rasterizer{rasterizer} {} 15 : memory_manager(memory_manager), rasterizer{rasterizer} {}
14 16
15void Fermi2D::WriteReg(u32 method, u32 value) { 17void Fermi2D::CallMethod(const GPU::MethodCall& method_call) {
16 ASSERT_MSG(method < Regs::NUM_REGS, 18 ASSERT_MSG(method_call.method < Regs::NUM_REGS,
17 "Invalid Fermi2D register, increase the size of the Regs structure"); 19 "Invalid Fermi2D register, increase the size of the Regs structure");
18 20
19 regs.reg_array[method] = value; 21 regs.reg_array[method_call.method] = method_call.argument;
20 22
21 switch (method) { 23 switch (method_call.method) {
22 case FERMI2D_REG_INDEX(trigger): { 24 case FERMI2D_REG_INDEX(trigger): {
23 HandleSurfaceCopy(); 25 HandleSurfaceCopy();
24 break; 26 break;
@@ -47,6 +49,9 @@ void Fermi2D::HandleSurfaceCopy() {
47 u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format); 49 u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format);
48 50
49 if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) { 51 if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) {
52 // All copies here update the main memory, so mark all rasterizer states as invalid.
53 Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
54
50 rasterizer.FlushRegion(source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height); 55 rasterizer.FlushRegion(source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height);
51 // We have to invalidate the destination region to evict any outdated surfaces from the 56 // We have to invalidate the destination region to evict any outdated surfaces from the
52 // cache. We do this before actually writing the new data because the destination address 57 // cache. We do this before actually writing the new data because the destination address
@@ -68,13 +73,13 @@ void Fermi2D::HandleSurfaceCopy() {
68 Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth, 73 Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth,
69 src_bytes_per_pixel, dst_bytes_per_pixel, src_buffer, 74 src_bytes_per_pixel, dst_bytes_per_pixel, src_buffer,
70 dst_buffer, true, regs.src.BlockHeight(), 75 dst_buffer, true, regs.src.BlockHeight(),
71 regs.src.BlockDepth()); 76 regs.src.BlockDepth(), 0);
72 } else { 77 } else {
73 // If the input is linear and the output is tiled, swizzle the input and copy it over. 78 // If the input is linear and the output is tiled, swizzle the input and copy it over.
74 Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth, 79 Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth,
75 src_bytes_per_pixel, dst_bytes_per_pixel, dst_buffer, 80 src_bytes_per_pixel, dst_bytes_per_pixel, dst_buffer,
76 src_buffer, false, regs.dst.BlockHeight(), 81 src_buffer, false, regs.dst.BlockHeight(),
77 regs.dst.BlockDepth()); 82 regs.dst.BlockDepth(), 0);
78 } 83 }
79 } 84 }
80} 85}
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index 2a6e8bbbb..50009bf75 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -27,7 +27,7 @@ public:
27 ~Fermi2D() = default; 27 ~Fermi2D() = default;
28 28
29 /// Write the value to the register identified by method. 29 /// Write the value to the register identified by method.
30 void WriteReg(u32 method, u32 value); 30 void CallMethod(const GPU::MethodCall& method_call);
31 31
32 struct Regs { 32 struct Regs {
33 static constexpr std::size_t NUM_REGS = 0x258; 33 static constexpr std::size_t NUM_REGS = 0x258;
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp
index 585290d9f..4880191fc 100644
--- a/src/video_core/engines/kepler_memory.cpp
+++ b/src/video_core/engines/kepler_memory.cpp
@@ -3,8 +3,10 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h"
6#include "core/memory.h" 7#include "core/memory.h"
7#include "video_core/engines/kepler_memory.h" 8#include "video_core/engines/kepler_memory.h"
9#include "video_core/engines/maxwell_3d.h"
8#include "video_core/rasterizer_interface.h" 10#include "video_core/rasterizer_interface.h"
9 11
10namespace Tegra::Engines { 12namespace Tegra::Engines {
@@ -15,19 +17,19 @@ KeplerMemory::KeplerMemory(VideoCore::RasterizerInterface& rasterizer,
15 17
16KeplerMemory::~KeplerMemory() = default; 18KeplerMemory::~KeplerMemory() = default;
17 19
18void KeplerMemory::WriteReg(u32 method, u32 value) { 20void KeplerMemory::CallMethod(const GPU::MethodCall& method_call) {
19 ASSERT_MSG(method < Regs::NUM_REGS, 21 ASSERT_MSG(method_call.method < Regs::NUM_REGS,
20 "Invalid KeplerMemory register, increase the size of the Regs structure"); 22 "Invalid KeplerMemory register, increase the size of the Regs structure");
21 23
22 regs.reg_array[method] = value; 24 regs.reg_array[method_call.method] = method_call.argument;
23 25
24 switch (method) { 26 switch (method_call.method) {
25 case KEPLERMEMORY_REG_INDEX(exec): { 27 case KEPLERMEMORY_REG_INDEX(exec): {
26 state.write_offset = 0; 28 state.write_offset = 0;
27 break; 29 break;
28 } 30 }
29 case KEPLERMEMORY_REG_INDEX(data): { 31 case KEPLERMEMORY_REG_INDEX(data): {
30 ProcessData(value); 32 ProcessData(method_call.argument);
31 break; 33 break;
32 } 34 }
33 } 35 }
@@ -47,6 +49,7 @@ void KeplerMemory::ProcessData(u32 data) {
47 rasterizer.InvalidateRegion(dest_address, sizeof(u32)); 49 rasterizer.InvalidateRegion(dest_address, sizeof(u32));
48 50
49 Memory::Write32(dest_address, data); 51 Memory::Write32(dest_address, data);
52 Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
50 53
51 state.write_offset++; 54 state.write_offset++;
52} 55}
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h
index bf4a13cff..fe9ebc5b9 100644
--- a/src/video_core/engines/kepler_memory.h
+++ b/src/video_core/engines/kepler_memory.h
@@ -9,6 +9,7 @@
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/gpu.h"
12#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
13 14
14namespace VideoCore { 15namespace VideoCore {
@@ -26,7 +27,7 @@ public:
26 ~KeplerMemory(); 27 ~KeplerMemory();
27 28
28 /// Write the value to the register identified by method. 29 /// Write the value to the register identified by method.
29 void WriteReg(u32 method, u32 value); 30 void CallMethod(const GPU::MethodCall& method_call);
30 31
31 struct Regs { 32 struct Regs {
32 static constexpr size_t NUM_REGS = 0x7F; 33 static constexpr size_t NUM_REGS = 0x7F;
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index d1777b25b..b19b3a75a 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -34,8 +34,8 @@ void Maxwell3D::InitializeRegisterDefaults() {
34 // Depth range near/far is not always set, but is expected to be the default 0.0f, 1.0f. This is 34 // Depth range near/far is not always set, but is expected to be the default 0.0f, 1.0f. This is
35 // needed for ARMS. 35 // needed for ARMS.
36 for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) { 36 for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) {
37 regs.viewport[viewport].depth_range_near = 0.0f; 37 regs.viewports[viewport].depth_range_near = 0.0f;
38 regs.viewport[viewport].depth_range_far = 1.0f; 38 regs.viewports[viewport].depth_range_far = 1.0f;
39 } 39 }
40 // Doom and Bomberman seems to use the uninitialized registers and just enable blend 40 // Doom and Bomberman seems to use the uninitialized registers and just enable blend
41 // so initialize blend registers with sane values 41 // so initialize blend registers with sane values
@@ -66,6 +66,18 @@ void Maxwell3D::InitializeRegisterDefaults() {
66 regs.stencil_back_func_func = Regs::ComparisonOp::Always; 66 regs.stencil_back_func_func = Regs::ComparisonOp::Always;
67 regs.stencil_back_func_mask = 0xFFFFFFFF; 67 regs.stencil_back_func_mask = 0xFFFFFFFF;
68 regs.stencil_back_mask = 0xFFFFFFFF; 68 regs.stencil_back_mask = 0xFFFFFFFF;
69 // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a
70 // register carrying a default value. Assume it's OpenGL's default (1).
71 regs.point_size = 1.0f;
72
73 // TODO(bunnei): Some games do not initialize the color masks (e.g. Sonic Mania). Assuming a
74 // default of enabled fixes rendering here.
75 for (std::size_t color_mask = 0; color_mask < Regs::NumRenderTargets; color_mask++) {
76 regs.color_mask[color_mask].R.Assign(1);
77 regs.color_mask[color_mask].G.Assign(1);
78 regs.color_mask[color_mask].B.Assign(1);
79 regs.color_mask[color_mask].A.Assign(1);
80 }
69} 81}
70 82
71void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { 83void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
@@ -85,59 +97,74 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
85 macro_interpreter.Execute(search->second, std::move(parameters)); 97 macro_interpreter.Execute(search->second, std::move(parameters));
86} 98}
87 99
88void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { 100void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
89 auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); 101 auto debug_context = Core::System::GetInstance().GetGPUDebugContext();
90 102
91 // It is an error to write to a register other than the current macro's ARG register before it 103 // It is an error to write to a register other than the current macro's ARG register before it
92 // has finished execution. 104 // has finished execution.
93 if (executing_macro != 0) { 105 if (executing_macro != 0) {
94 ASSERT(method == executing_macro + 1); 106 ASSERT(method_call.method == executing_macro + 1);
95 } 107 }
96 108
97 // Methods after 0xE00 are special, they're actually triggers for some microcode that was 109 // Methods after 0xE00 are special, they're actually triggers for some microcode that was
98 // uploaded to the GPU during initialization. 110 // uploaded to the GPU during initialization.
99 if (method >= MacroRegistersStart) { 111 if (method_call.method >= MacroRegistersStart) {
100 // We're trying to execute a macro 112 // We're trying to execute a macro
101 if (executing_macro == 0) { 113 if (executing_macro == 0) {
102 // A macro call must begin by writing the macro method's register, not its argument. 114 // A macro call must begin by writing the macro method's register, not its argument.
103 ASSERT_MSG((method % 2) == 0, 115 ASSERT_MSG((method_call.method % 2) == 0,
104 "Can't start macro execution by writing to the ARGS register"); 116 "Can't start macro execution by writing to the ARGS register");
105 executing_macro = method; 117 executing_macro = method_call.method;
106 } 118 }
107 119
108 macro_params.push_back(value); 120 macro_params.push_back(method_call.argument);
109 121
110 // Call the macro when there are no more parameters in the command buffer 122 // Call the macro when there are no more parameters in the command buffer
111 if (remaining_params == 0) { 123 if (method_call.IsLastCall()) {
112 CallMacroMethod(executing_macro, std::move(macro_params)); 124 CallMacroMethod(executing_macro, std::move(macro_params));
113 } 125 }
114 return; 126 return;
115 } 127 }
116 128
117 ASSERT_MSG(method < Regs::NUM_REGS, 129 ASSERT_MSG(method_call.method < Regs::NUM_REGS,
118 "Invalid Maxwell3D register, increase the size of the Regs structure"); 130 "Invalid Maxwell3D register, increase the size of the Regs structure");
119 131
120 if (debug_context) { 132 if (debug_context) {
121 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr); 133 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr);
122 } 134 }
123 135
124 u32 old = regs.reg_array[method]; 136 if (regs.reg_array[method_call.method] != method_call.argument) {
125 regs.reg_array[method] = value; 137 regs.reg_array[method_call.method] = method_call.argument;
126 138 // Vertex format
127 if (value != old) { 139 if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) &&
128 if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) && 140 method_call.method <
129 method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) { 141 MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) {
130 dirty_flags.vertex_attrib_format = true; 142 dirty_flags.vertex_attrib_format = true;
131 } 143 }
144
145 // Vertex buffer
146 if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_array) &&
147 method_call.method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * 32) {
148 dirty_flags.vertex_array |=
149 1u << ((method_call.method - MAXWELL3D_REG_INDEX(vertex_array)) >> 2);
150 } else if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_array_limit) &&
151 method_call.method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * 32) {
152 dirty_flags.vertex_array |=
153 1u << ((method_call.method - MAXWELL3D_REG_INDEX(vertex_array_limit)) >> 1);
154 } else if (method_call.method >= MAXWELL3D_REG_INDEX(instanced_arrays) &&
155 method_call.method < MAXWELL3D_REG_INDEX(instanced_arrays) + 32) {
156 dirty_flags.vertex_array |=
157 1u << (method_call.method - MAXWELL3D_REG_INDEX(instanced_arrays));
158 }
132 } 159 }
133 160
134 switch (method) { 161 switch (method_call.method) {
135 case MAXWELL3D_REG_INDEX(macros.data): { 162 case MAXWELL3D_REG_INDEX(macros.data): {
136 ProcessMacroUpload(value); 163 ProcessMacroUpload(method_call.argument);
137 break; 164 break;
138 } 165 }
139 case MAXWELL3D_REG_INDEX(macros.bind): { 166 case MAXWELL3D_REG_INDEX(macros.bind): {
140 ProcessMacroBind(value); 167 ProcessMacroBind(method_call.argument);
141 break; 168 break;
142 } 169 }
143 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): 170 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
@@ -156,7 +183,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
156 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): 183 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
157 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): 184 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
158 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): { 185 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): {
159 ProcessCBData(value); 186 ProcessCBData(method_call.argument);
160 break; 187 break;
161 } 188 }
162 case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): { 189 case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): {
@@ -260,6 +287,7 @@ void Maxwell3D::ProcessQueryGet() {
260 query_result.timestamp = CoreTiming::GetTicks(); 287 query_result.timestamp = CoreTiming::GetTicks();
261 Memory::WriteBlock(*address, &query_result, sizeof(query_result)); 288 Memory::WriteBlock(*address, &query_result, sizeof(query_result));
262 } 289 }
290 dirty_flags.OnMemoryWrite();
263 break; 291 break;
264 } 292 }
265 default: 293 default:
@@ -336,6 +364,7 @@ void Maxwell3D::ProcessCBData(u32 value) {
336 memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos); 364 memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos);
337 365
338 Memory::Write32(*address, value); 366 Memory::Write32(*address, value);
367 dirty_flags.OnMemoryWrite();
339 368
340 // Increment the current buffer position. 369 // Increment the current buffer position.
341 regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4; 370 regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4;
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 91ca57883..25bb7604a 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -42,6 +42,7 @@ public:
42 static constexpr std::size_t NumVertexArrays = 32; 42 static constexpr std::size_t NumVertexArrays = 32;
43 static constexpr std::size_t NumVertexAttributes = 32; 43 static constexpr std::size_t NumVertexAttributes = 32;
44 static constexpr std::size_t NumTextureSamplers = 32; 44 static constexpr std::size_t NumTextureSamplers = 32;
45 static constexpr std::size_t NumClipDistances = 8;
45 static constexpr std::size_t MaxShaderProgram = 6; 46 static constexpr std::size_t MaxShaderProgram = 6;
46 static constexpr std::size_t MaxShaderStage = 5; 47 static constexpr std::size_t MaxShaderStage = 5;
47 // Maximum number of const buffers per shader stage. 48 // Maximum number of const buffers per shader stage.
@@ -389,6 +390,13 @@ public:
389 ReverseSubtract = 3, 390 ReverseSubtract = 3,
390 Min = 4, 391 Min = 4,
391 Max = 5, 392 Max = 5,
393
394 // These values are used by Nouveau and some games.
395 AddGL = 0x8006,
396 SubtractGL = 0x8007,
397 ReverseSubtractGL = 0x8008,
398 MinGL = 0x800a,
399 MaxGL = 0x800b
392 }; 400 };
393 401
394 enum class Factor : u32 { 402 enum class Factor : u32 {
@@ -480,6 +488,67 @@ public:
480 }; 488 };
481 }; 489 };
482 490
491 struct ViewportTransform {
492 f32 scale_x;
493 f32 scale_y;
494 f32 scale_z;
495 f32 translate_x;
496 f32 translate_y;
497 f32 translate_z;
498 INSERT_PADDING_WORDS(2);
499
500 MathUtil::Rectangle<s32> GetRect() const {
501 return {
502 GetX(), // left
503 GetY() + GetHeight(), // top
504 GetX() + GetWidth(), // right
505 GetY() // bottom
506 };
507 };
508
509 s32 GetX() const {
510 return static_cast<s32>(std::max(0.0f, translate_x - std::fabs(scale_x)));
511 }
512
513 s32 GetY() const {
514 return static_cast<s32>(std::max(0.0f, translate_y - std::fabs(scale_y)));
515 }
516
517 s32 GetWidth() const {
518 return static_cast<s32>(translate_x + std::fabs(scale_x)) - GetX();
519 }
520
521 s32 GetHeight() const {
522 return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY();
523 }
524 };
525
526 struct ScissorTest {
527 u32 enable;
528 union {
529 BitField<0, 16, u32> min_x;
530 BitField<16, 16, u32> max_x;
531 };
532 union {
533 BitField<0, 16, u32> min_y;
534 BitField<16, 16, u32> max_y;
535 };
536 u32 fill;
537 };
538
539 struct ViewPort {
540 union {
541 BitField<0, 16, u32> x;
542 BitField<16, 16, u32> width;
543 };
544 union {
545 BitField<0, 16, u32> y;
546 BitField<16, 16, u32> height;
547 };
548 float depth_range_near;
549 float depth_range_far;
550 };
551
483 bool IsShaderConfigEnabled(std::size_t index) const { 552 bool IsShaderConfigEnabled(std::size_t index) const {
484 // The VertexB is always enabled. 553 // The VertexB is always enabled.
485 if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) { 554 if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
@@ -505,55 +574,11 @@ public:
505 574
506 INSERT_PADDING_WORDS(0x2E); 575 INSERT_PADDING_WORDS(0x2E);
507 576
508 RenderTargetConfig rt[NumRenderTargets]; 577 std::array<RenderTargetConfig, NumRenderTargets> rt;
509 578
510 struct { 579 std::array<ViewportTransform, NumViewports> viewport_transform;
511 f32 scale_x;
512 f32 scale_y;
513 f32 scale_z;
514 f32 translate_x;
515 f32 translate_y;
516 f32 translate_z;
517 INSERT_PADDING_WORDS(2);
518
519 MathUtil::Rectangle<s32> GetRect() const {
520 return {
521 GetX(), // left
522 GetY() + GetHeight(), // top
523 GetX() + GetWidth(), // right
524 GetY() // bottom
525 };
526 };
527 580
528 s32 GetX() const { 581 std::array<ViewPort, NumViewports> viewports;
529 return static_cast<s32>(std::max(0.0f, translate_x - std::fabs(scale_x)));
530 }
531
532 s32 GetY() const {
533 return static_cast<s32>(std::max(0.0f, translate_y - std::fabs(scale_y)));
534 }
535
536 s32 GetWidth() const {
537 return static_cast<s32>(translate_x + std::fabs(scale_x)) - GetX();
538 }
539
540 s32 GetHeight() const {
541 return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY();
542 }
543 } viewport_transform[NumViewports];
544
545 struct {
546 union {
547 BitField<0, 16, u32> x;
548 BitField<16, 16, u32> width;
549 };
550 union {
551 BitField<0, 16, u32> y;
552 BitField<16, 16, u32> height;
553 };
554 float depth_range_near;
555 float depth_range_far;
556 } viewport[NumViewports];
557 582
558 INSERT_PADDING_WORDS(0x1D); 583 INSERT_PADDING_WORDS(0x1D);
559 584
@@ -566,24 +591,22 @@ public:
566 591
567 float clear_color[4]; 592 float clear_color[4];
568 float clear_depth; 593 float clear_depth;
594
569 INSERT_PADDING_WORDS(0x3); 595 INSERT_PADDING_WORDS(0x3);
596
570 s32 clear_stencil; 597 s32 clear_stencil;
571 598
572 INSERT_PADDING_WORDS(0x17); 599 INSERT_PADDING_WORDS(0x7);
573 600
574 struct { 601 u32 polygon_offset_point_enable;
575 u32 enable; 602 u32 polygon_offset_line_enable;
576 union { 603 u32 polygon_offset_fill_enable;
577 BitField<0, 16, u32> min_x; 604
578 BitField<16, 16, u32> max_x; 605 INSERT_PADDING_WORDS(0xD);
579 }; 606
580 union { 607 std::array<ScissorTest, NumViewports> scissor_test;
581 BitField<0, 16, u32> min_y;
582 BitField<16, 16, u32> max_y;
583 };
584 } scissor_test;
585 608
586 INSERT_PADDING_WORDS(0x52); 609 INSERT_PADDING_WORDS(0x15);
587 610
588 s32 stencil_back_func_ref; 611 s32 stencil_back_func_ref;
589 u32 stencil_back_mask; 612 u32 stencil_back_mask;
@@ -617,7 +640,16 @@ public:
617 } 640 }
618 } zeta; 641 } zeta;
619 642
620 INSERT_PADDING_WORDS(0x5B); 643 INSERT_PADDING_WORDS(0x41);
644
645 union {
646 BitField<0, 4, u32> stencil;
647 BitField<4, 4, u32> unknown;
648 BitField<8, 4, u32> scissor;
649 BitField<12, 4, u32> viewport;
650 } clear_flags;
651
652 INSERT_PADDING_WORDS(0x19);
621 653
622 std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; 654 std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format;
623 655
@@ -700,9 +732,12 @@ public:
700 u32 stencil_front_func_mask; 732 u32 stencil_front_func_mask;
701 u32 stencil_front_mask; 733 u32 stencil_front_mask;
702 734
703 INSERT_PADDING_WORDS(0x3); 735 INSERT_PADDING_WORDS(0x2);
736
737 u32 frag_color_clamp;
704 738
705 union { 739 union {
740 BitField<0, 1, u32> y_negate;
706 BitField<4, 1, u32> triangle_rast_flip; 741 BitField<4, 1, u32> triangle_rast_flip;
707 } screen_y_control; 742 } screen_y_control;
708 743
@@ -710,7 +745,20 @@ public:
710 745
711 u32 vb_element_base; 746 u32 vb_element_base;
712 747
713 INSERT_PADDING_WORDS(0x38); 748 INSERT_PADDING_WORDS(0x36);
749
750 union {
751 BitField<0, 1, u32> c0;
752 BitField<1, 1, u32> c1;
753 BitField<2, 1, u32> c2;
754 BitField<3, 1, u32> c3;
755 BitField<4, 1, u32> c4;
756 BitField<5, 1, u32> c5;
757 BitField<6, 1, u32> c6;
758 BitField<7, 1, u32> c7;
759 } clip_distance_enabled;
760
761 INSERT_PADDING_WORDS(0x1);
714 762
715 float point_size; 763 float point_size;
716 764
@@ -718,7 +766,12 @@ public:
718 766
719 u32 zeta_enable; 767 u32 zeta_enable;
720 768
721 INSERT_PADDING_WORDS(0x8); 769 union {
770 BitField<0, 1, u32> alpha_to_coverage;
771 BitField<4, 1, u32> alpha_to_one;
772 } multisample_control;
773
774 INSERT_PADDING_WORDS(0x7);
722 775
723 struct { 776 struct {
724 u32 tsc_address_high; 777 u32 tsc_address_high;
@@ -731,7 +784,11 @@ public:
731 } 784 }
732 } tsc; 785 } tsc;
733 786
734 INSERT_PADDING_WORDS(0x3); 787 INSERT_PADDING_WORDS(0x1);
788
789 float polygon_offset_factor;
790
791 INSERT_PADDING_WORDS(0x1);
735 792
736 struct { 793 struct {
737 u32 tic_address_high; 794 u32 tic_address_high;
@@ -756,7 +813,9 @@ public:
756 813
757 u32 framebuffer_srgb; 814 u32 framebuffer_srgb;
758 815
759 INSERT_PADDING_WORDS(0x12); 816 float polygon_offset_units;
817
818 INSERT_PADDING_WORDS(0x11);
760 819
761 union { 820 union {
762 BitField<2, 1, u32> coord_origin; 821 BitField<2, 1, u32> coord_origin;
@@ -833,7 +892,9 @@ public:
833 892
834 INSERT_PADDING_WORDS(0x7); 893 INSERT_PADDING_WORDS(0x7);
835 894
836 INSERT_PADDING_WORDS(0x20); 895 INSERT_PADDING_WORDS(0x1F);
896
897 float polygon_offset_clamp;
837 898
838 struct { 899 struct {
839 u32 is_instanced[NumVertexArrays]; 900 u32 is_instanced[NumVertexArrays];
@@ -849,8 +910,21 @@ public:
849 910
850 Cull cull; 911 Cull cull;
851 912
852 INSERT_PADDING_WORDS(0x28); 913 u32 pixel_center_integer;
853 914
915 INSERT_PADDING_WORDS(0x1);
916
917 u32 viewport_transform_enabled;
918
919 INSERT_PADDING_WORDS(0x3);
920
921 union {
922 BitField<0, 1, u32> depth_range_0_1;
923 BitField<3, 1, u32> depth_clamp_near;
924 BitField<4, 1, u32> depth_clamp_far;
925 } view_volume_clip_control;
926
927 INSERT_PADDING_WORDS(0x21);
854 struct { 928 struct {
855 u32 enable; 929 u32 enable;
856 LogicOperation operation; 930 LogicOperation operation;
@@ -1014,6 +1088,11 @@ public:
1014 1088
1015 struct DirtyFlags { 1089 struct DirtyFlags {
1016 bool vertex_attrib_format = true; 1090 bool vertex_attrib_format = true;
1091 u32 vertex_array = 0xFFFFFFFF;
1092
1093 void OnMemoryWrite() {
1094 vertex_array = 0xFFFFFFFF;
1095 }
1017 }; 1096 };
1018 1097
1019 DirtyFlags dirty_flags; 1098 DirtyFlags dirty_flags;
@@ -1022,7 +1101,7 @@ public:
1022 u32 GetRegisterValue(u32 method) const; 1101 u32 GetRegisterValue(u32 method) const;
1023 1102
1024 /// Write the value to the register identified by method. 1103 /// Write the value to the register identified by method.
1025 void WriteReg(u32 method, u32 value, u32 remaining_params); 1104 void CallMethod(const GPU::MethodCall& method_call);
1026 1105
1027 /// Returns a list of enabled textures for the specified shader stage. 1106 /// Returns a list of enabled textures for the specified shader stage.
1028 std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; 1107 std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const;
@@ -1100,12 +1179,15 @@ private:
1100ASSERT_REG_POSITION(macros, 0x45); 1179ASSERT_REG_POSITION(macros, 0x45);
1101ASSERT_REG_POSITION(tfb_enabled, 0x1D1); 1180ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
1102ASSERT_REG_POSITION(rt, 0x200); 1181ASSERT_REG_POSITION(rt, 0x200);
1103ASSERT_REG_POSITION(viewport_transform[0], 0x280); 1182ASSERT_REG_POSITION(viewport_transform, 0x280);
1104ASSERT_REG_POSITION(viewport, 0x300); 1183ASSERT_REG_POSITION(viewports, 0x300);
1105ASSERT_REG_POSITION(vertex_buffer, 0x35D); 1184ASSERT_REG_POSITION(vertex_buffer, 0x35D);
1106ASSERT_REG_POSITION(clear_color[0], 0x360); 1185ASSERT_REG_POSITION(clear_color[0], 0x360);
1107ASSERT_REG_POSITION(clear_depth, 0x364); 1186ASSERT_REG_POSITION(clear_depth, 0x364);
1108ASSERT_REG_POSITION(clear_stencil, 0x368); 1187ASSERT_REG_POSITION(clear_stencil, 0x368);
1188ASSERT_REG_POSITION(polygon_offset_point_enable, 0x370);
1189ASSERT_REG_POSITION(polygon_offset_line_enable, 0x371);
1190ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372);
1109ASSERT_REG_POSITION(scissor_test, 0x380); 1191ASSERT_REG_POSITION(scissor_test, 0x380);
1110ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); 1192ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
1111ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); 1193ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
@@ -1113,6 +1195,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
1113ASSERT_REG_POSITION(color_mask_common, 0x3E4); 1195ASSERT_REG_POSITION(color_mask_common, 0x3E4);
1114ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); 1196ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
1115ASSERT_REG_POSITION(zeta, 0x3F8); 1197ASSERT_REG_POSITION(zeta, 0x3F8);
1198ASSERT_REG_POSITION(clear_flags, 0x43E);
1116ASSERT_REG_POSITION(vertex_attrib_format, 0x458); 1199ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
1117ASSERT_REG_POSITION(rt_control, 0x487); 1200ASSERT_REG_POSITION(rt_control, 0x487);
1118ASSERT_REG_POSITION(zeta_width, 0x48a); 1201ASSERT_REG_POSITION(zeta_width, 0x48a);
@@ -1136,11 +1219,15 @@ ASSERT_REG_POSITION(stencil_front_func_func, 0x4E4);
1136ASSERT_REG_POSITION(stencil_front_func_ref, 0x4E5); 1219ASSERT_REG_POSITION(stencil_front_func_ref, 0x4E5);
1137ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6); 1220ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6);
1138ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); 1221ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
1222ASSERT_REG_POSITION(frag_color_clamp, 0x4EA);
1139ASSERT_REG_POSITION(screen_y_control, 0x4EB); 1223ASSERT_REG_POSITION(screen_y_control, 0x4EB);
1140ASSERT_REG_POSITION(vb_element_base, 0x50D); 1224ASSERT_REG_POSITION(vb_element_base, 0x50D);
1225ASSERT_REG_POSITION(clip_distance_enabled, 0x544);
1141ASSERT_REG_POSITION(point_size, 0x546); 1226ASSERT_REG_POSITION(point_size, 0x546);
1142ASSERT_REG_POSITION(zeta_enable, 0x54E); 1227ASSERT_REG_POSITION(zeta_enable, 0x54E);
1228ASSERT_REG_POSITION(multisample_control, 0x54F);
1143ASSERT_REG_POSITION(tsc, 0x557); 1229ASSERT_REG_POSITION(tsc, 0x557);
1230ASSERT_REG_POSITION(polygon_offset_factor, 0x55b);
1144ASSERT_REG_POSITION(tic, 0x55D); 1231ASSERT_REG_POSITION(tic, 0x55D);
1145ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); 1232ASSERT_REG_POSITION(stencil_two_side_enable, 0x565);
1146ASSERT_REG_POSITION(stencil_back_op_fail, 0x566); 1233ASSERT_REG_POSITION(stencil_back_op_fail, 0x566);
@@ -1148,13 +1235,18 @@ ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567);
1148ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); 1235ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568);
1149ASSERT_REG_POSITION(stencil_back_func_func, 0x569); 1236ASSERT_REG_POSITION(stencil_back_func_func, 0x569);
1150ASSERT_REG_POSITION(framebuffer_srgb, 0x56E); 1237ASSERT_REG_POSITION(framebuffer_srgb, 0x56E);
1238ASSERT_REG_POSITION(polygon_offset_units, 0x56F);
1151ASSERT_REG_POSITION(point_coord_replace, 0x581); 1239ASSERT_REG_POSITION(point_coord_replace, 0x581);
1152ASSERT_REG_POSITION(code_address, 0x582); 1240ASSERT_REG_POSITION(code_address, 0x582);
1153ASSERT_REG_POSITION(draw, 0x585); 1241ASSERT_REG_POSITION(draw, 0x585);
1154ASSERT_REG_POSITION(primitive_restart, 0x591); 1242ASSERT_REG_POSITION(primitive_restart, 0x591);
1155ASSERT_REG_POSITION(index_array, 0x5F2); 1243ASSERT_REG_POSITION(index_array, 0x5F2);
1244ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F);
1156ASSERT_REG_POSITION(instanced_arrays, 0x620); 1245ASSERT_REG_POSITION(instanced_arrays, 0x620);
1157ASSERT_REG_POSITION(cull, 0x646); 1246ASSERT_REG_POSITION(cull, 0x646);
1247ASSERT_REG_POSITION(pixel_center_integer, 0x649);
1248ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B);
1249ASSERT_REG_POSITION(view_volume_clip_control, 0x64F);
1158ASSERT_REG_POSITION(logic_op, 0x671); 1250ASSERT_REG_POSITION(logic_op, 0x671);
1159ASSERT_REG_POSITION(clear_buffers, 0x674); 1251ASSERT_REG_POSITION(clear_buffers, 0x674);
1160ASSERT_REG_POSITION(color_mask, 0x680); 1252ASSERT_REG_POSITION(color_mask, 0x680);
diff --git a/src/video_core/engines/maxwell_compute.cpp b/src/video_core/engines/maxwell_compute.cpp
index 8b5f08351..656db6a61 100644
--- a/src/video_core/engines/maxwell_compute.cpp
+++ b/src/video_core/engines/maxwell_compute.cpp
@@ -8,13 +8,13 @@
8 8
9namespace Tegra::Engines { 9namespace Tegra::Engines {
10 10
11void MaxwellCompute::WriteReg(u32 method, u32 value) { 11void MaxwellCompute::CallMethod(const GPU::MethodCall& method_call) {
12 ASSERT_MSG(method < Regs::NUM_REGS, 12 ASSERT_MSG(method_call.method < Regs::NUM_REGS,
13 "Invalid MaxwellCompute register, increase the size of the Regs structure"); 13 "Invalid MaxwellCompute register, increase the size of the Regs structure");
14 14
15 regs.reg_array[method] = value; 15 regs.reg_array[method_call.method] = method_call.argument;
16 16
17 switch (method) { 17 switch (method_call.method) {
18 case MAXWELL_COMPUTE_REG_INDEX(compute): { 18 case MAXWELL_COMPUTE_REG_INDEX(compute): {
19 LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented"); 19 LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented");
20 UNREACHABLE(); 20 UNREACHABLE();
diff --git a/src/video_core/engines/maxwell_compute.h b/src/video_core/engines/maxwell_compute.h
index 6ea934fb9..1d71f11bd 100644
--- a/src/video_core/engines/maxwell_compute.h
+++ b/src/video_core/engines/maxwell_compute.h
@@ -9,6 +9,7 @@
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/gpu.h"
12 13
13namespace Tegra::Engines { 14namespace Tegra::Engines {
14 15
@@ -42,7 +43,7 @@ public:
42 "MaxwellCompute Regs has wrong size"); 43 "MaxwellCompute Regs has wrong size");
43 44
44 /// Write the value to the register identified by method. 45 /// Write the value to the register identified by method.
45 void WriteReg(u32 method, u32 value); 46 void CallMethod(const GPU::MethodCall& method_call);
46}; 47};
47 48
48#define ASSERT_REG_POSITION(field_name, position) \ 49#define ASSERT_REG_POSITION(field_name, position) \
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index b8a78cf82..06462f570 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -2,7 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h"
5#include "core/memory.h" 6#include "core/memory.h"
7#include "video_core/engines/maxwell_3d.h"
6#include "video_core/engines/maxwell_dma.h" 8#include "video_core/engines/maxwell_dma.h"
7#include "video_core/rasterizer_interface.h" 9#include "video_core/rasterizer_interface.h"
8#include "video_core/textures/decoders.h" 10#include "video_core/textures/decoders.h"
@@ -12,16 +14,16 @@ namespace Tegra::Engines {
12MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) 14MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
13 : memory_manager(memory_manager), rasterizer{rasterizer} {} 15 : memory_manager(memory_manager), rasterizer{rasterizer} {}
14 16
15void MaxwellDMA::WriteReg(u32 method, u32 value) { 17void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) {
16 ASSERT_MSG(method < Regs::NUM_REGS, 18 ASSERT_MSG(method_call.method < Regs::NUM_REGS,
17 "Invalid MaxwellDMA register, increase the size of the Regs structure"); 19 "Invalid MaxwellDMA register, increase the size of the Regs structure");
18 20
19 regs.reg_array[method] = value; 21 regs.reg_array[method_call.method] = method_call.argument;
20 22
21#define MAXWELLDMA_REG_INDEX(field_name) \ 23#define MAXWELLDMA_REG_INDEX(field_name) \
22 (offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32)) 24 (offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32))
23 25
24 switch (method) { 26 switch (method_call.method) {
25 case MAXWELLDMA_REG_INDEX(exec): { 27 case MAXWELLDMA_REG_INDEX(exec): {
26 HandleCopy(); 28 HandleCopy();
27 break; 29 break;
@@ -54,6 +56,9 @@ void MaxwellDMA::HandleCopy() {
54 return; 56 return;
55 } 57 }
56 58
59 // All copies here update the main memory, so mark all rasterizer states as invalid.
60 Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
61
57 if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { 62 if (regs.exec.is_dst_linear && regs.exec.is_src_linear) {
58 // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D 63 // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D
59 // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count, 64 // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count,
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index 5f3704f05..1f8cd65d2 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -24,7 +24,7 @@ public:
24 ~MaxwellDMA() = default; 24 ~MaxwellDMA() = default;
25 25
26 /// Write the value to the register identified by method. 26 /// Write the value to the register identified by method.
27 void WriteReg(u32 method, u32 value); 27 void CallMethod(const GPU::MethodCall& method_call);
28 28
29 struct Regs { 29 struct Regs {
30 static constexpr std::size_t NUM_REGS = 0x1D6; 30 static constexpr std::size_t NUM_REGS = 0x1D6;
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 83a6fd875..b9faaf8e0 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -82,6 +82,8 @@ union Attribute {
82 Position = 7, 82 Position = 7,
83 Attribute_0 = 8, 83 Attribute_0 = 8,
84 Attribute_31 = 39, 84 Attribute_31 = 39,
85 ClipDistances0123 = 44,
86 ClipDistances4567 = 45,
85 PointCoord = 46, 87 PointCoord = 46,
86 // This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex 88 // This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex
87 // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval 89 // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval
@@ -153,6 +155,7 @@ enum class PredCondition : u64 {
153 NotEqual = 5, 155 NotEqual = 5,
154 GreaterEqual = 6, 156 GreaterEqual = 6,
155 LessThanWithNan = 9, 157 LessThanWithNan = 9,
158 LessEqualWithNan = 11,
156 GreaterThanWithNan = 12, 159 GreaterThanWithNan = 12,
157 NotEqualWithNan = 13, 160 NotEqualWithNan = 13,
158 GreaterEqualWithNan = 14, 161 GreaterEqualWithNan = 14,
@@ -261,7 +264,7 @@ enum class FlowCondition : u64 {
261 Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? 264 Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
262}; 265};
263 266
264enum class ControlCode : u64 { 267enum class ConditionCode : u64 {
265 F = 0, 268 F = 0,
266 LT = 1, 269 LT = 1,
267 EQ = 2, 270 EQ = 2,
@@ -365,6 +368,11 @@ enum class HalfPrecision : u64 {
365 FMZ = 2, 368 FMZ = 2,
366}; 369};
367 370
371enum class R2pMode : u64 {
372 Pr = 0,
373 Cc = 1,
374};
375
368enum class IpaInterpMode : u64 { 376enum class IpaInterpMode : u64 {
369 Linear = 0, 377 Linear = 0,
370 Perspective = 1, 378 Perspective = 1,
@@ -569,7 +577,6 @@ union Instruction {
569 BitField<39, 2, u64> tab5cb8_2; 577 BitField<39, 2, u64> tab5cb8_2;
570 BitField<41, 3, u64> tab5c68_1; 578 BitField<41, 3, u64> tab5c68_1;
571 BitField<44, 2, u64> tab5c68_0; 579 BitField<44, 2, u64> tab5c68_0;
572 BitField<47, 1, u64> cc;
573 BitField<48, 1, u64> negate_b; 580 BitField<48, 1, u64> negate_b;
574 } fmul; 581 } fmul;
575 582
@@ -831,7 +838,7 @@ union Instruction {
831 union { 838 union {
832 BitField<0, 3, u64> pred0; 839 BitField<0, 3, u64> pred0;
833 BitField<3, 3, u64> pred3; 840 BitField<3, 3, u64> pred3;
834 BitField<8, 5, ControlCode> cc; // flag in cc 841 BitField<8, 5, ConditionCode> cc; // flag in cc
835 BitField<39, 3, u64> pred39; 842 BitField<39, 3, u64> pred39;
836 BitField<42, 1, u64> neg_pred39; 843 BitField<42, 1, u64> neg_pred39;
837 BitField<45, 4, PredOperation> op; // op with pred39 844 BitField<45, 4, PredOperation> op; // op with pred39
@@ -855,6 +862,12 @@ union Instruction {
855 } hsetp2; 862 } hsetp2;
856 863
857 union { 864 union {
865 BitField<40, 1, R2pMode> mode;
866 BitField<41, 2, u64> byte;
867 BitField<20, 7, u64> immediate_mask;
868 } r2p;
869
870 union {
858 BitField<39, 3, u64> pred39; 871 BitField<39, 3, u64> pred39;
859 BitField<42, 1, u64> neg_pred; 872 BitField<42, 1, u64> neg_pred;
860 BitField<43, 1, u64> neg_a; 873 BitField<43, 1, u64> neg_a;
@@ -1235,7 +1248,7 @@ union Instruction {
1235 BitField<60, 1, u64> is_b_gpr; 1248 BitField<60, 1, u64> is_b_gpr;
1236 BitField<59, 1, u64> is_c_gpr; 1249 BitField<59, 1, u64> is_c_gpr;
1237 BitField<20, 24, s64> smem_imm; 1250 BitField<20, 24, s64> smem_imm;
1238 BitField<0, 5, ControlCode> flow_control_code; 1251 BitField<0, 5, ConditionCode> flow_condition_code;
1239 1252
1240 Attribute attribute; 1253 Attribute attribute;
1241 Sampler sampler; 1254 Sampler sampler;
@@ -1256,6 +1269,7 @@ public:
1256 BFE_C, 1269 BFE_C,
1257 BFE_R, 1270 BFE_R,
1258 BFE_IMM, 1271 BFE_IMM,
1272 BFI_IMM_R,
1259 BRA, 1273 BRA,
1260 PBK, 1274 PBK,
1261 LD_A, 1275 LD_A,
@@ -1381,6 +1395,7 @@ public:
1381 PSETP, 1395 PSETP,
1382 PSET, 1396 PSET,
1383 CSETP, 1397 CSETP,
1398 R2P_IMM,
1384 XMAD_IMM, 1399 XMAD_IMM,
1385 XMAD_CR, 1400 XMAD_CR,
1386 XMAD_RC, 1401 XMAD_RC,
@@ -1396,6 +1411,7 @@ public:
1396 ArithmeticHalf, 1411 ArithmeticHalf,
1397 ArithmeticHalfImmediate, 1412 ArithmeticHalfImmediate,
1398 Bfe, 1413 Bfe,
1414 Bfi,
1399 Shift, 1415 Shift,
1400 Ffma, 1416 Ffma,
1401 Hfma2, 1417 Hfma2,
@@ -1410,6 +1426,7 @@ public:
1410 HalfSetPredicate, 1426 HalfSetPredicate,
1411 PredicateSetPredicate, 1427 PredicateSetPredicate,
1412 PredicateSetRegister, 1428 PredicateSetRegister,
1429 RegisterSetPredicate,
1413 Conversion, 1430 Conversion,
1414 Xmad, 1431 Xmad,
1415 Unknown, 1432 Unknown,
@@ -1613,6 +1630,7 @@ private:
1613 INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"), 1630 INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"),
1614 INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"), 1631 INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"),
1615 INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"), 1632 INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"),
1633 INST("0011011-11110---", Id::BFI_IMM_R, Type::Bfi, "BFI_IMM_R"),
1616 INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"), 1634 INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"),
1617 INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"), 1635 INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"),
1618 INST("0011100001000---", Id::LOP_IMM, Type::ArithmeticInteger, "LOP_IMM"), 1636 INST("0011100001000---", Id::LOP_IMM, Type::ArithmeticInteger, "LOP_IMM"),
@@ -1647,6 +1665,7 @@ private:
1647 INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), 1665 INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
1648 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), 1666 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
1649 INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"), 1667 INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"),
1668 INST("0011100-11110---", Id::R2P_IMM, Type::RegisterSetPredicate, "R2P_IMM"),
1650 INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), 1669 INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
1651 INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), 1670 INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
1652 INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), 1671 INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),
diff --git a/src/video_core/engines/shader_header.h b/src/video_core/engines/shader_header.h
index a0e015c4b..99c34649f 100644
--- a/src/video_core/engines/shader_header.h
+++ b/src/video_core/engines/shader_header.h
@@ -62,7 +62,16 @@ struct Header {
62 INSERT_PADDING_BYTES(1); // ImapSystemValuesB 62 INSERT_PADDING_BYTES(1); // ImapSystemValuesB
63 INSERT_PADDING_BYTES(16); // ImapGenericVector[32] 63 INSERT_PADDING_BYTES(16); // ImapGenericVector[32]
64 INSERT_PADDING_BYTES(2); // ImapColor 64 INSERT_PADDING_BYTES(2); // ImapColor
65 INSERT_PADDING_BYTES(2); // ImapSystemValuesC 65 union {
66 BitField<0, 8, u16> clip_distances;
67 BitField<8, 1, u16> point_sprite_s;
68 BitField<9, 1, u16> point_sprite_t;
69 BitField<10, 1, u16> fog_coordinate;
70 BitField<12, 1, u16> tessellation_eval_point_u;
71 BitField<13, 1, u16> tessellation_eval_point_v;
72 BitField<14, 1, u16> instance_id;
73 BitField<15, 1, u16> vertex_id;
74 };
66 INSERT_PADDING_BYTES(5); // ImapFixedFncTexture[10] 75 INSERT_PADDING_BYTES(5); // ImapFixedFncTexture[10]
67 INSERT_PADDING_BYTES(1); // ImapReserved 76 INSERT_PADDING_BYTES(1); // ImapReserved
68 INSERT_PADDING_BYTES(3); // OmapSystemValuesA 77 INSERT_PADDING_BYTES(3); // OmapSystemValuesA
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 83c7e5b0b..88c45a423 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -17,6 +17,8 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
17 switch (format) { 17 switch (format) {
18 case PixelFormat::ABGR8: 18 case PixelFormat::ABGR8:
19 return 4; 19 return 4;
20 default:
21 return 4;
20 } 22 }
21 23
22 UNREACHABLE(); 24 UNREACHABLE();
@@ -24,6 +26,7 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
24 26
25GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { 27GPU::GPU(VideoCore::RasterizerInterface& rasterizer) {
26 memory_manager = std::make_unique<Tegra::MemoryManager>(); 28 memory_manager = std::make_unique<Tegra::MemoryManager>();
29 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
27 maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); 30 maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager);
28 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); 31 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager);
29 maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); 32 maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
@@ -49,6 +52,14 @@ const MemoryManager& GPU::MemoryManager() const {
49 return *memory_manager; 52 return *memory_manager;
50} 53}
51 54
55DmaPusher& GPU::DmaPusher() {
56 return *dma_pusher;
57}
58
59const DmaPusher& GPU::DmaPusher() const {
60 return *dma_pusher;
61}
62
52u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { 63u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
53 ASSERT(format != RenderTargetFormat::NONE); 64 ASSERT(format != RenderTargetFormat::NONE);
54 65
@@ -111,4 +122,52 @@ u32 DepthFormatBytesPerPixel(DepthFormat format) {
111 } 122 }
112} 123}
113 124
125enum class BufferMethods {
126 BindObject = 0,
127 CountBufferMethods = 0x40,
128};
129
130void GPU::CallMethod(const MethodCall& method_call) {
131 LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method,
132 method_call.subchannel);
133
134 ASSERT(method_call.subchannel < bound_engines.size());
135
136 if (method_call.method == static_cast<u32>(BufferMethods::BindObject)) {
137 // Bind the current subchannel to the desired engine id.
138 LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel,
139 method_call.argument);
140 bound_engines[method_call.subchannel] = static_cast<EngineID>(method_call.argument);
141 return;
142 }
143
144 if (method_call.method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
145 // TODO(Subv): Research and implement these methods.
146 LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
147 return;
148 }
149
150 const EngineID engine = bound_engines[method_call.subchannel];
151
152 switch (engine) {
153 case EngineID::FERMI_TWOD_A:
154 fermi_2d->CallMethod(method_call);
155 break;
156 case EngineID::MAXWELL_B:
157 maxwell_3d->CallMethod(method_call);
158 break;
159 case EngineID::MAXWELL_COMPUTE_B:
160 maxwell_compute->CallMethod(method_call);
161 break;
162 case EngineID::MAXWELL_DMA_COPY_A:
163 maxwell_dma->CallMethod(method_call);
164 break;
165 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
166 kepler_memory->CallMethod(method_call);
167 break;
168 default:
169 UNIMPLEMENTED_MSG("Unimplemented engine");
170 }
171}
172
114} // namespace Tegra 173} // namespace Tegra
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 5cc1e19ca..af5ccd1e9 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -9,6 +9,7 @@
9#include <vector> 9#include <vector>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/service/nvflinger/buffer_queue.h" 11#include "core/hle/service/nvflinger/buffer_queue.h"
12#include "video_core/dma_pusher.h"
12#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
13 14
14namespace VideoCore { 15namespace VideoCore {
@@ -119,8 +120,23 @@ public:
119 explicit GPU(VideoCore::RasterizerInterface& rasterizer); 120 explicit GPU(VideoCore::RasterizerInterface& rasterizer);
120 ~GPU(); 121 ~GPU();
121 122
122 /// Processes a command list stored at the specified address in GPU memory. 123 struct MethodCall {
123 void ProcessCommandLists(const std::vector<CommandListHeader>& commands); 124 u32 method{};
125 u32 argument{};
126 u32 subchannel{};
127 u32 method_count{};
128
129 bool IsLastCall() const {
130 return method_count <= 1;
131 }
132
133 MethodCall(u32 method, u32 argument, u32 subchannel = 0, u32 method_count = 0)
134 : method(method), argument(argument), subchannel(subchannel),
135 method_count(method_count) {}
136 };
137
138 /// Calls a GPU method.
139 void CallMethod(const MethodCall& method_call);
124 140
125 /// Returns a reference to the Maxwell3D GPU engine. 141 /// Returns a reference to the Maxwell3D GPU engine.
126 Engines::Maxwell3D& Maxwell3D(); 142 Engines::Maxwell3D& Maxwell3D();
@@ -134,7 +150,14 @@ public:
134 /// Returns a const reference to the GPU memory manager. 150 /// Returns a const reference to the GPU memory manager.
135 const Tegra::MemoryManager& MemoryManager() const; 151 const Tegra::MemoryManager& MemoryManager() const;
136 152
153 /// Returns a reference to the GPU DMA pusher.
154 Tegra::DmaPusher& DmaPusher();
155
156 /// Returns a const reference to the GPU DMA pusher.
157 const Tegra::DmaPusher& DmaPusher() const;
158
137private: 159private:
160 std::unique_ptr<Tegra::DmaPusher> dma_pusher;
138 std::unique_ptr<Tegra::MemoryManager> memory_manager; 161 std::unique_ptr<Tegra::MemoryManager> memory_manager;
139 162
140 /// Mapping of command subchannels to their bound engine ids. 163 /// Mapping of command subchannels to their bound engine ids.
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index 335a8d407..9c55e9f1e 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -35,6 +35,7 @@ void MacroInterpreter::Reset() {
35 // The next parameter index starts at 1, because $r1 already has the value of the first 35 // The next parameter index starts at 1, because $r1 already has the value of the first
36 // parameter. 36 // parameter.
37 next_parameter_index = 1; 37 next_parameter_index = 1;
38 carry_flag = false;
38} 39}
39 40
40bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) { 41bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
@@ -135,14 +136,28 @@ MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const {
135 return {macro_memory[offset + pc / sizeof(u32)]}; 136 return {macro_memory[offset + pc / sizeof(u32)]};
136} 137}
137 138
138u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const { 139u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) {
139 switch (operation) { 140 switch (operation) {
140 case ALUOperation::Add: 141 case ALUOperation::Add: {
141 return src_a + src_b; 142 const u64 result{static_cast<u64>(src_a) + src_b};
142 // TODO(Subv): Implement AddWithCarry 143 carry_flag = result > 0xffffffff;
143 case ALUOperation::Subtract: 144 return static_cast<u32>(result);
144 return src_a - src_b; 145 }
145 // TODO(Subv): Implement SubtractWithBorrow 146 case ALUOperation::AddWithCarry: {
147 const u64 result{static_cast<u64>(src_a) + src_b + (carry_flag ? 1ULL : 0ULL)};
148 carry_flag = result > 0xffffffff;
149 return static_cast<u32>(result);
150 }
151 case ALUOperation::Subtract: {
152 const u64 result{static_cast<u64>(src_a) - src_b};
153 carry_flag = result < 0x100000000;
154 return static_cast<u32>(result);
155 }
156 case ALUOperation::SubtractWithBorrow: {
157 const u64 result{static_cast<u64>(src_a) - src_b - (carry_flag ? 0ULL : 1ULL)};
158 carry_flag = result < 0x100000000;
159 return static_cast<u32>(result);
160 }
146 case ALUOperation::Xor: 161 case ALUOperation::Xor:
147 return src_a ^ src_b; 162 return src_a ^ src_b;
148 case ALUOperation::Or: 163 case ALUOperation::Or:
@@ -235,7 +250,7 @@ void MacroInterpreter::SetMethodAddress(u32 address) {
235} 250}
236 251
237void MacroInterpreter::Send(u32 value) { 252void MacroInterpreter::Send(u32 value) {
238 maxwell3d.WriteReg(method_address.address, value, 0); 253 maxwell3d.CallMethod({method_address.address, value});
239 // Increment the method address by the method increment. 254 // Increment the method address by the method increment.
240 method_address.address.Assign(method_address.address.Value() + 255 method_address.address.Assign(method_address.address.Value() +
241 method_address.increment.Value()); 256 method_address.increment.Value());
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h
index 62d1ce289..cde360288 100644
--- a/src/video_core/macro_interpreter.h
+++ b/src/video_core/macro_interpreter.h
@@ -117,7 +117,7 @@ private:
117 bool Step(u32 offset, bool is_delay_slot); 117 bool Step(u32 offset, bool is_delay_slot);
118 118
119 /// Calculates the result of an ALU operation. src_a OP src_b; 119 /// Calculates the result of an ALU operation. src_a OP src_b;
120 u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const; 120 u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b);
121 121
122 /// Performs the result operation on the input result and stores it in the specified register 122 /// Performs the result operation on the input result and stores it in the specified register
123 /// (if necessary). 123 /// (if necessary).
@@ -165,5 +165,7 @@ private:
165 std::vector<u32> parameters; 165 std::vector<u32> parameters;
166 /// Index of the next parameter that will be fetched by the 'parm' instruction. 166 /// Index of the next parameter that will be fetched by the 'parm' instruction.
167 u32 next_parameter_index = 0; 167 u32 next_parameter_index = 0;
168
169 bool carry_flag{};
168}; 170};
169} // namespace Tegra 171} // namespace Tegra
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 77a20bb84..47247f097 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -9,6 +9,13 @@
9 9
10namespace Tegra { 10namespace Tegra {
11 11
12MemoryManager::MemoryManager() {
13 // Mark the first page as reserved, so that 0 is not a valid GPUVAddr. Otherwise, games might
14 // try to use 0 as a valid address, which is also used to mean nullptr. This fixes a bug with
15 // Undertale using 0 for a render target.
16 PageSlot(0) = static_cast<u64>(PageStatus::Reserved);
17}
18
12GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { 19GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
13 const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, align, PageStatus::Unmapped)}; 20 const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, align, PageStatus::Unmapped)};
14 21
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 4eb338aa2..fb03497ca 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -18,7 +18,7 @@ using GPUVAddr = u64;
18 18
19class MemoryManager final { 19class MemoryManager final {
20public: 20public:
21 MemoryManager() = default; 21 MemoryManager();
22 22
23 GPUVAddr AllocateSpace(u64 size, u64 align); 23 GPUVAddr AllocateSpace(u64 size, u64 align);
24 GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align); 24 GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align);
@@ -37,6 +37,7 @@ private:
37 enum class PageStatus : u64 { 37 enum class PageStatus : u64 {
38 Unmapped = 0xFFFFFFFFFFFFFFFFULL, 38 Unmapped = 0xFFFFFFFFFFFFFFFFULL,
39 Allocated = 0xFFFFFFFFFFFFFFFEULL, 39 Allocated = 0xFFFFFFFFFFFFFFFEULL,
40 Reserved = 0xFFFFFFFFFFFFFFFDULL,
40 }; 41 };
41 42
42 std::optional<GPUVAddr> FindFreeBlock(GPUVAddr region_start, u64 size, u64 align, 43 std::optional<GPUVAddr> FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp
new file mode 100644
index 000000000..a310491a8
--- /dev/null
+++ b/src/video_core/morton.cpp
@@ -0,0 +1,355 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <cstring>
7#include "common/assert.h"
8#include "common/common_types.h"
9#include "core/memory.h"
10#include "video_core/morton.h"
11#include "video_core/surface.h"
12#include "video_core/textures/decoders.h"
13
14namespace VideoCore {
15
16using Surface::GetBytesPerPixel;
17using Surface::PixelFormat;
18
19using MortonCopyFn = void (*)(u32, u32, u32, u32, u32, u32, u8*, std::size_t, VAddr);
20using ConversionArray = std::array<MortonCopyFn, Surface::MaxPixelFormat>;
21
22template <bool morton_to_linear, PixelFormat format>
23static void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth,
24 u32 tile_width_spacing, u8* buffer, std::size_t buffer_size, VAddr addr) {
25 constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
26
27 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
28 // pixel values.
29 const u32 tile_size_x{GetDefaultBlockWidth(format)};
30 const u32 tile_size_y{GetDefaultBlockHeight(format)};
31
32 if constexpr (morton_to_linear) {
33 Tegra::Texture::UnswizzleTexture(buffer, addr, tile_size_x, tile_size_y, bytes_per_pixel,
34 stride, height, depth, block_height, block_depth,
35 tile_width_spacing);
36 } else {
37 Tegra::Texture::CopySwizzledData(
38 (stride + tile_size_x - 1) / tile_size_x, (height + tile_size_y - 1) / tile_size_y,
39 depth, bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr), buffer, false,
40 block_height, block_depth, tile_width_spacing);
41 }
42}
43
44static constexpr ConversionArray morton_to_linear_fns = {
45 // clang-format off
46 MortonCopy<true, PixelFormat::ABGR8U>,
47 MortonCopy<true, PixelFormat::ABGR8S>,
48 MortonCopy<true, PixelFormat::ABGR8UI>,
49 MortonCopy<true, PixelFormat::B5G6R5U>,
50 MortonCopy<true, PixelFormat::A2B10G10R10U>,
51 MortonCopy<true, PixelFormat::A1B5G5R5U>,
52 MortonCopy<true, PixelFormat::R8U>,
53 MortonCopy<true, PixelFormat::R8UI>,
54 MortonCopy<true, PixelFormat::RGBA16F>,
55 MortonCopy<true, PixelFormat::RGBA16U>,
56 MortonCopy<true, PixelFormat::RGBA16UI>,
57 MortonCopy<true, PixelFormat::R11FG11FB10F>,
58 MortonCopy<true, PixelFormat::RGBA32UI>,
59 MortonCopy<true, PixelFormat::DXT1>,
60 MortonCopy<true, PixelFormat::DXT23>,
61 MortonCopy<true, PixelFormat::DXT45>,
62 MortonCopy<true, PixelFormat::DXN1>,
63 MortonCopy<true, PixelFormat::DXN2UNORM>,
64 MortonCopy<true, PixelFormat::DXN2SNORM>,
65 MortonCopy<true, PixelFormat::BC7U>,
66 MortonCopy<true, PixelFormat::BC6H_UF16>,
67 MortonCopy<true, PixelFormat::BC6H_SF16>,
68 MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
69 MortonCopy<true, PixelFormat::G8R8U>,
70 MortonCopy<true, PixelFormat::G8R8S>,
71 MortonCopy<true, PixelFormat::BGRA8>,
72 MortonCopy<true, PixelFormat::RGBA32F>,
73 MortonCopy<true, PixelFormat::RG32F>,
74 MortonCopy<true, PixelFormat::R32F>,
75 MortonCopy<true, PixelFormat::R16F>,
76 MortonCopy<true, PixelFormat::R16U>,
77 MortonCopy<true, PixelFormat::R16S>,
78 MortonCopy<true, PixelFormat::R16UI>,
79 MortonCopy<true, PixelFormat::R16I>,
80 MortonCopy<true, PixelFormat::RG16>,
81 MortonCopy<true, PixelFormat::RG16F>,
82 MortonCopy<true, PixelFormat::RG16UI>,
83 MortonCopy<true, PixelFormat::RG16I>,
84 MortonCopy<true, PixelFormat::RG16S>,
85 MortonCopy<true, PixelFormat::RGB32F>,
86 MortonCopy<true, PixelFormat::RGBA8_SRGB>,
87 MortonCopy<true, PixelFormat::RG8U>,
88 MortonCopy<true, PixelFormat::RG8S>,
89 MortonCopy<true, PixelFormat::RG32UI>,
90 MortonCopy<true, PixelFormat::R32UI>,
91 MortonCopy<true, PixelFormat::ASTC_2D_8X8>,
92 MortonCopy<true, PixelFormat::ASTC_2D_8X5>,
93 MortonCopy<true, PixelFormat::ASTC_2D_5X4>,
94 MortonCopy<true, PixelFormat::BGRA8_SRGB>,
95 MortonCopy<true, PixelFormat::DXT1_SRGB>,
96 MortonCopy<true, PixelFormat::DXT23_SRGB>,
97 MortonCopy<true, PixelFormat::DXT45_SRGB>,
98 MortonCopy<true, PixelFormat::BC7U_SRGB>,
99 MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>,
100 MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>,
101 MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>,
102 MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>,
103 MortonCopy<true, PixelFormat::ASTC_2D_5X5>,
104 MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
105 MortonCopy<true, PixelFormat::ASTC_2D_10X8>,
106 MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>,
107 MortonCopy<true, PixelFormat::Z32F>,
108 MortonCopy<true, PixelFormat::Z16>,
109 MortonCopy<true, PixelFormat::Z24S8>,
110 MortonCopy<true, PixelFormat::S8Z24>,
111 MortonCopy<true, PixelFormat::Z32FS8>,
112 // clang-format on
113};
114
115static constexpr ConversionArray linear_to_morton_fns = {
116 // clang-format off
117 MortonCopy<false, PixelFormat::ABGR8U>,
118 MortonCopy<false, PixelFormat::ABGR8S>,
119 MortonCopy<false, PixelFormat::ABGR8UI>,
120 MortonCopy<false, PixelFormat::B5G6R5U>,
121 MortonCopy<false, PixelFormat::A2B10G10R10U>,
122 MortonCopy<false, PixelFormat::A1B5G5R5U>,
123 MortonCopy<false, PixelFormat::R8U>,
124 MortonCopy<false, PixelFormat::R8UI>,
125 MortonCopy<false, PixelFormat::RGBA16F>,
126 MortonCopy<false, PixelFormat::RGBA16U>,
127 MortonCopy<false, PixelFormat::RGBA16UI>,
128 MortonCopy<false, PixelFormat::R11FG11FB10F>,
129 MortonCopy<false, PixelFormat::RGBA32UI>,
130 MortonCopy<false, PixelFormat::DXT1>,
131 MortonCopy<false, PixelFormat::DXT23>,
132 MortonCopy<false, PixelFormat::DXT45>,
133 MortonCopy<false, PixelFormat::DXN1>,
134 MortonCopy<false, PixelFormat::DXN2UNORM>,
135 MortonCopy<false, PixelFormat::DXN2SNORM>,
136 MortonCopy<false, PixelFormat::BC7U>,
137 MortonCopy<false, PixelFormat::BC6H_UF16>,
138 MortonCopy<false, PixelFormat::BC6H_SF16>,
139 // TODO(Subv): Swizzling ASTC formats are not supported
140 nullptr,
141 MortonCopy<false, PixelFormat::G8R8U>,
142 MortonCopy<false, PixelFormat::G8R8S>,
143 MortonCopy<false, PixelFormat::BGRA8>,
144 MortonCopy<false, PixelFormat::RGBA32F>,
145 MortonCopy<false, PixelFormat::RG32F>,
146 MortonCopy<false, PixelFormat::R32F>,
147 MortonCopy<false, PixelFormat::R16F>,
148 MortonCopy<false, PixelFormat::R16U>,
149 MortonCopy<false, PixelFormat::R16S>,
150 MortonCopy<false, PixelFormat::R16UI>,
151 MortonCopy<false, PixelFormat::R16I>,
152 MortonCopy<false, PixelFormat::RG16>,
153 MortonCopy<false, PixelFormat::RG16F>,
154 MortonCopy<false, PixelFormat::RG16UI>,
155 MortonCopy<false, PixelFormat::RG16I>,
156 MortonCopy<false, PixelFormat::RG16S>,
157 MortonCopy<false, PixelFormat::RGB32F>,
158 MortonCopy<false, PixelFormat::RGBA8_SRGB>,
159 MortonCopy<false, PixelFormat::RG8U>,
160 MortonCopy<false, PixelFormat::RG8S>,
161 MortonCopy<false, PixelFormat::RG32UI>,
162 MortonCopy<false, PixelFormat::R32UI>,
163 nullptr,
164 nullptr,
165 nullptr,
166 MortonCopy<false, PixelFormat::BGRA8_SRGB>,
167 MortonCopy<false, PixelFormat::DXT1_SRGB>,
168 MortonCopy<false, PixelFormat::DXT23_SRGB>,
169 MortonCopy<false, PixelFormat::DXT45_SRGB>,
170 MortonCopy<false, PixelFormat::BC7U_SRGB>,
171 nullptr,
172 nullptr,
173 nullptr,
174 nullptr,
175 nullptr,
176 nullptr,
177 nullptr,
178 nullptr,
179 MortonCopy<false, PixelFormat::Z32F>,
180 MortonCopy<false, PixelFormat::Z16>,
181 MortonCopy<false, PixelFormat::Z24S8>,
182 MortonCopy<false, PixelFormat::S8Z24>,
183 MortonCopy<false, PixelFormat::Z32FS8>,
184 // clang-format on
185};
186
187static MortonCopyFn GetSwizzleFunction(MortonSwizzleMode mode, Surface::PixelFormat format) {
188 switch (mode) {
189 case MortonSwizzleMode::MortonToLinear:
190 return morton_to_linear_fns[static_cast<std::size_t>(format)];
191 case MortonSwizzleMode::LinearToMorton:
192 return linear_to_morton_fns[static_cast<std::size_t>(format)];
193 }
194 UNREACHABLE();
195}
196
197/// 8x8 Z-Order coordinate from 2D coordinates
198static u32 MortonInterleave(u32 x, u32 y) {
199 static const u32 xlut[] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15};
200 static const u32 ylut[] = {0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a};
201 return xlut[x % 8] + ylut[y % 8];
202}
203
204/// Calculates the offset of the position of the pixel in Morton order
205static u32 GetMortonOffset(u32 x, u32 y, u32 bytes_per_pixel) {
206 // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each
207 // of which is composed of four 2x2 subtiles each of which is composed of four texels.
208 // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g.
209 // texels are laid out in a 2x2 subtile like this:
210 // 2 3
211 // 0 1
212 //
213 // The full 8x8 tile has the texels arranged like this:
214 //
215 // 42 43 46 47 58 59 62 63
216 // 40 41 44 45 56 57 60 61
217 // 34 35 38 39 50 51 54 55
218 // 32 33 36 37 48 49 52 53
219 // 10 11 14 15 26 27 30 31
220 // 08 09 12 13 24 25 28 29
221 // 02 03 06 07 18 19 22 23
222 // 00 01 04 05 16 17 20 21
223 //
224 // This pattern is what's called Z-order curve, or Morton order.
225
226 const unsigned int block_height = 8;
227 const unsigned int coarse_x = x & ~7;
228
229 u32 i = MortonInterleave(x, y);
230
231 const unsigned int offset = coarse_x * block_height;
232
233 return (i + offset) * bytes_per_pixel;
234}
235
236static u32 MortonInterleave128(u32 x, u32 y) {
237 // 128x128 Z-Order coordinate from 2D coordinates
238 static constexpr u32 xlut[] = {
239 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
240 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
241 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
242 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
243 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
244 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
245 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
246 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
247 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
248 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
249 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
250 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
251 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
252 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
253 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
254 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
255 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
256 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
257 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
258 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
259 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
260 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
261 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
262 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
263 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
264 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
265 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
266 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
267 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
268 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
269 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
270 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
271 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
272 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
273 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
274 };
275 static constexpr u32 ylut[] = {
276 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
277 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
278 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
279 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
280 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
281 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
282 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
283 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
284 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
285 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
286 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
287 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
288 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
289 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
290 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
291 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
292 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
293 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
294 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
295 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
296 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
297 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
298 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
299 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
300 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
301 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
302 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
303 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
304 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
305 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
306 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
307 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
308 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
309 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
310 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
311 };
312 return xlut[x % 128] + ylut[y % 128];
313}
314
315static u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
316 // Calculates the offset of the position of the pixel in Morton order
317 // Framebuffer images are split into 128x128 tiles.
318
319 constexpr u32 block_height = 128;
320 const u32 coarse_x = x & ~127;
321
322 const u32 i = MortonInterleave128(x, y);
323
324 const u32 offset = coarse_x * block_height;
325
326 return (i + offset) * bytes_per_pixel;
327}
328
329void MortonSwizzle(MortonSwizzleMode mode, Surface::PixelFormat format, u32 stride,
330 u32 block_height, u32 height, u32 block_depth, u32 depth, u32 tile_width_spacing,
331 u8* buffer, std::size_t buffer_size, VAddr addr) {
332
333 GetSwizzleFunction(mode, format)(stride, block_height, height, block_depth, depth,
334 tile_width_spacing, buffer, buffer_size, addr);
335}
336
337void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32 linear_bytes_per_pixel,
338 u8* morton_data, u8* linear_data, bool morton_to_linear) {
339 u8* data_ptrs[2];
340 for (u32 y = 0; y < height; ++y) {
341 for (u32 x = 0; x < width; ++x) {
342 const u32 coarse_y = y & ~127;
343 const u32 morton_offset =
344 GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
345 const u32 linear_pixel_index = (x + y * width) * linear_bytes_per_pixel;
346
347 data_ptrs[morton_to_linear ? 1 : 0] = morton_data + morton_offset;
348 data_ptrs[morton_to_linear ? 0 : 1] = &linear_data[linear_pixel_index];
349
350 std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
351 }
352 }
353}
354
355} // namespace VideoCore
diff --git a/src/video_core/morton.h b/src/video_core/morton.h
new file mode 100644
index 000000000..065f59ce3
--- /dev/null
+++ b/src/video_core/morton.h
@@ -0,0 +1,21 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "video_core/surface.h"
9
10namespace VideoCore {
11
12enum class MortonSwizzleMode { MortonToLinear, LinearToMorton };
13
14void MortonSwizzle(MortonSwizzleMode mode, VideoCore::Surface::PixelFormat format, u32 stride,
15 u32 block_height, u32 height, u32 block_depth, u32 depth, u32 tile_width_spacing,
16 u8* buffer, std::size_t buffer_size, VAddr addr);
17
18void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32 linear_bytes_per_pixel,
19 u8* morton_data, u8* linear_data, bool morton_to_linear);
20
21} // namespace VideoCore
diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h
index 6d41321fa..bcf0c15a4 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <set> 7#include <set>
8#include <unordered_map>
8 9
9#include <boost/icl/interval_map.hpp> 10#include <boost/icl/interval_map.hpp>
10#include <boost/range/iterator_range_core.hpp> 11#include <boost/range/iterator_range_core.hpp>
@@ -88,29 +89,25 @@ public:
88 89
89 /// Invalidates everything in the cache 90 /// Invalidates everything in the cache
90 void InvalidateAll() { 91 void InvalidateAll() {
91 while (object_cache.begin() != object_cache.end()) { 92 while (interval_cache.begin() != interval_cache.end()) {
92 Unregister(*object_cache.begin()->second.begin()); 93 Unregister(*interval_cache.begin()->second.begin());
93 } 94 }
94 } 95 }
95 96
96protected: 97protected:
97 /// Tries to get an object from the cache with the specified address 98 /// Tries to get an object from the cache with the specified address
98 T TryGet(VAddr addr) const { 99 T TryGet(VAddr addr) const {
99 const ObjectInterval interval{addr}; 100 const auto iter = map_cache.find(addr);
100 for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) { 101 if (iter != map_cache.end())
101 for (auto& cached_object : pair.second) { 102 return iter->second;
102 if (cached_object->GetAddr() == addr) {
103 return cached_object;
104 }
105 }
106 }
107 return nullptr; 103 return nullptr;
108 } 104 }
109 105
110 /// Register an object into the cache 106 /// Register an object into the cache
111 void Register(const T& object) { 107 void Register(const T& object) {
112 object->SetIsRegistered(true); 108 object->SetIsRegistered(true);
113 object_cache.add({GetInterval(object), ObjectSet{object}}); 109 interval_cache.add({GetInterval(object), ObjectSet{object}});
110 map_cache.insert({object->GetAddr(), object});
114 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1); 111 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1);
115 } 112 }
116 113
@@ -118,13 +115,13 @@ protected:
118 void Unregister(const T& object) { 115 void Unregister(const T& object) {
119 object->SetIsRegistered(false); 116 object->SetIsRegistered(false);
120 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1); 117 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1);
121
122 // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit 118 // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit
123 if (Settings::values.use_accurate_gpu_emulation) { 119 if (Settings::values.use_accurate_gpu_emulation) {
124 FlushObject(object); 120 FlushObject(object);
125 } 121 }
126 122
127 object_cache.subtract({GetInterval(object), ObjectSet{object}}); 123 interval_cache.subtract({GetInterval(object), ObjectSet{object}});
124 map_cache.erase(object->GetAddr());
128 } 125 }
129 126
130 /// Returns a ticks counter used for tracking when cached objects were last modified 127 /// Returns a ticks counter used for tracking when cached objects were last modified
@@ -141,7 +138,7 @@ private:
141 138
142 std::vector<T> objects; 139 std::vector<T> objects;
143 const ObjectInterval interval{addr, addr + size}; 140 const ObjectInterval interval{addr, addr + size};
144 for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) { 141 for (auto& pair : boost::make_iterator_range(interval_cache.equal_range(interval))) {
145 for (auto& cached_object : pair.second) { 142 for (auto& cached_object : pair.second) {
146 if (!cached_object) { 143 if (!cached_object) {
147 continue; 144 continue;
@@ -167,15 +164,17 @@ private:
167 } 164 }
168 165
169 using ObjectSet = std::set<T>; 166 using ObjectSet = std::set<T>;
170 using ObjectCache = boost::icl::interval_map<VAddr, ObjectSet>; 167 using ObjectCache = std::unordered_map<VAddr, T>;
171 using ObjectInterval = typename ObjectCache::interval_type; 168 using IntervalCache = boost::icl::interval_map<VAddr, ObjectSet>;
169 using ObjectInterval = typename IntervalCache::interval_type;
172 170
173 static auto GetInterval(const T& object) { 171 static auto GetInterval(const T& object) {
174 return ObjectInterval::right_open(object->GetAddr(), 172 return ObjectInterval::right_open(object->GetAddr(),
175 object->GetAddr() + object->GetSizeInBytes()); 173 object->GetAddr() + object->GetSizeInBytes());
176 } 174 }
177 175
178 ObjectCache object_cache; ///< Cache of objects 176 ObjectCache map_cache;
179 u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing 177 IntervalCache interval_cache; ///< Cache of objects
178 u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing
180 VideoCore::RasterizerInterface& rasterizer; 179 VideoCore::RasterizerInterface& rasterizer;
181}; 180};
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index 0df3725c2..1482cdb40 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -5,7 +5,6 @@
5#include "core/frontend/emu_window.h" 5#include "core/frontend/emu_window.h"
6#include "core/settings.h" 6#include "core/settings.h"
7#include "video_core/renderer_base.h" 7#include "video_core/renderer_base.h"
8#include "video_core/renderer_opengl/gl_rasterizer.h"
9 8
10namespace VideoCore { 9namespace VideoCore {
11 10
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index 075192c3f..46a6c0308 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -76,7 +76,7 @@ std::tuple<u8*, GLintptr> OGLBufferCache::ReserveMemory(std::size_t size, std::s
76 return std::make_tuple(uploaded_ptr, uploaded_offset); 76 return std::make_tuple(uploaded_ptr, uploaded_offset);
77} 77}
78 78
79void OGLBufferCache::Map(std::size_t max_size) { 79bool OGLBufferCache::Map(std::size_t max_size) {
80 bool invalidate; 80 bool invalidate;
81 std::tie(buffer_ptr, buffer_offset_base, invalidate) = 81 std::tie(buffer_ptr, buffer_offset_base, invalidate) =
82 stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4); 82 stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4);
@@ -85,6 +85,7 @@ void OGLBufferCache::Map(std::size_t max_size) {
85 if (invalidate) { 85 if (invalidate) {
86 InvalidateAll(); 86 InvalidateAll();
87 } 87 }
88 return invalidate;
88} 89}
89 90
90void OGLBufferCache::Unmap() { 91void OGLBufferCache::Unmap() {
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 91fca3f6c..c11acfb79 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -50,7 +50,7 @@ public:
50 /// Reserves memory to be used by host's CPU. Returns mapped address and offset. 50 /// Reserves memory to be used by host's CPU. Returns mapped address and offset.
51 std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4); 51 std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4);
52 52
53 void Map(std::size_t max_size); 53 bool Map(std::size_t max_size);
54 void Unmap(); 54 void Unmap();
55 55
56 GLuint GetHandle() const; 56 GLuint GetHandle() const;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 54cc47a9b..9e93bd609 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -88,27 +88,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
88 state.texture_units[i].sampler = texture_samplers[i].sampler.handle; 88 state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
89 } 89 }
90 90
91 GLint ext_num;
92 glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
93 for (GLint i = 0; i < ext_num; i++) {
94 const std::string_view extension{
95 reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))};
96
97 if (extension == "GL_ARB_direct_state_access") {
98 has_ARB_direct_state_access = true;
99 } else if (extension == "GL_ARB_multi_bind") {
100 has_ARB_multi_bind = true;
101 } else if (extension == "GL_ARB_separate_shader_objects") {
102 has_ARB_separate_shader_objects = true;
103 } else if (extension == "GL_ARB_vertex_attrib_binding") {
104 has_ARB_vertex_attrib_binding = true;
105 }
106 }
107
108 ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
109 OpenGLState::ApplyDefaultState(); 91 OpenGLState::ApplyDefaultState();
110 // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
111 state.clip_distance[0] = true;
112 92
113 // Create render framebuffer 93 // Create render framebuffer
114 framebuffer.Create(); 94 framebuffer.Create();
@@ -120,10 +100,24 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
120 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); 100 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
121 101
122 LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); 102 LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
103 CheckExtensions();
123} 104}
124 105
125RasterizerOpenGL::~RasterizerOpenGL() {} 106RasterizerOpenGL::~RasterizerOpenGL() {}
126 107
108void RasterizerOpenGL::CheckExtensions() {
109 if (!GLAD_GL_ARB_texture_filter_anisotropic && !GLAD_GL_EXT_texture_filter_anisotropic) {
110 LOG_WARNING(
111 Render_OpenGL,
112 "Anisotropic filter is not supported! This can cause graphical issues in some games.");
113 }
114 if (!GLAD_GL_ARB_buffer_storage) {
115 LOG_WARNING(
116 Render_OpenGL,
117 "Buffer storage control is not supported! This can cause performance degradation.");
118 }
119}
120
127void RasterizerOpenGL::SetupVertexFormat() { 121void RasterizerOpenGL::SetupVertexFormat() {
128 auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); 122 auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
129 const auto& regs = gpu.regs; 123 const auto& regs = gpu.regs;
@@ -183,15 +177,25 @@ void RasterizerOpenGL::SetupVertexFormat() {
183 } 177 }
184 state.draw.vertex_array = VAO.handle; 178 state.draw.vertex_array = VAO.handle;
185 state.ApplyVertexBufferState(); 179 state.ApplyVertexBufferState();
180
181 // Rebinding the VAO invalidates the vertex buffer bindings.
182 gpu.dirty_flags.vertex_array = 0xFFFFFFFF;
186} 183}
187 184
188void RasterizerOpenGL::SetupVertexBuffer() { 185void RasterizerOpenGL::SetupVertexBuffer() {
189 MICROPROFILE_SCOPE(OpenGL_VB); 186 auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
190 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
191 const auto& regs = gpu.regs; 187 const auto& regs = gpu.regs;
192 188
189 if (!gpu.dirty_flags.vertex_array)
190 return;
191
192 MICROPROFILE_SCOPE(OpenGL_VB);
193
193 // Upload all guest vertex arrays sequentially to our buffer 194 // Upload all guest vertex arrays sequentially to our buffer
194 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { 195 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
196 if (~gpu.dirty_flags.vertex_array & (1u << index))
197 continue;
198
195 const auto& vertex_array = regs.vertex_array[index]; 199 const auto& vertex_array = regs.vertex_array[index];
196 if (!vertex_array.IsEnabled()) 200 if (!vertex_array.IsEnabled())
197 continue; 201 continue;
@@ -218,6 +222,8 @@ void RasterizerOpenGL::SetupVertexBuffer() {
218 222
219 // Implicit set by glBindVertexBuffer. Stupid glstate handling... 223 // Implicit set by glBindVertexBuffer. Stupid glstate handling...
220 state.draw.vertex_buffer = buffer_cache.GetHandle(); 224 state.draw.vertex_buffer = buffer_cache.GetHandle();
225
226 gpu.dirty_flags.vertex_array = 0;
221} 227}
222 228
223DrawParameters RasterizerOpenGL::SetupDraw() { 229DrawParameters RasterizerOpenGL::SetupDraw() {
@@ -276,6 +282,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
276 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. 282 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
277 u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; 283 u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
278 u32 current_texture_bindpoint = 0; 284 u32 current_texture_bindpoint = 0;
285 std::array<bool, Maxwell::NumClipDistances> clip_distances{};
279 286
280 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 287 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
281 const auto& shader_config = gpu.regs.shader_config[index]; 288 const auto& shader_config = gpu.regs.shader_config[index];
@@ -336,12 +343,22 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
336 current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader, 343 current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
337 primitive_mode, current_texture_bindpoint); 344 primitive_mode, current_texture_bindpoint);
338 345
346 // Workaround for Intel drivers.
347 // When a clip distance is enabled but not set in the shader it crops parts of the screen
348 // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
349 // clip distances only when it's written by a shader stage.
350 for (std::size_t i = 0; i < Maxwell::NumClipDistances; ++i) {
351 clip_distances[i] |= shader->GetShaderEntries().clip_distances[i];
352 }
353
339 // When VertexA is enabled, we have dual vertex shaders 354 // When VertexA is enabled, we have dual vertex shaders
340 if (program == Maxwell::ShaderProgram::VertexA) { 355 if (program == Maxwell::ShaderProgram::VertexA) {
341 // VertexB was combined with VertexA, so we skip the VertexB iteration 356 // VertexB was combined with VertexA, so we skip the VertexB iteration
342 index++; 357 index++;
343 } 358 }
344 } 359 }
360
361 SyncClipEnabled(clip_distances);
345} 362}
346 363
347std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { 364std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
@@ -424,7 +441,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
424 // TODO(bunnei): Figure out how the below register works. According to envytools, this should be 441 // TODO(bunnei): Figure out how the below register works. According to envytools, this should be
425 // used to enable multiple render targets. However, it is left unset on all games that I have 442 // used to enable multiple render targets. However, it is left unset on all games that I have
426 // tested. 443 // tested.
427 ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); 444 UNIMPLEMENTED_IF(regs.rt_separate_frag_data != 0);
428 445
429 // Bind the framebuffer surfaces 446 // Bind the framebuffer surfaces
430 current_state.draw.draw_framebuffer = framebuffer.handle; 447 current_state.draw.draw_framebuffer = framebuffer.handle;
@@ -544,6 +561,30 @@ void RasterizerOpenGL::Clear() {
544 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); 561 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
545 use_stencil = true; 562 use_stencil = true;
546 clear_state.stencil.test_enabled = true; 563 clear_state.stencil.test_enabled = true;
564 if (regs.clear_flags.stencil) {
565 // Stencil affects the clear so fill it with the used masks
566 clear_state.stencil.front.test_func = GL_ALWAYS;
567 clear_state.stencil.front.test_mask = regs.stencil_front_func_mask;
568 clear_state.stencil.front.action_stencil_fail = GL_KEEP;
569 clear_state.stencil.front.action_depth_fail = GL_KEEP;
570 clear_state.stencil.front.action_depth_pass = GL_KEEP;
571 clear_state.stencil.front.write_mask = regs.stencil_front_mask;
572 if (regs.stencil_two_side_enable) {
573 clear_state.stencil.back.test_func = GL_ALWAYS;
574 clear_state.stencil.back.test_mask = regs.stencil_back_func_mask;
575 clear_state.stencil.back.action_stencil_fail = GL_KEEP;
576 clear_state.stencil.back.action_depth_fail = GL_KEEP;
577 clear_state.stencil.back.action_depth_pass = GL_KEEP;
578 clear_state.stencil.back.write_mask = regs.stencil_back_mask;
579 } else {
580 clear_state.stencil.back.test_func = GL_ALWAYS;
581 clear_state.stencil.back.test_mask = 0xFFFFFFFF;
582 clear_state.stencil.back.write_mask = 0xFFFFFFFF;
583 clear_state.stencil.back.action_stencil_fail = GL_KEEP;
584 clear_state.stencil.back.action_depth_fail = GL_KEEP;
585 clear_state.stencil.back.action_depth_pass = GL_KEEP;
586 }
587 }
547 } 588 }
548 589
549 if (!use_color && !use_depth && !use_stencil) { 590 if (!use_color && !use_depth && !use_stencil) {
@@ -555,6 +596,14 @@ void RasterizerOpenGL::Clear() {
555 596
556 ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, 597 ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
557 regs.clear_buffers.RT.Value()); 598 regs.clear_buffers.RT.Value());
599 if (regs.clear_flags.scissor) {
600 SyncScissorTest(clear_state);
601 }
602
603 if (regs.clear_flags.viewport) {
604 clear_state.EmulateViewportWithScissor();
605 }
606
558 clear_state.Apply(); 607 clear_state.Apply();
559 608
560 if (use_color) { 609 if (use_color) {
@@ -575,25 +624,27 @@ void RasterizerOpenGL::DrawArrays() {
575 return; 624 return;
576 625
577 MICROPROFILE_SCOPE(OpenGL_Drawing); 626 MICROPROFILE_SCOPE(OpenGL_Drawing);
578 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); 627 auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
579 const auto& regs = gpu.regs; 628 const auto& regs = gpu.regs;
580 629
581 ScopeAcquireGLContext acquire_context{emu_window}; 630 ScopeAcquireGLContext acquire_context{emu_window};
582 631
583 ConfigureFramebuffers(state); 632 ConfigureFramebuffers(state);
584 SyncColorMask(); 633 SyncColorMask();
634 SyncFragmentColorClampState();
635 SyncMultiSampleState();
585 SyncDepthTestState(); 636 SyncDepthTestState();
586 SyncStencilTestState(); 637 SyncStencilTestState();
587 SyncBlendState(); 638 SyncBlendState();
588 SyncLogicOpState(); 639 SyncLogicOpState();
589 SyncCullMode(); 640 SyncCullMode();
590 SyncPrimitiveRestart(); 641 SyncPrimitiveRestart();
591 SyncScissorTest(); 642 SyncScissorTest(state);
592 // Alpha Testing is synced on shaders. 643 // Alpha Testing is synced on shaders.
593 SyncTransformFeedback(); 644 SyncTransformFeedback();
594 SyncPointState(); 645 SyncPointState();
595 CheckAlphaTests(); 646 CheckAlphaTests();
596 647 SyncPolygonOffset();
597 // TODO(bunnei): Sync framebuffer_scale uniform here 648 // TODO(bunnei): Sync framebuffer_scale uniform here
598 // TODO(bunnei): Sync scissorbox uniform(s) here 649 // TODO(bunnei): Sync scissorbox uniform(s) here
599 650
@@ -626,7 +677,11 @@ void RasterizerOpenGL::DrawArrays() {
626 // Add space for at least 18 constant buffers 677 // Add space for at least 18 constant buffers
627 buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment); 678 buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment);
628 679
629 buffer_cache.Map(buffer_size); 680 bool invalidate = buffer_cache.Map(buffer_size);
681 if (invalidate) {
682 // As all cached buffers are invalidated, we need to recheck their state.
683 gpu.dirty_flags.vertex_array = 0xFFFFFFFF;
684 }
630 685
631 SetupVertexFormat(); 686 SetupVertexFormat();
632 SetupVertexBuffer(); 687 SetupVertexBuffer();
@@ -642,7 +697,7 @@ void RasterizerOpenGL::DrawArrays() {
642 params.DispatchDraw(); 697 params.DispatchDraw();
643 698
644 // Disable scissor test 699 // Disable scissor test
645 state.scissor.enabled = false; 700 state.viewports[0].scissor.enabled = false;
646 701
647 accelerate_draw = AccelDraw::Disabled; 702 accelerate_draw = AccelDraw::Disabled;
648 703
@@ -733,9 +788,8 @@ void RasterizerOpenGL::SamplerInfo::Create() {
733 glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); 788 glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
734} 789}
735 790
736void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTextureInfo& info) { 791void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) {
737 const GLuint s = sampler.handle; 792 const GLuint s = sampler.handle;
738 const Tegra::Texture::TSCEntry& config = info.tsc;
739 if (mag_filter != config.mag_filter) { 793 if (mag_filter != config.mag_filter) {
740 mag_filter = config.mag_filter; 794 mag_filter = config.mag_filter;
741 glSamplerParameteri( 795 glSamplerParameteri(
@@ -777,30 +831,50 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTex
777 MaxwellToGL::DepthCompareFunc(depth_compare_func)); 831 MaxwellToGL::DepthCompareFunc(depth_compare_func));
778 } 832 }
779 833
780 if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border || 834 GLvec4 new_border_color;
781 wrap_p == Tegra::Texture::WrapMode::Border) { 835 if (config.srgb_conversion) {
782 const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, 836 new_border_color[0] = config.srgb_border_color_r / 255.0f;
783 config.border_color_b, config.border_color_a}}; 837 new_border_color[1] = config.srgb_border_color_g / 255.0f;
784 if (border_color != new_border_color) { 838 new_border_color[2] = config.srgb_border_color_g / 255.0f;
785 border_color = new_border_color; 839 } else {
786 glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); 840 new_border_color[0] = config.border_color_r;
787 } 841 new_border_color[1] = config.border_color_g;
842 new_border_color[2] = config.border_color_b;
788 } 843 }
789 if (info.tic.use_header_opt_control == 0) { 844 new_border_color[3] = config.border_color_a;
845
846 if (border_color != new_border_color) {
847 border_color = new_border_color;
848 glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data());
849 }
850
851 const float anisotropic_max = static_cast<float>(1 << config.max_anisotropy.Value());
852 if (anisotropic_max != max_anisotropic) {
853 max_anisotropic = anisotropic_max;
790 if (GLAD_GL_ARB_texture_filter_anisotropic) { 854 if (GLAD_GL_ARB_texture_filter_anisotropic) {
791 glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, 855 glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, max_anisotropic);
792 static_cast<float>(1 << info.tic.max_anisotropy.Value()));
793 } else if (GLAD_GL_EXT_texture_filter_anisotropic) { 856 } else if (GLAD_GL_EXT_texture_filter_anisotropic) {
794 glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, 857 glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropic);
795 static_cast<float>(1 << info.tic.max_anisotropy.Value()));
796 } 858 }
797 glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, 859 }
798 static_cast<float>(info.tic.res_min_mip_level.Value())); 860 const float lod_min = static_cast<float>(config.min_lod_clamp.Value()) / 256.0f;
799 glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, 861 if (lod_min != min_lod) {
800 static_cast<float>(info.tic.res_max_mip_level.Value() == 0 862 min_lod = lod_min;
801 ? 16 863 glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, min_lod);
802 : info.tic.res_max_mip_level.Value())); 864 }
803 glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, info.tic.mip_lod_bias.Value() / 256.f); 865
866 const float lod_max = static_cast<float>(config.max_lod_clamp.Value()) / 256.0f;
867 if (lod_max != max_lod) {
868 max_lod = lod_max;
869 glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, max_lod);
870 }
871 const u32 bias = config.mip_lod_bias.Value();
872 // Sign extend the 13-bit value.
873 constexpr u32 mask = 1U << (13 - 1);
874 const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f;
875 if (lod_bias != bias_lod) {
876 lod_bias = bias_lod;
877 glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, lod_bias);
804 } 878 }
805} 879}
806 880
@@ -899,7 +973,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
899 continue; 973 continue;
900 } 974 }
901 975
902 texture_samplers[current_bindpoint].SyncWithConfig(texture); 976 texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
903 Surface surface = res_cache.GetTextureSurface(texture, entry); 977 Surface surface = res_cache.GetTextureSurface(texture, entry);
904 if (surface != nullptr) { 978 if (surface != nullptr) {
905 state.texture_units[current_bindpoint].texture = surface->Texture().handle; 979 state.texture_units[current_bindpoint].texture = surface->Texture().handle;
@@ -923,24 +997,42 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
923 997
924void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { 998void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
925 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 999 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
926 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 1000 const bool geometry_shaders_enabled =
927 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; 1001 regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry));
1002 const std::size_t viewport_count =
1003 geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1;
1004 for (std::size_t i = 0; i < viewport_count; i++) {
928 auto& viewport = current_state.viewports[i]; 1005 auto& viewport = current_state.viewports[i];
1006 const auto& src = regs.viewports[i];
1007 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
929 viewport.x = viewport_rect.left; 1008 viewport.x = viewport_rect.left;
930 viewport.y = viewport_rect.bottom; 1009 viewport.y = viewport_rect.bottom;
931 viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth()); 1010 viewport.width = viewport_rect.GetWidth();
932 viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight()); 1011 viewport.height = viewport_rect.GetHeight();
933 viewport.depth_range_far = regs.viewport[i].depth_range_far; 1012 viewport.depth_range_far = regs.viewports[i].depth_range_far;
934 viewport.depth_range_near = regs.viewport[i].depth_range_near; 1013 viewport.depth_range_near = regs.viewports[i].depth_range_near;
935 } 1014 }
1015 state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0;
1016 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
936} 1017}
937 1018
938void RasterizerOpenGL::SyncClipEnabled() { 1019void RasterizerOpenGL::SyncClipEnabled(
939 UNREACHABLE(); 1020 const std::array<bool, Maxwell::Regs::NumClipDistances>& clip_mask) {
1021
1022 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1023 const std::array<bool, Maxwell::Regs::NumClipDistances> reg_state{
1024 regs.clip_distance_enabled.c0 != 0, regs.clip_distance_enabled.c1 != 0,
1025 regs.clip_distance_enabled.c2 != 0, regs.clip_distance_enabled.c3 != 0,
1026 regs.clip_distance_enabled.c4 != 0, regs.clip_distance_enabled.c5 != 0,
1027 regs.clip_distance_enabled.c6 != 0, regs.clip_distance_enabled.c7 != 0};
1028
1029 for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) {
1030 state.clip_distance[i] = reg_state[i] && clip_mask[i];
1031 }
940} 1032}
941 1033
942void RasterizerOpenGL::SyncClipCoef() { 1034void RasterizerOpenGL::SyncClipCoef() {
943 UNREACHABLE(); 1035 UNIMPLEMENTED();
944} 1036}
945 1037
946void RasterizerOpenGL::SyncCullMode() { 1038void RasterizerOpenGL::SyncCullMode() {
@@ -1022,7 +1114,9 @@ void RasterizerOpenGL::SyncStencilTestState() {
1022 1114
1023void RasterizerOpenGL::SyncColorMask() { 1115void RasterizerOpenGL::SyncColorMask() {
1024 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1116 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1025 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 1117 const std::size_t count =
1118 regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1;
1119 for (std::size_t i = 0; i < count; i++) {
1026 const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i]; 1120 const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i];
1027 auto& dest = state.color_mask[i]; 1121 auto& dest = state.color_mask[i];
1028 dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE; 1122 dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE;
@@ -1032,6 +1126,17 @@ void RasterizerOpenGL::SyncColorMask() {
1032 } 1126 }
1033} 1127}
1034 1128
1129void RasterizerOpenGL::SyncMultiSampleState() {
1130 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1131 state.multisample_control.alpha_to_coverage = regs.multisample_control.alpha_to_coverage != 0;
1132 state.multisample_control.alpha_to_one = regs.multisample_control.alpha_to_one != 0;
1133}
1134
1135void RasterizerOpenGL::SyncFragmentColorClampState() {
1136 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1137 state.fragment_color_clamp.enabled = regs.frag_color_clamp != 0;
1138}
1139
1035void RasterizerOpenGL::SyncBlendState() { 1140void RasterizerOpenGL::SyncBlendState() {
1036 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1141 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1037 1142
@@ -1043,43 +1148,40 @@ void RasterizerOpenGL::SyncBlendState() {
1043 state.independant_blend.enabled = regs.independent_blend_enable; 1148 state.independant_blend.enabled = regs.independent_blend_enable;
1044 if (!state.independant_blend.enabled) { 1149 if (!state.independant_blend.enabled) {
1045 auto& blend = state.blend[0]; 1150 auto& blend = state.blend[0];
1046 blend.enabled = regs.blend.enable[0] != 0; 1151 const auto& src = regs.blend;
1047 blend.separate_alpha = regs.blend.separate_alpha; 1152 blend.enabled = src.enable[0] != 0;
1048 blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb); 1153 if (blend.enabled) {
1049 blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb); 1154 blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb);
1050 blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb); 1155 blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb);
1051 if (blend.separate_alpha) { 1156 blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb);
1052 blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a); 1157 blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a);
1053 blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a); 1158 blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a);
1054 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a); 1159 blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a);
1055 } 1160 }
1056 for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 1161 for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1057 state.blend[i].enabled = false; 1162 state.blend[i].enabled = false;
1058 } 1163 }
1059 return; 1164 return;
1060 } 1165 }
1061 1166
1062 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 1167 for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1063 auto& blend = state.blend[i]; 1168 auto& blend = state.blend[i];
1169 const auto& src = regs.independent_blend[i];
1064 blend.enabled = regs.blend.enable[i] != 0; 1170 blend.enabled = regs.blend.enable[i] != 0;
1065 if (!blend.enabled) 1171 if (!blend.enabled)
1066 continue; 1172 continue;
1067 blend.separate_alpha = regs.independent_blend[i].separate_alpha; 1173 blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb);
1068 blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb); 1174 blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb);
1069 blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb); 1175 blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb);
1070 blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb); 1176 blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a);
1071 if (blend.separate_alpha) { 1177 blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a);
1072 blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a); 1178 blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a);
1073 blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_a);
1074 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_a);
1075 }
1076 } 1179 }
1077} 1180}
1078 1181
1079void RasterizerOpenGL::SyncLogicOpState() { 1182void RasterizerOpenGL::SyncLogicOpState() {
1080 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1183 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1081 1184
1082 // TODO(Subv): Support more than just render target 0.
1083 state.logic_op.enabled = regs.logic_op.enable != 0; 1185 state.logic_op.enabled = regs.logic_op.enable != 0;
1084 1186
1085 if (!state.logic_op.enabled) 1187 if (!state.logic_op.enabled)
@@ -1091,20 +1193,26 @@ void RasterizerOpenGL::SyncLogicOpState() {
1091 state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); 1193 state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
1092} 1194}
1093 1195
1094void RasterizerOpenGL::SyncScissorTest() { 1196void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
1095 // TODO: what is the correct behavior here, a single scissor for all targets
1096 // or scissor disabled for the rest of the targets?
1097 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1197 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1098 state.scissor.enabled = (regs.scissor_test.enable != 0); 1198 const bool geometry_shaders_enabled =
1099 if (regs.scissor_test.enable == 0) { 1199 regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry));
1100 return; 1200 const std::size_t viewport_count =
1201 geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1;
1202 for (std::size_t i = 0; i < viewport_count; i++) {
1203 const auto& src = regs.scissor_test[i];
1204 auto& dst = current_state.viewports[i].scissor;
1205 dst.enabled = (src.enable != 0);
1206 if (dst.enabled == 0) {
1207 return;
1208 }
1209 const u32 width = src.max_x - src.min_x;
1210 const u32 height = src.max_y - src.min_y;
1211 dst.x = src.min_x;
1212 dst.y = src.min_y;
1213 dst.width = width;
1214 dst.height = height;
1101 } 1215 }
1102 const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
1103 const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
1104 state.scissor.x = regs.scissor_test.min_x;
1105 state.scissor.y = regs.scissor_test.min_y;
1106 state.scissor.width = width;
1107 state.scissor.height = height;
1108} 1216}
1109 1217
1110void RasterizerOpenGL::SyncTransformFeedback() { 1218void RasterizerOpenGL::SyncTransformFeedback() {
@@ -1118,11 +1226,17 @@ void RasterizerOpenGL::SyncTransformFeedback() {
1118 1226
1119void RasterizerOpenGL::SyncPointState() { 1227void RasterizerOpenGL::SyncPointState() {
1120 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1228 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1229 state.point.size = regs.point_size;
1230}
1121 1231
1122 // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a 1232void RasterizerOpenGL::SyncPolygonOffset() {
1123 // register carrying a default value. For now, if the point size is zero, assume it's 1233 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1124 // OpenGL's default (1). 1234 state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0;
1125 state.point.size = regs.point_size == 0 ? 1 : regs.point_size; 1235 state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0;
1236 state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0;
1237 state.polygon_offset.units = regs.polygon_offset_units;
1238 state.polygon_offset.factor = regs.polygon_offset_factor;
1239 state.polygon_offset.clamp = regs.polygon_offset_clamp;
1126} 1240}
1127 1241
1128void RasterizerOpenGL::CheckAlphaTests() { 1242void RasterizerOpenGL::CheckAlphaTests() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 8ef0f6c12..988fa3e27 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -60,20 +60,6 @@ public:
60 bool AccelerateDrawBatch(bool is_indexed) override; 60 bool AccelerateDrawBatch(bool is_indexed) override;
61 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) override; 61 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) override;
62 62
63 /// OpenGL shader generated for a given Maxwell register state
64 struct MaxwellShader {
65 /// OpenGL shader resource
66 OGLProgram shader;
67 };
68
69 struct VertexShader {
70 OGLShader shader;
71 };
72
73 struct FragmentShader {
74 OGLShader shader;
75 };
76
77 /// Maximum supported size that a constbuffer can have in bytes. 63 /// Maximum supported size that a constbuffer can have in bytes.
78 static constexpr std::size_t MaxConstbufferSize = 0x10000; 64 static constexpr std::size_t MaxConstbufferSize = 0x10000;
79 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, 65 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0,
@@ -88,18 +74,23 @@ private:
88 /// SamplerInfo struct. 74 /// SamplerInfo struct.
89 void Create(); 75 void Create();
90 /// Syncs the sampler object with the config, updating any necessary state. 76 /// Syncs the sampler object with the config, updating any necessary state.
91 void SyncWithConfig(const Tegra::Texture::FullTextureInfo& info); 77 void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
92 78
93 private: 79 private:
94 Tegra::Texture::TextureFilter mag_filter; 80 Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest;
95 Tegra::Texture::TextureFilter min_filter; 81 Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest;
96 Tegra::Texture::TextureMipmapFilter mip_filter; 82 Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None;
97 Tegra::Texture::WrapMode wrap_u; 83 Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge;
98 Tegra::Texture::WrapMode wrap_v; 84 Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge;
99 Tegra::Texture::WrapMode wrap_p; 85 Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge;
100 bool uses_depth_compare; 86 bool uses_depth_compare = false;
101 Tegra::Texture::DepthCompareFunc depth_compare_func; 87 Tegra::Texture::DepthCompareFunc depth_compare_func =
102 GLvec4 border_color; 88 Tegra::Texture::DepthCompareFunc::Always;
89 GLvec4 border_color = {};
90 float min_lod = 0.0f;
91 float max_lod = 16.0f;
92 float lod_bias = 0.0f;
93 float max_anisotropic = 1.0f;
103 }; 94 };
104 95
105 /** 96 /**
@@ -137,7 +128,8 @@ private:
137 void SyncViewport(OpenGLState& current_state); 128 void SyncViewport(OpenGLState& current_state);
138 129
139 /// Syncs the clip enabled status to match the guest state 130 /// Syncs the clip enabled status to match the guest state
140 void SyncClipEnabled(); 131 void SyncClipEnabled(
132 const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& clip_mask);
141 133
142 /// Syncs the clip coefficients to match the guest state 134 /// Syncs the clip coefficients to match the guest state
143 void SyncClipCoef(); 135 void SyncClipCoef();
@@ -160,8 +152,14 @@ private:
160 /// Syncs the LogicOp state to match the guest state 152 /// Syncs the LogicOp state to match the guest state
161 void SyncLogicOpState(); 153 void SyncLogicOpState();
162 154
155 /// Syncs the the color clamp state
156 void SyncFragmentColorClampState();
157
158 /// Syncs the alpha coverage and alpha to one
159 void SyncMultiSampleState();
160
163 /// Syncs the scissor test state to match the guest state 161 /// Syncs the scissor test state to match the guest state
164 void SyncScissorTest(); 162 void SyncScissorTest(OpenGLState& current_state);
165 163
166 /// Syncs the transform feedback state to match the guest state 164 /// Syncs the transform feedback state to match the guest state
167 void SyncTransformFeedback(); 165 void SyncTransformFeedback();
@@ -172,13 +170,15 @@ private:
172 /// Syncs Color Mask 170 /// Syncs Color Mask
173 void SyncColorMask(); 171 void SyncColorMask();
174 172
173 /// Syncs the polygon offsets
174 void SyncPolygonOffset();
175
175 /// Check asserts for alpha testing. 176 /// Check asserts for alpha testing.
176 void CheckAlphaTests(); 177 void CheckAlphaTests();
177 178
178 bool has_ARB_direct_state_access = false; 179 /// Check for extension that are not strictly required
179 bool has_ARB_multi_bind = false; 180 /// but are needed for correct emulation
180 bool has_ARB_separate_shader_objects = false; 181 void CheckExtensions();
181 bool has_ARB_vertex_attrib_binding = false;
182 182
183 OpenGLState state; 183 OpenGLState state;
184 184
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 894f4f294..5f4cdd119 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -15,6 +15,7 @@
15#include "core/memory.h" 15#include "core/memory.h"
16#include "core/settings.h" 16#include "core/settings.h"
17#include "video_core/engines/maxwell_3d.h" 17#include "video_core/engines/maxwell_3d.h"
18#include "video_core/morton.h"
18#include "video_core/renderer_opengl/gl_rasterizer.h" 19#include "video_core/renderer_opengl/gl_rasterizer.h"
19#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 20#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
20#include "video_core/renderer_opengl/gl_state.h" 21#include "video_core/renderer_opengl/gl_state.h"
@@ -22,10 +23,11 @@
22#include "video_core/surface.h" 23#include "video_core/surface.h"
23#include "video_core/textures/astc.h" 24#include "video_core/textures/astc.h"
24#include "video_core/textures/decoders.h" 25#include "video_core/textures/decoders.h"
25#include "video_core/utils.h"
26 26
27namespace OpenGL { 27namespace OpenGL {
28 28
29using VideoCore::MortonSwizzle;
30using VideoCore::MortonSwizzleMode;
29using VideoCore::Surface::ComponentTypeFromDepthFormat; 31using VideoCore::Surface::ComponentTypeFromDepthFormat;
30using VideoCore::Surface::ComponentTypeFromRenderTarget; 32using VideoCore::Surface::ComponentTypeFromRenderTarget;
31using VideoCore::Surface::ComponentTypeFromTexture; 33using VideoCore::Surface::ComponentTypeFromTexture;
@@ -95,6 +97,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
95 params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, 97 params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0,
96 params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, 98 params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0,
97 params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, 99 params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0,
100 params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1;
98 params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); 101 params.srgb_conversion = config.tic.IsSrgbConversionEnabled();
99 params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), 102 params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(),
100 params.srgb_conversion); 103 params.srgb_conversion);
@@ -160,6 +163,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
160 params.block_width = 1 << config.memory_layout.block_width; 163 params.block_width = 1 << config.memory_layout.block_width;
161 params.block_height = 1 << config.memory_layout.block_height; 164 params.block_height = 1 << config.memory_layout.block_height;
162 params.block_depth = 1 << config.memory_layout.block_depth; 165 params.block_depth = 1 << config.memory_layout.block_depth;
166 params.tile_width_spacing = 1;
163 params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); 167 params.pixel_format = PixelFormatFromRenderTargetFormat(config.format);
164 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || 168 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB ||
165 config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; 169 config.format == Tegra::RenderTargetFormat::RGBA8_SRGB;
@@ -195,6 +199,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
195 params.block_width = 1 << std::min(block_width, 5U); 199 params.block_width = 1 << std::min(block_width, 5U);
196 params.block_height = 1 << std::min(block_height, 5U); 200 params.block_height = 1 << std::min(block_height, 5U);
197 params.block_depth = 1 << std::min(block_depth, 5U); 201 params.block_depth = 1 << std::min(block_depth, 5U);
202 params.tile_width_spacing = 1;
198 params.pixel_format = PixelFormatFromDepthFormat(format); 203 params.pixel_format = PixelFormatFromDepthFormat(format);
199 params.component_type = ComponentTypeFromDepthFormat(format); 204 params.component_type = ComponentTypeFromDepthFormat(format);
200 params.type = GetFormatType(params.pixel_format); 205 params.type = GetFormatType(params.pixel_format);
@@ -221,6 +226,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
221 params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0, 226 params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0,
222 params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, 227 params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0,
223 params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0, 228 params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0,
229 params.tile_width_spacing = 1;
224 params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); 230 params.pixel_format = PixelFormatFromRenderTargetFormat(config.format);
225 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || 231 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB ||
226 config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; 232 config.format == Tegra::RenderTargetFormat::RGBA8_SRGB;
@@ -265,11 +271,11 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
265 {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 271 {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
266 true}, // DXN2UNORM 272 true}, // DXN2UNORM
267 {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM 273 {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM
268 {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 274 {GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
269 true}, // BC7U 275 true}, // BC7U
270 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, 276 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
271 ComponentType::Float, true}, // BC6H_UF16 277 true}, // BC6H_UF16
272 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float, 278 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
273 true}, // BC6H_SF16 279 true}, // BC6H_SF16
274 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 280 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
275 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U 281 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
@@ -306,14 +312,16 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
306 true}, // DXT23_SRGB 312 true}, // DXT23_SRGB
307 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 313 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
308 true}, // DXT45_SRGB 314 true}, // DXT45_SRGB
309 {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 315 {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
310 ComponentType::UNorm, true}, // BC7U_SRGB 316 true}, // BC7U_SRGB
311 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB 317 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB
312 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB 318 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
313 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB 319 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
314 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB 320 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB
315 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5 321 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5
316 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB 322 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB
323 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8
324 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8_SRGB
317 325
318 // Depth formats 326 // Depth formats
319 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F 327 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
@@ -344,7 +352,7 @@ static GLenum SurfaceTargetToGL(SurfaceTarget target) {
344 case SurfaceTarget::TextureCubemap: 352 case SurfaceTarget::TextureCubemap:
345 return GL_TEXTURE_CUBE_MAP; 353 return GL_TEXTURE_CUBE_MAP;
346 case SurfaceTarget::TextureCubeArray: 354 case SurfaceTarget::TextureCubeArray:
347 return GL_TEXTURE_CUBE_MAP_ARRAY_ARB; 355 return GL_TEXTURE_CUBE_MAP_ARRAY;
348 } 356 }
349 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); 357 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
350 UNREACHABLE(); 358 UNREACHABLE();
@@ -368,173 +376,7 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
368 return {0, actual_height, MipWidth(mip_level), 0}; 376 return {0, actual_height, MipWidth(mip_level), 0};
369} 377}
370 378
371template <bool morton_to_gl, PixelFormat format> 379void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params,
372void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
373 std::size_t gl_buffer_size, VAddr addr) {
374 constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
375
376 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
377 // pixel values.
378 const u32 tile_size_x{GetDefaultBlockWidth(format)};
379 const u32 tile_size_y{GetDefaultBlockHeight(format)};
380
381 if (morton_to_gl) {
382 const std::vector<u8> data =
383 Tegra::Texture::UnswizzleTexture(addr, tile_size_x, tile_size_y, bytes_per_pixel,
384 stride, height, depth, block_height, block_depth);
385 const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())};
386 memcpy(gl_buffer, data.data(), size_to_copy);
387 } else {
388 Tegra::Texture::CopySwizzledData((stride + tile_size_x - 1) / tile_size_x,
389 (height + tile_size_y - 1) / tile_size_y, depth,
390 bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr),
391 gl_buffer, false, block_height, block_depth);
392 }
393}
394
395using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
396 VideoCore::Surface::MaxPixelFormat>;
397
398static constexpr GLConversionArray morton_to_gl_fns = {
399 // clang-format off
400 MortonCopy<true, PixelFormat::ABGR8U>,
401 MortonCopy<true, PixelFormat::ABGR8S>,
402 MortonCopy<true, PixelFormat::ABGR8UI>,
403 MortonCopy<true, PixelFormat::B5G6R5U>,
404 MortonCopy<true, PixelFormat::A2B10G10R10U>,
405 MortonCopy<true, PixelFormat::A1B5G5R5U>,
406 MortonCopy<true, PixelFormat::R8U>,
407 MortonCopy<true, PixelFormat::R8UI>,
408 MortonCopy<true, PixelFormat::RGBA16F>,
409 MortonCopy<true, PixelFormat::RGBA16U>,
410 MortonCopy<true, PixelFormat::RGBA16UI>,
411 MortonCopy<true, PixelFormat::R11FG11FB10F>,
412 MortonCopy<true, PixelFormat::RGBA32UI>,
413 MortonCopy<true, PixelFormat::DXT1>,
414 MortonCopy<true, PixelFormat::DXT23>,
415 MortonCopy<true, PixelFormat::DXT45>,
416 MortonCopy<true, PixelFormat::DXN1>,
417 MortonCopy<true, PixelFormat::DXN2UNORM>,
418 MortonCopy<true, PixelFormat::DXN2SNORM>,
419 MortonCopy<true, PixelFormat::BC7U>,
420 MortonCopy<true, PixelFormat::BC6H_UF16>,
421 MortonCopy<true, PixelFormat::BC6H_SF16>,
422 MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
423 MortonCopy<true, PixelFormat::G8R8U>,
424 MortonCopy<true, PixelFormat::G8R8S>,
425 MortonCopy<true, PixelFormat::BGRA8>,
426 MortonCopy<true, PixelFormat::RGBA32F>,
427 MortonCopy<true, PixelFormat::RG32F>,
428 MortonCopy<true, PixelFormat::R32F>,
429 MortonCopy<true, PixelFormat::R16F>,
430 MortonCopy<true, PixelFormat::R16U>,
431 MortonCopy<true, PixelFormat::R16S>,
432 MortonCopy<true, PixelFormat::R16UI>,
433 MortonCopy<true, PixelFormat::R16I>,
434 MortonCopy<true, PixelFormat::RG16>,
435 MortonCopy<true, PixelFormat::RG16F>,
436 MortonCopy<true, PixelFormat::RG16UI>,
437 MortonCopy<true, PixelFormat::RG16I>,
438 MortonCopy<true, PixelFormat::RG16S>,
439 MortonCopy<true, PixelFormat::RGB32F>,
440 MortonCopy<true, PixelFormat::RGBA8_SRGB>,
441 MortonCopy<true, PixelFormat::RG8U>,
442 MortonCopy<true, PixelFormat::RG8S>,
443 MortonCopy<true, PixelFormat::RG32UI>,
444 MortonCopy<true, PixelFormat::R32UI>,
445 MortonCopy<true, PixelFormat::ASTC_2D_8X8>,
446 MortonCopy<true, PixelFormat::ASTC_2D_8X5>,
447 MortonCopy<true, PixelFormat::ASTC_2D_5X4>,
448 MortonCopy<true, PixelFormat::BGRA8_SRGB>,
449 MortonCopy<true, PixelFormat::DXT1_SRGB>,
450 MortonCopy<true, PixelFormat::DXT23_SRGB>,
451 MortonCopy<true, PixelFormat::DXT45_SRGB>,
452 MortonCopy<true, PixelFormat::BC7U_SRGB>,
453 MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>,
454 MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>,
455 MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>,
456 MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>,
457 MortonCopy<true, PixelFormat::ASTC_2D_5X5>,
458 MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
459 MortonCopy<true, PixelFormat::Z32F>,
460 MortonCopy<true, PixelFormat::Z16>,
461 MortonCopy<true, PixelFormat::Z24S8>,
462 MortonCopy<true, PixelFormat::S8Z24>,
463 MortonCopy<true, PixelFormat::Z32FS8>,
464 // clang-format on
465};
466
467static constexpr GLConversionArray gl_to_morton_fns = {
468 // clang-format off
469 MortonCopy<false, PixelFormat::ABGR8U>,
470 MortonCopy<false, PixelFormat::ABGR8S>,
471 MortonCopy<false, PixelFormat::ABGR8UI>,
472 MortonCopy<false, PixelFormat::B5G6R5U>,
473 MortonCopy<false, PixelFormat::A2B10G10R10U>,
474 MortonCopy<false, PixelFormat::A1B5G5R5U>,
475 MortonCopy<false, PixelFormat::R8U>,
476 MortonCopy<false, PixelFormat::R8UI>,
477 MortonCopy<false, PixelFormat::RGBA16F>,
478 MortonCopy<false, PixelFormat::RGBA16U>,
479 MortonCopy<false, PixelFormat::RGBA16UI>,
480 MortonCopy<false, PixelFormat::R11FG11FB10F>,
481 MortonCopy<false, PixelFormat::RGBA32UI>,
482 MortonCopy<false, PixelFormat::DXT1>,
483 MortonCopy<false, PixelFormat::DXT23>,
484 MortonCopy<false, PixelFormat::DXT45>,
485 MortonCopy<false, PixelFormat::DXN1>,
486 MortonCopy<false, PixelFormat::DXN2UNORM>,
487 MortonCopy<false, PixelFormat::DXN2SNORM>,
488 MortonCopy<false, PixelFormat::BC7U>,
489 MortonCopy<false, PixelFormat::BC6H_UF16>,
490 MortonCopy<false, PixelFormat::BC6H_SF16>,
491 // TODO(Subv): Swizzling ASTC formats are not supported
492 nullptr,
493 MortonCopy<false, PixelFormat::G8R8U>,
494 MortonCopy<false, PixelFormat::G8R8S>,
495 MortonCopy<false, PixelFormat::BGRA8>,
496 MortonCopy<false, PixelFormat::RGBA32F>,
497 MortonCopy<false, PixelFormat::RG32F>,
498 MortonCopy<false, PixelFormat::R32F>,
499 MortonCopy<false, PixelFormat::R16F>,
500 MortonCopy<false, PixelFormat::R16U>,
501 MortonCopy<false, PixelFormat::R16S>,
502 MortonCopy<false, PixelFormat::R16UI>,
503 MortonCopy<false, PixelFormat::R16I>,
504 MortonCopy<false, PixelFormat::RG16>,
505 MortonCopy<false, PixelFormat::RG16F>,
506 MortonCopy<false, PixelFormat::RG16UI>,
507 MortonCopy<false, PixelFormat::RG16I>,
508 MortonCopy<false, PixelFormat::RG16S>,
509 MortonCopy<false, PixelFormat::RGB32F>,
510 MortonCopy<false, PixelFormat::RGBA8_SRGB>,
511 MortonCopy<false, PixelFormat::RG8U>,
512 MortonCopy<false, PixelFormat::RG8S>,
513 MortonCopy<false, PixelFormat::RG32UI>,
514 MortonCopy<false, PixelFormat::R32UI>,
515 nullptr,
516 nullptr,
517 nullptr,
518 MortonCopy<false, PixelFormat::BGRA8_SRGB>,
519 MortonCopy<false, PixelFormat::DXT1_SRGB>,
520 MortonCopy<false, PixelFormat::DXT23_SRGB>,
521 MortonCopy<false, PixelFormat::DXT45_SRGB>,
522 MortonCopy<false, PixelFormat::BC7U_SRGB>,
523 nullptr,
524 nullptr,
525 nullptr,
526 nullptr,
527 nullptr,
528 nullptr,
529 MortonCopy<false, PixelFormat::Z32F>,
530 MortonCopy<false, PixelFormat::Z16>,
531 MortonCopy<false, PixelFormat::Z24S8>,
532 MortonCopy<false, PixelFormat::S8Z24>,
533 MortonCopy<false, PixelFormat::Z32FS8>,
534 // clang-format on
535};
536
537void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
538 std::vector<u8>& gl_buffer, u32 mip_level) { 380 std::vector<u8>& gl_buffer, u32 mip_level) {
539 u32 depth = params.MipDepth(mip_level); 381 u32 depth = params.MipDepth(mip_level);
540 if (params.target == SurfaceTarget::Texture2D) { 382 if (params.target == SurfaceTarget::Texture2D) {
@@ -544,157 +386,25 @@ void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params
544 if (params.is_layered) { 386 if (params.is_layered) {
545 u64 offset = params.GetMipmapLevelOffset(mip_level); 387 u64 offset = params.GetMipmapLevelOffset(mip_level);
546 u64 offset_gl = 0; 388 u64 offset_gl = 0;
547 u64 layer_size = params.LayerMemorySize(); 389 const u64 layer_size = params.LayerMemorySize();
548 u64 gl_size = params.LayerSizeGL(mip_level); 390 const u64 gl_size = params.LayerSizeGL(mip_level);
549 for (u32 i = 0; i < params.depth; i++) { 391 for (u32 i = 0; i < params.depth; i++) {
550 functions[static_cast<std::size_t>(params.pixel_format)]( 392 MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level),
551 params.MipWidth(mip_level), params.MipBlockHeight(mip_level), 393 params.MipBlockHeight(mip_level), params.MipHeight(mip_level),
552 params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1, 394 params.MipBlockDepth(mip_level), params.tile_width_spacing, 1,
553 gl_buffer.data() + offset_gl, gl_size, params.addr + offset); 395 gl_buffer.data() + offset_gl, gl_size, params.addr + offset);
554 offset += layer_size; 396 offset += layer_size;
555 offset_gl += gl_size; 397 offset_gl += gl_size;
556 } 398 }
557 } else { 399 } else {
558 u64 offset = params.GetMipmapLevelOffset(mip_level); 400 const u64 offset = params.GetMipmapLevelOffset(mip_level);
559 functions[static_cast<std::size_t>(params.pixel_format)]( 401 MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level),
560 params.MipWidth(mip_level), params.MipBlockHeight(mip_level), 402 params.MipBlockHeight(mip_level), params.MipHeight(mip_level),
561 params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(), 403 params.MipBlockDepth(mip_level), depth, params.tile_width_spacing,
562 gl_buffer.size(), params.addr + offset); 404 gl_buffer.data(), gl_buffer.size(), params.addr + offset);
563 } 405 }
564} 406}
565 407
566MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
567static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
568 GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0,
569 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
570 MICROPROFILE_SCOPE(OpenGL_BlitSurface);
571
572 const auto& src_params{src_surface->GetSurfaceParams()};
573 const auto& dst_params{dst_surface->GetSurfaceParams()};
574
575 OpenGLState prev_state{OpenGLState::GetCurState()};
576 SCOPE_EXIT({ prev_state.Apply(); });
577
578 OpenGLState state;
579 state.draw.read_framebuffer = read_fb_handle;
580 state.draw.draw_framebuffer = draw_fb_handle;
581 // Set sRGB enabled if the destination surfaces need it
582 state.framebuffer_srgb.enabled = dst_params.srgb_conversion;
583 state.ApplyFramebufferState();
584
585 u32 buffers{};
586
587 if (src_params.type == SurfaceType::ColorTexture) {
588 switch (src_params.target) {
589 case SurfaceTarget::Texture2D:
590 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
591 GL_TEXTURE_2D, src_surface->Texture().handle, 0);
592 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
593 0, 0);
594 break;
595 case SurfaceTarget::TextureCubemap:
596 glFramebufferTexture2D(
597 GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
598 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
599 src_surface->Texture().handle, 0);
600 glFramebufferTexture2D(
601 GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
602 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
603 break;
604 case SurfaceTarget::Texture2DArray:
605 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
606 src_surface->Texture().handle, 0, 0);
607 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
608 break;
609 case SurfaceTarget::Texture3D:
610 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
611 SurfaceTargetToGL(src_params.target),
612 src_surface->Texture().handle, 0, 0);
613 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
614 SurfaceTargetToGL(src_params.target), 0, 0, 0);
615 break;
616 default:
617 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
618 GL_TEXTURE_2D, src_surface->Texture().handle, 0);
619 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
620 0, 0);
621 break;
622 }
623
624 switch (dst_params.target) {
625 case SurfaceTarget::Texture2D:
626 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
627 GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
628 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
629 0, 0);
630 break;
631 case SurfaceTarget::TextureCubemap:
632 glFramebufferTexture2D(
633 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
634 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
635 dst_surface->Texture().handle, 0);
636 glFramebufferTexture2D(
637 GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
638 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
639 break;
640 case SurfaceTarget::Texture2DArray:
641 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
642 dst_surface->Texture().handle, 0, 0);
643 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
644 break;
645
646 case SurfaceTarget::Texture3D:
647 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
648 SurfaceTargetToGL(dst_params.target),
649 dst_surface->Texture().handle, 0, 0);
650 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
651 SurfaceTargetToGL(dst_params.target), 0, 0, 0);
652 break;
653 default:
654 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
655 GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
656 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
657 0, 0);
658 break;
659 }
660
661 buffers = GL_COLOR_BUFFER_BIT;
662 } else if (src_params.type == SurfaceType::Depth) {
663 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
664 GL_TEXTURE_2D, 0, 0);
665 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
666 src_surface->Texture().handle, 0);
667 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
668
669 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
670 GL_TEXTURE_2D, 0, 0);
671 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
672 dst_surface->Texture().handle, 0);
673 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
674
675 buffers = GL_DEPTH_BUFFER_BIT;
676 } else if (src_params.type == SurfaceType::DepthStencil) {
677 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
678 GL_TEXTURE_2D, 0, 0);
679 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
680 src_surface->Texture().handle, 0);
681
682 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
683 GL_TEXTURE_2D, 0, 0);
684 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
685 dst_surface->Texture().handle, 0);
686
687 buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
688 }
689
690 const auto& rect{src_params.GetRect()};
691 glBlitFramebuffer(rect.left, rect.bottom, rect.right, rect.top, rect.left, rect.bottom,
692 rect.right, rect.top, buffers,
693 buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
694
695 return true;
696}
697
698static void FastCopySurface(const Surface& src_surface, const Surface& dst_surface) { 408static void FastCopySurface(const Surface& src_surface, const Surface& dst_surface) {
699 const auto& src_params{src_surface->GetSurfaceParams()}; 409 const auto& src_params{src_surface->GetSurfaceParams()};
700 const auto& dst_params{dst_surface->GetSurfaceParams()}; 410 const auto& dst_params{dst_surface->GetSurfaceParams()};
@@ -709,21 +419,21 @@ static void FastCopySurface(const Surface& src_surface, const Surface& dst_surfa
709 419
710MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); 420MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64));
711static void CopySurface(const Surface& src_surface, const Surface& dst_surface, 421static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
712 GLuint copy_pbo_handle, GLenum src_attachment = 0, 422 const GLuint copy_pbo_handle, const GLenum src_attachment = 0,
713 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { 423 const GLenum dst_attachment = 0, const std::size_t cubemap_face = 0) {
714 MICROPROFILE_SCOPE(OpenGL_CopySurface); 424 MICROPROFILE_SCOPE(OpenGL_CopySurface);
715 ASSERT_MSG(dst_attachment == 0, "Unimplemented"); 425 ASSERT_MSG(dst_attachment == 0, "Unimplemented");
716 426
717 const auto& src_params{src_surface->GetSurfaceParams()}; 427 const auto& src_params{src_surface->GetSurfaceParams()};
718 const auto& dst_params{dst_surface->GetSurfaceParams()}; 428 const auto& dst_params{dst_surface->GetSurfaceParams()};
719 429
720 auto source_format = GetFormatTuple(src_params.pixel_format, src_params.component_type); 430 const auto source_format = GetFormatTuple(src_params.pixel_format, src_params.component_type);
721 auto dest_format = GetFormatTuple(dst_params.pixel_format, dst_params.component_type); 431 const auto dest_format = GetFormatTuple(dst_params.pixel_format, dst_params.component_type);
722 432
723 std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes); 433 const std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes);
724 434
725 glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle); 435 glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle);
726 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); 436 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW);
727 if (source_format.compressed) { 437 if (source_format.compressed) {
728 glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment, 438 glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment,
729 static_cast<GLsizei>(src_params.size_in_bytes), nullptr); 439 static_cast<GLsizei>(src_params.size_in_bytes), nullptr);
@@ -744,13 +454,10 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
744 LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " 454 LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during "
745 "reinterpretation but the texture is tiled."); 455 "reinterpretation but the texture is tiled.");
746 } 456 }
747 std::size_t remaining_size = dst_params.size_in_bytes - src_params.size_in_bytes; 457 const std::size_t remaining_size = dst_params.size_in_bytes - src_params.size_in_bytes;
748 std::vector<u8> data(remaining_size);
749 std::memcpy(data.data(), Memory::GetPointer(dst_params.addr + src_params.size_in_bytes),
750 data.size());
751 458
752 glBufferSubData(GL_PIXEL_PACK_BUFFER, src_params.size_in_bytes, remaining_size, 459 glBufferSubData(GL_PIXEL_PACK_BUFFER, src_params.size_in_bytes, remaining_size,
753 data.data()); 460 Memory::GetPointer(dst_params.addr + src_params.size_in_bytes));
754 } 461 }
755 462
756 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 463 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
@@ -932,7 +639,9 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
932 case PixelFormat::ASTC_2D_8X8_SRGB: 639 case PixelFormat::ASTC_2D_8X8_SRGB:
933 case PixelFormat::ASTC_2D_8X5_SRGB: 640 case PixelFormat::ASTC_2D_8X5_SRGB:
934 case PixelFormat::ASTC_2D_5X4_SRGB: 641 case PixelFormat::ASTC_2D_5X4_SRGB:
935 case PixelFormat::ASTC_2D_5X5_SRGB: { 642 case PixelFormat::ASTC_2D_5X5_SRGB:
643 case PixelFormat::ASTC_2D_10X8:
644 case PixelFormat::ASTC_2D_10X8_SRGB: {
936 // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. 645 // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
937 u32 block_width{}; 646 u32 block_width{};
938 u32 block_height{}; 647 u32 block_height{};
@@ -967,7 +676,11 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
967 case PixelFormat::ASTC_2D_4X4: 676 case PixelFormat::ASTC_2D_4X4:
968 case PixelFormat::ASTC_2D_8X8: 677 case PixelFormat::ASTC_2D_8X8:
969 case PixelFormat::ASTC_2D_4X4_SRGB: 678 case PixelFormat::ASTC_2D_4X4_SRGB:
970 case PixelFormat::ASTC_2D_8X8_SRGB: { 679 case PixelFormat::ASTC_2D_8X8_SRGB:
680 case PixelFormat::ASTC_2D_5X5:
681 case PixelFormat::ASTC_2D_5X5_SRGB:
682 case PixelFormat::ASTC_2D_10X8:
683 case PixelFormat::ASTC_2D_10X8_SRGB: {
971 LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented", 684 LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented",
972 static_cast<u32>(pixel_format)); 685 static_cast<u32>(pixel_format));
973 UNREACHABLE(); 686 UNREACHABLE();
@@ -990,15 +703,16 @@ void CachedSurface::LoadGLBuffer() {
990 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 703 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
991 params.block_width, static_cast<u32>(params.target)); 704 params.block_width, static_cast<u32>(params.target));
992 for (u32 i = 0; i < params.max_mip_level; i++) 705 for (u32 i = 0; i < params.max_mip_level; i++)
993 SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i); 706 SwizzleFunc(MortonSwizzleMode::MortonToLinear, params, gl_buffer[i], i);
994 } else { 707 } else {
995 const auto texture_src_data{Memory::GetPointer(params.addr)}; 708 const auto texture_src_data{Memory::GetPointer(params.addr)};
996 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; 709 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
997 gl_buffer[0].assign(texture_src_data, texture_src_data_end); 710 gl_buffer[0].assign(texture_src_data, texture_src_data_end);
998 } 711 }
999 for (u32 i = 0; i < params.max_mip_level; i++) 712 for (u32 i = 0; i < params.max_mip_level; i++) {
1000 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i), 713 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
1001 params.MipHeight(i), params.MipDepth(i)); 714 params.MipHeight(i), params.MipDepth(i));
715 }
1002} 716}
1003 717
1004MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 718MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
@@ -1029,7 +743,7 @@ void CachedSurface::FlushGLBuffer() {
1029 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 743 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
1030 params.block_width, static_cast<u32>(params.target)); 744 params.block_width, static_cast<u32>(params.target));
1031 745
1032 SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0); 746 SwizzleFunc(MortonSwizzleMode::LinearToMorton, params, gl_buffer[0], 0);
1033 } else { 747 } else {
1034 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes()); 748 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes());
1035 } 749 }
@@ -1269,6 +983,31 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) {
1269 return surface; 983 return surface;
1270} 984}
1271 985
986void RasterizerCacheOpenGL::FastLayeredCopySurface(const Surface& src_surface,
987 const Surface& dst_surface) {
988 const auto& init_params{src_surface->GetSurfaceParams()};
989 const auto& dst_params{dst_surface->GetSurfaceParams()};
990 VAddr address = init_params.addr;
991 const std::size_t layer_size = dst_params.LayerMemorySize();
992 for (u32 layer = 0; layer < dst_params.depth; layer++) {
993 for (u32 mipmap = 0; mipmap < dst_params.max_mip_level; mipmap++) {
994 const VAddr sub_address = address + dst_params.GetMipmapLevelOffset(mipmap);
995 const Surface& copy = TryGet(sub_address);
996 if (!copy)
997 continue;
998 const auto& src_params{copy->GetSurfaceParams()};
999 const u32 width{std::min(src_params.width, dst_params.MipWidth(mipmap))};
1000 const u32 height{std::min(src_params.height, dst_params.MipHeight(mipmap))};
1001
1002 glCopyImageSubData(copy->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0,
1003 0, 0, dst_surface->Texture().handle,
1004 SurfaceTargetToGL(dst_params.target), mipmap, 0, 0, layer, width,
1005 height, 1);
1006 }
1007 address += layer_size;
1008 }
1009}
1010
1272void RasterizerCacheOpenGL::FermiCopySurface( 1011void RasterizerCacheOpenGL::FermiCopySurface(
1273 const Tegra::Engines::Fermi2D::Regs::Surface& src_config, 1012 const Tegra::Engines::Fermi2D::Regs::Surface& src_config,
1274 const Tegra::Engines::Fermi2D::Regs::Surface& dst_config) { 1013 const Tegra::Engines::Fermi2D::Regs::Surface& dst_config) {
@@ -1293,7 +1032,10 @@ void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface,
1293 const Surface& dst_surface) { 1032 const Surface& dst_surface) {
1294 const auto& src_params{src_surface->GetSurfaceParams()}; 1033 const auto& src_params{src_surface->GetSurfaceParams()};
1295 const auto& dst_params{dst_surface->GetSurfaceParams()}; 1034 const auto& dst_params{dst_surface->GetSurfaceParams()};
1296 FlushRegion(src_params.addr, dst_params.MemorySize()); 1035
1036 // Flush enough memory for both the source and destination surface
1037 FlushRegion(src_params.addr, std::max(src_params.MemorySize(), dst_params.MemorySize()));
1038
1297 LoadSurface(dst_surface); 1039 LoadSurface(dst_surface);
1298} 1040}
1299 1041
@@ -1319,26 +1061,18 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1319 return new_surface; 1061 return new_surface;
1320 } 1062 }
1321 1063
1322 // If the format is the same, just do a framebuffer blit. This is significantly faster than
1323 // using PBOs. The is also likely less accurate, as textures will be converted rather than
1324 // reinterpreted. When use_accurate_gpu_emulation setting is enabled, perform a more accurate
1325 // surface copy, where pixels are reinterpreted as a new format (without conversion). This
1326 // code path uses OpenGL PBOs and is quite slow.
1327 const bool is_blit{old_params.pixel_format == new_params.pixel_format};
1328
1329 switch (new_params.target) { 1064 switch (new_params.target) {
1330 case SurfaceTarget::Texture2D: 1065 case SurfaceTarget::Texture2D:
1331 if (is_blit) { 1066 CopySurface(old_surface, new_surface, copy_pbo.handle);
1332 BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
1333 } else {
1334 CopySurface(old_surface, new_surface, copy_pbo.handle);
1335 }
1336 break; 1067 break;
1337 case SurfaceTarget::TextureCubemap:
1338 case SurfaceTarget::Texture3D: 1068 case SurfaceTarget::Texture3D:
1339 case SurfaceTarget::TextureCubeArray:
1340 AccurateCopySurface(old_surface, new_surface); 1069 AccurateCopySurface(old_surface, new_surface);
1341 break; 1070 break;
1071 case SurfaceTarget::TextureCubemap:
1072 case SurfaceTarget::Texture2DArray:
1073 case SurfaceTarget::TextureCubeArray:
1074 FastLayeredCopySurface(old_surface, new_surface);
1075 break;
1342 default: 1076 default:
1343 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 1077 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
1344 static_cast<u32>(new_params.target)); 1078 static_cast<u32>(new_params.target));
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 494f6b903..c710aa245 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -196,9 +196,15 @@ struct SurfaceParams {
196 196
197 /// Checks if surfaces are compatible for caching 197 /// Checks if surfaces are compatible for caching
198 bool IsCompatibleSurface(const SurfaceParams& other) const { 198 bool IsCompatibleSurface(const SurfaceParams& other) const {
199 return std::tie(pixel_format, type, width, height, target, depth) == 199 if (std::tie(pixel_format, type, width, height, target, depth, is_tiled) ==
200 std::tie(other.pixel_format, other.type, other.width, other.height, other.target, 200 std::tie(other.pixel_format, other.type, other.width, other.height, other.target,
201 other.depth); 201 other.depth, other.is_tiled)) {
202 if (!is_tiled)
203 return true;
204 return std::tie(block_height, block_depth, tile_width_spacing) ==
205 std::tie(other.block_height, other.block_depth, other.tile_width_spacing);
206 }
207 return false;
202 } 208 }
203 209
204 /// Initializes parameters for caching, should be called after everything has been initialized 210 /// Initializes parameters for caching, should be called after everything has been initialized
@@ -208,6 +214,7 @@ struct SurfaceParams {
208 u32 block_width; 214 u32 block_width;
209 u32 block_height; 215 u32 block_height;
210 u32 block_depth; 216 u32 block_depth;
217 u32 tile_width_spacing;
211 PixelFormat pixel_format; 218 PixelFormat pixel_format;
212 ComponentType component_type; 219 ComponentType component_type;
213 SurfaceType type; 220 SurfaceType type;
@@ -350,6 +357,7 @@ private:
350 357
351 /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data 358 /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data
352 void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); 359 void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface);
360 void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface);
353 361
354 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have 362 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
355 /// previously been used. This is to prevent surfaces from being constantly created and 363 /// previously been used. This is to prevent surfaces from being constantly created and
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index a85a7c0c5..038b25c75 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -84,6 +84,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
84 } 84 }
85 85
86 entries = program_result.second; 86 entries = program_result.second;
87 shader_length = entries.shader_length;
87 88
88 if (program_type != Maxwell::ShaderProgram::Geometry) { 89 if (program_type != Maxwell::ShaderProgram::Geometry) {
89 OGLShader shader; 90 OGLShader shader;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index ffbf21831..08f470de3 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -30,7 +30,7 @@ public:
30 } 30 }
31 31
32 std::size_t GetSizeInBytes() const override { 32 std::size_t GetSizeInBytes() const override {
33 return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64); 33 return shader_length;
34 } 34 }
35 35
36 // We do not have to flush this cache as things in it are never modified by us. 36 // We do not have to flush this cache as things in it are never modified by us.
@@ -82,6 +82,7 @@ private:
82 u32 max_vertices, const std::string& debug_name); 82 u32 max_vertices, const std::string& debug_name);
83 83
84 VAddr addr; 84 VAddr addr;
85 std::size_t shader_length;
85 Maxwell::ShaderProgram program_type; 86 Maxwell::ShaderProgram program_type;
86 GLShader::ShaderSetup setup; 87 GLShader::ShaderSetup setup;
87 GLShader::ShaderEntries entries; 88 GLShader::ShaderEntries entries;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 5fde22ad4..8d68156bf 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -34,6 +34,17 @@ constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header);
34constexpr u32 MAX_GEOMETRY_BUFFERS = 6; 34constexpr u32 MAX_GEOMETRY_BUFFERS = 6;
35constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested 35constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested
36 36
37static const char* INTERNAL_FLAG_NAMES[] = {"zero_flag", "sign_flag", "carry_flag",
38 "overflow_flag"};
39
40enum class InternalFlag : u64 {
41 ZeroFlag = 0,
42 SignFlag = 1,
43 CarryFlag = 2,
44 OverflowFlag = 3,
45 Amount
46};
47
37class DecompileFail : public std::runtime_error { 48class DecompileFail : public std::runtime_error {
38public: 49public:
39 using std::runtime_error::runtime_error; 50 using std::runtime_error::runtime_error;
@@ -49,8 +60,7 @@ static std::string GetTopologyName(Tegra::Shader::OutputTopology topology) {
49 case Tegra::Shader::OutputTopology::TriangleStrip: 60 case Tegra::Shader::OutputTopology::TriangleStrip:
50 return "triangle_strip"; 61 return "triangle_strip";
51 default: 62 default:
52 LOG_CRITICAL(Render_OpenGL, "Unknown output topology {}", static_cast<u32>(topology)); 63 UNIMPLEMENTED_MSG("Unknown output topology: {}", static_cast<u32>(topology));
53 UNREACHABLE();
54 return "points"; 64 return "points";
55 } 65 }
56} 66}
@@ -85,7 +95,8 @@ struct Subroutine {
85class ControlFlowAnalyzer { 95class ControlFlowAnalyzer {
86public: 96public:
87 ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix) 97 ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix)
88 : program_code(program_code) { 98 : program_code(program_code), shader_coverage_begin(main_offset),
99 shader_coverage_end(main_offset + 1) {
89 100
90 // Recursively finds all subroutines. 101 // Recursively finds all subroutines.
91 const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix); 102 const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix);
@@ -97,10 +108,16 @@ public:
97 return std::move(subroutines); 108 return std::move(subroutines);
98 } 109 }
99 110
111 std::size_t GetShaderLength() const {
112 return shader_coverage_end * sizeof(u64);
113 }
114
100private: 115private:
101 const ProgramCode& program_code; 116 const ProgramCode& program_code;
102 std::set<Subroutine> subroutines; 117 std::set<Subroutine> subroutines;
103 std::map<std::pair<u32, u32>, ExitMethod> exit_method_map; 118 std::map<std::pair<u32, u32>, ExitMethod> exit_method_map;
119 u32 shader_coverage_begin;
120 u32 shader_coverage_end;
104 121
105 /// Adds and analyzes a new subroutine if it is not added yet. 122 /// Adds and analyzes a new subroutine if it is not added yet.
106 const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) { 123 const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) {
@@ -142,6 +159,9 @@ private:
142 return exit_method; 159 return exit_method;
143 160
144 for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { 161 for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
162 shader_coverage_begin = std::min(shader_coverage_begin, offset);
163 shader_coverage_end = std::max(shader_coverage_end, offset + 1);
164
145 const Instruction instr = {program_code[offset]}; 165 const Instruction instr = {program_code[offset]};
146 if (const auto opcode = OpCode::Decode(instr)) { 166 if (const auto opcode = OpCode::Decode(instr)) {
147 switch (opcode->get().GetId()) { 167 switch (opcode->get().GetId()) {
@@ -167,8 +187,8 @@ private:
167 case OpCode::Id::SSY: 187 case OpCode::Id::SSY:
168 case OpCode::Id::PBK: { 188 case OpCode::Id::PBK: {
169 // The SSY and PBK use a similar encoding as the BRA instruction. 189 // The SSY and PBK use a similar encoding as the BRA instruction.
170 ASSERT_MSG(instr.bra.constant_buffer == 0, 190 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
171 "Constant buffer branching is not supported"); 191 "Constant buffer branching is not supported");
172 const u32 target = offset + instr.bra.GetBranchTarget(); 192 const u32 target = offset + instr.bra.GetBranchTarget();
173 labels.insert(target); 193 labels.insert(target);
174 // Continue scanning for an exit method. 194 // Continue scanning for an exit method.
@@ -181,14 +201,53 @@ private:
181 } 201 }
182}; 202};
183 203
204template <typename T>
205class ShaderScopedScope {
206public:
207 explicit ShaderScopedScope(T& writer, std::string_view begin_expr, std::string end_expr)
208 : writer(writer), end_expr(std::move(end_expr)) {
209
210 if (begin_expr.empty()) {
211 writer.AddLine('{');
212 } else {
213 writer.AddExpression(begin_expr);
214 writer.AddLine(" {");
215 }
216 ++writer.scope;
217 }
218
219 ShaderScopedScope(const ShaderScopedScope&) = delete;
220
221 ~ShaderScopedScope() {
222 --writer.scope;
223 if (end_expr.empty()) {
224 writer.AddLine('}');
225 } else {
226 writer.AddExpression("} ");
227 writer.AddExpression(end_expr);
228 writer.AddLine(';');
229 }
230 }
231
232 ShaderScopedScope& operator=(const ShaderScopedScope&) = delete;
233
234private:
235 T& writer;
236 std::string end_expr;
237};
238
184class ShaderWriter { 239class ShaderWriter {
185public: 240public:
186 void AddLine(std::string_view text) { 241 void AddExpression(std::string_view text) {
187 DEBUG_ASSERT(scope >= 0); 242 DEBUG_ASSERT(scope >= 0);
188 if (!text.empty()) { 243 if (!text.empty()) {
189 AppendIndentation(); 244 AppendIndentation();
190 } 245 }
191 shader_source += text; 246 shader_source += text;
247 }
248
249 void AddLine(std::string_view text) {
250 AddExpression(text);
192 AddNewLine(); 251 AddNewLine();
193 } 252 }
194 253
@@ -208,6 +267,11 @@ public:
208 return std::move(shader_source); 267 return std::move(shader_source);
209 } 268 }
210 269
270 ShaderScopedScope<ShaderWriter> Scope(std::string_view begin_expr = {},
271 std::string end_expr = {}) {
272 return ShaderScopedScope(*this, begin_expr, end_expr);
273 }
274
211 int scope = 0; 275 int scope = 0;
212 276
213private: 277private:
@@ -258,14 +322,6 @@ private:
258 const std::string& suffix; 322 const std::string& suffix;
259}; 323};
260 324
261enum class InternalFlag : u64 {
262 ZeroFlag = 0,
263 CarryFlag = 1,
264 OverflowFlag = 2,
265 NaNFlag = 3,
266 Amount
267};
268
269/** 325/**
270 * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state 326 * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
271 * of all registers (e.g. whether they are currently being used as Floats or Integers), and 327 * of all registers (e.g. whether they are currently being used as Floats or Integers), and
@@ -299,8 +355,7 @@ public:
299 // Default - do nothing 355 // Default - do nothing
300 return value; 356 return value;
301 default: 357 default:
302 LOG_CRITICAL(HW_GPU, "Unimplemented conversion size {}", static_cast<u32>(size)); 358 UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size));
303 UNREACHABLE();
304 } 359 }
305 } 360 }
306 361
@@ -363,7 +418,7 @@ public:
363 u64 value_num_components, bool is_saturated = false, 418 u64 value_num_components, bool is_saturated = false,
364 u64 dest_elem = 0, Register::Size size = Register::Size::Word, 419 u64 dest_elem = 0, Register::Size size = Register::Size::Word,
365 bool sets_cc = false) { 420 bool sets_cc = false) {
366 ASSERT_MSG(!is_saturated, "Unimplemented"); 421 UNIMPLEMENTED_IF(is_saturated);
367 422
368 const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"}; 423 const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"};
369 424
@@ -373,7 +428,7 @@ public:
373 if (sets_cc) { 428 if (sets_cc) {
374 const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; 429 const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
375 SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); 430 SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
376 LOG_WARNING(HW_GPU, "Control Codes Imcomplete."); 431 LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete.");
377 } 432 }
378 } 433 }
379 434
@@ -392,7 +447,7 @@ public:
392 Tegra::Shader::HalfMerge merge, u64 dest_num_components, 447 Tegra::Shader::HalfMerge merge, u64 dest_num_components,
393 u64 value_num_components, bool is_saturated = false, 448 u64 value_num_components, bool is_saturated = false,
394 u64 dest_elem = 0) { 449 u64 dest_elem = 0) {
395 ASSERT_MSG(!is_saturated, "Unimplemented"); 450 UNIMPLEMENTED_IF(is_saturated);
396 451
397 const std::string result = [&]() { 452 const std::string result = [&]() {
398 switch (merge) { 453 switch (merge) {
@@ -456,24 +511,25 @@ public:
456 shader.AddLine("lmem[" + index + "] = " + func + '(' + value + ");"); 511 shader.AddLine("lmem[" + index + "] = " + func + '(' + value + ");");
457 } 512 }
458 513
459 std::string GetControlCode(const Tegra::Shader::ControlCode cc) const { 514 std::string GetConditionCode(const Tegra::Shader::ConditionCode cc) const {
460 switch (cc) { 515 switch (cc) {
461 case Tegra::Shader::ControlCode::NEU: 516 case Tegra::Shader::ConditionCode::NEU:
462 return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')'; 517 return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')';
463 default: 518 default:
464 LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc)); 519 UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
465 UNREACHABLE();
466 return "false"; 520 return "false";
467 } 521 }
468 } 522 }
469 523
470 std::string GetInternalFlag(const InternalFlag ii) const { 524 std::string GetInternalFlag(const InternalFlag flag) const {
471 const u32 code = static_cast<u32>(ii); 525 const auto index = static_cast<u32>(flag);
472 return "internalFlag_" + std::to_string(code) + suffix; 526 ASSERT(index < static_cast<u32>(InternalFlag::Amount));
527
528 return std::string(INTERNAL_FLAG_NAMES[index]) + '_' + suffix;
473 } 529 }
474 530
475 void SetInternalFlag(const InternalFlag ii, const std::string& value) const { 531 void SetInternalFlag(const InternalFlag flag, const std::string& value) const {
476 shader.AddLine(GetInternalFlag(ii) + " = " + value + ';'); 532 shader.AddLine(GetInternalFlag(flag) + " = " + value + ';');
477 } 533 }
478 534
479 /** 535 /**
@@ -488,27 +544,43 @@ public:
488 const Register& buf_reg) { 544 const Register& buf_reg) {
489 const std::string dest = GetOutputAttribute(attribute); 545 const std::string dest = GetOutputAttribute(attribute);
490 const std::string src = GetRegisterAsFloat(val_reg); 546 const std::string src = GetRegisterAsFloat(val_reg);
547 if (dest.empty())
548 return;
491 549
492 if (!dest.empty()) { 550 // Can happen with unknown/unimplemented output attributes, in which case we ignore the
493 // Can happen with unknown/unimplemented output attributes, in which case we ignore the 551 // instruction for now.
494 // instruction for now. 552 if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
495 if (stage == Maxwell3D::Regs::ShaderStage::Geometry) { 553 // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
496 // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry 554 // shader. These instructions use a dirty register as buffer index, to avoid some
497 // shader. These instructions use a dirty register as buffer index, to avoid some 555 // drivers from complaining about out of boundary writes, guard them.
498 // drivers from complaining about out of boundary writes, guard them. 556 const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " +
499 const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " + 557 std::to_string(MAX_GEOMETRY_BUFFERS) + ')'};
500 std::to_string(MAX_GEOMETRY_BUFFERS) + ')'}; 558 shader.AddLine("amem[" + buf_index + "][" +
501 shader.AddLine("amem[" + buf_index + "][" + 559 std::to_string(static_cast<u32>(attribute)) + ']' + GetSwizzle(elem) +
502 std::to_string(static_cast<u32>(attribute)) + ']' + 560 " = " + src + ';');
503 GetSwizzle(elem) + " = " + src + ';'); 561 return;
504 } else { 562 }
505 if (attribute == Attribute::Index::PointSize) { 563
506 fixed_pipeline_output_attributes_used.insert(attribute); 564 switch (attribute) {
507 shader.AddLine(dest + " = " + src + ';'); 565 case Attribute::Index::ClipDistances0123:
508 } else { 566 case Attribute::Index::ClipDistances4567: {
509 shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';'); 567 const u64 index = (attribute == Attribute::Index::ClipDistances4567 ? 4 : 0) + elem;
510 } 568 UNIMPLEMENTED_IF_MSG(
511 } 569 ((header.vtg.clip_distances >> index) & 1) == 0,
570 "Shader is setting gl_ClipDistance{} without enabling it in the header", index);
571
572 clip_distances[index] = true;
573 fixed_pipeline_output_attributes_used.insert(attribute);
574 shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';');
575 break;
576 }
577 case Attribute::Index::PointSize:
578 fixed_pipeline_output_attributes_used.insert(attribute);
579 shader.AddLine(dest + " = " + src + ';');
580 break;
581 default:
582 shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';');
583 break;
512 } 584 }
513 } 585 }
514 586
@@ -575,6 +647,11 @@ public:
575 return used_samplers; 647 return used_samplers;
576 } 648 }
577 649
650 /// Returns an array of the used clip distances.
651 const std::array<bool, Maxwell::NumClipDistances>& GetClipDistances() const {
652 return clip_distances;
653 }
654
578 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if 655 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
579 /// necessary. 656 /// necessary.
580 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, 657 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
@@ -624,8 +701,8 @@ private:
624 701
625 /// Generates declarations for internal flags. 702 /// Generates declarations for internal flags.
626 void GenerateInternalFlags() { 703 void GenerateInternalFlags() {
627 for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) { 704 for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) {
628 const InternalFlag code = static_cast<InternalFlag>(ii); 705 const InternalFlag code = static_cast<InternalFlag>(flag);
629 declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); 706 declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
630 } 707 }
631 declarations.AddNewLine(); 708 declarations.AddNewLine();
@@ -728,12 +805,19 @@ private:
728 void GenerateVertex() { 805 void GenerateVertex() {
729 if (stage != Maxwell3D::Regs::ShaderStage::Vertex) 806 if (stage != Maxwell3D::Regs::ShaderStage::Vertex)
730 return; 807 return;
808 bool clip_distances_declared = false;
809
731 declarations.AddLine("out gl_PerVertex {"); 810 declarations.AddLine("out gl_PerVertex {");
732 ++declarations.scope; 811 ++declarations.scope;
733 declarations.AddLine("vec4 gl_Position;"); 812 declarations.AddLine("vec4 gl_Position;");
734 for (auto& o : fixed_pipeline_output_attributes_used) { 813 for (auto& o : fixed_pipeline_output_attributes_used) {
735 if (o == Attribute::Index::PointSize) 814 if (o == Attribute::Index::PointSize)
736 declarations.AddLine("float gl_PointSize;"); 815 declarations.AddLine("float gl_PointSize;");
816 if (!clip_distances_declared && (o == Attribute::Index::ClipDistances0123 ||
817 o == Attribute::Index::ClipDistances4567)) {
818 declarations.AddLine("float gl_ClipDistance[];");
819 clip_distances_declared = true;
820 }
737 } 821 }
738 --declarations.scope; 822 --declarations.scope;
739 declarations.AddLine("};"); 823 declarations.AddLine("};");
@@ -761,8 +845,7 @@ private:
761 u64 dest_num_components, u64 value_num_components, u64 dest_elem, 845 u64 dest_num_components, u64 value_num_components, u64 dest_elem,
762 bool precise) { 846 bool precise) {
763 if (reg == Register::ZeroIndex) { 847 if (reg == Register::ZeroIndex) {
764 LOG_CRITICAL(HW_GPU, "Cannot set Register::ZeroIndex"); 848 // Setting RZ is a nop in hardware.
765 UNREACHABLE();
766 return; 849 return;
767 } 850 }
768 851
@@ -777,14 +860,12 @@ private:
777 } 860 }
778 861
779 if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) { 862 if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) {
780 shader.AddLine('{'); 863 const auto scope = shader.Scope();
781 ++shader.scope; 864
782 // This avoids optimizations of constant propagation and keeps the code as the original 865 // This avoids optimizations of constant propagation and keeps the code as the original
783 // Sadly using the precise keyword causes "linking" errors on fragment shaders. 866 // Sadly using the precise keyword causes "linking" errors on fragment shaders.
784 shader.AddLine("precise float tmp = " + src + ';'); 867 shader.AddLine("precise float tmp = " + src + ';');
785 shader.AddLine(dest + " = tmp;"); 868 shader.AddLine(dest + " = tmp;");
786 --shader.scope;
787 shader.AddLine('}');
788 } else { 869 } else {
789 shader.AddLine(dest + " = " + src + ';'); 870 shader.AddLine(dest + " = " + src + ';');
790 } 871 }
@@ -834,7 +915,8 @@ private:
834 // vertex shader, and what's the value of the fourth element when inside a Tess Eval 915 // vertex shader, and what's the value of the fourth element when inside a Tess Eval
835 // shader. 916 // shader.
836 ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex); 917 ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex);
837 return "vec4(0, 0, uintBitsToFloat(instance_id.x), uintBitsToFloat(gl_VertexID))"; 918 // Config pack's first value is instance_id.
919 return "vec4(0, 0, uintBitsToFloat(config_pack[0]), uintBitsToFloat(gl_VertexID))";
838 case Attribute::Index::FrontFacing: 920 case Attribute::Index::FrontFacing:
839 // TODO(Subv): Find out what the values are for the other elements. 921 // TODO(Subv): Find out what the values are for the other elements.
840 ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); 922 ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment);
@@ -847,16 +929,13 @@ private:
847 if (declr_input_attribute.count(attribute) == 0) { 929 if (declr_input_attribute.count(attribute) == 0) {
848 declr_input_attribute[attribute] = input_mode; 930 declr_input_attribute[attribute] = input_mode;
849 } else { 931 } else {
850 if (declr_input_attribute[attribute] != input_mode) { 932 UNIMPLEMENTED_IF_MSG(declr_input_attribute[attribute] != input_mode,
851 LOG_CRITICAL(HW_GPU, "Same Input multiple input modes"); 933 "Multiple input modes for the same attribute");
852 UNREACHABLE();
853 }
854 } 934 }
855 return GeometryPass("input_attribute_" + std::to_string(index)); 935 return GeometryPass("input_attribute_" + std::to_string(index));
856 } 936 }
857 937
858 LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", static_cast<u32>(attribute)); 938 UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute));
859 UNREACHABLE();
860 } 939 }
861 940
862 return "vec4(0, 0, 0, 0)"; 941 return "vec4(0, 0, 0, 0)";
@@ -882,24 +961,20 @@ private:
882 break; 961 break;
883 } 962 }
884 default: { 963 default: {
885 LOG_CRITICAL(HW_GPU, "Unhandled Ipa InterpMode: {}", static_cast<u32>(interp_mode)); 964 UNIMPLEMENTED_MSG("Unhandled IPA interp mode: {}", static_cast<u32>(interp_mode));
886 UNREACHABLE();
887 } 965 }
888 } 966 }
889 switch (sample_mode) { 967 switch (sample_mode) {
890 case Tegra::Shader::IpaSampleMode::Centroid: { 968 case Tegra::Shader::IpaSampleMode::Centroid:
891 // Note not implemented, it can be implemented with the "centroid " keyword in glsl; 969 // It can be implemented with the "centroid " keyword in glsl
892 LOG_CRITICAL(HW_GPU, "Ipa Sampler Mode: centroid, not implemented"); 970 UNIMPLEMENTED_MSG("Unimplemented IPA sampler mode centroid");
893 UNREACHABLE();
894 break; 971 break;
895 } 972 case Tegra::Shader::IpaSampleMode::Default:
896 case Tegra::Shader::IpaSampleMode::Default: {
897 // Default, n/a 973 // Default, n/a
898 break; 974 break;
899 }
900 default: { 975 default: {
901 LOG_CRITICAL(HW_GPU, "Unhandled Ipa SampleMode: {}", static_cast<u32>(sample_mode)); 976 UNIMPLEMENTED_MSG("Unimplemented IPA sampler mode: {}", static_cast<u32>(sample_mode));
902 UNREACHABLE(); 977 break;
903 } 978 }
904 } 979 }
905 return out; 980 return out;
@@ -912,6 +987,10 @@ private:
912 return "gl_PointSize"; 987 return "gl_PointSize";
913 case Attribute::Index::Position: 988 case Attribute::Index::Position:
914 return "position"; 989 return "position";
990 case Attribute::Index::ClipDistances0123:
991 case Attribute::Index::ClipDistances4567: {
992 return "gl_ClipDistance";
993 }
915 default: 994 default:
916 const u32 index{static_cast<u32>(attribute) - 995 const u32 index{static_cast<u32>(attribute) -
917 static_cast<u32>(Attribute::Index::Attribute_0)}; 996 static_cast<u32>(Attribute::Index::Attribute_0)};
@@ -920,8 +999,7 @@ private:
920 return "output_attribute_" + std::to_string(index); 999 return "output_attribute_" + std::to_string(index);
921 } 1000 }
922 1001
923 LOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index); 1002 UNIMPLEMENTED_MSG("Unhandled output attribute={}", index);
924 UNREACHABLE();
925 return {}; 1003 return {};
926 } 1004 }
927 } 1005 }
@@ -945,15 +1023,17 @@ private:
945 const std::string& suffix; 1023 const std::string& suffix;
946 const Tegra::Shader::Header& header; 1024 const Tegra::Shader::Header& header;
947 std::unordered_set<Attribute::Index> fixed_pipeline_output_attributes_used; 1025 std::unordered_set<Attribute::Index> fixed_pipeline_output_attributes_used;
1026 std::array<bool, Maxwell::NumClipDistances> clip_distances{};
948 u64 local_memory_size; 1027 u64 local_memory_size;
949}; 1028};
950 1029
951class GLSLGenerator { 1030class GLSLGenerator {
952public: 1031public:
953 GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, 1032 GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
954 u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix) 1033 u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix,
1034 std::size_t shader_length)
955 : subroutines(subroutines), program_code(program_code), main_offset(main_offset), 1035 : subroutines(subroutines), program_code(program_code), main_offset(main_offset),
956 stage(stage), suffix(suffix) { 1036 stage(stage), suffix(suffix), shader_length(shader_length) {
957 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); 1037 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
958 local_memory_size = header.GetLocalMemorySize(); 1038 local_memory_size = header.GetLocalMemorySize();
959 regs.SetLocalMemory(local_memory_size); 1039 regs.SetLocalMemory(local_memory_size);
@@ -966,7 +1046,8 @@ public:
966 1046
967 /// Returns entries in the shader that are useful for external functions 1047 /// Returns entries in the shader that are useful for external functions
968 ShaderEntries GetEntries() const { 1048 ShaderEntries GetEntries() const {
969 return {regs.GetConstBuffersDeclarations(), regs.GetSamplers()}; 1049 return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), regs.GetClipDistances(),
1050 shader_length};
970 } 1051 }
971 1052
972private: 1053private:
@@ -1071,19 +1152,26 @@ private:
1071 const std::string& op_a, const std::string& op_b) const { 1152 const std::string& op_a, const std::string& op_b) const {
1072 using Tegra::Shader::PredCondition; 1153 using Tegra::Shader::PredCondition;
1073 static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = { 1154 static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = {
1074 {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="}, 1155 {PredCondition::LessThan, "<"},
1075 {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"}, 1156 {PredCondition::Equal, "=="},
1076 {PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="}, 1157 {PredCondition::LessEqual, "<="},
1077 {PredCondition::LessThanWithNan, "<"}, {PredCondition::NotEqualWithNan, "!="}, 1158 {PredCondition::GreaterThan, ">"},
1078 {PredCondition::GreaterThanWithNan, ">"}, {PredCondition::GreaterEqualWithNan, ">="}}; 1159 {PredCondition::NotEqual, "!="},
1160 {PredCondition::GreaterEqual, ">="},
1161 {PredCondition::LessThanWithNan, "<"},
1162 {PredCondition::NotEqualWithNan, "!="},
1163 {PredCondition::LessEqualWithNan, "<="},
1164 {PredCondition::GreaterThanWithNan, ">"},
1165 {PredCondition::GreaterEqualWithNan, ">="}};
1079 1166
1080 const auto& comparison{PredicateComparisonStrings.find(condition)}; 1167 const auto& comparison{PredicateComparisonStrings.find(condition)};
1081 ASSERT_MSG(comparison != PredicateComparisonStrings.end(), 1168 UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonStrings.end(),
1082 "Unknown predicate comparison operation"); 1169 "Unknown predicate comparison operation");
1083 1170
1084 std::string predicate{'(' + op_a + ") " + comparison->second + " (" + op_b + ')'}; 1171 std::string predicate{'(' + op_a + ") " + comparison->second + " (" + op_b + ')'};
1085 if (condition == PredCondition::LessThanWithNan || 1172 if (condition == PredCondition::LessThanWithNan ||
1086 condition == PredCondition::NotEqualWithNan || 1173 condition == PredCondition::NotEqualWithNan ||
1174 condition == PredCondition::LessEqualWithNan ||
1087 condition == PredCondition::GreaterThanWithNan || 1175 condition == PredCondition::GreaterThanWithNan ||
1088 condition == PredCondition::GreaterEqualWithNan) { 1176 condition == PredCondition::GreaterEqualWithNan) {
1089 predicate += " || isnan(" + op_a + ") || isnan(" + op_b + ')'; 1177 predicate += " || isnan(" + op_a + ") || isnan(" + op_b + ')';
@@ -1107,7 +1195,7 @@ private:
1107 }; 1195 };
1108 1196
1109 auto op = PredicateOperationStrings.find(operation); 1197 auto op = PredicateOperationStrings.find(operation);
1110 ASSERT_MSG(op != PredicateOperationStrings.end(), "Unknown predicate operation"); 1198 UNIMPLEMENTED_IF_MSG(op == PredicateOperationStrings.end(), "Unknown predicate operation");
1111 return op->second; 1199 return op->second;
1112 } 1200 }
1113 1201
@@ -1205,8 +1293,7 @@ private:
1205 break; 1293 break;
1206 } 1294 }
1207 default: 1295 default:
1208 LOG_CRITICAL(HW_GPU, "Unimplemented logic operation: {}", static_cast<u32>(logic_op)); 1296 UNIMPLEMENTED_MSG("Unimplemented logic operation={}", static_cast<u32>(logic_op));
1209 UNREACHABLE();
1210 } 1297 }
1211 1298
1212 if (dest != Tegra::Shader::Register::ZeroIndex) { 1299 if (dest != Tegra::Shader::Register::ZeroIndex) {
@@ -1224,9 +1311,8 @@ private:
1224 SetPredicate(static_cast<u64>(predicate), '(' + result + ") != 0"); 1311 SetPredicate(static_cast<u64>(predicate), '(' + result + ") != 0");
1225 break; 1312 break;
1226 default: 1313 default:
1227 LOG_CRITICAL(HW_GPU, "Unimplemented predicate result mode: {}", 1314 UNIMPLEMENTED_MSG("Unimplemented predicate result mode: {}",
1228 static_cast<u32>(predicate_mode)); 1315 static_cast<u32>(predicate_mode));
1229 UNREACHABLE();
1230 } 1316 }
1231 } 1317 }
1232 1318
@@ -1257,14 +1343,7 @@ private:
1257 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1); 1343 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1);
1258 } 1344 }
1259 1345
1260 void WriteTexsInstruction(const Instruction& instr, const std::string& coord, 1346 void WriteTexsInstruction(const Instruction& instr, const std::string& texture) {
1261 const std::string& texture) {
1262 // Add an extra scope and declare the texture coords inside to prevent
1263 // overwriting them in case they are used as outputs of the texs instruction.
1264 shader.AddLine('{');
1265 ++shader.scope;
1266 shader.AddLine(coord);
1267
1268 // TEXS has two destination registers and a swizzle. The first two elements in the swizzle 1347 // TEXS has two destination registers and a swizzle. The first two elements in the swizzle
1269 // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 1348 // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1
1270 1349
@@ -1287,26 +1366,19 @@ private:
1287 1366
1288 ++written_components; 1367 ++written_components;
1289 } 1368 }
1290
1291 --shader.scope;
1292 shader.AddLine('}');
1293 } 1369 }
1294 1370
1295 static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) { 1371 static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) {
1296 switch (texture_type) { 1372 switch (texture_type) {
1297 case Tegra::Shader::TextureType::Texture1D: { 1373 case Tegra::Shader::TextureType::Texture1D:
1298 return 1; 1374 return 1;
1299 } 1375 case Tegra::Shader::TextureType::Texture2D:
1300 case Tegra::Shader::TextureType::Texture2D: {
1301 return 2; 1376 return 2;
1302 }
1303 case Tegra::Shader::TextureType::Texture3D: 1377 case Tegra::Shader::TextureType::Texture3D:
1304 case Tegra::Shader::TextureType::TextureCube: { 1378 case Tegra::Shader::TextureType::TextureCube:
1305 return 3; 1379 return 3;
1306 }
1307 default: 1380 default:
1308 LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", static_cast<u32>(texture_type)); 1381 UNIMPLEMENTED_MSG("Unhandled texture type: {}", static_cast<u32>(texture_type));
1309 UNREACHABLE();
1310 return 0; 1382 return 0;
1311 } 1383 }
1312 } 1384 }
@@ -1316,12 +1388,10 @@ private:
1316 * top. 1388 * top.
1317 */ 1389 */
1318 void EmitPushToFlowStack(u32 target) { 1390 void EmitPushToFlowStack(u32 target) {
1319 shader.AddLine('{'); 1391 const auto scope = shader.Scope();
1320 ++shader.scope; 1392
1321 shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;"); 1393 shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;");
1322 shader.AddLine("flow_stack_top++;"); 1394 shader.AddLine("flow_stack_top++;");
1323 --shader.scope;
1324 shader.AddLine('}');
1325 } 1395 }
1326 1396
1327 /* 1397 /*
@@ -1329,20 +1399,18 @@ private:
1329 * popped address and decrementing the stack top. 1399 * popped address and decrementing the stack top.
1330 */ 1400 */
1331 void EmitPopFromFlowStack() { 1401 void EmitPopFromFlowStack() {
1332 shader.AddLine('{'); 1402 const auto scope = shader.Scope();
1333 ++shader.scope; 1403
1334 shader.AddLine("flow_stack_top--;"); 1404 shader.AddLine("flow_stack_top--;");
1335 shader.AddLine("jmp_to = flow_stack[flow_stack_top];"); 1405 shader.AddLine("jmp_to = flow_stack[flow_stack_top];");
1336 shader.AddLine("break;"); 1406 shader.AddLine("break;");
1337 --shader.scope;
1338 shader.AddLine('}');
1339 } 1407 }
1340 1408
1341 /// Writes the output values from a fragment shader to the corresponding GLSL output variables. 1409 /// Writes the output values from a fragment shader to the corresponding GLSL output variables.
1342 void EmitFragmentOutputsWrite() { 1410 void EmitFragmentOutputsWrite() {
1343 ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); 1411 ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment);
1344 1412
1345 ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented"); 1413 UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Samplemask write is unimplemented");
1346 1414
1347 shader.AddLine("if (alpha_test[0] != 0) {"); 1415 shader.AddLine("if (alpha_test[0] != 0) {");
1348 ++shader.scope; 1416 ++shader.scope;
@@ -1408,7 +1476,7 @@ private:
1408 case Tegra::Shader::VideoType::Size32: 1476 case Tegra::Shader::VideoType::Size32:
1409 // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when 1477 // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when
1410 // this type is used (1 * 1 + 0 == 0x5b800000). Until a better 1478 // this type is used (1 * 1 + 0 == 0x5b800000). Until a better
1411 // explanation is found: assert. 1479 // explanation is found: abort.
1412 UNIMPLEMENTED(); 1480 UNIMPLEMENTED();
1413 return zero; 1481 return zero;
1414 case Tegra::Shader::VideoType::Invalid: 1482 case Tegra::Shader::VideoType::Invalid:
@@ -1447,6 +1515,161 @@ private:
1447 } 1515 }
1448 } 1516 }
1449 1517
1518 std::pair<size_t, std::string> ValidateAndGetCoordinateElement(
1519 const Tegra::Shader::TextureType texture_type, const bool depth_compare,
1520 const bool is_array, const bool lod_bias_enabled, size_t max_coords, size_t max_inputs) {
1521 const size_t coord_count = TextureCoordinates(texture_type);
1522
1523 size_t total_coord_count = coord_count + (is_array ? 1 : 0) + (depth_compare ? 1 : 0);
1524 const size_t total_reg_count = total_coord_count + (lod_bias_enabled ? 1 : 0);
1525 if (total_coord_count > max_coords || total_reg_count > max_inputs) {
1526 UNIMPLEMENTED_MSG("Unsupported Texture operation");
1527 total_coord_count = std::min(total_coord_count, max_coords);
1528 }
1529 // 1D.DC opengl is using a vec3 but 2nd component is ignored later.
1530 total_coord_count +=
1531 (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D)
1532 ? 1
1533 : 0;
1534
1535 constexpr std::array<const char*, 5> coord_container{
1536 {"", "float coord = (", "vec2 coord = vec2(", "vec3 coord = vec3(",
1537 "vec4 coord = vec4("}};
1538
1539 return std::pair<size_t, std::string>(coord_count, coord_container[total_coord_count]);
1540 }
1541
1542 std::string GetTextureCode(const Tegra::Shader::Instruction& instr,
1543 const Tegra::Shader::TextureType texture_type,
1544 const Tegra::Shader::TextureProcessMode process_mode,
1545 const bool depth_compare, const bool is_array,
1546 const size_t bias_offset) {
1547
1548 if ((texture_type == Tegra::Shader::TextureType::Texture3D &&
1549 (is_array || depth_compare)) ||
1550 (texture_type == Tegra::Shader::TextureType::TextureCube && is_array &&
1551 depth_compare)) {
1552 UNIMPLEMENTED_MSG("This method is not supported.");
1553 }
1554
1555 const std::string sampler =
1556 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
1557
1558 const bool lod_needed = process_mode == Tegra::Shader::TextureProcessMode::LZ ||
1559 process_mode == Tegra::Shader::TextureProcessMode::LL ||
1560 process_mode == Tegra::Shader::TextureProcessMode::LLA;
1561
1562 const bool gl_lod_supported = !(
1563 (texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) ||
1564 (texture_type == Tegra::Shader::TextureType::TextureCube && !is_array &&
1565 depth_compare));
1566
1567 const std::string read_method = lod_needed && gl_lod_supported ? "textureLod(" : "texture(";
1568 std::string texture = read_method + sampler + ", coord";
1569
1570 if (process_mode != Tegra::Shader::TextureProcessMode::None) {
1571 if (process_mode == Tegra::Shader::TextureProcessMode::LZ) {
1572 if (gl_lod_supported) {
1573 texture += ", 0";
1574 } else {
1575 // Lod 0 is emulated by a big negative bias
1576 // in scenarios that are not supported by glsl
1577 texture += ", -1000";
1578 }
1579 } else {
1580 // If present, lod or bias are always stored in the register indexed by the
1581 // gpr20
1582 // field with an offset depending on the usage of the other registers
1583 texture += ',' + regs.GetRegisterAsFloat(instr.gpr20.Value() + bias_offset);
1584 }
1585 }
1586 texture += ")";
1587 return texture;
1588 }
1589
1590 std::pair<std::string, std::string> GetTEXCode(
1591 const Instruction& instr, const Tegra::Shader::TextureType texture_type,
1592 const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
1593 const bool is_array) {
1594 const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
1595 process_mode != Tegra::Shader::TextureProcessMode::LZ);
1596
1597 const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
1598 texture_type, depth_compare, is_array, lod_bias_enabled, 4, 5);
1599 // If enabled arrays index is always stored in the gpr8 field
1600 const u64 array_register = instr.gpr8.Value();
1601 // First coordinate index is the gpr8 or gpr8 + 1 when arrays are used
1602 const u64 coord_register = array_register + (is_array ? 1 : 0);
1603
1604 std::string coord = coord_dcl;
1605 for (size_t i = 0; i < coord_count;) {
1606 coord += regs.GetRegisterAsFloat(coord_register + i);
1607 ++i;
1608 if (i != coord_count) {
1609 coord += ',';
1610 }
1611 }
1612 // 1D.DC in opengl the 2nd component is ignored.
1613 if (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D) {
1614 coord += ",0.0";
1615 }
1616 if (depth_compare) {
1617 // Depth is always stored in the register signaled by gpr20
1618 // or in the next register if lod or bias are used
1619 const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
1620 coord += ',' + regs.GetRegisterAsFloat(depth_register);
1621 }
1622 if (is_array) {
1623 coord += ',' + regs.GetRegisterAsInteger(array_register);
1624 }
1625 coord += ");";
1626 return std::make_pair(
1627 coord, GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, 0));
1628 }
1629
1630 std::pair<std::string, std::string> GetTEXSCode(
1631 const Instruction& instr, const Tegra::Shader::TextureType texture_type,
1632 const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
1633 const bool is_array) {
1634 const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
1635 process_mode != Tegra::Shader::TextureProcessMode::LZ);
1636
1637 const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
1638 texture_type, depth_compare, is_array, lod_bias_enabled, 4, 4);
1639 // If enabled arrays index is always stored in the gpr8 field
1640 const u64 array_register = instr.gpr8.Value();
1641 // First coordinate index is stored in gpr8 field or (gpr8 + 1) when arrays are used
1642 const u64 coord_register = array_register + (is_array ? 1 : 0);
1643 const u64 last_coord_register =
1644 (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2))
1645 ? static_cast<u64>(instr.gpr20.Value())
1646 : coord_register + 1;
1647
1648 std::string coord = coord_dcl;
1649 for (size_t i = 0; i < coord_count; ++i) {
1650 const bool last = (i == (coord_count - 1)) && (coord_count > 1);
1651 coord += regs.GetRegisterAsFloat(last ? last_coord_register : coord_register + i);
1652 if (!last) {
1653 coord += ',';
1654 }
1655 }
1656
1657 if (depth_compare) {
1658 // Depth is always stored in the register signaled by gpr20
1659 // or in the next register if lod or bias are used
1660 const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
1661 coord += ',' + regs.GetRegisterAsFloat(depth_register);
1662 }
1663 if (is_array) {
1664 coord += ',' + regs.GetRegisterAsInteger(array_register);
1665 }
1666 coord += ");";
1667
1668 return std::make_pair(coord,
1669 GetTextureCode(instr, texture_type, process_mode, depth_compare,
1670 is_array, (coord_count > 2 ? 1 : 0)));
1671 }
1672
1450 /** 1673 /**
1451 * Compiles a single instruction from Tegra to GLSL. 1674 * Compiles a single instruction from Tegra to GLSL.
1452 * @param offset the offset of the Tegra shader instruction. 1675 * @param offset the offset of the Tegra shader instruction.
@@ -1464,8 +1687,7 @@ private:
1464 1687
1465 // Decoding failure 1688 // Decoding failure
1466 if (!opcode) { 1689 if (!opcode) {
1467 LOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value); 1690 UNIMPLEMENTED_MSG("Unhandled instruction: {0:x}", instr.value);
1468 UNREACHABLE();
1469 return offset + 1; 1691 return offset + 1;
1470 } 1692 }
1471 1693
@@ -1473,8 +1695,8 @@ private:
1473 fmt::format("// {}: {} (0x{:016x})", offset, opcode->get().GetName(), instr.value)); 1695 fmt::format("// {}: {} (0x{:016x})", offset, opcode->get().GetName(), instr.value));
1474 1696
1475 using Tegra::Shader::Pred; 1697 using Tegra::Shader::Pred;
1476 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute, 1698 UNIMPLEMENTED_IF_MSG(instr.pred.full_pred == Pred::NeverExecute,
1477 "NeverExecute predicate not implemented"); 1699 "NeverExecute predicate not implemented");
1478 1700
1479 // Some instructions (like SSY) don't have a predicate field, they are always 1701 // Some instructions (like SSY) don't have a predicate field, they are always
1480 // unconditionally executed. 1702 // unconditionally executed.
@@ -1517,37 +1739,36 @@ private:
1517 case OpCode::Id::FMUL_R: 1739 case OpCode::Id::FMUL_R:
1518 case OpCode::Id::FMUL_IMM: { 1740 case OpCode::Id::FMUL_IMM: {
1519 // FMUL does not have 'abs' bits and only the second operand has a 'neg' bit. 1741 // FMUL does not have 'abs' bits and only the second operand has a 'neg' bit.
1520 ASSERT_MSG(instr.fmul.tab5cb8_2 == 0, "FMUL tab5cb8_2({}) is not implemented", 1742 UNIMPLEMENTED_IF_MSG(instr.fmul.tab5cb8_2 != 0,
1521 instr.fmul.tab5cb8_2.Value()); 1743 "FMUL tab5cb8_2({}) is not implemented",
1522 ASSERT_MSG(instr.fmul.tab5c68_1 == 0, "FMUL tab5cb8_1({}) is not implemented", 1744 instr.fmul.tab5cb8_2.Value());
1523 instr.fmul.tab5c68_1.Value()); 1745 UNIMPLEMENTED_IF_MSG(instr.fmul.tab5c68_1 != 0,
1524 ASSERT_MSG(instr.fmul.tab5c68_0 == 1, "FMUL tab5cb8_0({}) is not implemented", 1746 "FMUL tab5cb8_1({}) is not implemented",
1525 instr.fmul.tab5c68_0 1747 instr.fmul.tab5c68_1.Value());
1526 .Value()); // SMO typical sends 1 here which seems to be the default 1748 UNIMPLEMENTED_IF_MSG(
1527 ASSERT_MSG(instr.fmul.cc == 0, "FMUL cc is not implemented"); 1749 instr.fmul.tab5c68_0 != 1, "FMUL tab5cb8_0({}) is not implemented",
1750 instr.fmul.tab5c68_0
1751 .Value()); // SMO typical sends 1 here which seems to be the default
1752 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1753 "Condition codes generation in FMUL is not implemented");
1528 1754
1529 op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b); 1755 op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b);
1530 1756
1531 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, 1757 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1,
1532 instr.alu.saturate_d, 0, true); 1758 instr.alu.saturate_d, 0, true);
1533 if (instr.generates_cc) {
1534 LOG_CRITICAL(HW_GPU, "FMUL Generates an unhandled Control Code");
1535 UNREACHABLE();
1536 }
1537 break; 1759 break;
1538 } 1760 }
1539 case OpCode::Id::FADD_C: 1761 case OpCode::Id::FADD_C:
1540 case OpCode::Id::FADD_R: 1762 case OpCode::Id::FADD_R:
1541 case OpCode::Id::FADD_IMM: { 1763 case OpCode::Id::FADD_IMM: {
1764 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1765 "Condition codes generation in FADD is not implemented");
1766
1542 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); 1767 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
1543 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); 1768 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
1544 1769
1545 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, 1770 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
1546 instr.alu.saturate_d, 0, true); 1771 instr.alu.saturate_d, 0, true);
1547 if (instr.generates_cc) {
1548 LOG_CRITICAL(HW_GPU, "FADD Generates an unhandled Control Code");
1549 UNREACHABLE();
1550 }
1551 break; 1772 break;
1552 } 1773 }
1553 case OpCode::Id::MUFU: { 1774 case OpCode::Id::MUFU: {
@@ -1582,15 +1803,17 @@ private:
1582 instr.alu.saturate_d, 0, true); 1803 instr.alu.saturate_d, 0, true);
1583 break; 1804 break;
1584 default: 1805 default:
1585 LOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}", 1806 UNIMPLEMENTED_MSG("Unhandled MUFU sub op={0:x}",
1586 static_cast<unsigned>(instr.sub_op.Value())); 1807 static_cast<unsigned>(instr.sub_op.Value()));
1587 UNREACHABLE();
1588 } 1808 }
1589 break; 1809 break;
1590 } 1810 }
1591 case OpCode::Id::FMNMX_C: 1811 case OpCode::Id::FMNMX_C:
1592 case OpCode::Id::FMNMX_R: 1812 case OpCode::Id::FMNMX_R:
1593 case OpCode::Id::FMNMX_IMM: { 1813 case OpCode::Id::FMNMX_IMM: {
1814 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1815 "Condition codes generation in FMNMX is not implemented");
1816
1594 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); 1817 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
1595 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); 1818 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
1596 1819
@@ -1601,10 +1824,6 @@ private:
1601 '(' + condition + ") ? min(" + parameters + ") : max(" + 1824 '(' + condition + ") ? min(" + parameters + ") : max(" +
1602 parameters + ')', 1825 parameters + ')',
1603 1, 1, false, 0, true); 1826 1, 1, false, 0, true);
1604 if (instr.generates_cc) {
1605 LOG_CRITICAL(HW_GPU, "FMNMX Generates an unhandled Control Code");
1606 UNREACHABLE();
1607 }
1608 break; 1827 break;
1609 } 1828 }
1610 case OpCode::Id::RRO_C: 1829 case OpCode::Id::RRO_C:
@@ -1617,9 +1836,7 @@ private:
1617 break; 1836 break;
1618 } 1837 }
1619 default: { 1838 default: {
1620 LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}", 1839 UNIMPLEMENTED_MSG("Unhandled arithmetic instruction: {}", opcode->get().GetName());
1621 opcode->get().GetName());
1622 UNREACHABLE();
1623 } 1840 }
1624 } 1841 }
1625 break; 1842 break;
@@ -1631,17 +1848,19 @@ private:
1631 break; 1848 break;
1632 } 1849 }
1633 case OpCode::Id::FMUL32_IMM: { 1850 case OpCode::Id::FMUL32_IMM: {
1851 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
1852 "Condition codes generation in FMUL32 is not implemented");
1853
1634 regs.SetRegisterToFloat(instr.gpr0, 0, 1854 regs.SetRegisterToFloat(instr.gpr0, 0,
1635 regs.GetRegisterAsFloat(instr.gpr8) + " * " + 1855 regs.GetRegisterAsFloat(instr.gpr8) + " * " +
1636 GetImmediate32(instr), 1856 GetImmediate32(instr),
1637 1, 1, instr.fmul32.saturate, 0, true); 1857 1, 1, instr.fmul32.saturate, 0, true);
1638 if (instr.op_32.generates_cc) {
1639 LOG_CRITICAL(HW_GPU, "FMUL32 Generates an unhandled Control Code");
1640 UNREACHABLE();
1641 }
1642 break; 1858 break;
1643 } 1859 }
1644 case OpCode::Id::FADD32I: { 1860 case OpCode::Id::FADD32I: {
1861 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
1862 "Condition codes generation in FADD32I is not implemented");
1863
1645 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1864 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
1646 std::string op_b = GetImmediate32(instr); 1865 std::string op_b = GetImmediate32(instr);
1647 1866
@@ -1662,23 +1881,22 @@ private:
1662 } 1881 }
1663 1882
1664 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true); 1883 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true);
1665 if (instr.op_32.generates_cc) {
1666 LOG_CRITICAL(HW_GPU, "FADD32 Generates an unhandled Control Code");
1667 UNREACHABLE();
1668 }
1669 break; 1884 break;
1670 } 1885 }
1671 } 1886 }
1672 break; 1887 break;
1673 } 1888 }
1674 case OpCode::Type::Bfe: { 1889 case OpCode::Type::Bfe: {
1675 ASSERT_MSG(!instr.bfe.negate_b, "Unimplemented"); 1890 UNIMPLEMENTED_IF(instr.bfe.negate_b);
1676 1891
1677 std::string op_a = instr.bfe.negate_a ? "-" : ""; 1892 std::string op_a = instr.bfe.negate_a ? "-" : "";
1678 op_a += regs.GetRegisterAsInteger(instr.gpr8); 1893 op_a += regs.GetRegisterAsInteger(instr.gpr8);
1679 1894
1680 switch (opcode->get().GetId()) { 1895 switch (opcode->get().GetId()) {
1681 case OpCode::Id::BFE_IMM: { 1896 case OpCode::Id::BFE_IMM: {
1897 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1898 "Condition codes generation in BFE is not implemented");
1899
1682 std::string inner_shift = 1900 std::string inner_shift =
1683 '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')'; 1901 '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')';
1684 std::string outer_shift = 1902 std::string outer_shift =
@@ -1686,20 +1904,35 @@ private:
1686 std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')'; 1904 std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')';
1687 1905
1688 regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1); 1906 regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1);
1689 if (instr.generates_cc) {
1690 LOG_CRITICAL(HW_GPU, "BFE Generates an unhandled Control Code");
1691 UNREACHABLE();
1692 }
1693 break; 1907 break;
1694 } 1908 }
1695 default: { 1909 default: {
1696 LOG_CRITICAL(HW_GPU, "Unhandled BFE instruction: {}", opcode->get().GetName()); 1910 UNIMPLEMENTED_MSG("Unhandled BFE instruction: {}", opcode->get().GetName());
1697 UNREACHABLE();
1698 } 1911 }
1699 } 1912 }
1700 1913
1701 break; 1914 break;
1702 } 1915 }
1916 case OpCode::Type::Bfi: {
1917 UNIMPLEMENTED_IF(instr.generates_cc);
1918
1919 const auto [base, packed_shift] = [&]() -> std::tuple<std::string, std::string> {
1920 switch (opcode->get().GetId()) {
1921 case OpCode::Id::BFI_IMM_R:
1922 return {regs.GetRegisterAsInteger(instr.gpr39, 0, false),
1923 std::to_string(instr.alu.GetSignedImm20_20())};
1924 default:
1925 UNREACHABLE();
1926 }
1927 }();
1928 const std::string offset = '(' + packed_shift + " & 0xff)";
1929 const std::string bits = "((" + packed_shift + " >> 8) & 0xff)";
1930 const std::string insert = regs.GetRegisterAsInteger(instr.gpr8, 0, false);
1931 regs.SetRegisterToInteger(
1932 instr.gpr0, false, 0,
1933 "bitfieldInsert(" + base + ", " + insert + ", " + offset + ", " + bits + ')', 1, 1);
1934 break;
1935 }
1703 case OpCode::Type::Shift: { 1936 case OpCode::Type::Shift: {
1704 std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true); 1937 std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true);
1705 std::string op_b; 1938 std::string op_b;
@@ -1719,6 +1952,9 @@ private:
1719 case OpCode::Id::SHR_C: 1952 case OpCode::Id::SHR_C:
1720 case OpCode::Id::SHR_R: 1953 case OpCode::Id::SHR_R:
1721 case OpCode::Id::SHR_IMM: { 1954 case OpCode::Id::SHR_IMM: {
1955 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1956 "Condition codes generation in SHR is not implemented");
1957
1722 if (!instr.shift.is_signed) { 1958 if (!instr.shift.is_signed) {
1723 // Logical shift right 1959 // Logical shift right
1724 op_a = "uint(" + op_a + ')'; 1960 op_a = "uint(" + op_a + ')';
@@ -1727,24 +1963,17 @@ private:
1727 // Cast to int is superfluous for arithmetic shift, it's only for a logical shift 1963 // Cast to int is superfluous for arithmetic shift, it's only for a logical shift
1728 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')', 1964 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')',
1729 1, 1); 1965 1, 1);
1730 if (instr.generates_cc) {
1731 LOG_CRITICAL(HW_GPU, "SHR Generates an unhandled Control Code");
1732 UNREACHABLE();
1733 }
1734 break; 1966 break;
1735 } 1967 }
1736 case OpCode::Id::SHL_C: 1968 case OpCode::Id::SHL_C:
1737 case OpCode::Id::SHL_R: 1969 case OpCode::Id::SHL_R:
1738 case OpCode::Id::SHL_IMM: 1970 case OpCode::Id::SHL_IMM:
1971 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1972 "Condition codes generation in SHL is not implemented");
1739 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); 1973 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
1740 if (instr.generates_cc) {
1741 LOG_CRITICAL(HW_GPU, "SHL Generates an unhandled Control Code");
1742 UNREACHABLE();
1743 }
1744 break; 1974 break;
1745 default: { 1975 default: {
1746 LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName()); 1976 UNIMPLEMENTED_MSG("Unhandled shift instruction: {}", opcode->get().GetName());
1747 UNREACHABLE();
1748 } 1977 }
1749 } 1978 }
1750 break; 1979 break;
@@ -1755,17 +1984,19 @@ private:
1755 1984
1756 switch (opcode->get().GetId()) { 1985 switch (opcode->get().GetId()) {
1757 case OpCode::Id::IADD32I: 1986 case OpCode::Id::IADD32I:
1987 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
1988 "Condition codes generation in IADD32I is not implemented");
1989
1758 if (instr.iadd32i.negate_a) 1990 if (instr.iadd32i.negate_a)
1759 op_a = "-(" + op_a + ')'; 1991 op_a = "-(" + op_a + ')';
1760 1992
1761 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, 1993 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
1762 instr.iadd32i.saturate != 0); 1994 instr.iadd32i.saturate != 0);
1763 if (instr.op_32.generates_cc) {
1764 LOG_CRITICAL(HW_GPU, "IADD32 Generates an unhandled Control Code");
1765 UNREACHABLE();
1766 }
1767 break; 1995 break;
1768 case OpCode::Id::LOP32I: { 1996 case OpCode::Id::LOP32I: {
1997 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
1998 "Condition codes generation in LOP32I is not implemented");
1999
1769 if (instr.alu.lop32i.invert_a) 2000 if (instr.alu.lop32i.invert_a)
1770 op_a = "~(" + op_a + ')'; 2001 op_a = "~(" + op_a + ')';
1771 2002
@@ -1775,16 +2006,11 @@ private:
1775 WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b, 2006 WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
1776 Tegra::Shader::PredicateResultMode::None, 2007 Tegra::Shader::PredicateResultMode::None,
1777 Tegra::Shader::Pred::UnusedIndex); 2008 Tegra::Shader::Pred::UnusedIndex);
1778 if (instr.op_32.generates_cc) {
1779 LOG_CRITICAL(HW_GPU, "LOP32I Generates an unhandled Control Code");
1780 UNREACHABLE();
1781 }
1782 break; 2009 break;
1783 } 2010 }
1784 default: { 2011 default: {
1785 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticIntegerImmediate instruction: {}", 2012 UNIMPLEMENTED_MSG("Unhandled ArithmeticIntegerImmediate instruction: {}",
1786 opcode->get().GetName()); 2013 opcode->get().GetName());
1787 UNREACHABLE();
1788 } 2014 }
1789 } 2015 }
1790 break; 2016 break;
@@ -1807,6 +2033,9 @@ private:
1807 case OpCode::Id::IADD_C: 2033 case OpCode::Id::IADD_C:
1808 case OpCode::Id::IADD_R: 2034 case OpCode::Id::IADD_R:
1809 case OpCode::Id::IADD_IMM: { 2035 case OpCode::Id::IADD_IMM: {
2036 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2037 "Condition codes generation in IADD is not implemented");
2038
1810 if (instr.alu_integer.negate_a) 2039 if (instr.alu_integer.negate_a)
1811 op_a = "-(" + op_a + ')'; 2040 op_a = "-(" + op_a + ')';
1812 2041
@@ -1815,15 +2044,14 @@ private:
1815 2044
1816 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, 2045 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
1817 instr.alu.saturate_d); 2046 instr.alu.saturate_d);
1818 if (instr.generates_cc) {
1819 LOG_CRITICAL(HW_GPU, "IADD Generates an unhandled Control Code");
1820 UNREACHABLE();
1821 }
1822 break; 2047 break;
1823 } 2048 }
1824 case OpCode::Id::IADD3_C: 2049 case OpCode::Id::IADD3_C:
1825 case OpCode::Id::IADD3_R: 2050 case OpCode::Id::IADD3_R:
1826 case OpCode::Id::IADD3_IMM: { 2051 case OpCode::Id::IADD3_IMM: {
2052 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2053 "Condition codes generation in IADD3 is not implemented");
2054
1827 std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); 2055 std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
1828 2056
1829 auto apply_height = [](auto height, auto& oprand) { 2057 auto apply_height = [](auto height, auto& oprand) {
@@ -1837,9 +2065,8 @@ private:
1837 oprand = "((" + oprand + ") >> 16)"; 2065 oprand = "((" + oprand + ") >> 16)";
1838 break; 2066 break;
1839 default: 2067 default:
1840 LOG_CRITICAL(HW_GPU, "Unhandled IADD3 height: {}", 2068 UNIMPLEMENTED_MSG("Unhandled IADD3 height: {}",
1841 static_cast<u32>(height.Value())); 2069 static_cast<u32>(height.Value()));
1842 UNREACHABLE();
1843 } 2070 }
1844 }; 2071 };
1845 2072
@@ -1880,16 +2107,14 @@ private:
1880 } 2107 }
1881 2108
1882 regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1); 2109 regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1);
1883
1884 if (instr.generates_cc) {
1885 LOG_CRITICAL(HW_GPU, "IADD3 Generates an unhandled Control Code");
1886 UNREACHABLE();
1887 }
1888 break; 2110 break;
1889 } 2111 }
1890 case OpCode::Id::ISCADD_C: 2112 case OpCode::Id::ISCADD_C:
1891 case OpCode::Id::ISCADD_R: 2113 case OpCode::Id::ISCADD_R:
1892 case OpCode::Id::ISCADD_IMM: { 2114 case OpCode::Id::ISCADD_IMM: {
2115 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2116 "Condition codes generation in ISCADD is not implemented");
2117
1893 if (instr.alu_integer.negate_a) 2118 if (instr.alu_integer.negate_a)
1894 op_a = "-(" + op_a + ')'; 2119 op_a = "-(" + op_a + ')';
1895 2120
@@ -1900,10 +2125,6 @@ private:
1900 2125
1901 regs.SetRegisterToInteger(instr.gpr0, true, 0, 2126 regs.SetRegisterToInteger(instr.gpr0, true, 0,
1902 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); 2127 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
1903 if (instr.generates_cc) {
1904 LOG_CRITICAL(HW_GPU, "ISCADD Generates an unhandled Control Code");
1905 UNREACHABLE();
1906 }
1907 break; 2128 break;
1908 } 2129 }
1909 case OpCode::Id::POPC_C: 2130 case OpCode::Id::POPC_C:
@@ -1927,6 +2148,9 @@ private:
1927 case OpCode::Id::LOP_C: 2148 case OpCode::Id::LOP_C:
1928 case OpCode::Id::LOP_R: 2149 case OpCode::Id::LOP_R:
1929 case OpCode::Id::LOP_IMM: { 2150 case OpCode::Id::LOP_IMM: {
2151 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2152 "Condition codes generation in LOP is not implemented");
2153
1930 if (instr.alu.lop.invert_a) 2154 if (instr.alu.lop.invert_a)
1931 op_a = "~(" + op_a + ')'; 2155 op_a = "~(" + op_a + ')';
1932 2156
@@ -1935,15 +2159,14 @@ private:
1935 2159
1936 WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b, 2160 WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b,
1937 instr.alu.lop.pred_result_mode, instr.alu.lop.pred48); 2161 instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
1938 if (instr.generates_cc) {
1939 LOG_CRITICAL(HW_GPU, "LOP Generates an unhandled Control Code");
1940 UNREACHABLE();
1941 }
1942 break; 2162 break;
1943 } 2163 }
1944 case OpCode::Id::LOP3_C: 2164 case OpCode::Id::LOP3_C:
1945 case OpCode::Id::LOP3_R: 2165 case OpCode::Id::LOP3_R:
1946 case OpCode::Id::LOP3_IMM: { 2166 case OpCode::Id::LOP3_IMM: {
2167 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2168 "Condition codes generation in LOP3 is not implemented");
2169
1947 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); 2170 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
1948 std::string lut; 2171 std::string lut;
1949 2172
@@ -1954,17 +2177,15 @@ private:
1954 } 2177 }
1955 2178
1956 WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut); 2179 WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut);
1957 if (instr.generates_cc) {
1958 LOG_CRITICAL(HW_GPU, "LOP3 Generates an unhandled Control Code");
1959 UNREACHABLE();
1960 }
1961 break; 2180 break;
1962 } 2181 }
1963 case OpCode::Id::IMNMX_C: 2182 case OpCode::Id::IMNMX_C:
1964 case OpCode::Id::IMNMX_R: 2183 case OpCode::Id::IMNMX_R:
1965 case OpCode::Id::IMNMX_IMM: { 2184 case OpCode::Id::IMNMX_IMM: {
1966 ASSERT_MSG(instr.imnmx.exchange == Tegra::Shader::IMinMaxExchange::None, 2185 UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None);
1967 "Unimplemented"); 2186 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2187 "Condition codes generation in IMNMX is not implemented");
2188
1968 const std::string condition = 2189 const std::string condition =
1969 GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0); 2190 GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0);
1970 const std::string parameters = op_a + ',' + op_b; 2191 const std::string parameters = op_a + ',' + op_b;
@@ -1972,10 +2193,6 @@ private:
1972 '(' + condition + ") ? min(" + parameters + ") : max(" + 2193 '(' + condition + ") ? min(" + parameters + ") : max(" +
1973 parameters + ')', 2194 parameters + ')',
1974 1, 1); 2195 1, 1);
1975 if (instr.generates_cc) {
1976 LOG_CRITICAL(HW_GPU, "IMNMX Generates an unhandled Control Code");
1977 UNREACHABLE();
1978 }
1979 break; 2196 break;
1980 } 2197 }
1981 case OpCode::Id::LEA_R2: 2198 case OpCode::Id::LEA_R2:
@@ -2030,24 +2247,19 @@ private:
2030 op_b = regs.GetRegisterAsInteger(instr.gpr8); 2247 op_b = regs.GetRegisterAsInteger(instr.gpr8);
2031 op_a = std::to_string(instr.lea.imm.entry_a); 2248 op_a = std::to_string(instr.lea.imm.entry_a);
2032 op_c = std::to_string(instr.lea.imm.entry_b); 2249 op_c = std::to_string(instr.lea.imm.entry_b);
2033 LOG_CRITICAL(HW_GPU, "Unhandled LEA subinstruction: {}", 2250 UNIMPLEMENTED_MSG("Unhandled LEA subinstruction: {}", opcode->get().GetName());
2034 opcode->get().GetName());
2035 UNREACHABLE();
2036 } 2251 }
2037 } 2252 }
2038 if (instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex)) { 2253 UNIMPLEMENTED_IF_MSG(instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex),
2039 LOG_ERROR(HW_GPU, "Unhandled LEA Predicate"); 2254 "Unhandled LEA Predicate");
2040 UNREACHABLE();
2041 }
2042 const std::string value = '(' + op_a + " + (" + op_b + "*(1 << " + op_c + ")))"; 2255 const std::string value = '(' + op_a + " + (" + op_b + "*(1 << " + op_c + ")))";
2043 regs.SetRegisterToInteger(instr.gpr0, true, 0, value, 1, 1); 2256 regs.SetRegisterToInteger(instr.gpr0, true, 0, value, 1, 1);
2044 2257
2045 break; 2258 break;
2046 } 2259 }
2047 default: { 2260 default: {
2048 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", 2261 UNIMPLEMENTED_MSG("Unhandled ArithmeticInteger instruction: {}",
2049 opcode->get().GetName()); 2262 opcode->get().GetName());
2050 UNREACHABLE();
2051 } 2263 }
2052 } 2264 }
2053 2265
@@ -2056,7 +2268,7 @@ private:
2056 case OpCode::Type::ArithmeticHalf: { 2268 case OpCode::Type::ArithmeticHalf: {
2057 if (opcode->get().GetId() == OpCode::Id::HADD2_C || 2269 if (opcode->get().GetId() == OpCode::Id::HADD2_C ||
2058 opcode->get().GetId() == OpCode::Id::HADD2_R) { 2270 opcode->get().GetId() == OpCode::Id::HADD2_R) {
2059 ASSERT_MSG(instr.alu_half.ftz == 0, "Unimplemented"); 2271 UNIMPLEMENTED_IF(instr.alu_half.ftz != 0);
2060 } 2272 }
2061 const bool negate_a = 2273 const bool negate_a =
2062 opcode->get().GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0; 2274 opcode->get().GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0;
@@ -2094,9 +2306,8 @@ private:
2094 case OpCode::Id::HMUL2_R: 2306 case OpCode::Id::HMUL2_R:
2095 return '(' + op_a + " * " + op_b + ')'; 2307 return '(' + op_a + " * " + op_b + ')';
2096 default: 2308 default:
2097 LOG_CRITICAL(HW_GPU, "Unhandled half float instruction: {}", 2309 UNIMPLEMENTED_MSG("Unhandled half float instruction: {}",
2098 opcode->get().GetName()); 2310 opcode->get().GetName());
2099 UNREACHABLE();
2100 return std::string("0"); 2311 return std::string("0");
2101 } 2312 }
2102 }(); 2313 }();
@@ -2107,10 +2318,10 @@ private:
2107 } 2318 }
2108 case OpCode::Type::ArithmeticHalfImmediate: { 2319 case OpCode::Type::ArithmeticHalfImmediate: {
2109 if (opcode->get().GetId() == OpCode::Id::HADD2_IMM) { 2320 if (opcode->get().GetId() == OpCode::Id::HADD2_IMM) {
2110 ASSERT_MSG(instr.alu_half_imm.ftz == 0, "Unimplemented"); 2321 UNIMPLEMENTED_IF(instr.alu_half_imm.ftz != 0);
2111 } else { 2322 } else {
2112 ASSERT_MSG(instr.alu_half_imm.precision == Tegra::Shader::HalfPrecision::None, 2323 UNIMPLEMENTED_IF(instr.alu_half_imm.precision !=
2113 "Unimplemented"); 2324 Tegra::Shader::HalfPrecision::None);
2114 } 2325 }
2115 2326
2116 const std::string op_a = GetHalfFloat( 2327 const std::string op_a = GetHalfFloat(
@@ -2140,11 +2351,14 @@ private:
2140 std::string op_b = instr.ffma.negate_b ? "-" : ""; 2351 std::string op_b = instr.ffma.negate_b ? "-" : "";
2141 std::string op_c = instr.ffma.negate_c ? "-" : ""; 2352 std::string op_c = instr.ffma.negate_c ? "-" : "";
2142 2353
2143 ASSERT_MSG(instr.ffma.cc == 0, "FFMA cc not implemented"); 2354 UNIMPLEMENTED_IF_MSG(instr.ffma.cc != 0, "FFMA cc not implemented");
2144 ASSERT_MSG(instr.ffma.tab5980_0 == 1, "FFMA tab5980_0({}) not implemented", 2355 UNIMPLEMENTED_IF_MSG(
2145 instr.ffma.tab5980_0.Value()); // Seems to be 1 by default based on SMO 2356 instr.ffma.tab5980_0 != 1, "FFMA tab5980_0({}) not implemented",
2146 ASSERT_MSG(instr.ffma.tab5980_1 == 0, "FFMA tab5980_1({}) not implemented", 2357 instr.ffma.tab5980_0.Value()); // Seems to be 1 by default based on SMO
2147 instr.ffma.tab5980_1.Value()); 2358 UNIMPLEMENTED_IF_MSG(instr.ffma.tab5980_1 != 0, "FFMA tab5980_1({}) not implemented",
2359 instr.ffma.tab5980_1.Value());
2360 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2361 "Condition codes generation in FFMA is not implemented");
2148 2362
2149 switch (opcode->get().GetId()) { 2363 switch (opcode->get().GetId()) {
2150 case OpCode::Id::FFMA_CR: { 2364 case OpCode::Id::FFMA_CR: {
@@ -2170,27 +2384,19 @@ private:
2170 break; 2384 break;
2171 } 2385 }
2172 default: { 2386 default: {
2173 LOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->get().GetName()); 2387 UNIMPLEMENTED_MSG("Unhandled FFMA instruction: {}", opcode->get().GetName());
2174 UNREACHABLE();
2175 } 2388 }
2176 } 2389 }
2177 2390
2178 regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')', 2391 regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')',
2179 1, 1, instr.alu.saturate_d, 0, true); 2392 1, 1, instr.alu.saturate_d, 0, true);
2180 if (instr.generates_cc) {
2181 LOG_CRITICAL(HW_GPU, "FFMA Generates an unhandled Control Code");
2182 UNREACHABLE();
2183 }
2184
2185 break; 2393 break;
2186 } 2394 }
2187 case OpCode::Type::Hfma2: { 2395 case OpCode::Type::Hfma2: {
2188 if (opcode->get().GetId() == OpCode::Id::HFMA2_RR) { 2396 if (opcode->get().GetId() == OpCode::Id::HFMA2_RR) {
2189 ASSERT_MSG(instr.hfma2.rr.precision == Tegra::Shader::HalfPrecision::None, 2397 UNIMPLEMENTED_IF(instr.hfma2.rr.precision != Tegra::Shader::HalfPrecision::None);
2190 "Unimplemented");
2191 } else { 2398 } else {
2192 ASSERT_MSG(instr.hfma2.precision == Tegra::Shader::HalfPrecision::None, 2399 UNIMPLEMENTED_IF(instr.hfma2.precision != Tegra::Shader::HalfPrecision::None);
2193 "Unimplemented");
2194 } 2400 }
2195 const bool saturate = opcode->get().GetId() == OpCode::Id::HFMA2_RR 2401 const bool saturate = opcode->get().GetId() == OpCode::Id::HFMA2_RR
2196 ? instr.hfma2.rr.saturate != 0 2402 ? instr.hfma2.rr.saturate != 0
@@ -2240,7 +2446,7 @@ private:
2240 case OpCode::Type::Conversion: { 2446 case OpCode::Type::Conversion: {
2241 switch (opcode->get().GetId()) { 2447 switch (opcode->get().GetId()) {
2242 case OpCode::Id::I2I_R: { 2448 case OpCode::Id::I2I_R: {
2243 ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); 2449 UNIMPLEMENTED_IF(instr.conversion.selector);
2244 2450
2245 std::string op_a = regs.GetRegisterAsInteger( 2451 std::string op_a = regs.GetRegisterAsInteger(
2246 instr.gpr20, 0, instr.conversion.is_input_signed, instr.conversion.src_size); 2452 instr.gpr20, 0, instr.conversion.is_input_signed, instr.conversion.src_size);
@@ -2260,10 +2466,11 @@ private:
2260 } 2466 }
2261 case OpCode::Id::I2F_R: 2467 case OpCode::Id::I2F_R:
2262 case OpCode::Id::I2F_C: { 2468 case OpCode::Id::I2F_C: {
2263 ASSERT_MSG(instr.conversion.dest_size == Register::Size::Word, "Unimplemented"); 2469 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
2264 ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); 2470 UNIMPLEMENTED_IF(instr.conversion.selector);
2265 2471 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2266 std::string op_a{}; 2472 "Condition codes generation in I2F is not implemented");
2473 std::string op_a;
2267 2474
2268 if (instr.is_b_gpr) { 2475 if (instr.is_b_gpr) {
2269 op_a = 2476 op_a =
@@ -2286,16 +2493,13 @@ private:
2286 } 2493 }
2287 2494
2288 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); 2495 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
2289
2290 if (instr.generates_cc) {
2291 LOG_CRITICAL(HW_GPU, "I2F Generates an unhandled Control Code");
2292 UNREACHABLE();
2293 }
2294 break; 2496 break;
2295 } 2497 }
2296 case OpCode::Id::F2F_R: { 2498 case OpCode::Id::F2F_R: {
2297 ASSERT_MSG(instr.conversion.dest_size == Register::Size::Word, "Unimplemented"); 2499 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
2298 ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented"); 2500 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
2501 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2502 "Condition codes generation in F2F is not implemented");
2299 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); 2503 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
2300 2504
2301 if (instr.conversion.abs_a) { 2505 if (instr.conversion.abs_a) {
@@ -2322,23 +2526,19 @@ private:
2322 op_a = "trunc(" + op_a + ')'; 2526 op_a = "trunc(" + op_a + ')';
2323 break; 2527 break;
2324 default: 2528 default:
2325 LOG_CRITICAL(HW_GPU, "Unimplemented f2f rounding mode {}", 2529 UNIMPLEMENTED_MSG("Unimplemented F2F rounding mode {}",
2326 static_cast<u32>(instr.conversion.f2f.rounding.Value())); 2530 static_cast<u32>(instr.conversion.f2f.rounding.Value()));
2327 UNREACHABLE();
2328 break; 2531 break;
2329 } 2532 }
2330 2533
2331 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d); 2534 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
2332
2333 if (instr.generates_cc) {
2334 LOG_CRITICAL(HW_GPU, "F2F Generates an unhandled Control Code");
2335 UNREACHABLE();
2336 }
2337 break; 2535 break;
2338 } 2536 }
2339 case OpCode::Id::F2I_R: 2537 case OpCode::Id::F2I_R:
2340 case OpCode::Id::F2I_C: { 2538 case OpCode::Id::F2I_C: {
2341 ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented"); 2539 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
2540 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2541 "Condition codes generation in F2I is not implemented");
2342 std::string op_a{}; 2542 std::string op_a{};
2343 2543
2344 if (instr.is_b_gpr) { 2544 if (instr.is_b_gpr) {
@@ -2369,9 +2569,8 @@ private:
2369 op_a = "trunc(" + op_a + ')'; 2569 op_a = "trunc(" + op_a + ')';
2370 break; 2570 break;
2371 default: 2571 default:
2372 LOG_CRITICAL(HW_GPU, "Unimplemented f2i rounding mode {}", 2572 UNIMPLEMENTED_MSG("Unimplemented F2I rounding mode {}",
2373 static_cast<u32>(instr.conversion.f2i.rounding.Value())); 2573 static_cast<u32>(instr.conversion.f2i.rounding.Value()));
2374 UNREACHABLE();
2375 break; 2574 break;
2376 } 2575 }
2377 2576
@@ -2383,16 +2582,10 @@ private:
2383 2582
2384 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, 2583 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
2385 1, false, 0, instr.conversion.dest_size); 2584 1, false, 0, instr.conversion.dest_size);
2386 if (instr.generates_cc) {
2387 LOG_CRITICAL(HW_GPU, "F2I Generates an unhandled Control Code");
2388 UNREACHABLE();
2389 }
2390 break; 2585 break;
2391 } 2586 }
2392 default: { 2587 default: {
2393 LOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", 2588 UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName());
2394 opcode->get().GetName());
2395 UNREACHABLE();
2396 } 2589 }
2397 } 2590 }
2398 break; 2591 break;
@@ -2401,10 +2594,10 @@ private:
2401 switch (opcode->get().GetId()) { 2594 switch (opcode->get().GetId()) {
2402 case OpCode::Id::LD_A: { 2595 case OpCode::Id::LD_A: {
2403 // Note: Shouldn't this be interp mode flat? As in no interpolation made. 2596 // Note: Shouldn't this be interp mode flat? As in no interpolation made.
2404 ASSERT_MSG(instr.gpr8.Value() == Register::ZeroIndex, 2597 UNIMPLEMENTED_IF_MSG(instr.gpr8.Value() != Register::ZeroIndex,
2405 "Indirect attribute loads are not supported"); 2598 "Indirect attribute loads are not supported");
2406 ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0, 2599 UNIMPLEMENTED_IF_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) != 0,
2407 "Unaligned attribute loads are not supported"); 2600 "Unaligned attribute loads are not supported");
2408 2601
2409 Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective, 2602 Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective,
2410 Tegra::Shader::IpaSampleMode::Default}; 2603 Tegra::Shader::IpaSampleMode::Default};
@@ -2431,12 +2624,9 @@ private:
2431 break; 2624 break;
2432 } 2625 }
2433 case OpCode::Id::LD_C: { 2626 case OpCode::Id::LD_C: {
2434 ASSERT_MSG(instr.ld_c.unknown == 0, "Unimplemented"); 2627 UNIMPLEMENTED_IF(instr.ld_c.unknown != 0);
2435 2628
2436 // Add an extra scope and declare the index register inside to prevent 2629 const auto scope = shader.Scope();
2437 // overwriting it in case it is used as an output of the LD instruction.
2438 shader.AddLine("{");
2439 ++shader.scope;
2440 2630
2441 shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + 2631 shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
2442 " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);"); 2632 " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);");
@@ -2459,20 +2649,16 @@ private:
2459 break; 2649 break;
2460 } 2650 }
2461 default: 2651 default:
2462 LOG_CRITICAL(HW_GPU, "Unhandled type: {}", 2652 UNIMPLEMENTED_MSG("Unhandled type: {}",
2463 static_cast<unsigned>(instr.ld_c.type.Value())); 2653 static_cast<unsigned>(instr.ld_c.type.Value()));
2464 UNREACHABLE();
2465 } 2654 }
2466
2467 --shader.scope;
2468 shader.AddLine("}");
2469 break; 2655 break;
2470 } 2656 }
2471 case OpCode::Id::LD_L: { 2657 case OpCode::Id::LD_L: {
2472 // Add an extra scope and declare the index register inside to prevent 2658 UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}",
2473 // overwriting it in case it is used as an output of the LD instruction. 2659 static_cast<unsigned>(instr.ld_l.unknown.Value()));
2474 shader.AddLine('{'); 2660
2475 ++shader.scope; 2661 const auto scope = shader.Scope();
2476 2662
2477 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + 2663 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " +
2478 std::to_string(instr.smem_imm.Value()) + ')'; 2664 std::to_string(instr.smem_imm.Value()) + ')';
@@ -2481,31 +2667,21 @@ private:
2481 2667
2482 const std::string op_a = regs.GetLocalMemoryAsFloat("index"); 2668 const std::string op_a = regs.GetLocalMemoryAsFloat("index");
2483 2669
2484 if (instr.ld_l.unknown != 1) {
2485 LOG_CRITICAL(HW_GPU, "LD_L Unhandled mode: {}",
2486 static_cast<unsigned>(instr.ld_l.unknown.Value()));
2487 UNREACHABLE();
2488 }
2489
2490 switch (instr.ldst_sl.type.Value()) { 2670 switch (instr.ldst_sl.type.Value()) {
2491 case Tegra::Shader::StoreType::Bytes32: 2671 case Tegra::Shader::StoreType::Bytes32:
2492 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); 2672 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
2493 break; 2673 break;
2494 default: 2674 default:
2495 LOG_CRITICAL(HW_GPU, "LD_L Unhandled type: {}", 2675 UNIMPLEMENTED_MSG("LD_L Unhandled type: {}",
2496 static_cast<unsigned>(instr.ldst_sl.type.Value())); 2676 static_cast<unsigned>(instr.ldst_sl.type.Value()));
2497 UNREACHABLE();
2498 } 2677 }
2499
2500 --shader.scope;
2501 shader.AddLine('}');
2502 break; 2678 break;
2503 } 2679 }
2504 case OpCode::Id::ST_A: { 2680 case OpCode::Id::ST_A: {
2505 ASSERT_MSG(instr.gpr8.Value() == Register::ZeroIndex, 2681 UNIMPLEMENTED_IF_MSG(instr.gpr8.Value() != Register::ZeroIndex,
2506 "Indirect attribute loads are not supported"); 2682 "Indirect attribute loads are not supported");
2507 ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0, 2683 UNIMPLEMENTED_IF_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) != 0,
2508 "Unaligned attribute loads are not supported"); 2684 "Unaligned attribute loads are not supported");
2509 2685
2510 u64 next_element = instr.attribute.fmt20.element; 2686 u64 next_element = instr.attribute.fmt20.element;
2511 u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value()); 2687 u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value());
@@ -2530,360 +2706,157 @@ private:
2530 break; 2706 break;
2531 } 2707 }
2532 case OpCode::Id::ST_L: { 2708 case OpCode::Id::ST_L: {
2533 // Add an extra scope and declare the index register inside to prevent 2709 UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}",
2534 // overwriting it in case it is used as an output of the LD instruction. 2710 static_cast<unsigned>(instr.st_l.unknown.Value()));
2535 shader.AddLine('{'); 2711
2536 ++shader.scope; 2712 const auto scope = shader.Scope();
2537 2713
2538 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + 2714 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " +
2539 std::to_string(instr.smem_imm.Value()) + ')'; 2715 std::to_string(instr.smem_imm.Value()) + ')';
2540 2716
2541 shader.AddLine("uint index = (" + op + " / 4);"); 2717 shader.AddLine("uint index = (" + op + " / 4);");
2542 2718
2543 if (instr.st_l.unknown != 0) {
2544 LOG_CRITICAL(HW_GPU, "ST_L Unhandled mode: {}",
2545 static_cast<unsigned>(instr.st_l.unknown.Value()));
2546 UNREACHABLE();
2547 }
2548
2549 switch (instr.ldst_sl.type.Value()) { 2719 switch (instr.ldst_sl.type.Value()) {
2550 case Tegra::Shader::StoreType::Bytes32: 2720 case Tegra::Shader::StoreType::Bytes32:
2551 regs.SetLocalMemoryAsFloat("index", regs.GetRegisterAsFloat(instr.gpr0)); 2721 regs.SetLocalMemoryAsFloat("index", regs.GetRegisterAsFloat(instr.gpr0));
2552 break; 2722 break;
2553 default: 2723 default:
2554 LOG_CRITICAL(HW_GPU, "ST_L Unhandled type: {}", 2724 UNIMPLEMENTED_MSG("ST_L Unhandled type: {}",
2555 static_cast<unsigned>(instr.ldst_sl.type.Value())); 2725 static_cast<unsigned>(instr.ldst_sl.type.Value()));
2556 UNREACHABLE();
2557 } 2726 }
2558
2559 --shader.scope;
2560 shader.AddLine('}');
2561 break; 2727 break;
2562 } 2728 }
2563 case OpCode::Id::TEX: { 2729 case OpCode::Id::TEX: {
2564 Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; 2730 Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
2565 std::string coord;
2566 const bool is_array = instr.tex.array != 0; 2731 const bool is_array = instr.tex.array != 0;
2567
2568 ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2569 "NODEP is not implemented");
2570 ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
2571 "AOFFI is not implemented");
2572
2573 const bool depth_compare = 2732 const bool depth_compare =
2574 instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2733 instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2575 u32 num_coordinates = TextureCoordinates(texture_type); 2734 const auto process_mode = instr.tex.GetTextureProcessMode();
2576 if (depth_compare) 2735 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2577 num_coordinates += 1; 2736 "NODEP is not implemented");
2578 2737 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
2579 switch (num_coordinates) { 2738 "AOFFI is not implemented");
2580 case 1: {
2581 if (is_array) {
2582 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2583 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2584 coord = "vec2 coords = vec2(" + x + ", " + index + ");";
2585 } else {
2586 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2587 coord = "float coords = " + x + ';';
2588 }
2589 break;
2590 }
2591 case 2: {
2592 if (is_array) {
2593 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2594 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2595 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
2596 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
2597 } else {
2598 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2599 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2600 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2601 }
2602 break;
2603 }
2604 case 3: {
2605 if (depth_compare) {
2606 if (is_array) {
2607 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2608 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2609 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2610 const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
2611 coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index +
2612 ");";
2613 } else {
2614 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2615 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2616 const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
2617 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
2618 }
2619 } else {
2620 if (is_array) {
2621 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2622 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2623 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
2624 const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 3);
2625 coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index +
2626 ");";
2627 } else {
2628 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2629 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2630 const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
2631 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
2632 }
2633 }
2634 break;
2635 }
2636 default:
2637 LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}",
2638 static_cast<u32>(num_coordinates));
2639 UNREACHABLE();
2640 2739
2641 // Fallback to interpreting as a 2D texture for now 2740 const auto [coord, texture] =
2642 const std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2741 GetTEXCode(instr, texture_type, process_mode, depth_compare, is_array);
2643 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2644 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2645 texture_type = Tegra::Shader::TextureType::Texture2D;
2646 }
2647 // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias
2648 // or lod.
2649 std::string op_c;
2650
2651 const std::string sampler =
2652 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
2653 // Add an extra scope and declare the texture coords inside to prevent
2654 // overwriting them in case they are used as outputs of the texs instruction.
2655 2742
2656 shader.AddLine("{"); 2743 const auto scope = shader.Scope();
2657 ++shader.scope;
2658 shader.AddLine(coord); 2744 shader.AddLine(coord);
2659 std::string texture;
2660 2745
2661 switch (instr.tex.GetTextureProcessMode()) { 2746 if (depth_compare) {
2662 case Tegra::Shader::TextureProcessMode::None: { 2747 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2663 texture = "texture(" + sampler + ", coords)"; 2748 } else {
2664 break; 2749 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2665 }
2666 case Tegra::Shader::TextureProcessMode::LZ: {
2667 texture = "textureLod(" + sampler + ", coords, 0.0)";
2668 break;
2669 }
2670 case Tegra::Shader::TextureProcessMode::LB:
2671 case Tegra::Shader::TextureProcessMode::LBA: {
2672 if (depth_compare) {
2673 if (is_array)
2674 op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 2);
2675 else
2676 op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
2677 } else {
2678 op_c = regs.GetRegisterAsFloat(instr.gpr20);
2679 }
2680 // TODO: Figure if A suffix changes the equation at all.
2681 texture = "texture(" + sampler + ", coords, " + op_c + ')';
2682 break;
2683 }
2684 case Tegra::Shader::TextureProcessMode::LL:
2685 case Tegra::Shader::TextureProcessMode::LLA: {
2686 if (num_coordinates <= 2) {
2687 op_c = regs.GetRegisterAsFloat(instr.gpr20);
2688 } else {
2689 op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
2690 }
2691 // TODO: Figure if A suffix changes the equation at all.
2692 texture = "textureLod(" + sampler + ", coords, " + op_c + ')';
2693 break;
2694 }
2695 default: {
2696 texture = "texture(" + sampler + ", coords)";
2697 LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}",
2698 static_cast<u32>(instr.tex.GetTextureProcessMode()));
2699 UNREACHABLE();
2700 }
2701 }
2702 if (!depth_compare) {
2703 std::size_t dest_elem{}; 2750 std::size_t dest_elem{};
2704 for (std::size_t elem = 0; elem < 4; ++elem) { 2751 for (std::size_t elem = 0; elem < 4; ++elem) {
2705 if (!instr.tex.IsComponentEnabled(elem)) { 2752 if (!instr.tex.IsComponentEnabled(elem)) {
2706 // Skip disabled components 2753 // Skip disabled components
2707 continue; 2754 continue;
2708 } 2755 }
2709 regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); 2756 regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false,
2757 dest_elem);
2710 ++dest_elem; 2758 ++dest_elem;
2711 } 2759 }
2712 } else {
2713 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2714 } 2760 }
2715 --shader.scope;
2716 shader.AddLine("}");
2717 break; 2761 break;
2718 } 2762 }
2719 case OpCode::Id::TEXS: { 2763 case OpCode::Id::TEXS: {
2720 std::string coord;
2721 Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; 2764 Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
2722 bool is_array{instr.texs.IsArrayTexture()}; 2765 const bool is_array{instr.texs.IsArrayTexture()};
2723
2724 ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2725 "NODEP is not implemented");
2726
2727 const bool depth_compare = 2766 const bool depth_compare =
2728 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2767 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2729 u32 num_coordinates = TextureCoordinates(texture_type); 2768 const auto process_mode = instr.texs.GetTextureProcessMode();
2730 if (depth_compare) 2769 UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2731 num_coordinates += 1; 2770 "NODEP is not implemented");
2732 2771
2733 switch (num_coordinates) { 2772 const auto scope = shader.Scope();
2734 case 2: { 2773
2735 if (is_array) { 2774 const auto [coord, texture] =
2736 const std::string index = regs.GetRegisterAsInteger(instr.gpr8); 2775 GetTEXSCode(instr, texture_type, process_mode, depth_compare, is_array);
2737 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2776
2738 const std::string y = regs.GetRegisterAsFloat(instr.gpr20); 2777 shader.AddLine(coord);
2739 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
2740 } else {
2741 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2742 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2743 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2744 }
2745 break;
2746 }
2747 case 3: {
2748 if (is_array) {
2749 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2750 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2751 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
2752 const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
2753 coord =
2754 "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + ");";
2755 } else {
2756 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2757 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2758 const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
2759 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
2760 }
2761 break;
2762 }
2763 default:
2764 LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}",
2765 static_cast<u32>(num_coordinates));
2766 UNREACHABLE();
2767 2778
2768 // Fallback to interpreting as a 2D texture for now
2769 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2770 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2771 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2772 texture_type = Tegra::Shader::TextureType::Texture2D;
2773 is_array = false;
2774 }
2775 const std::string sampler =
2776 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
2777 std::string texture;
2778 switch (instr.texs.GetTextureProcessMode()) {
2779 case Tegra::Shader::TextureProcessMode::None: {
2780 texture = "texture(" + sampler + ", coords)";
2781 break;
2782 }
2783 case Tegra::Shader::TextureProcessMode::LZ: {
2784 if (depth_compare && is_array) {
2785 texture = "texture(" + sampler + ", coords)";
2786 } else {
2787 texture = "textureLod(" + sampler + ", coords, 0.0)";
2788 }
2789 break;
2790 }
2791 case Tegra::Shader::TextureProcessMode::LL: {
2792 const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
2793 texture = "textureLod(" + sampler + ", coords, " + op_c + ')';
2794 break;
2795 }
2796 default: {
2797 texture = "texture(" + sampler + ", coords)";
2798 LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}",
2799 static_cast<u32>(instr.texs.GetTextureProcessMode()));
2800 UNREACHABLE();
2801 }
2802 }
2803 if (!depth_compare) { 2779 if (!depth_compare) {
2804 WriteTexsInstruction(instr, coord, texture); 2780 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2781
2805 } else { 2782 } else {
2806 WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); 2783 shader.AddLine("vec4 texture_tmp = vec4(" + texture + ");");
2807 } 2784 }
2785
2786 WriteTexsInstruction(instr, "texture_tmp");
2808 break; 2787 break;
2809 } 2788 }
2810 case OpCode::Id::TLDS: { 2789 case OpCode::Id::TLDS: {
2811 std::string coord;
2812 const Tegra::Shader::TextureType texture_type{instr.tlds.GetTextureType()}; 2790 const Tegra::Shader::TextureType texture_type{instr.tlds.GetTextureType()};
2813 const bool is_array{instr.tlds.IsArrayTexture()}; 2791 const bool is_array{instr.tlds.IsArrayTexture()};
2814 2792
2815 ASSERT(texture_type == Tegra::Shader::TextureType::Texture2D); 2793 ASSERT(texture_type == Tegra::Shader::TextureType::Texture2D);
2816 ASSERT(is_array == false); 2794 ASSERT(is_array == false);
2817 2795
2818 ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2796 UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2819 "NODEP is not implemented"); 2797 "NODEP is not implemented");
2820 ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), 2798 UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
2821 "AOFFI is not implemented"); 2799 "AOFFI is not implemented");
2822 ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ), 2800 UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ),
2823 "MZ is not implemented"); 2801 "MZ is not implemented");
2824 2802
2825 u32 op_c_offset = 0; 2803 u32 extra_op_offset = 0;
2804
2805 ShaderScopedScope scope = shader.Scope();
2826 2806
2827 switch (texture_type) { 2807 switch (texture_type) {
2828 case Tegra::Shader::TextureType::Texture1D: { 2808 case Tegra::Shader::TextureType::Texture1D: {
2829 const std::string x = regs.GetRegisterAsInteger(instr.gpr8); 2809 const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
2830 coord = "int coords = " + x + ';'; 2810 shader.AddLine("float coords = " + x + ';');
2831 break; 2811 break;
2832 } 2812 }
2833 case Tegra::Shader::TextureType::Texture2D: { 2813 case Tegra::Shader::TextureType::Texture2D: {
2834 if (is_array) { 2814 UNIMPLEMENTED_IF_MSG(is_array, "Unhandled 2d array texture");
2835 LOG_CRITICAL(HW_GPU, "Unhandled 2d array texture"); 2815
2836 UNREACHABLE(); 2816 const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
2837 } else { 2817 const std::string y = regs.GetRegisterAsInteger(instr.gpr20);
2838 const std::string x = regs.GetRegisterAsInteger(instr.gpr8); 2818 // shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
2839 const std::string y = regs.GetRegisterAsInteger(instr.gpr20); 2819 shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
2840 coord = "ivec2 coords = ivec2(" + x + ", " + y + ");"; 2820 extra_op_offset = 1;
2841 op_c_offset = 1;
2842 }
2843 break; 2821 break;
2844 } 2822 }
2845 default: 2823 default:
2846 LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", 2824 UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast<u32>(texture_type));
2847 static_cast<u32>(texture_type));
2848 UNREACHABLE();
2849 } 2825 }
2850 const std::string sampler = 2826 const std::string sampler =
2851 GetSampler(instr.sampler, texture_type, is_array, false); 2827 GetSampler(instr.sampler, texture_type, is_array, false);
2852 std::string texture = "texelFetch(" + sampler + ", coords, 0)"; 2828
2853 switch (instr.tlds.GetTextureProcessMode()) { 2829 const std::string texture = [&]() {
2854 case Tegra::Shader::TextureProcessMode::LZ: { 2830 switch (instr.tlds.GetTextureProcessMode()) {
2855 texture = "texelFetch(" + sampler + ", coords, 0)"; 2831 case Tegra::Shader::TextureProcessMode::LZ:
2856 break; 2832 return "texelFetch(" + sampler + ", coords, 0)";
2857 } 2833 case Tegra::Shader::TextureProcessMode::LL:
2858 case Tegra::Shader::TextureProcessMode::LL: { 2834 shader.AddLine(
2859 const std::string op_c = 2835 "float lod = " +
2860 regs.GetRegisterAsInteger(instr.gpr20.Value() + op_c_offset); 2836 regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';');
2861 texture = "texelFetch(" + sampler + ", coords, " + op_c + ')'; 2837 return "texelFetch(" + sampler + ", coords, lod)";
2862 break; 2838 default:
2863 } 2839 UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
2864 default: { 2840 static_cast<u32>(instr.tlds.GetTextureProcessMode()));
2865 texture = "texelFetch(" + sampler + ", coords, 0)"; 2841 return "texelFetch(" + sampler + ", coords, 0)";
2866 LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}", 2842 }
2867 static_cast<u32>(instr.tlds.GetTextureProcessMode())); 2843 }();
2868 UNREACHABLE(); 2844
2869 } 2845 WriteTexsInstruction(instr, texture);
2870 }
2871 WriteTexsInstruction(instr, coord, texture);
2872 break; 2846 break;
2873 } 2847 }
2874 case OpCode::Id::TLD4: { 2848 case OpCode::Id::TLD4: {
2875 ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); 2849 ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
2876 ASSERT(instr.tld4.array == 0); 2850 ASSERT(instr.tld4.array == 0);
2877 std::string coord; 2851
2878 2852 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2879 ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2853 "NODEP is not implemented");
2880 "NODEP is not implemented"); 2854 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
2881 ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), 2855 "AOFFI is not implemented");
2882 "AOFFI is not implemented"); 2856 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
2883 ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), 2857 "NDV is not implemented");
2884 "NDV is not implemented"); 2858 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP),
2885 ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP), 2859 "PTP is not implemented");
2886 "PTP is not implemented");
2887 const bool depth_compare = 2860 const bool depth_compare =
2888 instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2861 instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2889 auto texture_type = instr.tld4.texture_type.Value(); 2862 auto texture_type = instr.tld4.texture_type.Value();
@@ -2891,40 +2864,40 @@ private:
2891 if (depth_compare) 2864 if (depth_compare)
2892 num_coordinates += 1; 2865 num_coordinates += 1;
2893 2866
2867 const auto scope = shader.Scope();
2868
2894 switch (num_coordinates) { 2869 switch (num_coordinates) {
2895 case 2: { 2870 case 2: {
2896 const std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2871 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2897 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2872 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2898 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 2873 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
2899 break; 2874 break;
2900 } 2875 }
2901 case 3: { 2876 case 3: {
2902 const std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2877 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2903 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2878 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2904 const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); 2879 const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
2905 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; 2880 shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");");
2906 break; 2881 break;
2907 } 2882 }
2908 default: 2883 default:
2909 LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}", 2884 UNIMPLEMENTED_MSG("Unhandled coordinates number {}",
2910 static_cast<u32>(num_coordinates)); 2885 static_cast<u32>(num_coordinates));
2911 UNREACHABLE();
2912 const std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2886 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2913 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2887 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2914 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 2888 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
2915 texture_type = Tegra::Shader::TextureType::Texture2D; 2889 texture_type = Tegra::Shader::TextureType::Texture2D;
2916 } 2890 }
2917 2891
2918 const std::string sampler = 2892 const std::string sampler =
2919 GetSampler(instr.sampler, texture_type, false, depth_compare); 2893 GetSampler(instr.sampler, texture_type, false, depth_compare);
2920 // Add an extra scope and declare the texture coords inside to prevent 2894
2921 // overwriting them in case they are used as outputs of the texs instruction.
2922 shader.AddLine("{");
2923 ++shader.scope;
2924 shader.AddLine(coord);
2925 const std::string texture = "textureGather(" + sampler + ", coords, " + 2895 const std::string texture = "textureGather(" + sampler + ", coords, " +
2926 std::to_string(instr.tld4.component) + ')'; 2896 std::to_string(instr.tld4.component) + ')';
2927 if (!depth_compare) { 2897
2898 if (depth_compare) {
2899 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2900 } else {
2928 std::size_t dest_elem{}; 2901 std::size_t dest_elem{};
2929 for (std::size_t elem = 0; elem < 4; ++elem) { 2902 for (std::size_t elem = 0; elem < 4; ++elem) {
2930 if (!instr.tex.IsComponentEnabled(elem)) { 2903 if (!instr.tex.IsComponentEnabled(elem)) {
@@ -2934,18 +2907,18 @@ private:
2934 regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); 2907 regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
2935 ++dest_elem; 2908 ++dest_elem;
2936 } 2909 }
2937 } else {
2938 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2939 } 2910 }
2940 --shader.scope;
2941 shader.AddLine("}");
2942 break; 2911 break;
2943 } 2912 }
2944 case OpCode::Id::TLD4S: { 2913 case OpCode::Id::TLD4S: {
2945 ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2914 UNIMPLEMENTED_IF_MSG(
2946 "NODEP is not implemented"); 2915 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2947 ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), 2916 "NODEP is not implemented");
2948 "AOFFI is not implemented"); 2917 UNIMPLEMENTED_IF_MSG(
2918 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
2919 "AOFFI is not implemented");
2920
2921 const auto scope = shader.Scope();
2949 2922
2950 const bool depth_compare = 2923 const bool depth_compare =
2951 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2924 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
@@ -2954,52 +2927,58 @@ private:
2954 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. 2927 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
2955 const std::string sampler = GetSampler( 2928 const std::string sampler = GetSampler(
2956 instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); 2929 instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare);
2957 std::string coord; 2930 if (depth_compare) {
2958 if (!depth_compare) {
2959 coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
2960 } else {
2961 // Note: TLD4S coordinate encoding works just like TEXS's 2931 // Note: TLD4S coordinate encoding works just like TEXS's
2962 const std::string op_c = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2932 const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2963 coord = "vec3 coords = vec3(" + op_a + ", " + op_c + ", " + op_b + ");"; 2933 shader.AddLine("vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");");
2934 } else {
2935 shader.AddLine("vec2 coords = vec2(" + op_a + ", " + op_b + ");");
2964 } 2936 }
2965 const std::string texture = "textureGather(" + sampler + ", coords, " +
2966 std::to_string(instr.tld4s.component) + ')';
2967 2937
2968 if (!depth_compare) { 2938 std::string texture = "textureGather(" + sampler + ", coords, " +
2969 WriteTexsInstruction(instr, coord, texture); 2939 std::to_string(instr.tld4s.component) + ')';
2970 } else { 2940 if (depth_compare) {
2971 WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); 2941 texture = "vec4(" + texture + ')';
2972 } 2942 }
2943 WriteTexsInstruction(instr, texture);
2973 break; 2944 break;
2974 } 2945 }
2975 case OpCode::Id::TXQ: { 2946 case OpCode::Id::TXQ: {
2976 ASSERT_MSG(!instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2947 UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2977 "NODEP is not implemented"); 2948 "NODEP is not implemented");
2949
2950 const auto scope = shader.Scope();
2978 2951
2979 // TODO: the new commits on the texture refactor, change the way samplers work. 2952 // TODO: The new commits on the texture refactor, change the way samplers work.
2980 // Sadly, not all texture instructions specify the type of texture their sampler 2953 // Sadly, not all texture instructions specify the type of texture their sampler
2981 // uses. This must be fixed at a later instance. 2954 // uses. This must be fixed at a later instance.
2982 const std::string sampler = 2955 const std::string sampler =
2983 GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false); 2956 GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false);
2984 switch (instr.txq.query_type) { 2957 switch (instr.txq.query_type) {
2985 case Tegra::Shader::TextureQueryType::Dimension: { 2958 case Tegra::Shader::TextureQueryType::Dimension: {
2986 const std::string texture = "textureQueryLevels(" + sampler + ')'; 2959 const std::string texture = "textureSize(" + sampler + ", " +
2987 regs.SetRegisterToInteger(instr.gpr0, true, 0, texture, 1, 1); 2960 regs.GetRegisterAsInteger(instr.gpr8) + ')';
2961 const std::string mip_level = "textureQueryLevels(" + sampler + ')';
2962 shader.AddLine("ivec2 sizes = " + texture + ';');
2963
2964 regs.SetRegisterToInteger(instr.gpr0.Value() + 0, true, 0, "sizes.x", 1, 1);
2965 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1);
2966 regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1);
2967 regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1);
2988 break; 2968 break;
2989 } 2969 }
2990 default: { 2970 default: {
2991 LOG_CRITICAL(HW_GPU, "Unhandled texture query type: {}", 2971 UNIMPLEMENTED_MSG("Unhandled texture query type: {}",
2992 static_cast<u32>(instr.txq.query_type.Value())); 2972 static_cast<u32>(instr.txq.query_type.Value()));
2993 UNREACHABLE();
2994 } 2973 }
2995 } 2974 }
2996 break; 2975 break;
2997 } 2976 }
2998 case OpCode::Id::TMML: { 2977 case OpCode::Id::TMML: {
2999 ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2978 UNIMPLEMENTED_IF_MSG(instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
3000 "NODEP is not implemented"); 2979 "NODEP is not implemented");
3001 ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), 2980 UNIMPLEMENTED_IF_MSG(instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
3002 "NDV is not implemented"); 2981 "NDV is not implemented");
3003 2982
3004 const std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2983 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
3005 const bool is_array = instr.tmml.array != 0; 2984 const bool is_array = instr.tmml.array != 0;
@@ -3007,47 +2986,38 @@ private:
3007 const std::string sampler = 2986 const std::string sampler =
3008 GetSampler(instr.sampler, texture_type, is_array, false); 2987 GetSampler(instr.sampler, texture_type, is_array, false);
3009 2988
3010 // TODO: add coordinates for different samplers once other texture types are 2989 const auto scope = shader.Scope();
2990
2991 // TODO: Add coordinates for different samplers once other texture types are
3011 // implemented. 2992 // implemented.
3012 std::string coord;
3013 switch (texture_type) { 2993 switch (texture_type) {
3014 case Tegra::Shader::TextureType::Texture1D: { 2994 case Tegra::Shader::TextureType::Texture1D: {
3015 coord = "float coords = " + x + ';'; 2995 shader.AddLine("float coords = " + x + ';');
3016 break; 2996 break;
3017 } 2997 }
3018 case Tegra::Shader::TextureType::Texture2D: { 2998 case Tegra::Shader::TextureType::Texture2D: {
3019 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2999 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
3020 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 3000 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
3021 break; 3001 break;
3022 } 3002 }
3023 default: 3003 default:
3024 LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", 3004 UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast<u32>(texture_type));
3025 static_cast<u32>(texture_type));
3026 UNREACHABLE();
3027 3005
3028 // Fallback to interpreting as a 2D texture for now 3006 // Fallback to interpreting as a 2D texture for now
3029 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 3007 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
3030 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 3008 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
3031 texture_type = Tegra::Shader::TextureType::Texture2D; 3009 texture_type = Tegra::Shader::TextureType::Texture2D;
3032 } 3010 }
3033 // Add an extra scope and declare the texture coords inside to prevent 3011
3034 // overwriting them in case they are used as outputs of the texs instruction.
3035 shader.AddLine('{');
3036 ++shader.scope;
3037 shader.AddLine(coord);
3038 const std::string texture = "textureQueryLod(" + sampler + ", coords)"; 3012 const std::string texture = "textureQueryLod(" + sampler + ", coords)";
3039 const std::string tmp = "vec2 tmp = " + texture + "*vec2(256.0, 256.0);"; 3013 shader.AddLine("vec2 tmp = " + texture + " * vec2(256.0, 256.0);");
3040 shader.AddLine(tmp);
3041 3014
3042 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1); 3015 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1);
3043 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1); 3016 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1);
3044 --shader.scope;
3045 shader.AddLine('}');
3046 break; 3017 break;
3047 } 3018 }
3048 default: { 3019 default: {
3049 LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->get().GetName()); 3020 UNIMPLEMENTED_MSG("Unhandled memory instruction: {}", opcode->get().GetName());
3050 UNREACHABLE();
3051 } 3021 }
3052 } 3022 }
3053 break; 3023 break;
@@ -3133,7 +3103,7 @@ private:
3133 break; 3103 break;
3134 } 3104 }
3135 case OpCode::Type::HalfSetPredicate: { 3105 case OpCode::Type::HalfSetPredicate: {
3136 ASSERT_MSG(instr.hsetp2.ftz == 0, "Unimplemented"); 3106 UNIMPLEMENTED_IF(instr.hsetp2.ftz != 0);
3137 3107
3138 const std::string op_a = 3108 const std::string op_a =
3139 GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.hsetp2.type_a, 3109 GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.hsetp2.type_a,
@@ -3178,6 +3148,9 @@ private:
3178 break; 3148 break;
3179 } 3149 }
3180 case OpCode::Type::PredicateSetRegister: { 3150 case OpCode::Type::PredicateSetRegister: {
3151 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
3152 "Condition codes generation in PSET is not implemented");
3153
3181 const std::string op_a = 3154 const std::string op_a =
3182 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0); 3155 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);
3183 const std::string op_b = 3156 const std::string op_b =
@@ -3198,12 +3171,6 @@ private:
3198 const std::string value = '(' + result + ") ? 1.0 : 0.0"; 3171 const std::string value = '(' + result + ") ? 1.0 : 0.0";
3199 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1); 3172 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
3200 } 3173 }
3201
3202 if (instr.generates_cc) {
3203 LOG_CRITICAL(HW_GPU, "PSET Generates an unhandled Control Code");
3204 UNREACHABLE();
3205 }
3206
3207 break; 3174 break;
3208 } 3175 }
3209 case OpCode::Type::PredicateSetPredicate: { 3176 case OpCode::Type::PredicateSetPredicate: {
@@ -3241,25 +3208,51 @@ private:
3241 const std::string pred = 3208 const std::string pred =
3242 GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0); 3209 GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0);
3243 const std::string combiner = GetPredicateCombiner(instr.csetp.op); 3210 const std::string combiner = GetPredicateCombiner(instr.csetp.op);
3244 const std::string control_code = regs.GetControlCode(instr.csetp.cc); 3211 const std::string condition_code = regs.GetConditionCode(instr.csetp.cc);
3245 if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) { 3212 if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
3246 SetPredicate(instr.csetp.pred3, 3213 SetPredicate(instr.csetp.pred3,
3247 '(' + control_code + ") " + combiner + " (" + pred + ')'); 3214 '(' + condition_code + ") " + combiner + " (" + pred + ')');
3248 } 3215 }
3249 if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { 3216 if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
3250 SetPredicate(instr.csetp.pred0, 3217 SetPredicate(instr.csetp.pred0,
3251 "!(" + control_code + ") " + combiner + " (" + pred + ')'); 3218 "!(" + condition_code + ") " + combiner + " (" + pred + ')');
3252 } 3219 }
3253 break; 3220 break;
3254 } 3221 }
3255 default: { 3222 default: {
3256 LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", 3223 UNIMPLEMENTED_MSG("Unhandled predicate instruction: {}", opcode->get().GetName());
3257 opcode->get().GetName());
3258 UNREACHABLE();
3259 } 3224 }
3260 } 3225 }
3261 break; 3226 break;
3262 } 3227 }
3228 case OpCode::Type::RegisterSetPredicate: {
3229 UNIMPLEMENTED_IF(instr.r2p.mode != Tegra::Shader::R2pMode::Pr);
3230
3231 const std::string apply_mask = [&]() {
3232 switch (opcode->get().GetId()) {
3233 case OpCode::Id::R2P_IMM:
3234 return std::to_string(instr.r2p.immediate_mask);
3235 default:
3236 UNREACHABLE();
3237 }
3238 }();
3239 const std::string mask = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
3240 " >> " + std::to_string(instr.r2p.byte) + ')';
3241
3242 constexpr u64 programmable_preds = 7;
3243 for (u64 pred = 0; pred < programmable_preds; ++pred) {
3244 const auto shift = std::to_string(1 << pred);
3245
3246 shader.AddLine("if ((" + apply_mask + " & " + shift + ") != 0) {");
3247 ++shader.scope;
3248
3249 SetPredicate(pred, '(' + mask + " & " + shift + ") != 0");
3250
3251 --shader.scope;
3252 shader.AddLine('}');
3253 }
3254 break;
3255 }
3263 case OpCode::Type::FloatSet: { 3256 case OpCode::Type::FloatSet: {
3264 const std::string op_a = GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8), 3257 const std::string op_a = GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8),
3265 instr.fset.abs_a != 0, instr.fset.neg_a != 0); 3258 instr.fset.abs_a != 0, instr.fset.neg_a != 0);
@@ -3297,6 +3290,10 @@ private:
3297 regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1, 3290 regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1,
3298 1); 3291 1);
3299 } 3292 }
3293 if (instr.generates_cc.Value() != 0) {
3294 regs.SetInternalFlag(InternalFlag::ZeroFlag, predicate);
3295 LOG_WARNING(HW_GPU, "FSET Condition Code is incomplete");
3296 }
3300 break; 3297 break;
3301 } 3298 }
3302 case OpCode::Type::IntegerSet: { 3299 case OpCode::Type::IntegerSet: {
@@ -3335,7 +3332,7 @@ private:
3335 break; 3332 break;
3336 } 3333 }
3337 case OpCode::Type::HalfSet: { 3334 case OpCode::Type::HalfSet: {
3338 ASSERT_MSG(instr.hset2.ftz == 0, "Unimplemented"); 3335 UNIMPLEMENTED_IF(instr.hset2.ftz != 0);
3339 3336
3340 const std::string op_a = 3337 const std::string op_a =
3341 GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.hset2.type_a, 3338 GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.hset2.type_a,
@@ -3379,15 +3376,17 @@ private:
3379 break; 3376 break;
3380 } 3377 }
3381 case OpCode::Type::Xmad: { 3378 case OpCode::Type::Xmad: {
3382 ASSERT_MSG(!instr.xmad.sign_a, "Unimplemented"); 3379 UNIMPLEMENTED_IF(instr.xmad.sign_a);
3383 ASSERT_MSG(!instr.xmad.sign_b, "Unimplemented"); 3380 UNIMPLEMENTED_IF(instr.xmad.sign_b);
3381 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
3382 "Condition codes generation in XMAD is not implemented");
3384 3383
3385 std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)}; 3384 std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)};
3386 std::string op_b; 3385 std::string op_b;
3387 std::string op_c; 3386 std::string op_c;
3388 3387
3389 // TODO(bunnei): Needs to be fixed once op_a or op_b is signed 3388 // TODO(bunnei): Needs to be fixed once op_a or op_b is signed
3390 ASSERT_MSG(instr.xmad.sign_a == instr.xmad.sign_b, "Unimplemented"); 3389 UNIMPLEMENTED_IF(instr.xmad.sign_a != instr.xmad.sign_b);
3391 const bool is_signed{instr.xmad.sign_a == 1}; 3390 const bool is_signed{instr.xmad.sign_a == 1};
3392 3391
3393 bool is_merge{}; 3392 bool is_merge{};
@@ -3420,8 +3419,7 @@ private:
3420 break; 3419 break;
3421 } 3420 }
3422 default: { 3421 default: {
3423 LOG_CRITICAL(HW_GPU, "Unhandled XMAD instruction: {}", opcode->get().GetName()); 3422 UNIMPLEMENTED_MSG("Unhandled XMAD instruction: {}", opcode->get().GetName());
3424 UNREACHABLE();
3425 } 3423 }
3426 } 3424 }
3427 3425
@@ -3457,9 +3455,8 @@ private:
3457 op_c = "((" + op_c + ") + (" + src2 + "<< 16))"; 3455 op_c = "((" + op_c + ") + (" + src2 + "<< 16))";
3458 break; 3456 break;
3459 default: { 3457 default: {
3460 LOG_CRITICAL(HW_GPU, "Unhandled XMAD mode: {}", 3458 UNIMPLEMENTED_MSG("Unhandled XMAD mode: {}",
3461 static_cast<u32>(instr.xmad.mode.Value())); 3459 static_cast<u32>(instr.xmad.mode.Value()));
3462 UNREACHABLE();
3463 } 3460 }
3464 } 3461 }
3465 3462
@@ -3469,25 +3466,19 @@ private:
3469 } 3466 }
3470 3467
3471 regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1); 3468 regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1);
3472 if (instr.generates_cc) {
3473 LOG_CRITICAL(HW_GPU, "XMAD Generates an unhandled Control Code");
3474 UNREACHABLE();
3475 }
3476 break; 3469 break;
3477 } 3470 }
3478 default: { 3471 default: {
3479 switch (opcode->get().GetId()) { 3472 switch (opcode->get().GetId()) {
3480 case OpCode::Id::EXIT: { 3473 case OpCode::Id::EXIT: {
3474 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3475 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
3476 "EXIT condition code used: {}", static_cast<u32>(cc));
3477
3481 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { 3478 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
3482 EmitFragmentOutputsWrite(); 3479 EmitFragmentOutputsWrite();
3483 } 3480 }
3484 3481
3485 const Tegra::Shader::ControlCode cc = instr.flow_control_code;
3486 if (cc != Tegra::Shader::ControlCode::T) {
3487 LOG_CRITICAL(HW_GPU, "EXIT Control Code used: {}", static_cast<u32>(cc));
3488 UNREACHABLE();
3489 }
3490
3491 switch (instr.flow.cond) { 3482 switch (instr.flow.cond) {
3492 case Tegra::Shader::FlowCondition::Always: 3483 case Tegra::Shader::FlowCondition::Always:
3493 shader.AddLine("return true;"); 3484 shader.AddLine("return true;");
@@ -3502,26 +3493,24 @@ private:
3502 case Tegra::Shader::FlowCondition::Fcsm_Tr: 3493 case Tegra::Shader::FlowCondition::Fcsm_Tr:
3503 // TODO(bunnei): What is this used for? If we assume this conditon is not 3494 // TODO(bunnei): What is this used for? If we assume this conditon is not
3504 // satisifed, dual vertex shaders in Farming Simulator make more sense 3495 // satisifed, dual vertex shaders in Farming Simulator make more sense
3505 LOG_CRITICAL(HW_GPU, "Skipping unknown FlowCondition::Fcsm_Tr"); 3496 UNIMPLEMENTED_MSG("Skipping unknown FlowCondition::Fcsm_Tr");
3506 break; 3497 break;
3507 3498
3508 default: 3499 default:
3509 LOG_CRITICAL(HW_GPU, "Unhandled flow condition: {}", 3500 UNIMPLEMENTED_MSG("Unhandled flow condition: {}",
3510 static_cast<u32>(instr.flow.cond.Value())); 3501 static_cast<u32>(instr.flow.cond.Value()));
3511 UNREACHABLE();
3512 } 3502 }
3513 break; 3503 break;
3514 } 3504 }
3515 case OpCode::Id::KIL: { 3505 case OpCode::Id::KIL: {
3516 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); 3506 UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always);
3507
3508 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3509 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
3510 "KIL condition code used: {}", static_cast<u32>(cc));
3517 3511
3518 // Enclose "discard" in a conditional, so that GLSL compilation does not complain 3512 // Enclose "discard" in a conditional, so that GLSL compilation does not complain
3519 // about unexecuted instructions that may follow this. 3513 // about unexecuted instructions that may follow this.
3520 const Tegra::Shader::ControlCode cc = instr.flow_control_code;
3521 if (cc != Tegra::Shader::ControlCode::T) {
3522 LOG_CRITICAL(HW_GPU, "KIL Control Code used: {}", static_cast<u32>(cc));
3523 UNREACHABLE();
3524 }
3525 shader.AddLine("if (true) {"); 3514 shader.AddLine("if (true) {");
3526 ++shader.scope; 3515 ++shader.scope;
3527 shader.AddLine("discard;"); 3516 shader.AddLine("discard;");
@@ -3531,7 +3520,8 @@ private:
3531 break; 3520 break;
3532 } 3521 }
3533 case OpCode::Id::OUT_R: { 3522 case OpCode::Id::OUT_R: {
3534 ASSERT(instr.gpr20.Value() == Register::ZeroIndex); 3523 UNIMPLEMENTED_IF_MSG(instr.gpr20.Value() != Register::ZeroIndex,
3524 "Stream buffer is not supported");
3535 ASSERT_MSG(stage == Maxwell3D::Regs::ShaderStage::Geometry, 3525 ASSERT_MSG(stage == Maxwell3D::Regs::ShaderStage::Geometry,
3536 "OUT is expected to be used in a geometry shader."); 3526 "OUT is expected to be used in a geometry shader.");
3537 3527
@@ -3557,19 +3547,23 @@ private:
3557 regs.SetRegisterToInteger(instr.gpr0, false, 0, "0u", 1, 1); 3547 regs.SetRegisterToInteger(instr.gpr0, false, 0, "0u", 1, 1);
3558 break; 3548 break;
3559 } 3549 }
3550 case Tegra::Shader::SystemVariable::Ydirection: {
3551 // Config pack's third value is Y_NEGATE's state.
3552 regs.SetRegisterToFloat(instr.gpr0, 0, "uintBitsToFloat(config_pack[2])", 1, 1);
3553 break;
3554 }
3560 default: { 3555 default: {
3561 LOG_CRITICAL(HW_GPU, "Unhandled system move: {}", 3556 UNIMPLEMENTED_MSG("Unhandled system move: {}",
3562 static_cast<u32>(instr.sys20.Value())); 3557 static_cast<u32>(instr.sys20.Value()));
3563 UNREACHABLE();
3564 } 3558 }
3565 } 3559 }
3566 break; 3560 break;
3567 } 3561 }
3568 case OpCode::Id::ISBERD: { 3562 case OpCode::Id::ISBERD: {
3569 ASSERT(instr.isberd.o == 0); 3563 UNIMPLEMENTED_IF(instr.isberd.o != 0);
3570 ASSERT(instr.isberd.skew == 0); 3564 UNIMPLEMENTED_IF(instr.isberd.skew != 0);
3571 ASSERT(instr.isberd.shift == Tegra::Shader::IsberdShift::None); 3565 UNIMPLEMENTED_IF(instr.isberd.shift != Tegra::Shader::IsberdShift::None);
3572 ASSERT(instr.isberd.mode == Tegra::Shader::IsberdMode::None); 3566 UNIMPLEMENTED_IF(instr.isberd.mode != Tegra::Shader::IsberdMode::None);
3573 ASSERT_MSG(stage == Maxwell3D::Regs::ShaderStage::Geometry, 3567 ASSERT_MSG(stage == Maxwell3D::Regs::ShaderStage::Geometry,
3574 "ISBERD is expected to be used in a geometry shader."); 3568 "ISBERD is expected to be used in a geometry shader.");
3575 LOG_WARNING(HW_GPU, "ISBERD instruction is incomplete"); 3569 LOG_WARNING(HW_GPU, "ISBERD instruction is incomplete");
@@ -3577,15 +3571,21 @@ private:
3577 break; 3571 break;
3578 } 3572 }
3579 case OpCode::Id::BRA: { 3573 case OpCode::Id::BRA: {
3580 ASSERT_MSG(instr.bra.constant_buffer == 0, 3574 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
3581 "BRA with constant buffers are not implemented"); 3575 "BRA with constant buffers are not implemented");
3582 const Tegra::Shader::ControlCode cc = instr.flow_control_code; 3576
3583 if (cc != Tegra::Shader::ControlCode::T) { 3577 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3584 LOG_CRITICAL(HW_GPU, "BRA Control Code used: {}", static_cast<u32>(cc));
3585 UNREACHABLE();
3586 }
3587 const u32 target = offset + instr.bra.GetBranchTarget(); 3578 const u32 target = offset + instr.bra.GetBranchTarget();
3588 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); 3579 if (cc != Tegra::Shader::ConditionCode::T) {
3580 const std::string condition_code = regs.GetConditionCode(cc);
3581 shader.AddLine("if (" + condition_code + "){");
3582 shader.scope++;
3583 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
3584 shader.scope--;
3585 shader.AddLine('}');
3586 } else {
3587 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
3588 }
3589 break; 3589 break;
3590 } 3590 }
3591 case OpCode::Id::IPA: { 3591 case OpCode::Id::IPA: {
@@ -3606,7 +3606,8 @@ private:
3606 // The SSY opcode tells the GPU where to re-converge divergent execution paths, it 3606 // The SSY opcode tells the GPU where to re-converge divergent execution paths, it
3607 // sets the target of the jump that the SYNC instruction will make. The SSY opcode 3607 // sets the target of the jump that the SYNC instruction will make. The SSY opcode
3608 // has a similar structure to the BRA opcode. 3608 // has a similar structure to the BRA opcode.
3609 ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer flow is not supported"); 3609 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
3610 "Constant buffer flow is not supported");
3610 3611
3611 const u32 target = offset + instr.bra.GetBranchTarget(); 3612 const u32 target = offset + instr.bra.GetBranchTarget();
3612 EmitPushToFlowStack(target); 3613 EmitPushToFlowStack(target);
@@ -3616,29 +3617,28 @@ private:
3616 // PBK pushes to a stack the address where BRK will jump to. This shares stack with 3617 // PBK pushes to a stack the address where BRK will jump to. This shares stack with
3617 // SSY but using SYNC on a PBK address will kill the shader execution. We don't 3618 // SSY but using SYNC on a PBK address will kill the shader execution. We don't
3618 // emulate this because it's very unlikely a driver will emit such invalid shader. 3619 // emulate this because it's very unlikely a driver will emit such invalid shader.
3619 ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer PBK is not supported"); 3620 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
3621 "Constant buffer PBK is not supported");
3620 3622
3621 const u32 target = offset + instr.bra.GetBranchTarget(); 3623 const u32 target = offset + instr.bra.GetBranchTarget();
3622 EmitPushToFlowStack(target); 3624 EmitPushToFlowStack(target);
3623 break; 3625 break;
3624 } 3626 }
3625 case OpCode::Id::SYNC: { 3627 case OpCode::Id::SYNC: {
3628 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3629 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
3630 "SYNC condition code used: {}", static_cast<u32>(cc));
3631
3626 // The SYNC opcode jumps to the address previously set by the SSY opcode 3632 // The SYNC opcode jumps to the address previously set by the SSY opcode
3627 const Tegra::Shader::ControlCode cc = instr.flow_control_code;
3628 if (cc != Tegra::Shader::ControlCode::T) {
3629 LOG_CRITICAL(HW_GPU, "SYNC Control Code used: {}", static_cast<u32>(cc));
3630 UNREACHABLE();
3631 }
3632 EmitPopFromFlowStack(); 3633 EmitPopFromFlowStack();
3633 break; 3634 break;
3634 } 3635 }
3635 case OpCode::Id::BRK: { 3636 case OpCode::Id::BRK: {
3636 // The BRK opcode jumps to the address previously set by the PBK opcode 3637 // The BRK opcode jumps to the address previously set by the PBK opcode
3637 const Tegra::Shader::ControlCode cc = instr.flow_control_code; 3638 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3638 if (cc != Tegra::Shader::ControlCode::T) { 3639 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
3639 LOG_CRITICAL(HW_GPU, "BRK Control Code used: {}", static_cast<u32>(cc)); 3640 "BRK condition code used: {}", static_cast<u32>(cc));
3640 UNREACHABLE(); 3641
3641 }
3642 EmitPopFromFlowStack(); 3642 EmitPopFromFlowStack();
3643 break; 3643 break;
3644 } 3644 }
@@ -3649,6 +3649,9 @@ private:
3649 break; 3649 break;
3650 } 3650 }
3651 case OpCode::Id::VMAD: { 3651 case OpCode::Id::VMAD: {
3652 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
3653 "Condition codes generation in VMAD is not implemented");
3654
3652 const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1; 3655 const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1;
3653 const std::string op_a = GetVideoOperandA(instr); 3656 const std::string op_a = GetVideoOperandA(instr);
3654 const std::string op_b = GetVideoOperandB(instr); 3657 const std::string op_b = GetVideoOperandB(instr);
@@ -3668,11 +3671,6 @@ private:
3668 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, 3671 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
3669 instr.vmad.saturate == 1, 0, Register::Size::Word, 3672 instr.vmad.saturate == 1, 0, Register::Size::Word,
3670 instr.vmad.cc); 3673 instr.vmad.cc);
3671 if (instr.generates_cc) {
3672 LOG_CRITICAL(HW_GPU, "VMAD Generates an unhandled Control Code");
3673 UNREACHABLE();
3674 }
3675
3676 break; 3674 break;
3677 } 3675 }
3678 case OpCode::Id::VSETP: { 3676 case OpCode::Id::VSETP: {
@@ -3699,10 +3697,7 @@ private:
3699 } 3697 }
3700 break; 3698 break;
3701 } 3699 }
3702 default: { 3700 default: { UNIMPLEMENTED_MSG("Unhandled instruction: {}", opcode->get().GetName()); }
3703 LOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->get().GetName());
3704 UNREACHABLE();
3705 }
3706 } 3701 }
3707 3702
3708 break; 3703 break;
@@ -3827,6 +3822,7 @@ private:
3827 Maxwell3D::Regs::ShaderStage stage; 3822 Maxwell3D::Regs::ShaderStage stage;
3828 const std::string& suffix; 3823 const std::string& suffix;
3829 u64 local_memory_size; 3824 u64 local_memory_size;
3825 std::size_t shader_length;
3830 3826
3831 ShaderWriter shader; 3827 ShaderWriter shader;
3832 ShaderWriter declarations; 3828 ShaderWriter declarations;
@@ -3845,9 +3841,10 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
3845 Maxwell3D::Regs::ShaderStage stage, 3841 Maxwell3D::Regs::ShaderStage stage,
3846 const std::string& suffix) { 3842 const std::string& suffix) {
3847 try { 3843 try {
3848 const auto subroutines = 3844 ControlFlowAnalyzer analyzer(program_code, main_offset, suffix);
3849 ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); 3845 const auto subroutines = analyzer.GetSubroutines();
3850 GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix); 3846 GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix,
3847 analyzer.GetShaderLength());
3851 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; 3848 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
3852 } catch (const DecompileFail& exception) { 3849 } catch (const DecompileFail& exception) {
3853 LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); 3850 LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
@@ -3855,4 +3852,4 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
3855 return {}; 3852 return {};
3856} 3853}
3857 3854
3858} // namespace OpenGL::GLShader::Decompiler 3855} // namespace OpenGL::GLShader::Decompiler \ No newline at end of file
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index eea090e52..23ed91e27 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -24,8 +24,7 @@ layout (location = 0) out vec4 position;
24 24
25layout(std140) uniform vs_config { 25layout(std140) uniform vs_config {
26 vec4 viewport_flip; 26 vec4 viewport_flip;
27 uvec4 instance_id; 27 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
28 uvec4 flip_stage;
29 uvec4 alpha_test; 28 uvec4 alpha_test;
30}; 29};
31)"; 30)";
@@ -63,7 +62,8 @@ void main() {
63 out += R"( 62 out += R"(
64 63
65 // Check if the flip stage is VertexB 64 // Check if the flip stage is VertexB
66 if (flip_stage[0] == 1) { 65 // Config pack's second value is flip_stage
66 if (config_pack[1] == 1) {
67 // Viewport can be flipped, which is unsupported by glViewport 67 // Viewport can be flipped, which is unsupported by glViewport
68 position.xy *= viewport_flip.xy; 68 position.xy *= viewport_flip.xy;
69 } 69 }
@@ -71,7 +71,7 @@ void main() {
71 71
72 // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0 72 // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0
73 // For now, this is here to bring order in lieu of proper emulation 73 // For now, this is here to bring order in lieu of proper emulation
74 if (flip_stage[0] == 1) { 74 if (config_pack[1] == 1) {
75 position.w = 1.0; 75 position.w = 1.0;
76 } 76 }
77} 77}
@@ -101,8 +101,7 @@ layout (location = 0) out vec4 position;
101 101
102layout (std140) uniform gs_config { 102layout (std140) uniform gs_config {
103 vec4 viewport_flip; 103 vec4 viewport_flip;
104 uvec4 instance_id; 104 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
105 uvec4 flip_stage;
106 uvec4 alpha_test; 105 uvec4 alpha_test;
107}; 106};
108 107
@@ -139,8 +138,7 @@ layout (location = 0) in vec4 position;
139 138
140layout (std140) uniform fs_config { 139layout (std140) uniform fs_config {
141 vec4 viewport_flip; 140 vec4 viewport_flip;
142 uvec4 instance_id; 141 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
143 uvec4 flip_stage;
144 uvec4 alpha_test; 142 uvec4 alpha_test;
145}; 143};
146 144
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index 520b9d4e3..4fa6d7612 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -163,6 +163,8 @@ private:
163struct ShaderEntries { 163struct ShaderEntries {
164 std::vector<ConstBufferEntry> const_buffer_entries; 164 std::vector<ConstBufferEntry> const_buffer_entries;
165 std::vector<SamplerEntry> texture_samplers; 165 std::vector<SamplerEntry> texture_samplers;
166 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> clip_distances;
167 std::size_t shader_length;
166}; 168};
167 169
168using ProgramResult = std::pair<std::string, ShaderEntries>; 170using ProgramResult = std::pair<std::string, ShaderEntries>;
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index 8b8869ecb..6a30c28d2 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -27,16 +27,18 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh
27 alpha_test.func = func; 27 alpha_test.func = func;
28 alpha_test.ref = regs.alpha_test_ref; 28 alpha_test.ref = regs.alpha_test_ref;
29 29
30 // We only assign the instance to the first component of the vector, the rest is just padding. 30 instance_id = state.current_instance;
31 instance_id[0] = state.current_instance;
32 31
33 // Assign in which stage the position has to be flipped 32 // Assign in which stage the position has to be flipped
34 // (the last stage before the fragment shader). 33 // (the last stage before the fragment shader).
35 if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) { 34 if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) {
36 flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); 35 flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry);
37 } else { 36 } else {
38 flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); 37 flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB);
39 } 38 }
39
40 // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value.
41 y_direction = regs.screen_y_control.y_negate == 0 ? 1.f : -1.f;
40} 42}
41 43
42} // namespace OpenGL::GLShader 44} // namespace OpenGL::GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 2a069cdd8..4970aafed 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -21,8 +21,11 @@ using Tegra::Engines::Maxwell3D;
21struct MaxwellUniformData { 21struct MaxwellUniformData {
22 void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage); 22 void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage);
23 alignas(16) GLvec4 viewport_flip; 23 alignas(16) GLvec4 viewport_flip;
24 alignas(16) GLuvec4 instance_id; 24 struct alignas(16) {
25 alignas(16) GLuvec4 flip_stage; 25 GLuint instance_id;
26 GLuint flip_stage;
27 GLfloat y_direction;
28 };
26 struct alignas(16) { 29 struct alignas(16) {
27 GLuint enabled; 30 GLuint enabled;
28 GLuint func; 31 GLuint func;
@@ -30,7 +33,7 @@ struct MaxwellUniformData {
30 GLuint padding; 33 GLuint padding;
31 } alpha_test; 34 } alpha_test;
32}; 35};
33static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect"); 36static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect");
34static_assert(sizeof(MaxwellUniformData) < 16384, 37static_assert(sizeof(MaxwellUniformData) < 16384,
35 "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); 38 "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
36 39
@@ -57,6 +60,17 @@ public:
57 } 60 }
58 61
59 void ApplyTo(OpenGLState& state) { 62 void ApplyTo(OpenGLState& state) {
63 UpdatePipeline();
64 state.draw.shader_program = 0;
65 state.draw.program_pipeline = pipeline.handle;
66 state.geometry_shaders.enabled = (gs != 0);
67 }
68
69private:
70 void UpdatePipeline() {
71 // Avoid updating the pipeline when values have no changed
72 if (old_vs == vs && old_fs == fs && old_gs == gs)
73 return;
60 // Workaround for AMD bug 74 // Workaround for AMD bug
61 glUseProgramStages(pipeline.handle, 75 glUseProgramStages(pipeline.handle,
62 GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, 76 GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT,
@@ -65,13 +79,16 @@ public:
65 glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vs); 79 glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vs);
66 glUseProgramStages(pipeline.handle, GL_GEOMETRY_SHADER_BIT, gs); 80 glUseProgramStages(pipeline.handle, GL_GEOMETRY_SHADER_BIT, gs);
67 glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs); 81 glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs);
68 state.draw.shader_program = 0; 82
69 state.draw.program_pipeline = pipeline.handle; 83 // Update the old values
84 old_vs = vs;
85 old_fs = fs;
86 old_gs = gs;
70 } 87 }
71 88
72private:
73 OGLPipeline pipeline; 89 OGLPipeline pipeline;
74 GLuint vs{}, fs{}, gs{}; 90 GLuint vs{}, fs{}, gs{};
91 GLuint old_vs{}, old_fs{}, old_gs{};
75}; 92};
76 93
77} // namespace OpenGL::GLShader 94} // namespace OpenGL::GLShader
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 2635f2b0c..dc0a5ed5e 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -14,7 +14,10 @@ OpenGLState OpenGLState::cur_state;
14bool OpenGLState::s_rgb_used; 14bool OpenGLState::s_rgb_used;
15OpenGLState::OpenGLState() { 15OpenGLState::OpenGLState() {
16 // These all match default OpenGL values 16 // These all match default OpenGL values
17 geometry_shaders.enabled = false;
17 framebuffer_srgb.enabled = false; 18 framebuffer_srgb.enabled = false;
19 multisample_control.alpha_to_coverage = false;
20 multisample_control.alpha_to_one = false;
18 cull.enabled = false; 21 cull.enabled = false;
19 cull.mode = GL_BACK; 22 cull.mode = GL_BACK;
20 cull.front_face = GL_CCW; 23 cull.front_face = GL_CCW;
@@ -50,12 +53,12 @@ OpenGLState::OpenGLState() {
50 item.height = 0; 53 item.height = 0;
51 item.depth_range_near = 0.0f; 54 item.depth_range_near = 0.0f;
52 item.depth_range_far = 1.0f; 55 item.depth_range_far = 1.0f;
56 item.scissor.enabled = false;
57 item.scissor.x = 0;
58 item.scissor.y = 0;
59 item.scissor.width = 0;
60 item.scissor.height = 0;
53 } 61 }
54 scissor.enabled = false;
55 scissor.x = 0;
56 scissor.y = 0;
57 scissor.width = 0;
58 scissor.height = 0;
59 for (auto& item : blend) { 62 for (auto& item : blend) {
60 item.enabled = true; 63 item.enabled = true;
61 item.rgb_equation = GL_FUNC_ADD; 64 item.rgb_equation = GL_FUNC_ADD;
@@ -88,6 +91,15 @@ OpenGLState::OpenGLState() {
88 clip_distance = {}; 91 clip_distance = {};
89 92
90 point.size = 1; 93 point.size = 1;
94 fragment_color_clamp.enabled = false;
95 depth_clamp.far_plane = false;
96 depth_clamp.near_plane = false;
97 polygon_offset.fill_enable = false;
98 polygon_offset.line_enable = false;
99 polygon_offset.point_enable = false;
100 polygon_offset.factor = 0.0f;
101 polygon_offset.units = 0.0f;
102 polygon_offset.clamp = 0.0f;
91} 103}
92 104
93void OpenGLState::ApplyDefaultState() { 105void OpenGLState::ApplyDefaultState() {
@@ -136,7 +148,7 @@ void OpenGLState::ApplyCulling() const {
136} 148}
137 149
138void OpenGLState::ApplyColorMask() const { 150void OpenGLState::ApplyColorMask() const {
139 if (GLAD_GL_ARB_viewport_array) { 151 if (independant_blend.enabled) {
140 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 152 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
141 const auto& updated = color_mask[i]; 153 const auto& updated = color_mask[i];
142 const auto& current = cur_state.color_mask[i]; 154 const auto& current = cur_state.color_mask[i];
@@ -229,37 +241,61 @@ void OpenGLState::ApplyStencilTest() const {
229 config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); 241 config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
230 } 242 }
231} 243}
232 244// Viewport does not affects glClearBuffer so emulate viewport using scissor test
233void OpenGLState::ApplyScissor() const { 245void OpenGLState::EmulateViewportWithScissor() {
234 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled; 246 auto& current = viewports[0];
235 if (scissor_changed) { 247 if (current.scissor.enabled) {
236 if (scissor.enabled) { 248 const GLint left = std::max(current.x, current.scissor.x);
237 glEnable(GL_SCISSOR_TEST); 249 const GLint right =
238 } else { 250 std::max(current.x + current.width, current.scissor.x + current.scissor.width);
239 glDisable(GL_SCISSOR_TEST); 251 const GLint bottom = std::max(current.y, current.scissor.y);
240 } 252 const GLint top =
241 } 253 std::max(current.y + current.height, current.scissor.y + current.scissor.height);
242 if (scissor.enabled && 254 current.scissor.x = std::max(left, 0);
243 (scissor_changed || scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y || 255 current.scissor.y = std::max(bottom, 0);
244 scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height)) { 256 current.scissor.width = std::max(right - left, 0);
245 glScissor(scissor.x, scissor.y, scissor.width, scissor.height); 257 current.scissor.height = std::max(top - bottom, 0);
258 } else {
259 current.scissor.enabled = true;
260 current.scissor.x = current.x;
261 current.scissor.y = current.y;
262 current.scissor.width = current.width;
263 current.scissor.height = current.height;
246 } 264 }
247} 265}
248 266
249void OpenGLState::ApplyViewport() const { 267void OpenGLState::ApplyViewport() const {
250 if (GLAD_GL_ARB_viewport_array) { 268 if (geometry_shaders.enabled) {
251 for (GLuint i = 0; 269 for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports);
252 i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) { 270 i++) {
253 const auto& current = cur_state.viewports[i]; 271 const auto& current = cur_state.viewports[i];
254 const auto& updated = viewports[i]; 272 const auto& updated = viewports[i];
255 if (updated.x != current.x || updated.y != current.y || 273 if (updated.x != current.x || updated.y != current.y ||
256 updated.width != current.width || updated.height != current.height) { 274 updated.width != current.width || updated.height != current.height) {
257 glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height); 275 glViewportIndexedf(
276 i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y),
277 static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height));
258 } 278 }
259 if (updated.depth_range_near != current.depth_range_near || 279 if (updated.depth_range_near != current.depth_range_near ||
260 updated.depth_range_far != current.depth_range_far) { 280 updated.depth_range_far != current.depth_range_far) {
261 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far); 281 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
262 } 282 }
283 const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled;
284 if (scissor_changed) {
285 if (updated.scissor.enabled) {
286 glEnablei(GL_SCISSOR_TEST, i);
287 } else {
288 glDisablei(GL_SCISSOR_TEST, i);
289 }
290 }
291 if (updated.scissor.enabled &&
292 (scissor_changed || updated.scissor.x != current.scissor.x ||
293 updated.scissor.y != current.scissor.y ||
294 updated.scissor.width != current.scissor.width ||
295 updated.scissor.height != current.scissor.height)) {
296 glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width,
297 updated.scissor.height);
298 }
263 } 299 }
264 } else { 300 } else {
265 const auto& current = cur_state.viewports[0]; 301 const auto& current = cur_state.viewports[0];
@@ -272,6 +308,21 @@ void OpenGLState::ApplyViewport() const {
272 updated.depth_range_far != current.depth_range_far) { 308 updated.depth_range_far != current.depth_range_far) {
273 glDepthRange(updated.depth_range_near, updated.depth_range_far); 309 glDepthRange(updated.depth_range_near, updated.depth_range_far);
274 } 310 }
311 const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled;
312 if (scissor_changed) {
313 if (updated.scissor.enabled) {
314 glEnable(GL_SCISSOR_TEST);
315 } else {
316 glDisable(GL_SCISSOR_TEST);
317 }
318 }
319 if (updated.scissor.enabled && (scissor_changed || updated.scissor.x != current.scissor.x ||
320 updated.scissor.y != current.scissor.y ||
321 updated.scissor.width != current.scissor.width ||
322 updated.scissor.height != current.scissor.height)) {
323 glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width,
324 updated.scissor.height);
325 }
275 } 326 }
276} 327}
277 328
@@ -289,31 +340,20 @@ void OpenGLState::ApplyGlobalBlending() const {
289 if (!updated.enabled) { 340 if (!updated.enabled) {
290 return; 341 return;
291 } 342 }
292 if (updated.separate_alpha) { 343 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
293 if (blend_changed || updated.src_rgb_func != current.src_rgb_func || 344 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
294 updated.dst_rgb_func != current.dst_rgb_func || 345 updated.dst_a_func != current.dst_a_func) {
295 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) { 346 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
296 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, 347 updated.dst_a_func);
297 updated.dst_a_func); 348 }
298 }
299
300 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
301 updated.a_equation != current.a_equation) {
302 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
303 }
304 } else {
305 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
306 updated.dst_rgb_func != current.dst_rgb_func) {
307 glBlendFunc(updated.src_rgb_func, updated.dst_rgb_func);
308 }
309 349
310 if (blend_changed || updated.rgb_equation != current.rgb_equation) { 350 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
311 glBlendEquation(updated.rgb_equation); 351 updated.a_equation != current.a_equation) {
312 } 352 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
313 } 353 }
314} 354}
315 355
316void OpenGLState::ApplyTargetBlending(int target, bool force) const { 356void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
317 const Blend& updated = blend[target]; 357 const Blend& updated = blend[target];
318 const Blend& current = cur_state.blend[target]; 358 const Blend& current = cur_state.blend[target];
319 const bool blend_changed = updated.enabled != current.enabled || force; 359 const bool blend_changed = updated.enabled != current.enabled || force;
@@ -327,29 +367,17 @@ void OpenGLState::ApplyTargetBlending(int target, bool force) const {
327 if (!updated.enabled) { 367 if (!updated.enabled) {
328 return; 368 return;
329 } 369 }
330 if (updated.separate_alpha) { 370 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
331 if (blend_changed || updated.src_rgb_func != current.src_rgb_func || 371 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
332 updated.dst_rgb_func != current.dst_rgb_func || 372 updated.dst_a_func != current.dst_a_func) {
333 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) { 373 glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func,
334 glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func, 374 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
335 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); 375 }
336 }
337
338 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
339 updated.a_equation != current.a_equation) {
340 glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
341 updated.a_equation);
342 }
343 } else {
344 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
345 updated.dst_rgb_func != current.dst_rgb_func) {
346 glBlendFunciARB(static_cast<GLuint>(target), updated.src_rgb_func,
347 updated.dst_rgb_func);
348 }
349 376
350 if (blend_changed || updated.rgb_equation != current.rgb_equation) { 377 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
351 glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation); 378 updated.a_equation != current.a_equation) {
352 } 379 glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation,
380 updated.a_equation);
353 } 381 }
354} 382}
355 383
@@ -386,6 +414,55 @@ void OpenGLState::ApplyLogicOp() const {
386 } 414 }
387} 415}
388 416
417void OpenGLState::ApplyPolygonOffset() const {
418
419 const bool fill_enable_changed =
420 polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable;
421 const bool line_enable_changed =
422 polygon_offset.line_enable != cur_state.polygon_offset.line_enable;
423 const bool point_enable_changed =
424 polygon_offset.point_enable != cur_state.polygon_offset.point_enable;
425 const bool factor_changed = polygon_offset.factor != cur_state.polygon_offset.factor;
426 const bool units_changed = polygon_offset.units != cur_state.polygon_offset.units;
427 const bool clamp_changed = polygon_offset.clamp != cur_state.polygon_offset.clamp;
428
429 if (fill_enable_changed) {
430 if (polygon_offset.fill_enable) {
431 glEnable(GL_POLYGON_OFFSET_FILL);
432 } else {
433 glDisable(GL_POLYGON_OFFSET_FILL);
434 }
435 }
436
437 if (line_enable_changed) {
438 if (polygon_offset.line_enable) {
439 glEnable(GL_POLYGON_OFFSET_LINE);
440 } else {
441 glDisable(GL_POLYGON_OFFSET_LINE);
442 }
443 }
444
445 if (point_enable_changed) {
446 if (polygon_offset.point_enable) {
447 glEnable(GL_POLYGON_OFFSET_POINT);
448 } else {
449 glDisable(GL_POLYGON_OFFSET_POINT);
450 }
451 }
452
453 if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) &&
454 (factor_changed || units_changed || clamp_changed)) {
455
456 if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) {
457 glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp);
458 } else {
459 glPolygonOffset(polygon_offset.factor, polygon_offset.units);
460 UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0,
461 "Unimplemented Depth polygon offset clamp.");
462 }
463 }
464}
465
389void OpenGLState::ApplyTextures() const { 466void OpenGLState::ApplyTextures() const {
390 for (std::size_t i = 0; i < std::size(texture_units); ++i) { 467 for (std::size_t i = 0; i < std::size(texture_units); ++i) {
391 const auto& texture_unit = texture_units[i]; 468 const auto& texture_unit = texture_units[i];
@@ -449,6 +526,21 @@ void OpenGLState::ApplyVertexBufferState() const {
449 } 526 }
450} 527}
451 528
529void OpenGLState::ApplyDepthClamp() const {
530 if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane &&
531 depth_clamp.near_plane == cur_state.depth_clamp.near_plane) {
532 return;
533 }
534 if (depth_clamp.far_plane != depth_clamp.near_plane) {
535 UNIMPLEMENTED_MSG("Unimplemented Depth Clamp Separation!");
536 }
537 if (depth_clamp.far_plane || depth_clamp.near_plane) {
538 glEnable(GL_DEPTH_CLAMP);
539 } else {
540 glDisable(GL_DEPTH_CLAMP);
541 }
542}
543
452void OpenGLState::Apply() const { 544void OpenGLState::Apply() const {
453 ApplyFramebufferState(); 545 ApplyFramebufferState();
454 ApplyVertexBufferState(); 546 ApplyVertexBufferState();
@@ -480,9 +572,27 @@ void OpenGLState::Apply() const {
480 if (point.size != cur_state.point.size) { 572 if (point.size != cur_state.point.size) {
481 glPointSize(point.size); 573 glPointSize(point.size);
482 } 574 }
575 if (fragment_color_clamp.enabled != cur_state.fragment_color_clamp.enabled) {
576 glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
577 fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE);
578 }
579 if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) {
580 if (multisample_control.alpha_to_coverage) {
581 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
582 } else {
583 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
584 }
585 }
586 if (multisample_control.alpha_to_one != cur_state.multisample_control.alpha_to_one) {
587 if (multisample_control.alpha_to_one) {
588 glEnable(GL_SAMPLE_ALPHA_TO_ONE);
589 } else {
590 glDisable(GL_SAMPLE_ALPHA_TO_ONE);
591 }
592 }
593 ApplyDepthClamp();
483 ApplyColorMask(); 594 ApplyColorMask();
484 ApplyViewport(); 595 ApplyViewport();
485 ApplyScissor();
486 ApplyStencilTest(); 596 ApplyStencilTest();
487 ApplySRgb(); 597 ApplySRgb();
488 ApplyCulling(); 598 ApplyCulling();
@@ -492,6 +602,7 @@ void OpenGLState::Apply() const {
492 ApplyLogicOp(); 602 ApplyLogicOp();
493 ApplyTextures(); 603 ApplyTextures();
494 ApplySamplers(); 604 ApplySamplers();
605 ApplyPolygonOffset();
495 cur_state = *this; 606 cur_state = *this;
496} 607}
497 608
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index eacca0b9c..439bfbc98 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -40,6 +40,24 @@ public:
40 } framebuffer_srgb; 40 } framebuffer_srgb;
41 41
42 struct { 42 struct {
43 bool alpha_to_coverage; // GL_ALPHA_TO_COVERAGE
44 bool alpha_to_one; // GL_ALPHA_TO_ONE
45 } multisample_control;
46
47 struct {
48 bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB
49 } fragment_color_clamp;
50
51 struct {
52 bool far_plane;
53 bool near_plane;
54 } depth_clamp; // GL_DEPTH_CLAMP
55
56 struct {
57 bool enabled; // viewports arrays are only supported when geometry shaders are enabled.
58 } geometry_shaders;
59
60 struct {
43 bool enabled; // GL_CULL_FACE 61 bool enabled; // GL_CULL_FACE
44 GLenum mode; // GL_CULL_FACE_MODE 62 GLenum mode; // GL_CULL_FACE_MODE
45 GLenum front_face; // GL_FRONT_FACE 63 GLenum front_face; // GL_FRONT_FACE
@@ -79,7 +97,6 @@ public:
79 97
80 struct Blend { 98 struct Blend {
81 bool enabled; // GL_BLEND 99 bool enabled; // GL_BLEND
82 bool separate_alpha; // Independent blend enabled
83 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB 100 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
84 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA 101 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
85 GLenum src_rgb_func; // GL_BLEND_SRC_RGB 102 GLenum src_rgb_func; // GL_BLEND_SRC_RGB
@@ -144,28 +161,36 @@ public:
144 } draw; 161 } draw;
145 162
146 struct viewport { 163 struct viewport {
147 GLfloat x; 164 GLint x;
148 GLfloat y; 165 GLint y;
149 GLfloat width; 166 GLint width;
150 GLfloat height; 167 GLint height;
151 GLfloat depth_range_near; // GL_DEPTH_RANGE 168 GLfloat depth_range_near; // GL_DEPTH_RANGE
152 GLfloat depth_range_far; // GL_DEPTH_RANGE 169 GLfloat depth_range_far; // GL_DEPTH_RANGE
170 struct {
171 bool enabled; // GL_SCISSOR_TEST
172 GLint x;
173 GLint y;
174 GLsizei width;
175 GLsizei height;
176 } scissor;
153 }; 177 };
154 std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports; 178 std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports;
155
156 struct {
157 bool enabled; // GL_SCISSOR_TEST
158 GLint x;
159 GLint y;
160 GLsizei width;
161 GLsizei height;
162 } scissor;
163 179
164 struct { 180 struct {
165 float size; // GL_POINT_SIZE 181 float size; // GL_POINT_SIZE
166 } point; 182 } point;
167 183
168 std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE 184 struct {
185 bool point_enable;
186 bool line_enable;
187 bool fill_enable;
188 GLfloat units;
189 GLfloat factor;
190 GLfloat clamp;
191 } polygon_offset;
192
193 std::array<bool, 8> clip_distance; // GL_CLIP_DISTANCE
169 194
170 OpenGLState(); 195 OpenGLState();
171 196
@@ -195,6 +220,7 @@ public:
195 OpenGLState& ResetBuffer(GLuint handle); 220 OpenGLState& ResetBuffer(GLuint handle);
196 OpenGLState& ResetVertexArray(GLuint handle); 221 OpenGLState& ResetVertexArray(GLuint handle);
197 OpenGLState& ResetFramebuffer(GLuint handle); 222 OpenGLState& ResetFramebuffer(GLuint handle);
223 void EmulateViewportWithScissor();
198 224
199private: 225private:
200 static OpenGLState cur_state; 226 static OpenGLState cur_state;
@@ -208,13 +234,14 @@ private:
208 void ApplyPrimitiveRestart() const; 234 void ApplyPrimitiveRestart() const;
209 void ApplyStencilTest() const; 235 void ApplyStencilTest() const;
210 void ApplyViewport() const; 236 void ApplyViewport() const;
211 void ApplyTargetBlending(int target, bool force) const; 237 void ApplyTargetBlending(std::size_t target, bool force) const;
212 void ApplyGlobalBlending() const; 238 void ApplyGlobalBlending() const;
213 void ApplyBlending() const; 239 void ApplyBlending() const;
214 void ApplyLogicOp() const; 240 void ApplyLogicOp() const;
215 void ApplyTextures() const; 241 void ApplyTextures() const;
216 void ApplySamplers() const; 242 void ApplySamplers() const;
217 void ApplyScissor() const; 243 void ApplyDepthClamp() const;
244 void ApplyPolygonOffset() const;
218}; 245};
219 246
220} // namespace OpenGL 247} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 3ce2cc6d2..a8833c06e 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -180,6 +180,12 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
180 return GL_CLAMP_TO_BORDER; 180 return GL_CLAMP_TO_BORDER;
181 case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: 181 case Tegra::Texture::WrapMode::MirrorOnceClampToEdge:
182 return GL_MIRROR_CLAMP_TO_EDGE; 182 return GL_MIRROR_CLAMP_TO_EDGE;
183 case Tegra::Texture::WrapMode::MirrorOnceBorder:
184 if (GL_EXT_texture_mirror_clamp) {
185 return GL_MIRROR_CLAMP_TO_BORDER_EXT;
186 } else {
187 return GL_MIRROR_CLAMP_TO_EDGE;
188 }
183 } 189 }
184 LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); 190 LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode));
185 return GL_REPEAT; 191 return GL_REPEAT;
@@ -212,14 +218,19 @@ inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) {
212inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { 218inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
213 switch (equation) { 219 switch (equation) {
214 case Maxwell::Blend::Equation::Add: 220 case Maxwell::Blend::Equation::Add:
221 case Maxwell::Blend::Equation::AddGL:
215 return GL_FUNC_ADD; 222 return GL_FUNC_ADD;
216 case Maxwell::Blend::Equation::Subtract: 223 case Maxwell::Blend::Equation::Subtract:
224 case Maxwell::Blend::Equation::SubtractGL:
217 return GL_FUNC_SUBTRACT; 225 return GL_FUNC_SUBTRACT;
218 case Maxwell::Blend::Equation::ReverseSubtract: 226 case Maxwell::Blend::Equation::ReverseSubtract:
227 case Maxwell::Blend::Equation::ReverseSubtractGL:
219 return GL_FUNC_REVERSE_SUBTRACT; 228 return GL_FUNC_REVERSE_SUBTRACT;
220 case Maxwell::Blend::Equation::Min: 229 case Maxwell::Blend::Equation::Min:
230 case Maxwell::Blend::Equation::MinGL:
221 return GL_MIN; 231 return GL_MIN;
222 case Maxwell::Blend::Equation::Max: 232 case Maxwell::Blend::Equation::Max:
233 case Maxwell::Blend::Equation::MaxGL:
223 return GL_MAX; 234 return GL_MAX;
224 } 235 }
225 LOG_ERROR(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); 236 LOG_ERROR(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation));
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index ea38da932..4fd0d66c5 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -19,9 +19,9 @@
19#include "core/settings.h" 19#include "core/settings.h"
20#include "core/telemetry_session.h" 20#include "core/telemetry_session.h"
21#include "core/tracer/recorder.h" 21#include "core/tracer/recorder.h"
22#include "video_core/morton.h"
22#include "video_core/renderer_opengl/gl_rasterizer.h" 23#include "video_core/renderer_opengl/gl_rasterizer.h"
23#include "video_core/renderer_opengl/renderer_opengl.h" 24#include "video_core/renderer_opengl/renderer_opengl.h"
24#include "video_core/utils.h"
25 25
26namespace OpenGL { 26namespace OpenGL {
27 27
@@ -304,6 +304,12 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
304 gl_framebuffer_data.resize(texture.width * texture.height * 4); 304 gl_framebuffer_data.resize(texture.width * texture.height * 4);
305 break; 305 break;
306 default: 306 default:
307 internal_format = GL_RGBA;
308 texture.gl_format = GL_RGBA;
309 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
310 gl_framebuffer_data.resize(texture.width * texture.height * 4);
311 LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer pixel format: {}",
312 static_cast<u32>(framebuffer.pixel_format));
307 UNREACHABLE(); 313 UNREACHABLE();
308 } 314 }
309 315
@@ -484,7 +490,7 @@ bool RendererOpenGL::Init() {
484 Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model); 490 Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model);
485 Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version); 491 Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version);
486 492
487 if (!GLAD_GL_VERSION_3_3) { 493 if (!GLAD_GL_VERSION_4_3) {
488 return false; 494 return false;
489 } 495 }
490 496
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 051ad3964..9582dd2ca 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -306,6 +306,8 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
306 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8; 306 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
307 case Tegra::Texture::TextureFormat::ASTC_2D_8X5: 307 case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
308 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5; 308 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
309 case Tegra::Texture::TextureFormat::ASTC_2D_10X8:
310 return is_srgb ? PixelFormat::ASTC_2D_10X8_SRGB : PixelFormat::ASTC_2D_10X8;
309 case Tegra::Texture::TextureFormat::R16_G16: 311 case Tegra::Texture::TextureFormat::R16_G16:
310 switch (component_type) { 312 switch (component_type) {
311 case Tegra::Texture::ComponentType::FLOAT: 313 case Tegra::Texture::ComponentType::FLOAT:
@@ -453,6 +455,8 @@ bool IsPixelFormatASTC(PixelFormat format) {
453 case PixelFormat::ASTC_2D_5X5_SRGB: 455 case PixelFormat::ASTC_2D_5X5_SRGB:
454 case PixelFormat::ASTC_2D_8X8_SRGB: 456 case PixelFormat::ASTC_2D_8X8_SRGB:
455 case PixelFormat::ASTC_2D_8X5_SRGB: 457 case PixelFormat::ASTC_2D_8X5_SRGB:
458 case PixelFormat::ASTC_2D_10X8:
459 case PixelFormat::ASTC_2D_10X8_SRGB:
456 return true; 460 return true;
457 default: 461 default:
458 return false; 462 return false;
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index dfdb8d122..0dd3eb2e4 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -74,19 +74,21 @@ enum class PixelFormat {
74 ASTC_2D_5X4_SRGB = 56, 74 ASTC_2D_5X4_SRGB = 56,
75 ASTC_2D_5X5 = 57, 75 ASTC_2D_5X5 = 57,
76 ASTC_2D_5X5_SRGB = 58, 76 ASTC_2D_5X5_SRGB = 58,
77 ASTC_2D_10X8 = 59,
78 ASTC_2D_10X8_SRGB = 60,
77 79
78 MaxColorFormat, 80 MaxColorFormat,
79 81
80 // Depth formats 82 // Depth formats
81 Z32F = 59, 83 Z32F = 61,
82 Z16 = 60, 84 Z16 = 62,
83 85
84 MaxDepthFormat, 86 MaxDepthFormat,
85 87
86 // DepthStencil formats 88 // DepthStencil formats
87 Z24S8 = 61, 89 Z24S8 = 63,
88 S8Z24 = 62, 90 S8Z24 = 64,
89 Z32FS8 = 63, 91 Z32FS8 = 65,
90 92
91 MaxDepthStencilFormat, 93 MaxDepthStencilFormat,
92 94
@@ -193,6 +195,8 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) {
193 4, // ASTC_2D_5X4_SRGB 195 4, // ASTC_2D_5X4_SRGB
194 4, // ASTC_2D_5X5 196 4, // ASTC_2D_5X5
195 4, // ASTC_2D_5X5_SRGB 197 4, // ASTC_2D_5X5_SRGB
198 4, // ASTC_2D_10X8
199 4, // ASTC_2D_10X8_SRGB
196 1, // Z32F 200 1, // Z32F
197 1, // Z16 201 1, // Z16
198 1, // Z24S8 202 1, // Z24S8
@@ -208,70 +212,72 @@ static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
208 if (format == PixelFormat::Invalid) 212 if (format == PixelFormat::Invalid)
209 return 0; 213 return 0;
210 constexpr std::array<u32, MaxPixelFormat> block_width_table = {{ 214 constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
211 1, // ABGR8U 215 1, // ABGR8U
212 1, // ABGR8S 216 1, // ABGR8S
213 1, // ABGR8UI 217 1, // ABGR8UI
214 1, // B5G6R5U 218 1, // B5G6R5U
215 1, // A2B10G10R10U 219 1, // A2B10G10R10U
216 1, // A1B5G5R5U 220 1, // A1B5G5R5U
217 1, // R8U 221 1, // R8U
218 1, // R8UI 222 1, // R8UI
219 1, // RGBA16F 223 1, // RGBA16F
220 1, // RGBA16U 224 1, // RGBA16U
221 1, // RGBA16UI 225 1, // RGBA16UI
222 1, // R11FG11FB10F 226 1, // R11FG11FB10F
223 1, // RGBA32UI 227 1, // RGBA32UI
224 4, // DXT1 228 4, // DXT1
225 4, // DXT23 229 4, // DXT23
226 4, // DXT45 230 4, // DXT45
227 4, // DXN1 231 4, // DXN1
228 4, // DXN2UNORM 232 4, // DXN2UNORM
229 4, // DXN2SNORM 233 4, // DXN2SNORM
230 4, // BC7U 234 4, // BC7U
231 4, // BC6H_UF16 235 4, // BC6H_UF16
232 4, // BC6H_SF16 236 4, // BC6H_SF16
233 4, // ASTC_2D_4X4 237 4, // ASTC_2D_4X4
234 1, // G8R8U 238 1, // G8R8U
235 1, // G8R8S 239 1, // G8R8S
236 1, // BGRA8 240 1, // BGRA8
237 1, // RGBA32F 241 1, // RGBA32F
238 1, // RG32F 242 1, // RG32F
239 1, // R32F 243 1, // R32F
240 1, // R16F 244 1, // R16F
241 1, // R16U 245 1, // R16U
242 1, // R16S 246 1, // R16S
243 1, // R16UI 247 1, // R16UI
244 1, // R16I 248 1, // R16I
245 1, // RG16 249 1, // RG16
246 1, // RG16F 250 1, // RG16F
247 1, // RG16UI 251 1, // RG16UI
248 1, // RG16I 252 1, // RG16I
249 1, // RG16S 253 1, // RG16S
250 1, // RGB32F 254 1, // RGB32F
251 1, // RGBA8_SRGB 255 1, // RGBA8_SRGB
252 1, // RG8U 256 1, // RG8U
253 1, // RG8S 257 1, // RG8S
254 1, // RG32UI 258 1, // RG32UI
255 1, // R32UI 259 1, // R32UI
256 8, // ASTC_2D_8X8 260 8, // ASTC_2D_8X8
257 8, // ASTC_2D_8X5 261 8, // ASTC_2D_8X5
258 5, // ASTC_2D_5X4 262 5, // ASTC_2D_5X4
259 1, // BGRA8_SRGB 263 1, // BGRA8_SRGB
260 4, // DXT1_SRGB 264 4, // DXT1_SRGB
261 4, // DXT23_SRGB 265 4, // DXT23_SRGB
262 4, // DXT45_SRGB 266 4, // DXT45_SRGB
263 4, // BC7U_SRGB 267 4, // BC7U_SRGB
264 4, // ASTC_2D_4X4_SRGB 268 4, // ASTC_2D_4X4_SRGB
265 8, // ASTC_2D_8X8_SRGB 269 8, // ASTC_2D_8X8_SRGB
266 8, // ASTC_2D_8X5_SRGB 270 8, // ASTC_2D_8X5_SRGB
267 5, // ASTC_2D_5X4_SRGB 271 5, // ASTC_2D_5X4_SRGB
268 5, // ASTC_2D_5X5 272 5, // ASTC_2D_5X5
269 5, // ASTC_2D_5X5_SRGB 273 5, // ASTC_2D_5X5_SRGB
270 1, // Z32F 274 10, // ASTC_2D_10X8
271 1, // Z16 275 10, // ASTC_2D_10X8_SRGB
272 1, // Z24S8 276 1, // Z32F
273 1, // S8Z24 277 1, // Z16
274 1, // Z32FS8 278 1, // Z24S8
279 1, // S8Z24
280 1, // Z32FS8
275 }}; 281 }};
276 ASSERT(static_cast<std::size_t>(format) < block_width_table.size()); 282 ASSERT(static_cast<std::size_t>(format) < block_width_table.size());
277 return block_width_table[static_cast<std::size_t>(format)]; 283 return block_width_table[static_cast<std::size_t>(format)];
@@ -341,6 +347,8 @@ static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
341 4, // ASTC_2D_5X4_SRGB 347 4, // ASTC_2D_5X4_SRGB
342 5, // ASTC_2D_5X5 348 5, // ASTC_2D_5X5
343 5, // ASTC_2D_5X5_SRGB 349 5, // ASTC_2D_5X5_SRGB
350 8, // ASTC_2D_10X8
351 8, // ASTC_2D_10X8_SRGB
344 1, // Z32F 352 1, // Z32F
345 1, // Z16 353 1, // Z16
346 1, // Z24S8 354 1, // Z24S8
@@ -416,6 +424,8 @@ static constexpr u32 GetFormatBpp(PixelFormat format) {
416 128, // ASTC_2D_5X4_SRGB 424 128, // ASTC_2D_5X4_SRGB
417 128, // ASTC_2D_5X5 425 128, // ASTC_2D_5X5
418 128, // ASTC_2D_5X5_SRGB 426 128, // ASTC_2D_5X5_SRGB
427 128, // ASTC_2D_10X8
428 128, // ASTC_2D_10X8_SRGB
419 32, // Z32F 429 32, // Z32F
420 16, // Z16 430 16, // Z16
421 32, // Z24S8 431 32, // Z24S8
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 3066abf61..bbae9285f 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -37,25 +37,28 @@ struct alignas(64) SwizzleTable {
37 std::array<std::array<u16, M>, N> values{}; 37 std::array<std::array<u16, M>, N> values{};
38}; 38};
39 39
40constexpr auto legacy_swizzle_table = SwizzleTable<8, 64, 1>(); 40constexpr u32 gob_size_x = 64;
41constexpr auto fast_swizzle_table = SwizzleTable<8, 4, 16>(); 41constexpr u32 gob_size_y = 8;
42constexpr u32 gob_size_z = 1;
43constexpr u32 gob_size = gob_size_x * gob_size_y * gob_size_z;
44constexpr u32 fast_swizzle_align = 16;
45
46constexpr auto legacy_swizzle_table = SwizzleTable<gob_size_y, gob_size_x, gob_size_z>();
47constexpr auto fast_swizzle_table = SwizzleTable<gob_size_y, 4, fast_swizzle_align>();
42 48
43/** 49/**
44 * This function manages ALL the GOBs(Group of Bytes) Inside a single block. 50 * This function manages ALL the GOBs(Group of Bytes) Inside a single block.
45 * Instead of going gob by gob, we map the coordinates inside a block and manage from 51 * Instead of going gob by gob, we map the coordinates inside a block and manage from
46 * those. Block_Width is assumed to be 1. 52 * those. Block_Width is assumed to be 1.
47 */ 53 */
48void PreciseProcessBlock(u8* swizzled_data, u8* unswizzled_data, const bool unswizzle, 54void PreciseProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, const bool unswizzle,
49 const u32 x_start, const u32 y_start, const u32 z_start, const u32 x_end, 55 const u32 x_start, const u32 y_start, const u32 z_start, const u32 x_end,
50 const u32 y_end, const u32 z_end, const u32 tile_offset, 56 const u32 y_end, const u32 z_end, const u32 tile_offset,
51 const u32 xy_block_size, const u32 layer_z, const u32 stride_x, 57 const u32 xy_block_size, const u32 layer_z, const u32 stride_x,
52 const u32 bytes_per_pixel, const u32 out_bytes_per_pixel) { 58 const u32 bytes_per_pixel, const u32 out_bytes_per_pixel) {
53 std::array<u8*, 2> data_ptrs; 59 std::array<u8*, 2> data_ptrs;
54 u32 z_address = tile_offset; 60 u32 z_address = tile_offset;
55 const u32 gob_size_x = 64; 61
56 const u32 gob_size_y = 8;
57 const u32 gob_size_z = 1;
58 const u32 gob_size = gob_size_x * gob_size_y * gob_size_z;
59 for (u32 z = z_start; z < z_end; z++) { 62 for (u32 z = z_start; z < z_end; z++) {
60 u32 y_address = z_address; 63 u32 y_address = z_address;
61 u32 pixel_base = layer_z * z + y_start * stride_x; 64 u32 pixel_base = layer_z * z + y_start * stride_x;
@@ -81,7 +84,7 @@ void PreciseProcessBlock(u8* swizzled_data, u8* unswizzled_data, const bool unsw
81 * Instead of going gob by gob, we map the coordinates inside a block and manage from 84 * Instead of going gob by gob, we map the coordinates inside a block and manage from
82 * those. Block_Width is assumed to be 1. 85 * those. Block_Width is assumed to be 1.
83 */ 86 */
84void FastProcessBlock(u8* swizzled_data, u8* unswizzled_data, const bool unswizzle, 87void FastProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, const bool unswizzle,
85 const u32 x_start, const u32 y_start, const u32 z_start, const u32 x_end, 88 const u32 x_start, const u32 y_start, const u32 z_start, const u32 x_end,
86 const u32 y_end, const u32 z_end, const u32 tile_offset, 89 const u32 y_end, const u32 z_end, const u32 tile_offset,
87 const u32 xy_block_size, const u32 layer_z, const u32 stride_x, 90 const u32 xy_block_size, const u32 layer_z, const u32 stride_x,
@@ -90,23 +93,19 @@ void FastProcessBlock(u8* swizzled_data, u8* unswizzled_data, const bool unswizz
90 u32 z_address = tile_offset; 93 u32 z_address = tile_offset;
91 const u32 x_startb = x_start * bytes_per_pixel; 94 const u32 x_startb = x_start * bytes_per_pixel;
92 const u32 x_endb = x_end * bytes_per_pixel; 95 const u32 x_endb = x_end * bytes_per_pixel;
93 const u32 copy_size = 16; 96
94 const u32 gob_size_x = 64;
95 const u32 gob_size_y = 8;
96 const u32 gob_size_z = 1;
97 const u32 gob_size = gob_size_x * gob_size_y * gob_size_z;
98 for (u32 z = z_start; z < z_end; z++) { 97 for (u32 z = z_start; z < z_end; z++) {
99 u32 y_address = z_address; 98 u32 y_address = z_address;
100 u32 pixel_base = layer_z * z + y_start * stride_x; 99 u32 pixel_base = layer_z * z + y_start * stride_x;
101 for (u32 y = y_start; y < y_end; y++) { 100 for (u32 y = y_start; y < y_end; y++) {
102 const auto& table = fast_swizzle_table[y % gob_size_y]; 101 const auto& table = fast_swizzle_table[y % gob_size_y];
103 for (u32 xb = x_startb; xb < x_endb; xb += copy_size) { 102 for (u32 xb = x_startb; xb < x_endb; xb += fast_swizzle_align) {
104 const u32 swizzle_offset{y_address + table[(xb / copy_size) % 4]}; 103 const u32 swizzle_offset{y_address + table[(xb / fast_swizzle_align) % 4]};
105 const u32 out_x = xb * out_bytes_per_pixel / bytes_per_pixel; 104 const u32 out_x = xb * out_bytes_per_pixel / bytes_per_pixel;
106 const u32 pixel_index{out_x + pixel_base}; 105 const u32 pixel_index{out_x + pixel_base};
107 data_ptrs[unswizzle] = swizzled_data + swizzle_offset; 106 data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
108 data_ptrs[!unswizzle] = unswizzled_data + pixel_index; 107 data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
109 std::memcpy(data_ptrs[0], data_ptrs[1], copy_size); 108 std::memcpy(data_ptrs[0], data_ptrs[1], fast_swizzle_align);
110 } 109 }
111 pixel_base += stride_x; 110 pixel_base += stride_x;
112 if ((y + 1) % gob_size_y == 0) 111 if ((y + 1) % gob_size_y == 0)
@@ -126,23 +125,23 @@ void FastProcessBlock(u8* swizzled_data, u8* unswizzled_data, const bool unswizz
126 * https://envytools.readthedocs.io/en/latest/hw/memory/g80-surface.html#blocklinear-surfaces 125 * https://envytools.readthedocs.io/en/latest/hw/memory/g80-surface.html#blocklinear-surfaces
127 */ 126 */
128template <bool fast> 127template <bool fast>
129void SwizzledData(u8* swizzled_data, u8* unswizzled_data, const bool unswizzle, const u32 width, 128void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool unswizzle,
130 const u32 height, const u32 depth, const u32 bytes_per_pixel, 129 const u32 width, const u32 height, const u32 depth, const u32 bytes_per_pixel,
131 const u32 out_bytes_per_pixel, const u32 block_height, const u32 block_depth) { 130 const u32 out_bytes_per_pixel, const u32 block_height, const u32 block_depth,
131 const u32 width_spacing) {
132 auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); }; 132 auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); };
133 const u32 stride_x = width * out_bytes_per_pixel; 133 const u32 stride_x = width * out_bytes_per_pixel;
134 const u32 layer_z = height * stride_x; 134 const u32 layer_z = height * stride_x;
135 const u32 gob_x_bytes = 64; 135 const u32 gob_elements_x = gob_size_x / bytes_per_pixel;
136 const u32 gob_elements_x = gob_x_bytes / bytes_per_pixel; 136 constexpr u32 gob_elements_y = gob_size_y;
137 const u32 gob_elements_y = 8; 137 constexpr u32 gob_elements_z = gob_size_z;
138 const u32 gob_elements_z = 1;
139 const u32 block_x_elements = gob_elements_x; 138 const u32 block_x_elements = gob_elements_x;
140 const u32 block_y_elements = gob_elements_y * block_height; 139 const u32 block_y_elements = gob_elements_y * block_height;
141 const u32 block_z_elements = gob_elements_z * block_depth; 140 const u32 block_z_elements = gob_elements_z * block_depth;
142 const u32 blocks_on_x = div_ceil(width, block_x_elements); 141 const u32 aligned_width = Common::AlignUp(width, gob_elements_x * width_spacing);
142 const u32 blocks_on_x = div_ceil(aligned_width, block_x_elements);
143 const u32 blocks_on_y = div_ceil(height, block_y_elements); 143 const u32 blocks_on_y = div_ceil(height, block_y_elements);
144 const u32 blocks_on_z = div_ceil(depth, block_z_elements); 144 const u32 blocks_on_z = div_ceil(depth, block_z_elements);
145 const u32 gob_size = gob_x_bytes * gob_elements_y * gob_elements_z;
146 const u32 xy_block_size = gob_size * block_height; 145 const u32 xy_block_size = gob_size * block_height;
147 const u32 block_size = xy_block_size * block_depth; 146 const u32 block_size = xy_block_size * block_depth;
148 u32 tile_offset = 0; 147 u32 tile_offset = 0;
@@ -171,14 +170,16 @@ void SwizzledData(u8* swizzled_data, u8* unswizzled_data, const bool unswizzle,
171} 170}
172 171
173void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, 172void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel,
174 u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, 173 u32 out_bytes_per_pixel, u8* const swizzled_data, u8* const unswizzled_data,
175 bool unswizzle, u32 block_height, u32 block_depth) { 174 bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing) {
176 if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) { 175 if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % fast_swizzle_align == 0) {
177 SwizzledData<true>(swizzled_data, unswizzled_data, unswizzle, width, height, depth, 176 SwizzledData<true>(swizzled_data, unswizzled_data, unswizzle, width, height, depth,
178 bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth); 177 bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth,
178 width_spacing);
179 } else { 179 } else {
180 SwizzledData<false>(swizzled_data, unswizzled_data, unswizzle, width, height, depth, 180 SwizzledData<false>(swizzled_data, unswizzled_data, unswizzle, width, height, depth,
181 bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth); 181 bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth,
182 width_spacing);
182 } 183 }
183} 184}
184 185
@@ -202,6 +203,8 @@ u32 BytesPerPixel(TextureFormat format) {
202 case TextureFormat::ASTC_2D_5X4: 203 case TextureFormat::ASTC_2D_5X4:
203 case TextureFormat::ASTC_2D_8X8: 204 case TextureFormat::ASTC_2D_8X8:
204 case TextureFormat::ASTC_2D_8X5: 205 case TextureFormat::ASTC_2D_8X5:
206 case TextureFormat::ASTC_2D_10X8:
207 case TextureFormat::ASTC_2D_5X5:
205 case TextureFormat::A8R8G8B8: 208 case TextureFormat::A8R8G8B8:
206 case TextureFormat::A2B10G10R10: 209 case TextureFormat::A2B10G10R10:
207 case TextureFormat::BF10GF11RF11: 210 case TextureFormat::BF10GF11RF11:
@@ -227,29 +230,38 @@ u32 BytesPerPixel(TextureFormat format) {
227 } 230 }
228} 231}
229 232
233void UnswizzleTexture(u8* const unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y,
234 u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height,
235 u32 block_depth, u32 width_spacing) {
236 CopySwizzledData((width + tile_size_x - 1) / tile_size_x,
237 (height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel,
238 bytes_per_pixel, Memory::GetPointer(address), unswizzled_data, true,
239 block_height, block_depth, width_spacing);
240}
241
230std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y, 242std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
231 u32 bytes_per_pixel, u32 width, u32 height, u32 depth, 243 u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
232 u32 block_height, u32 block_depth) { 244 u32 block_height, u32 block_depth, u32 width_spacing) {
233 std::vector<u8> unswizzled_data(width * height * depth * bytes_per_pixel); 245 std::vector<u8> unswizzled_data(width * height * depth * bytes_per_pixel);
234 CopySwizzledData((width + tile_size_x - 1) / tile_size_x, 246 UnswizzleTexture(unswizzled_data.data(), address, tile_size_x, tile_size_y, bytes_per_pixel,
235 (height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel, 247 width, height, depth, block_height, block_depth, width_spacing);
236 bytes_per_pixel, Memory::GetPointer(address), unswizzled_data.data(), true,
237 block_height, block_depth);
238 return unswizzled_data; 248 return unswizzled_data;
239} 249}
240 250
241void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width, 251void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
242 u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data, 252 u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
243 u32 block_height) { 253 u32 block_height) {
244 const u32 image_width_in_gobs{(swizzled_width * bytes_per_pixel + 63) / 64}; 254 const u32 image_width_in_gobs{(swizzled_width * bytes_per_pixel + (gob_size_x - 1)) /
255 gob_size_x};
245 for (u32 line = 0; line < subrect_height; ++line) { 256 for (u32 line = 0; line < subrect_height; ++line) {
246 const u32 gob_address_y = 257 const u32 gob_address_y =
247 (line / (8 * block_height)) * 512 * block_height * image_width_in_gobs + 258 (line / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs +
248 (line % (8 * block_height) / 8) * 512; 259 ((line % (gob_size_y * block_height)) / gob_size_y) * gob_size;
249 const auto& table = legacy_swizzle_table[line % 8]; 260 const auto& table = legacy_swizzle_table[line % gob_size_y];
250 for (u32 x = 0; x < subrect_width; ++x) { 261 for (u32 x = 0; x < subrect_width; ++x) {
251 const u32 gob_address = gob_address_y + (x * bytes_per_pixel / 64) * 512 * block_height; 262 const u32 gob_address =
252 const u32 swizzled_offset = gob_address + table[(x * bytes_per_pixel) % 64]; 263 gob_address_y + (x * bytes_per_pixel / gob_size_x) * gob_size * block_height;
264 const u32 swizzled_offset = gob_address + table[(x * bytes_per_pixel) % gob_size_x];
253 const VAddr source_line = unswizzled_data + line * source_pitch + x * bytes_per_pixel; 265 const VAddr source_line = unswizzled_data + line * source_pitch + x * bytes_per_pixel;
254 const VAddr dest_addr = swizzled_data + swizzled_offset; 266 const VAddr dest_addr = swizzled_data + swizzled_offset;
255 267
@@ -263,13 +275,13 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32
263 u32 block_height, u32 offset_x, u32 offset_y) { 275 u32 block_height, u32 offset_x, u32 offset_y) {
264 for (u32 line = 0; line < subrect_height; ++line) { 276 for (u32 line = 0; line < subrect_height; ++line) {
265 const u32 y2 = line + offset_y; 277 const u32 y2 = line + offset_y;
266 const u32 gob_address_y = 278 const u32 gob_address_y = (y2 / (gob_size_y * block_height)) * gob_size * block_height +
267 (y2 / (8 * block_height)) * 512 * block_height + (y2 % (8 * block_height) / 8) * 512; 279 ((y2 % (gob_size_y * block_height)) / gob_size_y) * gob_size;
268 const auto& table = legacy_swizzle_table[y2 % 8]; 280 const auto& table = legacy_swizzle_table[y2 % gob_size_y];
269 for (u32 x = 0; x < subrect_width; ++x) { 281 for (u32 x = 0; x < subrect_width; ++x) {
270 const u32 x2 = (x + offset_x) * bytes_per_pixel; 282 const u32 x2 = (x + offset_x) * bytes_per_pixel;
271 const u32 gob_address = gob_address_y + (x2 / 64) * 512 * block_height; 283 const u32 gob_address = gob_address_y + (x2 / gob_size_x) * gob_size * block_height;
272 const u32 swizzled_offset = gob_address + table[x2 % 64]; 284 const u32 swizzled_offset = gob_address + table[x2 % gob_size_x];
273 const VAddr dest_line = unswizzled_data + line * dest_pitch + x * bytes_per_pixel; 285 const VAddr dest_line = unswizzled_data + line * dest_pitch + x * bytes_per_pixel;
274 const VAddr source_addr = swizzled_data + swizzled_offset; 286 const VAddr source_addr = swizzled_data + swizzled_offset;
275 287
@@ -294,6 +306,8 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
294 case TextureFormat::BC6H_SF16: 306 case TextureFormat::BC6H_SF16:
295 case TextureFormat::ASTC_2D_4X4: 307 case TextureFormat::ASTC_2D_4X4:
296 case TextureFormat::ASTC_2D_8X8: 308 case TextureFormat::ASTC_2D_8X8:
309 case TextureFormat::ASTC_2D_5X5:
310 case TextureFormat::ASTC_2D_10X8:
297 case TextureFormat::A8R8G8B8: 311 case TextureFormat::A8R8G8B8:
298 case TextureFormat::A2B10G10R10: 312 case TextureFormat::A2B10G10R10:
299 case TextureFormat::A1B5G5R5: 313 case TextureFormat::A1B5G5R5:
@@ -321,12 +335,9 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
321std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, 335std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
322 u32 block_height, u32 block_depth) { 336 u32 block_height, u32 block_depth) {
323 if (tiled) { 337 if (tiled) {
324 const u32 gobs_in_x = 64; 338 const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gob_size_x);
325 const u32 gobs_in_y = 8; 339 const u32 aligned_height = Common::AlignUp(height, gob_size_y * block_height);
326 const u32 gobs_in_z = 1; 340 const u32 aligned_depth = Common::AlignUp(depth, gob_size_z * block_depth);
327 const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gobs_in_x);
328 const u32 aligned_height = Common::AlignUp(height, gobs_in_y * block_height);
329 const u32 aligned_depth = Common::AlignUp(depth, gobs_in_z * block_depth);
330 return aligned_width * aligned_height * aligned_depth; 341 return aligned_width * aligned_height * aligned_depth;
331 } else { 342 } else {
332 return width * height * depth * bytes_per_pixel; 343 return width * height * depth * bytes_per_pixel;
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index ba065510b..85b7e9f7b 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -19,15 +19,23 @@ inline std::size_t GetGOBSize() {
19/** 19/**
20 * Unswizzles a swizzled texture without changing its format. 20 * Unswizzles a swizzled texture without changing its format.
21 */ 21 */
22void UnswizzleTexture(u8* unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y,
23 u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
24 u32 block_height = TICEntry::DefaultBlockHeight,
25 u32 block_depth = TICEntry::DefaultBlockHeight, u32 width_spacing = 0);
26/**
27 * Unswizzles a swizzled texture without changing its format.
28 */
22std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y, 29std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
23 u32 bytes_per_pixel, u32 width, u32 height, u32 depth, 30 u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
24 u32 block_height = TICEntry::DefaultBlockHeight, 31 u32 block_height = TICEntry::DefaultBlockHeight,
25 u32 block_depth = TICEntry::DefaultBlockHeight); 32 u32 block_depth = TICEntry::DefaultBlockHeight,
33 u32 width_spacing = 0);
26 34
27/// Copies texture data from a buffer and performs swizzling/unswizzling as necessary. 35/// Copies texture data from a buffer and performs swizzling/unswizzling as necessary.
28void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, 36void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel,
29 u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, 37 u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data,
30 bool unswizzle, u32 block_height, u32 block_depth); 38 bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing);
31 39
32/** 40/**
33 * Decodes an unswizzled texture into a A8R8G8B8 texture. 41 * Decodes an unswizzled texture into a A8R8G8B8 texture.
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index e199d019a..e7c78bee2 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -166,6 +166,8 @@ struct TICEntry {
166 BitField<3, 3, u32> block_height; 166 BitField<3, 3, u32> block_height;
167 BitField<6, 3, u32> block_depth; 167 BitField<6, 3, u32> block_depth;
168 168
169 BitField<10, 3, u32> tile_width_spacing;
170
169 // High 16 bits of the pitch value 171 // High 16 bits of the pitch value
170 BitField<0, 16, u32> pitch_high; 172 BitField<0, 16, u32> pitch_high;
171 BitField<26, 1, u32> use_header_opt_control; 173 BitField<26, 1, u32> use_header_opt_control;
@@ -190,6 +192,7 @@ struct TICEntry {
190 union { 192 union {
191 BitField<0, 4, u32> res_min_mip_level; 193 BitField<0, 4, u32> res_min_mip_level;
192 BitField<4, 4, u32> res_max_mip_level; 194 BitField<4, 4, u32> res_max_mip_level;
195 BitField<12, 12, u32> min_lod_clamp;
193 }; 196 };
194 197
195 GPUVAddr Address() const { 198 GPUVAddr Address() const {
@@ -284,13 +287,25 @@ struct TSCEntry {
284 BitField<6, 3, WrapMode> wrap_p; 287 BitField<6, 3, WrapMode> wrap_p;
285 BitField<9, 1, u32> depth_compare_enabled; 288 BitField<9, 1, u32> depth_compare_enabled;
286 BitField<10, 3, DepthCompareFunc> depth_compare_func; 289 BitField<10, 3, DepthCompareFunc> depth_compare_func;
290 BitField<13, 1, u32> srgb_conversion;
291 BitField<20, 3, u32> max_anisotropy;
287 }; 292 };
288 union { 293 union {
289 BitField<0, 2, TextureFilter> mag_filter; 294 BitField<0, 2, TextureFilter> mag_filter;
290 BitField<4, 2, TextureFilter> min_filter; 295 BitField<4, 2, TextureFilter> min_filter;
291 BitField<6, 2, TextureMipmapFilter> mip_filter; 296 BitField<6, 2, TextureMipmapFilter> mip_filter;
297 BitField<9, 1, u32> cubemap_interface_filtering;
298 BitField<12, 13, u32> mip_lod_bias;
299 };
300 union {
301 BitField<0, 12, u32> min_lod_clamp;
302 BitField<12, 12, u32> max_lod_clamp;
303 BitField<24, 8, u32> srgb_border_color_r;
304 };
305 union {
306 BitField<12, 8, u32> srgb_border_color_g;
307 BitField<20, 8, u32> srgb_border_color_b;
292 }; 308 };
293 INSERT_PADDING_BYTES(8);
294 float border_color_r; 309 float border_color_r;
295 float border_color_g; 310 float border_color_g;
296 float border_color_b; 311 float border_color_b;
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
deleted file mode 100644
index e0a14d48f..000000000
--- a/src/video_core/utils.h
+++ /dev/null
@@ -1,164 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9namespace VideoCore {
10
11// 8x8 Z-Order coordinate from 2D coordinates
12static inline u32 MortonInterleave(u32 x, u32 y) {
13 static const u32 xlut[] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15};
14 static const u32 ylut[] = {0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a};
15 return xlut[x % 8] + ylut[y % 8];
16}
17
18/**
19 * Calculates the offset of the position of the pixel in Morton order
20 */
21static inline u32 GetMortonOffset(u32 x, u32 y, u32 bytes_per_pixel) {
22 // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each
23 // of which is composed of four 2x2 subtiles each of which is composed of four texels.
24 // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g.
25 // texels are laid out in a 2x2 subtile like this:
26 // 2 3
27 // 0 1
28 //
29 // The full 8x8 tile has the texels arranged like this:
30 //
31 // 42 43 46 47 58 59 62 63
32 // 40 41 44 45 56 57 60 61
33 // 34 35 38 39 50 51 54 55
34 // 32 33 36 37 48 49 52 53
35 // 10 11 14 15 26 27 30 31
36 // 08 09 12 13 24 25 28 29
37 // 02 03 06 07 18 19 22 23
38 // 00 01 04 05 16 17 20 21
39 //
40 // This pattern is what's called Z-order curve, or Morton order.
41
42 const unsigned int block_height = 8;
43 const unsigned int coarse_x = x & ~7;
44
45 u32 i = VideoCore::MortonInterleave(x, y);
46
47 const unsigned int offset = coarse_x * block_height;
48
49 return (i + offset) * bytes_per_pixel;
50}
51
52static inline u32 MortonInterleave128(u32 x, u32 y) {
53 // 128x128 Z-Order coordinate from 2D coordinates
54 static constexpr u32 xlut[] = {
55 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
56 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
57 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
58 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
59 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
60 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
61 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
62 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
63 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
64 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
65 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
66 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
67 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
68 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
69 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
70 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
71 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
72 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
73 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
74 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
75 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
76 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
77 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
78 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
79 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
80 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
81 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
82 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
83 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
84 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
85 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
86 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
87 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
88 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
89 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
90 };
91 static constexpr u32 ylut[] = {
92 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
93 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
94 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
95 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
96 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
97 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
98 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
99 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
100 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
101 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
102 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
103 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
104 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
105 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
106 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
107 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
108 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
109 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
110 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
111 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
112 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
113 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
114 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
115 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
116 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
117 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
118 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
119 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
120 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
121 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
122 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
123 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
124 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
125 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
126 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
127 };
128 return xlut[x % 128] + ylut[y % 128];
129}
130
131static inline u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
132 // Calculates the offset of the position of the pixel in Morton order
133 // Framebuffer images are split into 128x128 tiles.
134
135 const unsigned int block_height = 128;
136 const unsigned int coarse_x = x & ~127;
137
138 u32 i = MortonInterleave128(x, y);
139
140 const unsigned int offset = coarse_x * block_height;
141
142 return (i + offset) * bytes_per_pixel;
143}
144
145static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel,
146 u32 gl_bytes_per_pixel, u8* morton_data, u8* gl_data,
147 bool morton_to_gl) {
148 u8* data_ptrs[2];
149 for (unsigned y = 0; y < height; ++y) {
150 for (unsigned x = 0; x < width; ++x) {
151 const u32 coarse_y = y & ~127;
152 u32 morton_offset =
153 GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
154 u32 gl_pixel_index = (x + y * width) * gl_bytes_per_pixel;
155
156 data_ptrs[morton_to_gl] = morton_data + morton_offset;
157 data_ptrs[!morton_to_gl] = &gl_data[gl_pixel_index];
158
159 memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
160 }
161 }
162}
163
164} // namespace VideoCore
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index f9ca2948e..cfca8f4a8 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -7,6 +7,8 @@ add_executable(yuzu
7 Info.plist 7 Info.plist
8 about_dialog.cpp 8 about_dialog.cpp
9 about_dialog.h 9 about_dialog.h
10 applets/software_keyboard.cpp
11 applets/software_keyboard.h
10 bootmanager.cpp 12 bootmanager.cpp
11 bootmanager.h 13 bootmanager.h
12 compatibility_list.cpp 14 compatibility_list.cpp
@@ -27,8 +29,14 @@ add_executable(yuzu
27 configuration/configure_graphics.h 29 configuration/configure_graphics.h
28 configuration/configure_input.cpp 30 configuration/configure_input.cpp
29 configuration/configure_input.h 31 configuration/configure_input.h
32 configuration/configure_input_player.cpp
33 configuration/configure_input_player.h
34 configuration/configure_mouse_advanced.cpp
35 configuration/configure_mouse_advanced.h
30 configuration/configure_system.cpp 36 configuration/configure_system.cpp
31 configuration/configure_system.h 37 configuration/configure_system.h
38 configuration/configure_touchscreen_advanced.cpp
39 configuration/configure_touchscreen_advanced.h
32 configuration/configure_web.cpp 40 configuration/configure_web.cpp
33 configuration/configure_web.h 41 configuration/configure_web.h
34 debugger/graphics/graphics_breakpoint_observer.cpp 42 debugger/graphics/graphics_breakpoint_observer.cpp
@@ -76,7 +84,10 @@ set(UIS
76 configuration/configure_general.ui 84 configuration/configure_general.ui
77 configuration/configure_graphics.ui 85 configuration/configure_graphics.ui
78 configuration/configure_input.ui 86 configuration/configure_input.ui
87 configuration/configure_input_player.ui
88 configuration/configure_mouse_advanced.ui
79 configuration/configure_system.ui 89 configuration/configure_system.ui
90 configuration/configure_touchscreen_advanced.ui
80 configuration/configure_web.ui 91 configuration/configure_web.ui
81 hotkeys.ui 92 hotkeys.ui
82 main.ui 93 main.ui
diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp
new file mode 100644
index 000000000..8a26fdff1
--- /dev/null
+++ b/src/yuzu/applets/software_keyboard.cpp
@@ -0,0 +1,152 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <mutex>
7#include <QDialogButtonBox>
8#include <QFont>
9#include <QLabel>
10#include <QLineEdit>
11#include <QVBoxLayout>
12#include "core/hle/lock.h"
13#include "yuzu/applets/software_keyboard.h"
14#include "yuzu/main.h"
15
16QtSoftwareKeyboardValidator::QtSoftwareKeyboardValidator(
17 Core::Frontend::SoftwareKeyboardParameters parameters)
18 : parameters(std::move(parameters)) {}
19
20QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int& pos) const {
21 if (input.size() > parameters.max_length)
22 return Invalid;
23 if (parameters.disable_space && input.contains(' '))
24 return Invalid;
25 if (parameters.disable_address && input.contains('@'))
26 return Invalid;
27 if (parameters.disable_percent && input.contains('%'))
28 return Invalid;
29 if (parameters.disable_slash && (input.contains('/') || input.contains('\\')))
30 return Invalid;
31 if (parameters.disable_number &&
32 std::any_of(input.begin(), input.end(), [](QChar c) { return c.isDigit(); })) {
33 return Invalid;
34 }
35
36 if (parameters.disable_download_code &&
37 std::any_of(input.begin(), input.end(), [](QChar c) { return c == 'O' || c == 'I'; })) {
38 return Invalid;
39 }
40
41 return Acceptable;
42}
43
44QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
45 QWidget* parent, Core::Frontend::SoftwareKeyboardParameters parameters_)
46 : QDialog(parent), parameters(std::move(parameters_)) {
47 layout = new QVBoxLayout;
48
49 header_label = new QLabel(QString::fromStdU16String(parameters.header_text));
50 header_label->setFont({header_label->font().family(), 11, QFont::Bold});
51 if (header_label->text().isEmpty())
52 header_label->setText(tr("Enter text:"));
53
54 sub_label = new QLabel(QString::fromStdU16String(parameters.sub_text));
55 sub_label->setFont({sub_label->font().family(), sub_label->font().pointSize(),
56 sub_label->font().weight(), true});
57 sub_label->setHidden(parameters.sub_text.empty());
58
59 guide_label = new QLabel(QString::fromStdU16String(parameters.guide_text));
60 guide_label->setHidden(parameters.guide_text.empty());
61
62 length_label = new QLabel(QStringLiteral("0/%1").arg(parameters.max_length));
63 length_label->setAlignment(Qt::AlignRight);
64 length_label->setFont({length_label->font().family(), 8});
65
66 line_edit = new QLineEdit;
67 line_edit->setValidator(new QtSoftwareKeyboardValidator(parameters));
68 line_edit->setMaxLength(static_cast<int>(parameters.max_length));
69 line_edit->setText(QString::fromStdU16String(parameters.initial_text));
70 line_edit->setCursorPosition(
71 parameters.cursor_at_beginning ? 0 : static_cast<int>(parameters.initial_text.size()));
72 line_edit->setEchoMode(parameters.password ? QLineEdit::Password : QLineEdit::Normal);
73
74 connect(line_edit, &QLineEdit::textChanged, this, [this](const QString& text) {
75 length_label->setText(QStringLiteral("%1/%2").arg(text.size()).arg(parameters.max_length));
76 });
77
78 buttons = new QDialogButtonBox;
79 buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
80 buttons->addButton(parameters.submit_text.empty()
81 ? tr("OK")
82 : QString::fromStdU16String(parameters.submit_text),
83 QDialogButtonBox::AcceptRole);
84
85 connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept);
86 connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject);
87 layout->addWidget(header_label);
88 layout->addWidget(sub_label);
89 layout->addWidget(guide_label);
90 layout->addWidget(length_label);
91 layout->addWidget(line_edit);
92 layout->addWidget(buttons);
93 setLayout(layout);
94 setWindowTitle(tr("Software Keyboard"));
95}
96
97QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default;
98
99void QtSoftwareKeyboardDialog::accept() {
100 ok = true;
101 text = line_edit->text().toStdU16String();
102 QDialog::accept();
103}
104
105void QtSoftwareKeyboardDialog::reject() {
106 ok = false;
107 text.clear();
108 QDialog::reject();
109}
110
111std::u16string QtSoftwareKeyboardDialog::GetText() const {
112 return text;
113}
114
115bool QtSoftwareKeyboardDialog::GetStatus() const {
116 return ok;
117}
118
119QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) {
120 connect(this, &QtSoftwareKeyboard::MainWindowGetText, &main_window,
121 &GMainWindow::SoftwareKeyboardGetText, Qt::QueuedConnection);
122 connect(this, &QtSoftwareKeyboard::MainWindowTextCheckDialog, &main_window,
123 &GMainWindow::SoftwareKeyboardInvokeCheckDialog, Qt::BlockingQueuedConnection);
124 connect(&main_window, &GMainWindow::SoftwareKeyboardFinishedText, this,
125 &QtSoftwareKeyboard::MainWindowFinishedText, Qt::QueuedConnection);
126}
127
128QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;
129
130void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out,
131 Core::Frontend::SoftwareKeyboardParameters parameters) const {
132 text_output = std::move(out);
133 emit MainWindowGetText(parameters);
134}
135
136void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message,
137 std::function<void()> finished_check) const {
138 this->finished_check = std::move(finished_check);
139 emit MainWindowTextCheckDialog(error_message);
140}
141
142void QtSoftwareKeyboard::MainWindowFinishedText(std::optional<std::u16string> text) {
143 // Acquire the HLE mutex
144 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
145 text_output(text);
146}
147
148void QtSoftwareKeyboard::MainWindowFinishedCheckDialog() {
149 // Acquire the HLE mutex
150 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
151 finished_check();
152}
diff --git a/src/yuzu/applets/software_keyboard.h b/src/yuzu/applets/software_keyboard.h
new file mode 100644
index 000000000..c63720ba4
--- /dev/null
+++ b/src/yuzu/applets/software_keyboard.h
@@ -0,0 +1,79 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDialog>
8#include <QValidator>
9#include "common/assert.h"
10#include "core/frontend/applets/software_keyboard.h"
11
12class GMainWindow;
13class QDialogButtonBox;
14class QLabel;
15class QLineEdit;
16class QVBoxLayout;
17class QtSoftwareKeyboard;
18
19class QtSoftwareKeyboardValidator final : public QValidator {
20public:
21 explicit QtSoftwareKeyboardValidator(Core::Frontend::SoftwareKeyboardParameters parameters);
22 State validate(QString& input, int& pos) const override;
23
24private:
25 Core::Frontend::SoftwareKeyboardParameters parameters;
26};
27
28class QtSoftwareKeyboardDialog final : public QDialog {
29 Q_OBJECT
30
31public:
32 QtSoftwareKeyboardDialog(QWidget* parent,
33 Core::Frontend::SoftwareKeyboardParameters parameters);
34 ~QtSoftwareKeyboardDialog() override;
35
36 void accept() override;
37 void reject() override;
38
39 std::u16string GetText() const;
40 bool GetStatus() const;
41
42private:
43 bool ok = false;
44 std::u16string text;
45
46 QDialogButtonBox* buttons;
47 QLabel* header_label;
48 QLabel* sub_label;
49 QLabel* guide_label;
50 QLabel* length_label;
51 QLineEdit* line_edit;
52 QVBoxLayout* layout;
53
54 Core::Frontend::SoftwareKeyboardParameters parameters;
55};
56
57class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet {
58 Q_OBJECT
59
60public:
61 explicit QtSoftwareKeyboard(GMainWindow& parent);
62 ~QtSoftwareKeyboard() override;
63
64 void RequestText(std::function<void(std::optional<std::u16string>)> out,
65 Core::Frontend::SoftwareKeyboardParameters parameters) const override;
66 void SendTextCheckDialog(std::u16string error_message,
67 std::function<void()> finished_check) const override;
68
69signals:
70 void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const;
71 void MainWindowTextCheckDialog(std::u16string error_message) const;
72
73private:
74 void MainWindowFinishedText(std::optional<std::u16string> text);
75 void MainWindowFinishedCheckDialog();
76
77 mutable std::function<void(std::optional<std::u16string>)> text_output;
78 mutable std::function<void()> finished_check;
79};
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 39eef8858..384e17921 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -310,7 +310,7 @@ void GRenderWindow::InitRenderTarget() {
310 // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, 310 // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
311 // WA_DontShowOnScreen, WA_DeleteOnClose 311 // WA_DontShowOnScreen, WA_DeleteOnClose
312 QGLFormat fmt; 312 QGLFormat fmt;
313 fmt.setVersion(3, 3); 313 fmt.setVersion(4, 3);
314 fmt.setProfile(QGLFormat::CoreProfile); 314 fmt.setProfile(QGLFormat::CoreProfile);
315 fmt.setSwapInterval(false); 315 fmt.setSwapInterval(false);
316 316
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index d4fd60a73..83ebbd1fe 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -5,6 +5,7 @@
5#include <QSettings> 5#include <QSettings>
6#include "common/file_util.h" 6#include "common/file_util.h"
7#include "core/hle/service/acc/profile_manager.h" 7#include "core/hle/service/acc/profile_manager.h"
8#include "core/hle/service/hid/controllers/npad.h"
8#include "input_common/main.h" 9#include "input_common/main.h"
9#include "yuzu/configuration/config.h" 10#include "yuzu/configuration/config.h"
10#include "yuzu/ui_settings.h" 11#include "yuzu/ui_settings.h"
@@ -47,40 +48,313 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config:
47 }, 48 },
48}}; 49}};
49 50
50void Config::ReadValues() { 51const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons =
51 qt_config->beginGroup("Controls"); 52 {
53 Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal,
54};
55
56const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> Config::default_keyboard_keys = {
57 0,
58 0,
59 0,
60 0,
61 Qt::Key_A,
62 Qt::Key_B,
63 Qt::Key_C,
64 Qt::Key_D,
65 Qt::Key_E,
66 Qt::Key_F,
67 Qt::Key_G,
68 Qt::Key_H,
69 Qt::Key_I,
70 Qt::Key_J,
71 Qt::Key_K,
72 Qt::Key_L,
73 Qt::Key_M,
74 Qt::Key_N,
75 Qt::Key_O,
76 Qt::Key_P,
77 Qt::Key_Q,
78 Qt::Key_R,
79 Qt::Key_S,
80 Qt::Key_T,
81 Qt::Key_U,
82 Qt::Key_V,
83 Qt::Key_W,
84 Qt::Key_X,
85 Qt::Key_Y,
86 Qt::Key_Z,
87 Qt::Key_1,
88 Qt::Key_2,
89 Qt::Key_3,
90 Qt::Key_4,
91 Qt::Key_5,
92 Qt::Key_6,
93 Qt::Key_7,
94 Qt::Key_8,
95 Qt::Key_9,
96 Qt::Key_0,
97 Qt::Key_Enter,
98 Qt::Key_Escape,
99 Qt::Key_Backspace,
100 Qt::Key_Tab,
101 Qt::Key_Space,
102 Qt::Key_Minus,
103 Qt::Key_Equal,
104 Qt::Key_BracketLeft,
105 Qt::Key_BracketRight,
106 Qt::Key_Backslash,
107 Qt::Key_Dead_Tilde,
108 Qt::Key_Semicolon,
109 Qt::Key_Apostrophe,
110 Qt::Key_Dead_Grave,
111 Qt::Key_Comma,
112 Qt::Key_Period,
113 Qt::Key_Slash,
114 Qt::Key_CapsLock,
115
116 Qt::Key_F1,
117 Qt::Key_F2,
118 Qt::Key_F3,
119 Qt::Key_F4,
120 Qt::Key_F5,
121 Qt::Key_F6,
122 Qt::Key_F7,
123 Qt::Key_F8,
124 Qt::Key_F9,
125 Qt::Key_F10,
126 Qt::Key_F11,
127 Qt::Key_F12,
128
129 Qt::Key_SysReq,
130 Qt::Key_ScrollLock,
131 Qt::Key_Pause,
132 Qt::Key_Insert,
133 Qt::Key_Home,
134 Qt::Key_PageUp,
135 Qt::Key_Delete,
136 Qt::Key_End,
137 Qt::Key_PageDown,
138 Qt::Key_Right,
139 Qt::Key_Left,
140 Qt::Key_Down,
141 Qt::Key_Up,
142
143 Qt::Key_NumLock,
144 Qt::Key_Slash,
145 Qt::Key_Asterisk,
146 Qt::Key_Minus,
147 Qt::Key_Plus,
148 Qt::Key_Enter,
149 Qt::Key_1,
150 Qt::Key_2,
151 Qt::Key_3,
152 Qt::Key_4,
153 Qt::Key_5,
154 Qt::Key_6,
155 Qt::Key_7,
156 Qt::Key_8,
157 Qt::Key_9,
158 Qt::Key_0,
159 Qt::Key_Period,
160
161 0,
162 0,
163 Qt::Key_PowerOff,
164 Qt::Key_Equal,
165
166 Qt::Key_F13,
167 Qt::Key_F14,
168 Qt::Key_F15,
169 Qt::Key_F16,
170 Qt::Key_F17,
171 Qt::Key_F18,
172 Qt::Key_F19,
173 Qt::Key_F20,
174 Qt::Key_F21,
175 Qt::Key_F22,
176 Qt::Key_F23,
177 Qt::Key_F24,
178
179 Qt::Key_Open,
180 Qt::Key_Help,
181 Qt::Key_Menu,
182 0,
183 Qt::Key_Stop,
184 Qt::Key_AudioRepeat,
185 Qt::Key_Undo,
186 Qt::Key_Cut,
187 Qt::Key_Copy,
188 Qt::Key_Paste,
189 Qt::Key_Find,
190 Qt::Key_VolumeMute,
191 Qt::Key_VolumeUp,
192 Qt::Key_VolumeDown,
193 Qt::Key_CapsLock,
194 Qt::Key_NumLock,
195 Qt::Key_ScrollLock,
196 Qt::Key_Comma,
197
198 Qt::Key_ParenLeft,
199 Qt::Key_ParenRight,
200};
201
202const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default_keyboard_mods = {
203 Qt::Key_Control, Qt::Key_Shift, Qt::Key_Alt, Qt::Key_ApplicationLeft,
204 Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight,
205};
206
207void Config::ReadPlayerValues() {
208 for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
209 Settings::values.players[p].connected =
210 qt_config->value(QString("player_%1_connected").arg(p), false).toBool();
211
212 Settings::values.players[p].type = static_cast<Settings::ControllerType>(
213 qt_config
214 ->value(QString("player_%1_type").arg(p),
215 static_cast<u8>(Settings::ControllerType::DualJoycon))
216 .toUInt());
217
218 Settings::values.players[p].body_color_left =
219 qt_config
220 ->value(QString("player_%1_body_color_left").arg(p),
221 Settings::JOYCON_BODY_NEON_BLUE)
222 .toUInt();
223 Settings::values.players[p].body_color_right =
224 qt_config
225 ->value(QString("player_%1_body_color_right").arg(p),
226 Settings::JOYCON_BODY_NEON_RED)
227 .toUInt();
228 Settings::values.players[p].button_color_left =
229 qt_config
230 ->value(QString("player_%1_button_color_left").arg(p),
231 Settings::JOYCON_BUTTONS_NEON_BLUE)
232 .toUInt();
233 Settings::values.players[p].button_color_right =
234 qt_config
235 ->value(QString("player_%1_button_color_right").arg(p),
236 Settings::JOYCON_BUTTONS_NEON_RED)
237 .toUInt();
238
239 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
240 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
241 Settings::values.players[p].buttons[i] =
242 qt_config
243 ->value(QString("player_%1_").arg(p) + Settings::NativeButton::mapping[i],
244 QString::fromStdString(default_param))
245 .toString()
246 .toStdString();
247 if (Settings::values.players[p].buttons[i].empty())
248 Settings::values.players[p].buttons[i] = default_param;
249 }
250
251 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
252 std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
253 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
254 default_analogs[i][3], default_analogs[i][4], 0.5f);
255 Settings::values.players[p].analogs[i] =
256 qt_config
257 ->value(QString("player_%1_").arg(p) + Settings::NativeAnalog::mapping[i],
258 QString::fromStdString(default_param))
259 .toString()
260 .toStdString();
261 if (Settings::values.players[p].analogs[i].empty())
262 Settings::values.players[p].analogs[i] = default_param;
263 }
264 }
265
266 std::stable_partition(
267 Settings::values.players.begin(),
268 Settings::values.players.begin() +
269 Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
270 [](const auto& player) { return player.connected; });
271}
272
273void Config::ReadDebugValues() {
274 Settings::values.debug_pad_enabled = qt_config->value("debug_pad_enabled", false).toBool();
52 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { 275 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
53 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); 276 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
54 Settings::values.buttons[i] = 277 Settings::values.debug_pad_buttons[i] =
55 qt_config 278 qt_config
56 ->value(Settings::NativeButton::mapping[i], QString::fromStdString(default_param)) 279 ->value(QString("debug_pad_") + Settings::NativeButton::mapping[i],
280 QString::fromStdString(default_param))
57 .toString() 281 .toString()
58 .toStdString(); 282 .toStdString();
59 if (Settings::values.buttons[i].empty()) 283 if (Settings::values.debug_pad_buttons[i].empty())
60 Settings::values.buttons[i] = default_param; 284 Settings::values.debug_pad_buttons[i] = default_param;
61 } 285 }
62 286
63 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { 287 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
64 std::string default_param = InputCommon::GenerateAnalogParamFromKeys( 288 std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
65 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], 289 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
66 default_analogs[i][3], default_analogs[i][4], 0.5f); 290 default_analogs[i][3], default_analogs[i][4], 0.5f);
67 Settings::values.analogs[i] = 291 Settings::values.debug_pad_analogs[i] =
292 qt_config
293 ->value(QString("debug_pad_") + Settings::NativeAnalog::mapping[i],
294 QString::fromStdString(default_param))
295 .toString()
296 .toStdString();
297 if (Settings::values.debug_pad_analogs[i].empty())
298 Settings::values.debug_pad_analogs[i] = default_param;
299 }
300}
301
302void Config::ReadKeyboardValues() {
303 Settings::values.keyboard_enabled = qt_config->value("keyboard_enabled", false).toBool();
304
305 std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(),
306 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
307 std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
308 Settings::values.keyboard_keys.begin() +
309 Settings::NativeKeyboard::LeftControlKey,
310 InputCommon::GenerateKeyboardParam);
311 std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
312 Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
313}
314
315void Config::ReadMouseValues() {
316 Settings::values.mouse_enabled = qt_config->value("mouse_enabled", false).toBool();
317
318 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
319 std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
320 Settings::values.mouse_buttons[i] =
68 qt_config 321 qt_config
69 ->value(Settings::NativeAnalog::mapping[i], QString::fromStdString(default_param)) 322 ->value(QString("mouse_") + Settings::NativeMouseButton::mapping[i],
323 QString::fromStdString(default_param))
70 .toString() 324 .toString()
71 .toStdString(); 325 .toStdString();
72 if (Settings::values.analogs[i].empty()) 326 if (Settings::values.mouse_buttons[i].empty())
73 Settings::values.analogs[i] = default_param; 327 Settings::values.mouse_buttons[i] = default_param;
74 } 328 }
329}
330
331void Config::ReadTouchscreenValues() {
332 Settings::values.touchscreen.enabled = qt_config->value("touchscreen_enabled", true).toBool();
333 Settings::values.touchscreen.device =
334 qt_config->value("touchscreen_device", "engine:emu_window").toString().toStdString();
335
336 Settings::values.touchscreen.finger = qt_config->value("touchscreen_finger", 0).toUInt();
337 Settings::values.touchscreen.rotation_angle = qt_config->value("touchscreen_angle", 0).toUInt();
338 Settings::values.touchscreen.diameter_x =
339 qt_config->value("touchscreen_diameter_x", 15).toUInt();
340 Settings::values.touchscreen.diameter_y =
341 qt_config->value("touchscreen_diameter_y", 15).toUInt();
342 qt_config->endGroup();
343}
344
345void Config::ReadValues() {
346 qt_config->beginGroup("Controls");
347
348 ReadPlayerValues();
349 ReadDebugValues();
350 ReadKeyboardValues();
351 ReadMouseValues();
352 ReadTouchscreenValues();
75 353
76 Settings::values.motion_device = 354 Settings::values.motion_device =
77 qt_config->value("motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01") 355 qt_config->value("motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01")
78 .toString() 356 .toString()
79 .toStdString(); 357 .toStdString();
80 Settings::values.touch_device =
81 qt_config->value("touch_device", "engine:emu_window").toString().toStdString();
82
83 qt_config->endGroup();
84 358
85 qt_config->beginGroup("Core"); 359 qt_config->beginGroup("Core");
86 Settings::values.use_cpu_jit = qt_config->value("use_cpu_jit", true).toBool(); 360 Settings::values.use_cpu_jit = qt_config->value("use_cpu_jit", true).toBool();
@@ -126,6 +400,11 @@ void Config::ReadValues() {
126 .toStdString()); 400 .toStdString());
127 qt_config->endGroup(); 401 qt_config->endGroup();
128 402
403 qt_config->beginGroup("Core");
404 Settings::values.use_cpu_jit = qt_config->value("use_cpu_jit", true).toBool();
405 Settings::values.use_multi_core = qt_config->value("use_multi_core", false).toBool();
406 qt_config->endGroup();
407
129 qt_config->beginGroup("System"); 408 qt_config->beginGroup("System");
130 Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool(); 409 Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool();
131 Settings::values.enable_nfc = qt_config->value("enable_nfc", true).toBool(); 410 Settings::values.enable_nfc = qt_config->value("enable_nfc", true).toBool();
@@ -134,6 +413,14 @@ void Config::ReadValues() {
134 Service::Account::MAX_USERS - 1); 413 Service::Account::MAX_USERS - 1);
135 414
136 Settings::values.language_index = qt_config->value("language_index", 1).toInt(); 415 Settings::values.language_index = qt_config->value("language_index", 1).toInt();
416
417 const auto enabled = qt_config->value("rng_seed_enabled", false).toBool();
418 if (enabled) {
419 Settings::values.rng_seed = qt_config->value("rng_seed", 0).toULongLong();
420 } else {
421 Settings::values.rng_seed = std::nullopt;
422 }
423
137 qt_config->endGroup(); 424 qt_config->endGroup();
138 425
139 qt_config->beginGroup("Miscellaneous"); 426 qt_config->beginGroup("Miscellaneous");
@@ -145,6 +432,8 @@ void Config::ReadValues() {
145 Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool(); 432 Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool();
146 Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt(); 433 Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt();
147 Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString(); 434 Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString();
435 Settings::values.dump_exefs = qt_config->value("dump_exefs", false).toBool();
436 Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool();
148 qt_config->endGroup(); 437 qt_config->endGroup();
149 438
150 qt_config->beginGroup("WebService"); 439 qt_config->beginGroup("WebService");
@@ -162,6 +451,7 @@ void Config::ReadValues() {
162 451
163 qt_config->beginGroup("UIGameList"); 452 qt_config->beginGroup("UIGameList");
164 UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool(); 453 UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool();
454 UISettings::values.show_add_ons = qt_config->value("show_add_ons", true).toBool();
165 UISettings::values.icon_size = qt_config->value("icon_size", 64).toUInt(); 455 UISettings::values.icon_size = qt_config->value("icon_size", 64).toUInt();
166 UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 3).toUInt(); 456 UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 3).toUInt();
167 UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 2).toUInt(); 457 UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 2).toUInt();
@@ -220,18 +510,81 @@ void Config::ReadValues() {
220 qt_config->endGroup(); 510 qt_config->endGroup();
221} 511}
222 512
223void Config::SaveValues() { 513void Config::SavePlayerValues() {
224 qt_config->beginGroup("Controls"); 514 for (int p = 0; p < Settings::values.players.size(); ++p) {
515 qt_config->setValue(QString("player_%1_connected").arg(p),
516 Settings::values.players[p].connected);
517 qt_config->setValue(QString("player_%1_type").arg(p),
518 static_cast<u8>(Settings::values.players[p].type));
519
520 qt_config->setValue(QString("player_%1_body_color_left").arg(p),
521 Settings::values.players[p].body_color_left);
522 qt_config->setValue(QString("player_%1_body_color_right").arg(p),
523 Settings::values.players[p].body_color_right);
524 qt_config->setValue(QString("player_%1_button_color_left").arg(p),
525 Settings::values.players[p].button_color_left);
526 qt_config->setValue(QString("player_%1_button_color_right").arg(p),
527 Settings::values.players[p].button_color_right);
528
529 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
530 qt_config->setValue(QString("player_%1_").arg(p) +
531 QString::fromStdString(Settings::NativeButton::mapping[i]),
532 QString::fromStdString(Settings::values.players[p].buttons[i]));
533 }
534 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
535 qt_config->setValue(QString("player_%1_").arg(p) +
536 QString::fromStdString(Settings::NativeAnalog::mapping[i]),
537 QString::fromStdString(Settings::values.players[p].analogs[i]));
538 }
539 }
540}
541
542void Config::SaveDebugValues() {
543 qt_config->setValue("debug_pad_enabled", Settings::values.debug_pad_enabled);
225 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { 544 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
226 qt_config->setValue(QString::fromStdString(Settings::NativeButton::mapping[i]), 545 qt_config->setValue(QString("debug_pad_") +
227 QString::fromStdString(Settings::values.buttons[i])); 546 QString::fromStdString(Settings::NativeButton::mapping[i]),
547 QString::fromStdString(Settings::values.debug_pad_buttons[i]));
228 } 548 }
229 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { 549 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
230 qt_config->setValue(QString::fromStdString(Settings::NativeAnalog::mapping[i]), 550 qt_config->setValue(QString("debug_pad_") +
231 QString::fromStdString(Settings::values.analogs[i])); 551 QString::fromStdString(Settings::NativeAnalog::mapping[i]),
552 QString::fromStdString(Settings::values.debug_pad_analogs[i]));
553 }
554}
555
556void Config::SaveMouseValues() {
557 qt_config->setValue("mouse_enabled", Settings::values.mouse_enabled);
558
559 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
560 qt_config->setValue(QString("mouse_") +
561 QString::fromStdString(Settings::NativeMouseButton::mapping[i]),
562 QString::fromStdString(Settings::values.mouse_buttons[i]));
232 } 563 }
564}
565
566void Config::SaveTouchscreenValues() {
567 qt_config->setValue("touchscreen_enabled", Settings::values.touchscreen.enabled);
568 qt_config->setValue("touchscreen_device",
569 QString::fromStdString(Settings::values.touchscreen.device));
570
571 qt_config->setValue("touchscreen_finger", Settings::values.touchscreen.finger);
572 qt_config->setValue("touchscreen_angle", Settings::values.touchscreen.rotation_angle);
573 qt_config->setValue("touchscreen_diameter_x", Settings::values.touchscreen.diameter_x);
574 qt_config->setValue("touchscreen_diameter_y", Settings::values.touchscreen.diameter_y);
575}
576
577void Config::SaveValues() {
578 qt_config->beginGroup("Controls");
579
580 SavePlayerValues();
581 SaveDebugValues();
582 SaveMouseValues();
583 SaveTouchscreenValues();
584
233 qt_config->setValue("motion_device", QString::fromStdString(Settings::values.motion_device)); 585 qt_config->setValue("motion_device", QString::fromStdString(Settings::values.motion_device));
234 qt_config->setValue("touch_device", QString::fromStdString(Settings::values.touch_device)); 586 qt_config->setValue("keyboard_enabled", Settings::values.keyboard_enabled);
587
235 qt_config->endGroup(); 588 qt_config->endGroup();
236 589
237 qt_config->beginGroup("Core"); 590 qt_config->beginGroup("Core");
@@ -270,8 +623,11 @@ void Config::SaveValues() {
270 qt_config->setValue("use_docked_mode", Settings::values.use_docked_mode); 623 qt_config->setValue("use_docked_mode", Settings::values.use_docked_mode);
271 qt_config->setValue("enable_nfc", Settings::values.enable_nfc); 624 qt_config->setValue("enable_nfc", Settings::values.enable_nfc);
272 qt_config->setValue("current_user", Settings::values.current_user); 625 qt_config->setValue("current_user", Settings::values.current_user);
273
274 qt_config->setValue("language_index", Settings::values.language_index); 626 qt_config->setValue("language_index", Settings::values.language_index);
627
628 qt_config->setValue("rng_seed_enabled", Settings::values.rng_seed.has_value());
629 qt_config->setValue("rng_seed", Settings::values.rng_seed.value_or(0));
630
275 qt_config->endGroup(); 631 qt_config->endGroup();
276 632
277 qt_config->beginGroup("Miscellaneous"); 633 qt_config->beginGroup("Miscellaneous");
@@ -283,6 +639,8 @@ void Config::SaveValues() {
283 qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub); 639 qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub);
284 qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port); 640 qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port);
285 qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args)); 641 qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args));
642 qt_config->setValue("dump_exefs", Settings::values.dump_exefs);
643 qt_config->setValue("dump_nso", Settings::values.dump_nso);
286 qt_config->endGroup(); 644 qt_config->endGroup();
287 645
288 qt_config->beginGroup("WebService"); 646 qt_config->beginGroup("WebService");
@@ -298,6 +656,7 @@ void Config::SaveValues() {
298 656
299 qt_config->beginGroup("UIGameList"); 657 qt_config->beginGroup("UIGameList");
300 qt_config->setValue("show_unknown", UISettings::values.show_unknown); 658 qt_config->setValue("show_unknown", UISettings::values.show_unknown);
659 qt_config->setValue("show_add_ons", UISettings::values.show_add_ons);
301 qt_config->setValue("icon_size", UISettings::values.icon_size); 660 qt_config->setValue("icon_size", UISettings::values.icon_size);
302 qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id); 661 qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id);
303 qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id); 662 qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id);
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 9c99c1b75..a1c27bbf9 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -22,10 +22,24 @@ public:
22 22
23 static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; 23 static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
24 static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs; 24 static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
25 static const std::array<int, Settings::NativeMouseButton::NumMouseButtons>
26 default_mouse_buttons;
27 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
28 static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
25 29
26private: 30private:
27 void ReadValues(); 31 void ReadValues();
32 void ReadPlayerValues();
33 void ReadDebugValues();
34 void ReadKeyboardValues();
35 void ReadMouseValues();
36 void ReadTouchscreenValues();
37
28 void SaveValues(); 38 void SaveValues();
39 void SavePlayerValues();
40 void SaveDebugValues();
41 void SaveMouseValues();
42 void SaveTouchscreenValues();
29 43
30 std::unique_ptr<QSettings> qt_config; 44 std::unique_ptr<QSettings> qt_config;
31 std::string qt_config_loc; 45 std::string qt_config_loc;
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 207f9dfb3..8771421c0 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -16,15 +16,14 @@ class ConfigureAudio : public QWidget {
16 16
17public: 17public:
18 explicit ConfigureAudio(QWidget* parent = nullptr); 18 explicit ConfigureAudio(QWidget* parent = nullptr);
19 ~ConfigureAudio(); 19 ~ConfigureAudio() override;
20 20
21 void applyConfiguration(); 21 void applyConfiguration();
22 void retranslateUi(); 22 void retranslateUi();
23 23
24public slots: 24private:
25 void updateAudioDevices(int sink_index); 25 void updateAudioDevices(int sink_index);
26 26
27private:
28 void setConfiguration(); 27 void setConfiguration();
29 void setOutputSinkFromSinkID(); 28 void setOutputSinkFromSinkID();
30 void setAudioDeviceFromDeviceID(); 29 void setAudioDeviceFromDeviceID();
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 9e765fc93..aa7de7b54 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -34,6 +34,8 @@ void ConfigureDebug::setConfiguration() {
34 ui->toggle_console->setChecked(UISettings::values.show_console); 34 ui->toggle_console->setChecked(UISettings::values.show_console);
35 ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); 35 ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
36 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); 36 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
37 ui->dump_exefs->setChecked(Settings::values.dump_exefs);
38 ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso);
37} 39}
38 40
39void ConfigureDebug::applyConfiguration() { 41void ConfigureDebug::applyConfiguration() {
@@ -42,6 +44,8 @@ void ConfigureDebug::applyConfiguration() {
42 UISettings::values.show_console = ui->toggle_console->isChecked(); 44 UISettings::values.show_console = ui->toggle_console->isChecked();
43 Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); 45 Settings::values.log_filter = ui->log_filter_edit->text().toStdString();
44 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); 46 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
47 Settings::values.dump_exefs = ui->dump_exefs->isChecked();
48 Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked();
45 Debugger::ToggleConsole(); 49 Debugger::ToggleConsole();
46 Log::Filter filter; 50 Log::Filter filter;
47 filter.ParseFilterString(Settings::values.log_filter); 51 filter.ParseFilterString(Settings::values.log_filter);
diff --git a/src/yuzu/configuration/configure_debug.h b/src/yuzu/configuration/configure_debug.h
index d167eb996..c6420b18c 100644
--- a/src/yuzu/configuration/configure_debug.h
+++ b/src/yuzu/configuration/configure_debug.h
@@ -16,13 +16,12 @@ class ConfigureDebug : public QWidget {
16 16
17public: 17public:
18 explicit ConfigureDebug(QWidget* parent = nullptr); 18 explicit ConfigureDebug(QWidget* parent = nullptr);
19 ~ConfigureDebug(); 19 ~ConfigureDebug() override;
20 20
21 void applyConfiguration(); 21 void applyConfiguration();
22 22
23private: 23private:
24 void setConfiguration(); 24 void setConfiguration();
25 25
26private:
27 std::unique_ptr<Ui::ConfigureDebug> ui; 26 std::unique_ptr<Ui::ConfigureDebug> ui;
28}; 27};
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index ff4987604..758a92335 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -7,7 +7,7 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>400</width> 9 <width>400</width>
10 <height>300</height> 10 <height>357</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -130,6 +130,35 @@
130 </widget> 130 </widget>
131 </item> 131 </item>
132 <item> 132 <item>
133 <widget class="QGroupBox" name="groupBox_4">
134 <property name="title">
135 <string>Dump</string>
136 </property>
137 <layout class="QVBoxLayout" name="verticalLayout_4">
138 <item>
139 <widget class="QCheckBox" name="dump_decompressed_nso">
140 <property name="whatsThis">
141 <string>When checked, any NSO yuzu tries to load or patch will be copied decompressed to the yuzu/dump directory.</string>
142 </property>
143 <property name="text">
144 <string>Dump Decompressed NSOs</string>
145 </property>
146 </widget>
147 </item>
148 <item>
149 <widget class="QCheckBox" name="dump_exefs">
150 <property name="whatsThis">
151 <string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string>
152 </property>
153 <property name="text">
154 <string>Dump ExeFS</string>
155 </property>
156 </widget>
157 </item>
158 </layout>
159 </widget>
160 </item>
161 <item>
133 <spacer name="verticalSpacer"> 162 <spacer name="verticalSpacer">
134 <property name="orientation"> 163 <property name="orientation">
135 <enum>Qt::Vertical</enum> 164 <enum>Qt::Vertical</enum>
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index bbbdacc29..f6df7b827 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -18,13 +18,12 @@ class ConfigureDialog : public QDialog {
18 18
19public: 19public:
20 explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry); 20 explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry);
21 ~ConfigureDialog(); 21 ~ConfigureDialog() override;
22 22
23 void applyConfiguration(); 23 void applyConfiguration();
24 24
25private: 25private:
26 void setConfiguration(); 26 void setConfiguration();
27 27
28private:
29 std::unique_ptr<Ui::ConfigureDialog> ui; 28 std::unique_ptr<Ui::ConfigureDialog> ui;
30}; 29};
diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp
index 8743ce982..ae8cac243 100644
--- a/src/yuzu/configuration/configure_gamelist.cpp
+++ b/src/yuzu/configuration/configure_gamelist.cpp
@@ -36,20 +36,36 @@ ConfigureGameList::ConfigureGameList(QWidget* parent)
36 InitializeRowComboBoxes(); 36 InitializeRowComboBoxes();
37 37
38 this->setConfiguration(); 38 this->setConfiguration();
39
40 // Force game list reload if any of the relevant settings are changed.
41 connect(ui->show_unknown, &QCheckBox::stateChanged, this,
42 &ConfigureGameList::RequestGameListUpdate);
43 connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
44 &ConfigureGameList::RequestGameListUpdate);
45 connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
46 &ConfigureGameList::RequestGameListUpdate);
47 connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
48 &ConfigureGameList::RequestGameListUpdate);
39} 49}
40 50
41ConfigureGameList::~ConfigureGameList() = default; 51ConfigureGameList::~ConfigureGameList() = default;
42 52
43void ConfigureGameList::applyConfiguration() { 53void ConfigureGameList::applyConfiguration() {
44 UISettings::values.show_unknown = ui->show_unknown->isChecked(); 54 UISettings::values.show_unknown = ui->show_unknown->isChecked();
55 UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
45 UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); 56 UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
46 UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); 57 UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
47 UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt(); 58 UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt();
48 Settings::Apply(); 59 Settings::Apply();
49} 60}
50 61
62void ConfigureGameList::RequestGameListUpdate() {
63 UISettings::values.is_game_list_reload_pending.exchange(true);
64}
65
51void ConfigureGameList::setConfiguration() { 66void ConfigureGameList::setConfiguration() {
52 ui->show_unknown->setChecked(UISettings::values.show_unknown); 67 ui->show_unknown->setChecked(UISettings::values.show_unknown);
68 ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
53 ui->icon_size_combobox->setCurrentIndex( 69 ui->icon_size_combobox->setCurrentIndex(
54 ui->icon_size_combobox->findData(UISettings::values.icon_size)); 70 ui->icon_size_combobox->findData(UISettings::values.icon_size));
55 ui->row_1_text_combobox->setCurrentIndex( 71 ui->row_1_text_combobox->setCurrentIndex(
diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h
index ff7406c60..bf3f1cdfa 100644
--- a/src/yuzu/configuration/configure_gamelist.h
+++ b/src/yuzu/configuration/configure_gamelist.h
@@ -16,11 +16,13 @@ class ConfigureGameList : public QWidget {
16 16
17public: 17public:
18 explicit ConfigureGameList(QWidget* parent = nullptr); 18 explicit ConfigureGameList(QWidget* parent = nullptr);
19 ~ConfigureGameList(); 19 ~ConfigureGameList() override;
20 20
21 void applyConfiguration(); 21 void applyConfiguration();
22 22
23private: 23private:
24 void RequestGameListUpdate();
25
24 void setConfiguration(); 26 void setConfiguration();
25 27
26 void changeEvent(QEvent*) override; 28 void changeEvent(QEvent*) override;
diff --git a/src/yuzu/configuration/configure_gamelist.ui b/src/yuzu/configuration/configure_gamelist.ui
index 7471fdb60..7a69377e7 100644
--- a/src/yuzu/configuration/configure_gamelist.ui
+++ b/src/yuzu/configuration/configure_gamelist.ui
@@ -1,126 +1,133 @@
1<?xml version="1.0" encoding="UTF-8"?> 1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0"> 2<ui version="4.0">
3 <class>ConfigureGameList</class> 3 <class>ConfigureGameList</class>
4 <widget class="QWidget" name="ConfigureGeneral"> 4 <widget class="QWidget" name="ConfigureGameList">
5 <property name="geometry"> 5 <property name="geometry">
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>300</width> 9 <width>300</width>
10 <height>377</height> 10 <height>377</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <layout class="QHBoxLayout" name="HorizontalLayout"> 16 <layout class="QHBoxLayout" name="HorizontalLayout">
17 <item> 17 <item>
18 <layout class="QVBoxLayout" name="VerticalLayout"> 18 <layout class="QVBoxLayout" name="VerticalLayout">
19 <item>
20 <widget class="QGroupBox" name="GeneralGroupBox">
21 <property name="title">
22 <string>General</string>
23 </property>
24 <layout class="QHBoxLayout" name="GeneralHorizontalLayout">
25 <item>
26 <layout class="QVBoxLayout" name="GeneralVerticalLayout">
19 <item> 27 <item>
20 <widget class="QGroupBox" name="GeneralGroupBox"> 28 <widget class="QCheckBox" name="show_unknown">
21 <property name="title"> 29 <property name="text">
22 <string>General</string> 30 <string>Show files with type 'Unknown'</string>
23 </property> 31 </property>
24 <layout class="QHBoxLayout" name="GeneralHorizontalLayout"> 32 </widget>
25 <item>
26 <layout class="QVBoxLayout" name="GeneralVerticalLayout">
27 <item>
28 <widget class="QCheckBox" name="show_unknown">
29 <property name="text">
30 <string>Show files with type 'Unknown'</string>
31 </property>
32 </widget>
33 </item>
34 </layout>
35 </item>
36 </layout>
37 </widget>
38 </item> 33 </item>
39 <item> 34 <item>
40 <widget class="QGroupBox" name="IconSizeGroupBox"> 35 <widget class="QCheckBox" name="show_add_ons">
41 <property name="title"> 36 <property name="text">
42 <string>Icon Size</string> 37 <string>Show Add-Ons Column</string>
43 </property> 38 </property>
44 <layout class="QHBoxLayout" name="icon_size_qhbox_layout"> 39 </widget>
45 <item>
46 <layout class="QVBoxLayout" name="icon_size_qvbox_layout">
47 <item>
48 <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
49 <item>
50 <widget class="QLabel" name="icon_size_label">
51 <property name="text">
52 <string>Icon Size:</string>
53 </property>
54 </widget>
55 </item>
56 <item>
57 <widget class="QComboBox" name="icon_size_combobox"/>
58 </item>
59 </layout>
60 </item>
61 </layout>
62 </item>
63 </layout>
64 </widget>
65 </item> 40 </item>
41 </layout>
42 </item>
43 </layout>
44 </widget>
45 </item>
46 <item>
47 <widget class="QGroupBox" name="IconSizeGroupBox">
48 <property name="title">
49 <string>Icon Size</string>
50 </property>
51 <layout class="QHBoxLayout" name="icon_size_qhbox_layout">
52 <item>
53 <layout class="QVBoxLayout" name="icon_size_qvbox_layout">
66 <item> 54 <item>
67 <widget class="QGroupBox" name="RowGroupBox"> 55 <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
68 <property name="title"> 56 <item>
69 <string>Row Text</string> 57 <widget class="QLabel" name="icon_size_label">
58 <property name="text">
59 <string>Icon Size:</string>
70 </property> 60 </property>
71 <layout class="QHBoxLayout" name="RowHorizontalLayout"> 61 </widget>
72 <item> 62 </item>
73 <layout class="QVBoxLayout" name="RowVerticalLayout"> 63 <item>
74 <item> 64 <widget class="QComboBox" name="icon_size_combobox"/>
75 <layout class="QHBoxLayout" name="row_1_qhbox_layout"> 65 </item>
76 <item> 66 </layout>
77 <widget class="QLabel" name="row_1_label">
78 <property name="text">
79 <string>Row 1 Text:</string>
80 </property>
81 </widget>
82 </item>
83 <item>
84 <widget class="QComboBox" name="row_1_text_combobox"/>
85 </item>
86 </layout>
87 </item>
88 <item>
89 <layout class="QHBoxLayout" name="row_2_qhbox_layout">
90 <item>
91 <widget class="QLabel" name="row_2_label">
92 <property name="text">
93 <string>Row 2 Text:</string>
94 </property>
95 </widget>
96 </item>
97 <item>
98 <widget class="QComboBox" name="row_2_text_combobox"/>
99 </item>
100 </layout>
101 </item>
102 </layout>
103 </item>
104 </layout>
105 </widget>
106 </item> 67 </item>
68 </layout>
69 </item>
70 </layout>
71 </widget>
72 </item>
73 <item>
74 <widget class="QGroupBox" name="RowGroupBox">
75 <property name="title">
76 <string>Row Text</string>
77 </property>
78 <layout class="QHBoxLayout" name="RowHorizontalLayout">
79 <item>
80 <layout class="QVBoxLayout" name="RowVerticalLayout">
107 <item> 81 <item>
108 <spacer name="verticalSpacer"> 82 <layout class="QHBoxLayout" name="row_1_qhbox_layout">
109 <property name="orientation"> 83 <item>
110 <enum>Qt::Vertical</enum> 84 <widget class="QLabel" name="row_1_label">
85 <property name="text">
86 <string>Row 1 Text:</string>
111 </property> 87 </property>
112 <property name="sizeHint" stdset="0"> 88 </widget>
113 <size> 89 </item>
114 <width>20</width> 90 <item>
115 <height>40</height> 91 <widget class="QComboBox" name="row_1_text_combobox"/>
116 </size> 92 </item>
93 </layout>
94 </item>
95 <item>
96 <layout class="QHBoxLayout" name="row_2_qhbox_layout">
97 <item>
98 <widget class="QLabel" name="row_2_label">
99 <property name="text">
100 <string>Row 2 Text:</string>
117 </property> 101 </property>
118 </spacer> 102 </widget>
103 </item>
104 <item>
105 <widget class="QComboBox" name="row_2_text_combobox"/>
106 </item>
107 </layout>
119 </item> 108 </item>
120 </layout> 109 </layout>
121 </item> 110 </item>
111 </layout>
112 </widget>
113 </item>
114 <item>
115 <spacer name="verticalSpacer">
116 <property name="orientation">
117 <enum>Qt::Vertical</enum>
118 </property>
119 <property name="sizeHint" stdset="0">
120 <size>
121 <width>20</width>
122 <height>40</height>
123 </size>
124 </property>
125 </spacer>
126 </item>
122 </layout> 127 </layout>
123 </widget> 128 </item>
129 </layout>
130 </widget>
124 <resources/> 131 <resources/>
125 <connections/> 132 <connections/>
126</ui> 133</ui>
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index b322258a0..92a441308 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -3,10 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/applet_ae.h"
8#include "core/hle/service/am/applet_oe.h"
9#include "core/hle/service/sm/sm.h"
10#include "core/settings.h" 6#include "core/settings.h"
11#include "ui_configure_general.h" 7#include "ui_configure_general.h"
12#include "yuzu/configuration/configure_general.h" 8#include "yuzu/configuration/configure_general.h"
@@ -23,6 +19,9 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
23 19
24 this->setConfiguration(); 20 this->setConfiguration();
25 21
22 connect(ui->toggle_deepscan, &QCheckBox::stateChanged, this,
23 [] { UISettings::values.is_game_list_reload_pending.exchange(true); });
24
26 ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 25 ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
27} 26}
28 27
@@ -33,7 +32,6 @@ void ConfigureGeneral::setConfiguration() {
33 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); 32 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
34 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); 33 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
35 ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit); 34 ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
36 ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
37 ui->enable_nfc->setChecked(Settings::values.enable_nfc); 35 ui->enable_nfc->setChecked(Settings::values.enable_nfc);
38} 36}
39 37
@@ -41,30 +39,6 @@ void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
41 ui->widget->Populate(registry); 39 ui->widget->Populate(registry);
42} 40}
43 41
44void ConfigureGeneral::OnDockedModeChanged(bool last_state, bool new_state) {
45 if (last_state == new_state) {
46 return;
47 }
48
49 Core::System& system{Core::System::GetInstance()};
50 Service::SM::ServiceManager& sm = system.ServiceManager();
51
52 // Message queue is shared between these services, we just need to signal an operation
53 // change to one and it will handle both automatically
54 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
55 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
56 bool has_signalled = false;
57
58 if (applet_oe != nullptr) {
59 applet_oe->GetMessageQueue()->OperationModeChanged();
60 has_signalled = true;
61 }
62
63 if (applet_ae != nullptr && !has_signalled) {
64 applet_ae->GetMessageQueue()->OperationModeChanged();
65 }
66}
67
68void ConfigureGeneral::applyConfiguration() { 42void ConfigureGeneral::applyConfiguration() {
69 UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); 43 UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked();
70 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); 44 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
@@ -72,9 +46,5 @@ void ConfigureGeneral::applyConfiguration() {
72 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); 46 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
73 47
74 Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked(); 48 Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
75 const bool pre_docked_mode = Settings::values.use_docked_mode;
76 Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
77 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
78
79 Settings::values.enable_nfc = ui->enable_nfc->isChecked(); 49 Settings::values.enable_nfc = ui->enable_nfc->isChecked();
80} 50}
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 2210d48da..59738af40 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -18,14 +18,13 @@ class ConfigureGeneral : public QWidget {
18 18
19public: 19public:
20 explicit ConfigureGeneral(QWidget* parent = nullptr); 20 explicit ConfigureGeneral(QWidget* parent = nullptr);
21 ~ConfigureGeneral(); 21 ~ConfigureGeneral() override;
22 22
23 void PopulateHotkeyList(const HotkeyRegistry& registry); 23 void PopulateHotkeyList(const HotkeyRegistry& registry);
24 void applyConfiguration(); 24 void applyConfiguration();
25 25
26private: 26private:
27 void setConfiguration(); 27 void setConfiguration();
28 void OnDockedModeChanged(bool last_state, bool new_state);
29 28
30 std::unique_ptr<Ui::ConfigureGeneral> ui; 29 std::unique_ptr<Ui::ConfigureGeneral> ui;
31}; 30};
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index b82fffde8..bf37446c6 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -7,7 +7,7 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>300</width> 9 <width>300</width>
10 <height>377</height> 10 <height>407</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -72,13 +72,6 @@
72 <item> 72 <item>
73 <layout class="QVBoxLayout" name="EmulationVerticalLayout"> 73 <layout class="QVBoxLayout" name="EmulationVerticalLayout">
74 <item> 74 <item>
75 <widget class="QCheckBox" name="use_docked_mode">
76 <property name="text">
77 <string>Enable docked mode</string>
78 </property>
79 </widget>
80 </item>
81 <item>
82 <widget class="QCheckBox" name="enable_nfc"> 75 <widget class="QCheckBox" name="enable_nfc">
83 <property name="text"> 76 <property name="text">
84 <string>Enable NFC</string> 77 <string>Enable NFC</string>
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 9bda26fd6..d6ffc6fde 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -16,14 +16,13 @@ class ConfigureGraphics : public QWidget {
16 16
17public: 17public:
18 explicit ConfigureGraphics(QWidget* parent = nullptr); 18 explicit ConfigureGraphics(QWidget* parent = nullptr);
19 ~ConfigureGraphics(); 19 ~ConfigureGraphics() override;
20 20
21 void applyConfiguration(); 21 void applyConfiguration();
22 22
23private: 23private:
24 void setConfiguration(); 24 void setConfiguration();
25 25
26private:
27 std::unique_ptr<Ui::ConfigureGraphics> ui; 26 std::unique_ptr<Ui::ConfigureGraphics> ui;
28 QColor bg_color; 27 QColor bg_color;
29}; 28};
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 91fcad994..e278cdd05 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -23,31 +23,31 @@
23 </property> 23 </property>
24 <layout class="QVBoxLayout" name="verticalLayout_2"> 24 <layout class="QVBoxLayout" name="verticalLayout_2">
25 <item> 25 <item>
26 <layout class="QHBoxLayout" name="horizontalLayout_2"> 26 <layout class="QHBoxLayout" name="horizontalLayout_2">
27 <item> 27 <item>
28 <widget class="QCheckBox" name="toggle_frame_limit"> 28 <widget class="QCheckBox" name="toggle_frame_limit">
29 <property name="text"> 29 <property name="text">
30 <string>Limit Speed Percent</string> 30 <string>Limit Speed Percent</string>
31 </property> 31 </property>
32 </widget> 32 </widget>
33 </item> 33 </item>
34 <item> 34 <item>
35 <widget class="QSpinBox" name="frame_limit"> 35 <widget class="QSpinBox" name="frame_limit">
36 <property name="suffix"> 36 <property name="suffix">
37 <string>%</string> 37 <string>%</string>
38 </property> 38 </property>
39 <property name="minimum"> 39 <property name="minimum">
40 <number>1</number> 40 <number>1</number>
41 </property> 41 </property>
42 <property name="maximum"> 42 <property name="maximum">
43 <number>9999</number> 43 <number>9999</number>
44 </property> 44 </property>
45 <property name="value"> 45 <property name="value">
46 <number>100</number> 46 <number>100</number>
47 </property> 47 </property>
48 </widget> 48 </widget>
49 </item> 49 </item>
50 </layout> 50 </layout>
51 </item> 51 </item>
52 <item> 52 <item>
53 <widget class="QCheckBox" name="use_accurate_gpu_emulation"> 53 <widget class="QCheckBox" name="use_accurate_gpu_emulation">
@@ -61,7 +61,7 @@
61 <item> 61 <item>
62 <widget class="QLabel" name="label"> 62 <widget class="QLabel" name="label">
63 <property name="text"> 63 <property name="text">
64 <string>Internal Resolution:(Currently does nothing.)</string> 64 <string>Internal Resolution</string>
65 </property> 65 </property>
66 </widget> 66 </widget>
67 </item> 67 </item>
@@ -96,27 +96,27 @@
96 </item> 96 </item>
97 </layout> 97 </layout>
98 </item> 98 </item>
99 <item> 99 <item>
100 <layout class="QHBoxLayout" name="horizontalLayout_6"> 100 <layout class="QHBoxLayout" name="horizontalLayout_6">
101 <item> 101 <item>
102 <widget class="QLabel" name="bg_label"> 102 <widget class="QLabel" name="bg_label">
103 <property name="text"> 103 <property name="text">
104 <string>Background Color:</string> 104 <string>Background Color:</string>
105 </property> 105 </property>
106 </widget> 106 </widget>
107 </item> 107 </item>
108 <item> 108 <item>
109 <widget class="QPushButton" name="bg_button"> 109 <widget class="QPushButton" name="bg_button">
110 <property name="maximumSize"> 110 <property name="maximumSize">
111 <size> 111 <size>
112 <width>40</width> 112 <width>40</width>
113 <height>16777215</height> 113 <height>16777215</height>
114 </size> 114 </size>
115 </property> 115 </property>
116 </widget> 116 </widget>
117 </item> 117 </item>
118 </layout> 118 </layout>
119 </item> 119 </item>
120 </layout> 120 </layout>
121 </widget> 121 </widget>
122 </item> 122 </item>
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 42a7beac6..830d26115 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -4,339 +4,209 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <memory> 6#include <memory>
7#include <utility> 7
8#include <QMenu>
9#include <QMessageBox>
10#include <QTimer> 8#include <QTimer>
11#include "common/param_package.h" 9
12#include "input_common/main.h" 10#include "configuration/configure_touchscreen_advanced.h"
13#include "yuzu/configuration/config.h" 11#include "core/core.h"
12#include "core/hle/service/am/am.h"
13#include "core/hle/service/am/applet_ae.h"
14#include "core/hle/service/am/applet_oe.h"
15#include "core/hle/service/hid/controllers/npad.h"
16#include "core/hle/service/sm/sm.h"
17#include "ui_configure_input.h"
18#include "ui_configure_input_player.h"
14#include "yuzu/configuration/configure_input.h" 19#include "yuzu/configuration/configure_input.h"
20#include "yuzu/configuration/configure_input_player.h"
21#include "yuzu/configuration/configure_mouse_advanced.h"
15 22
16const std::array<std::string, ConfigureInput::ANALOG_SUB_BUTTONS_NUM> 23namespace {
17 ConfigureInput::analog_sub_buttons{{ 24template <typename Dialog, typename... Args>
18 "up", 25void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
19 "down", 26 parent.applyConfiguration();
20 "left", 27 Dialog dialog(&parent, std::forward<Args>(args)...);
21 "right",
22 "modifier",
23 }};
24
25static QString getKeyName(int key_code) {
26 switch (key_code) {
27 case Qt::Key_Shift:
28 return QObject::tr("Shift");
29 case Qt::Key_Control:
30 return QObject::tr("Ctrl");
31 case Qt::Key_Alt:
32 return QObject::tr("Alt");
33 case Qt::Key_Meta:
34 return "";
35 default:
36 return QKeySequence(key_code).toString();
37 }
38}
39 28
40static void SetAnalogButton(const Common::ParamPackage& input_param, 29 const auto res = dialog.exec();
41 Common::ParamPackage& analog_param, const std::string& button_name) { 30 if (res == QDialog::Accepted) {
42 if (analog_param.Get("engine", "") != "analog_from_button") { 31 dialog.applyConfiguration();
43 analog_param = {
44 {"engine", "analog_from_button"},
45 {"modifier_scale", "0.5"},
46 };
47 } 32 }
48 analog_param.Set(button_name, input_param.Serialize());
49} 33}
50 34} // Anonymous namespace
51static QString ButtonToText(const Common::ParamPackage& param) {
52 if (!param.Has("engine")) {
53 return QObject::tr("[not set]");
54 } else if (param.Get("engine", "") == "keyboard") {
55 return getKeyName(param.Get("code", 0));
56 } else if (param.Get("engine", "") == "sdl") {
57 if (param.Has("hat")) {
58 return QString(QObject::tr("Hat %1 %2"))
59 .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
60 }
61 if (param.Has("axis")) {
62 return QString(QObject::tr("Axis %1%2"))
63 .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
64 }
65 if (param.Has("button")) {
66 return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
67 }
68 return QString();
69 } else {
70 return QObject::tr("[unknown]");
71 }
72};
73
74static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) {
75 if (!param.Has("engine")) {
76 return QObject::tr("[not set]");
77 } else if (param.Get("engine", "") == "analog_from_button") {
78 return ButtonToText(Common::ParamPackage{param.Get(dir, "")});
79 } else if (param.Get("engine", "") == "sdl") {
80 if (dir == "modifier") {
81 return QString(QObject::tr("[unused]"));
82 }
83
84 if (dir == "left" || dir == "right") {
85 return QString(QObject::tr("Axis %1")).arg(param.Get("axis_x", "").c_str());
86 } else if (dir == "up" || dir == "down") {
87 return QString(QObject::tr("Axis %1")).arg(param.Get("axis_y", "").c_str());
88 }
89 return QString();
90 } else {
91 return QObject::tr("[unknown]");
92 }
93};
94 35
95ConfigureInput::ConfigureInput(QWidget* parent) 36ConfigureInput::ConfigureInput(QWidget* parent)
96 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()), 37 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
97 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
98
99 ui->setupUi(this); 38 ui->setupUi(this);
100 setFocusPolicy(Qt::ClickFocus); 39
101 40 players_controller = {
102 button_map = { 41 ui->player1_combobox, ui->player2_combobox, ui->player3_combobox, ui->player4_combobox,
103 ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, 42 ui->player5_combobox, ui->player6_combobox, ui->player7_combobox, ui->player8_combobox,
104 ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
105 ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
106 ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
107 ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown,
108 ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown,
109 ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
110 }; 43 };
111 44
112 analog_map_buttons = {{ 45 players_configure = {
113 { 46 ui->player1_configure, ui->player2_configure, ui->player3_configure, ui->player4_configure,
114 ui->buttonLStickUp, 47 ui->player5_configure, ui->player6_configure, ui->player7_configure, ui->player8_configure,
115 ui->buttonLStickDown, 48 };
116 ui->buttonLStickLeft,
117 ui->buttonLStickRight,
118 ui->buttonLStickMod,
119 },
120 {
121 ui->buttonRStickUp,
122 ui->buttonRStickDown,
123 ui->buttonRStickLeft,
124 ui->buttonRStickRight,
125 ui->buttonRStickMod,
126 },
127 }};
128
129 analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
130
131 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
132 if (!button_map[button_id])
133 continue;
134 button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
135 connect(button_map[button_id], &QPushButton::released, [=]() {
136 handleClick(
137 button_map[button_id],
138 [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
139 InputCommon::Polling::DeviceType::Button);
140 });
141 connect(button_map[button_id], &QPushButton::customContextMenuRequested,
142 [=](const QPoint& menu_location) {
143 QMenu context_menu;
144 context_menu.addAction(tr("Clear"), [&] {
145 buttons_param[button_id].Clear();
146 button_map[button_id]->setText(tr("[not set]"));
147 });
148 context_menu.addAction(tr("Restore Default"), [&] {
149 buttons_param[button_id] = Common::ParamPackage{
150 InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
151 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
152 });
153 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
154 });
155 }
156 49
157 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { 50 for (auto* controller_box : players_controller) {
158 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { 51 controller_box->addItems({"None", "Pro Controller", "Dual Joycons", "Single Right Joycon",
159 if (!analog_map_buttons[analog_id][sub_button_id]) 52 "Single Left Joycon"});
160 continue;
161 analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
162 Qt::CustomContextMenu);
163 connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, [=]() {
164 handleClick(analog_map_buttons[analog_id][sub_button_id],
165 [=](const Common::ParamPackage& params) {
166 SetAnalogButton(params, analogs_param[analog_id],
167 analog_sub_buttons[sub_button_id]);
168 },
169 InputCommon::Polling::DeviceType::Button);
170 });
171 connect(analog_map_buttons[analog_id][sub_button_id],
172 &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
173 QMenu context_menu;
174 context_menu.addAction(tr("Clear"), [&] {
175 analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
176 analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
177 });
178 context_menu.addAction(tr("Restore Default"), [&] {
179 Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
180 Config::default_analogs[analog_id][sub_button_id])};
181 SetAnalogButton(params, analogs_param[analog_id],
182 analog_sub_buttons[sub_button_id]);
183 analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
184 analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
185 });
186 context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
187 menu_location));
188 });
189 }
190 connect(analog_map_stick[analog_id], &QPushButton::released, [=]() {
191 QMessageBox::information(this, tr("Information"),
192 tr("After pressing OK, first move your joystick horizontally, "
193 "and then vertically."));
194 handleClick(
195 analog_map_stick[analog_id],
196 [=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; },
197 InputCommon::Polling::DeviceType::Analog);
198 });
199 } 53 }
200 54
201 connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); }); 55 this->loadConfiguration();
202 connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); }); 56 updateUIEnabled();
203 57
204 timeout_timer->setSingleShot(true); 58 connect(ui->restore_defaults_button, &QPushButton::pressed, this,
205 connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); }); 59 &ConfigureInput::restoreDefaults);
206 60
207 connect(poll_timer.get(), &QTimer::timeout, [this]() { 61 for (auto* enabled : players_controller)
208 Common::ParamPackage params; 62 connect(enabled, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
209 for (auto& poller : device_pollers) { 63 &ConfigureInput::updateUIEnabled);
210 params = poller->GetNextInput(); 64 connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
211 if (params.Has("engine")) { 65 connect(ui->handheld_connected, &QCheckBox::stateChanged, this,
212 setPollingResult(params, false); 66 &ConfigureInput::updateUIEnabled);
213 return; 67 connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
214 } 68 connect(ui->keyboard_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
215 } 69 connect(ui->debug_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
216 }); 70 connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this,
71 &ConfigureInput::updateUIEnabled);
217 72
218 this->loadConfiguration(); 73 for (std::size_t i = 0; i < players_configure.size(); ++i) {
74 connect(players_configure[i], &QPushButton::pressed, this,
75 [this, i] { CallConfigureDialog<ConfigureInputPlayer>(*this, i, false); });
76 }
219 77
220 // TODO(wwylele): enable this when we actually emulate it 78 connect(ui->handheld_configure, &QPushButton::pressed, this,
221 ui->buttonHome->setEnabled(false); 79 [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 8, false); });
222}
223 80
224void ConfigureInput::applyConfiguration() { 81 connect(ui->debug_configure, &QPushButton::pressed, this,
225 std::transform(buttons_param.begin(), buttons_param.end(), Settings::values.buttons.begin(), 82 [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 9, true); });
226 [](const Common::ParamPackage& param) { return param.Serialize(); });
227 std::transform(analogs_param.begin(), analogs_param.end(), Settings::values.analogs.begin(),
228 [](const Common::ParamPackage& param) { return param.Serialize(); });
229}
230 83
231void ConfigureInput::loadConfiguration() { 84 connect(ui->mouse_advanced, &QPushButton::pressed, this,
232 std::transform(Settings::values.buttons.begin(), Settings::values.buttons.end(), 85 [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); });
233 buttons_param.begin(), 86
234 [](const std::string& str) { return Common::ParamPackage(str); }); 87 connect(ui->touchscreen_advanced, &QPushButton::pressed, this,
235 std::transform(Settings::values.analogs.begin(), Settings::values.analogs.end(), 88 [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
236 analogs_param.begin(),
237 [](const std::string& str) { return Common::ParamPackage(str); });
238 updateButtonLabels();
239} 89}
240 90
241void ConfigureInput::restoreDefaults() { 91ConfigureInput::~ConfigureInput() = default;
242 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
243 buttons_param[button_id] = Common::ParamPackage{
244 InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
245 }
246 92
247 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { 93void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) {
248 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { 94 if (ui->use_docked_mode->isChecked() && ui->handheld_connected->isChecked()) {
249 Common::ParamPackage params{InputCommon::GenerateKeyboardParam( 95 ui->handheld_connected->setChecked(false);
250 Config::default_analogs[analog_id][sub_button_id])};
251 SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
252 }
253 } 96 }
254 updateButtonLabels();
255}
256 97
257void ConfigureInput::ClearAll() { 98 if (last_state == new_state) {
258 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { 99 return;
259 if (button_map[button_id] && button_map[button_id]->isEnabled())
260 buttons_param[button_id].Clear();
261 } 100 }
262 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { 101
263 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { 102 Core::System& system{Core::System::GetInstance()};
264 if (analog_map_buttons[analog_id][sub_button_id] && 103 if (!system.IsPoweredOn()) {
265 analog_map_buttons[analog_id][sub_button_id]->isEnabled()) 104 return;
266 analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
267 }
268 } 105 }
269 updateButtonLabels(); 106 Service::SM::ServiceManager& sm = system.ServiceManager();
270}
271 107
272void ConfigureInput::updateButtonLabels() { 108 // Message queue is shared between these services, we just need to signal an operation
273 for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { 109 // change to one and it will handle both automatically
274 button_map[button]->setText(ButtonToText(buttons_param[button])); 110 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
111 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
112 bool has_signalled = false;
113
114 if (applet_oe != nullptr) {
115 applet_oe->GetMessageQueue()->OperationModeChanged();
116 has_signalled = true;
275 } 117 }
276 118
277 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { 119 if (applet_ae != nullptr && !has_signalled) {
278 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { 120 applet_ae->GetMessageQueue()->OperationModeChanged();
279 if (analog_map_buttons[analog_id][sub_button_id]) {
280 analog_map_buttons[analog_id][sub_button_id]->setText(
281 AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
282 }
283 }
284 analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
285 } 121 }
286} 122}
287 123
288void ConfigureInput::handleClick(QPushButton* button, 124void ConfigureInput::applyConfiguration() {
289 std::function<void(const Common::ParamPackage&)> new_input_setter, 125 for (std::size_t i = 0; i < players_controller.size(); ++i) {
290 InputCommon::Polling::DeviceType type) { 126 const auto controller_type_index = players_controller[i]->currentIndex();
291 button->setText(tr("[press key]"));
292 button->setFocus();
293
294 input_setter = new_input_setter;
295
296 device_pollers = InputCommon::Polling::GetPollers(type);
297 127
298 // Keyboard keys can only be used as button devices 128 Settings::values.players[i].connected = controller_type_index != 0;
299 want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
300 129
301 for (auto& poller : device_pollers) { 130 if (controller_type_index > 0) {
302 poller->Start(); 131 Settings::values.players[i].type =
132 static_cast<Settings::ControllerType>(controller_type_index - 1);
133 } else {
134 Settings::values.players[i].type = Settings::ControllerType::DualJoycon;
135 }
303 } 136 }
304 137
305 grabKeyboard(); 138 const bool pre_docked_mode = Settings::values.use_docked_mode;
306 grabMouse(); 139 Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
307 timeout_timer->start(5000); // Cancel after 5 seconds 140 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
308 poll_timer->start(200); // Check for new inputs every 200ms 141 Settings::values
142 .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
143 .connected = ui->handheld_connected->isChecked();
144 Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
145 Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
146 Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
147 Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
309} 148}
310 149
311void ConfigureInput::setPollingResult(const Common::ParamPackage& params, bool abort) { 150void ConfigureInput::updateUIEnabled() {
312 releaseKeyboard(); 151 bool hit_disabled = false;
313 releaseMouse(); 152 for (auto* player : players_controller) {
314 timeout_timer->stop(); 153 player->setDisabled(hit_disabled);
315 poll_timer->stop(); 154 if (hit_disabled)
316 for (auto& poller : device_pollers) { 155 player->setCurrentIndex(0);
317 poller->Stop(); 156 if (!hit_disabled && player->currentIndex() == 0)
157 hit_disabled = true;
318 } 158 }
319 159
320 if (!abort) { 160 for (std::size_t i = 0; i < players_controller.size(); ++i) {
321 (*input_setter)(params); 161 players_configure[i]->setEnabled(players_controller[i]->currentIndex() != 0);
322 } 162 }
323 163
324 updateButtonLabels(); 164 ui->handheld_connected->setEnabled(!ui->use_docked_mode->isChecked());
325 input_setter = {}; 165 ui->handheld_configure->setEnabled(ui->handheld_connected->isChecked() &&
166 !ui->use_docked_mode->isChecked());
167 ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
168 ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
169 ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
326} 170}
327 171
328void ConfigureInput::keyPressEvent(QKeyEvent* event) { 172void ConfigureInput::loadConfiguration() {
329 if (!input_setter || !event) 173 std::stable_partition(
330 return; 174 Settings::values.players.begin(),
175 Settings::values.players.begin() +
176 Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
177 [](const auto& player) { return player.connected; });
178
179 for (std::size_t i = 0; i < players_controller.size(); ++i) {
180 const auto connected = Settings::values.players[i].connected;
181 players_controller[i]->setCurrentIndex(
182 connected ? static_cast<u8>(Settings::values.players[i].type) + 1 : 0);
183 }
184
185 ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
186 ui->handheld_connected->setChecked(
187 Settings::values
188 .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
189 .connected);
190 ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
191 ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
192 ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
193 ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
194
195 updateUIEnabled();
196}
331 197
332 if (event->key() != Qt::Key_Escape) { 198void ConfigureInput::restoreDefaults() {
333 if (want_keyboard_keys) { 199 players_controller[0]->setCurrentIndex(2);
334 setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, 200
335 false); 201 for (std::size_t i = 1; i < players_controller.size(); ++i) {
336 } else { 202 players_controller[i]->setCurrentIndex(0);
337 // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
338 return;
339 }
340 } 203 }
341 setPollingResult({}, true); 204
205 ui->use_docked_mode->setCheckState(Qt::Unchecked);
206 ui->handheld_connected->setCheckState(Qt::Unchecked);
207 ui->mouse_enabled->setCheckState(Qt::Unchecked);
208 ui->keyboard_enabled->setCheckState(Qt::Unchecked);
209 ui->debug_enabled->setCheckState(Qt::Unchecked);
210 ui->touchscreen_enabled->setCheckState(Qt::Checked);
211 updateUIEnabled();
342} 212}
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index 32c7183f9..1649e4c0b 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -5,18 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <functional>
9#include <memory> 8#include <memory>
10#include <optional>
11#include <string>
12#include <unordered_map>
13 9
14#include <QKeyEvent> 10#include <QKeyEvent>
15#include <QWidget> 11#include <QWidget>
16 12
17#include "common/param_package.h"
18#include "core/settings.h"
19#include "input_common/main.h"
20#include "ui_configure_input.h" 13#include "ui_configure_input.h"
21 14
22class QPushButton; 15class QPushButton;
@@ -32,62 +25,23 @@ class ConfigureInput : public QWidget {
32 25
33public: 26public:
34 explicit ConfigureInput(QWidget* parent = nullptr); 27 explicit ConfigureInput(QWidget* parent = nullptr);
28 ~ConfigureInput() override;
35 29
36 /// Save all button configurations to settings file 30 /// Save all button configurations to settings file
37 void applyConfiguration(); 31 void applyConfiguration();
38 32
39private: 33private:
40 std::unique_ptr<Ui::ConfigureInput> ui; 34 void updateUIEnabled();
41
42 std::unique_ptr<QTimer> timeout_timer;
43 std::unique_ptr<QTimer> poll_timer;
44
45 /// This will be the the setting function when an input is awaiting configuration.
46 std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
47
48 std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
49 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
50
51 static constexpr int ANALOG_SUB_BUTTONS_NUM = 5;
52
53 /// Each button input is represented by a QPushButton.
54 std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map;
55
56 /// A group of five QPushButtons represent one analog input. The buttons each represent up,
57 /// down, left, right, and modifier, respectively.
58 std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs>
59 analog_map_buttons;
60 35
61 /// Analog inputs are also represented each with a single button, used to configure with an 36 void OnDockedModeChanged(bool last_state, bool new_state);
62 /// actual analog stick
63 std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick;
64
65 static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
66
67 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
68
69 /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
70 /// keyboard events are ignored.
71 bool want_keyboard_keys = false;
72 37
73 /// Load configuration settings. 38 /// Load configuration settings.
74 void loadConfiguration(); 39 void loadConfiguration();
75 /// Restore all buttons to their default values. 40 /// Restore all buttons to their default values.
76 void restoreDefaults(); 41 void restoreDefaults();
77 /// Clear all input configuration
78 void ClearAll();
79 42
80 /// Update UI to reflect current configuration. 43 std::unique_ptr<Ui::ConfigureInput> ui;
81 void updateButtonLabels();
82
83 /// Called when the button was pressed.
84 void handleClick(QPushButton* button,
85 std::function<void(const Common::ParamPackage&)> new_input_setter,
86 InputCommon::Polling::DeviceType type);
87
88 /// Finish polling and configure input using the input_setter
89 void setPollingResult(const Common::ParamPackage& params, bool abort);
90 44
91 /// Handle key press events. 45 std::array<QComboBox*, 8> players_controller;
92 void keyPressEvent(QKeyEvent* event) override; 46 std::array<QPushButton*, 8> players_configure;
93}; 47};
diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index 8a019a693..dae8277bc 100644
--- a/src/yuzu/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
@@ -6,8 +6,8 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>343</width> 9 <width>473</width>
10 <height>677</height> 10 <height>685</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -15,740 +15,470 @@
15 </property> 15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_5"> 16 <layout class="QVBoxLayout" name="verticalLayout_5">
17 <item> 17 <item>
18 <layout class="QGridLayout" name="buttons"> 18 <layout class="QVBoxLayout" name="verticalLayout">
19 <item row="3" column="1"> 19 <item>
20 <widget class="QGroupBox" name="misc"> 20 <widget class="QGroupBox" name="gridGroupBox">
21 <property name="title"> 21 <property name="title">
22 <string>Misc.</string> 22 <string>Players</string>
23 </property>
24 <property name="flat">
25 <bool>false</bool>
26 </property>
27 <property name="checkable">
28 <bool>false</bool>
29 </property> 23 </property>
30 <layout class="QGridLayout" name="gridLayout_6"> 24 <layout class="QGridLayout" name="gridLayout">
31 <item row="0" column="0"> 25 <item row="1" column="2">
32 <layout class="QVBoxLayout" name="buttonMiscMinusVerticalLayout"> 26 <widget class="QComboBox" name="player1_combobox">
33 <item> 27 <property name="minimumSize">
34 <widget class="QLabel" name="labelMinus"> 28 <size>
35 <property name="text"> 29 <width>110</width>
36 <string>Minus:</string> 30 <height>0</height>
37 </property> 31 </size>
38 </widget> 32 </property>
39 </item> 33 </widget>
40 <item>
41 <widget class="QPushButton" name="buttonMinus">
42 <property name="text">
43 <string/>
44 </property>
45 </widget>
46 </item>
47 </layout>
48 </item> 34 </item>
49 <item row="0" column="1"> 35 <item row="1" column="3">
50 <layout class="QVBoxLayout" name="buttonMiscPlusVerticalLayout"> 36 <widget class="QPushButton" name="player1_configure">
51 <item> 37 <property name="text">
52 <widget class="QLabel" name="labelPlus"> 38 <string>Configure</string>
53 <property name="text"> 39 </property>
54 <string>Plus:</string> 40 </widget>
55 </property>
56 </widget>
57 </item>
58 <item>
59 <widget class="QPushButton" name="buttonPlus">
60 <property name="text">
61 <string/>
62 </property>
63 </widget>
64 </item>
65 </layout>
66 </item> 41 </item>
67 <item row="1" column="0"> 42 <item row="0" column="2">
68 <layout class="QVBoxLayout" name="buttonMiscHomeVerticalLayout"> 43 <widget class="QLabel" name="label">
69 <item> 44 <property name="text">
70 <widget class="QLabel" name="labelHome"> 45 <string>Controller Type</string>
71 <property name="text"> 46 </property>
72 <string>Home:</string> 47 <property name="alignment">
73 </property> 48 <set>Qt::AlignCenter</set>
74 </widget> 49 </property>
75 </item> 50 </widget>
76 <item>
77 <widget class="QPushButton" name="buttonHome">
78 <property name="text">
79 <string/>
80 </property>
81 </widget>
82 </item>
83 </layout>
84 </item> 51 </item>
85 <item row="1" column="1"> 52 <item row="2" column="2">
86 <layout class="QVBoxLayout" name="buttonMiscScrCapVerticalLayout"> 53 <widget class="QComboBox" name="player2_combobox">
87 <item> 54 <property name="minimumSize">
88 <widget class="QLabel" name="labelScrCap"> 55 <size>
89 <property name="text"> 56 <width>110</width>
90 <string>Screen 57 <height>0</height>
91Capture:</string> 58 </size>
92 </property> 59 </property>
93 </widget> 60 </widget>
94 </item>
95 <item>
96 <widget class="QPushButton" name="buttonScreenshot">
97 <property name="text">
98 <string/>
99 </property>
100 </widget>
101 </item>
102 </layout>
103 </item> 61 </item>
104 <item row="2" column="1"> 62 <item row="3" column="2">
105 <spacer name="verticalSpacer"> 63 <widget class="QComboBox" name="player3_combobox">
64 <property name="minimumSize">
65 <size>
66 <width>110</width>
67 <height>0</height>
68 </size>
69 </property>
70 </widget>
71 </item>
72 <item row="4" column="2">
73 <widget class="QComboBox" name="player4_combobox">
74 <property name="minimumSize">
75 <size>
76 <width>110</width>
77 <height>0</height>
78 </size>
79 </property>
80 </widget>
81 </item>
82 <item row="5" column="2">
83 <widget class="QComboBox" name="player5_combobox">
84 <property name="minimumSize">
85 <size>
86 <width>110</width>
87 <height>0</height>
88 </size>
89 </property>
90 </widget>
91 </item>
92 <item row="6" column="2">
93 <widget class="QComboBox" name="player6_combobox">
94 <property name="minimumSize">
95 <size>
96 <width>110</width>
97 <height>0</height>
98 </size>
99 </property>
100 </widget>
101 </item>
102 <item row="7" column="2">
103 <widget class="QComboBox" name="player7_combobox">
104 <property name="minimumSize">
105 <size>
106 <width>110</width>
107 <height>0</height>
108 </size>
109 </property>
110 </widget>
111 </item>
112 <item row="8" column="2">
113 <widget class="QComboBox" name="player8_combobox">
114 <property name="minimumSize">
115 <size>
116 <width>110</width>
117 <height>0</height>
118 </size>
119 </property>
120 </widget>
121 </item>
122 <item row="2" column="3">
123 <widget class="QPushButton" name="player2_configure">
124 <property name="text">
125 <string>Configure</string>
126 </property>
127 </widget>
128 </item>
129 <item row="3" column="3">
130 <widget class="QPushButton" name="player3_configure">
131 <property name="text">
132 <string>Configure</string>
133 </property>
134 </widget>
135 </item>
136 <item row="4" column="3">
137 <widget class="QPushButton" name="player4_configure">
138 <property name="text">
139 <string>Configure</string>
140 </property>
141 </widget>
142 </item>
143 <item row="5" column="3">
144 <widget class="QPushButton" name="player5_configure">
145 <property name="text">
146 <string>Configure</string>
147 </property>
148 </widget>
149 </item>
150 <item row="6" column="3">
151 <widget class="QPushButton" name="player6_configure">
152 <property name="text">
153 <string>Configure</string>
154 </property>
155 </widget>
156 </item>
157 <item row="7" column="3">
158 <widget class="QPushButton" name="player7_configure">
159 <property name="text">
160 <string>Configure</string>
161 </property>
162 </widget>
163 </item>
164 <item row="8" column="3">
165 <widget class="QPushButton" name="player8_configure">
166 <property name="text">
167 <string>Configure</string>
168 </property>
169 </widget>
170 </item>
171 <item row="0" column="0">
172 <spacer name="horizontalSpacer">
106 <property name="orientation"> 173 <property name="orientation">
107 <enum>Qt::Vertical</enum> 174 <enum>Qt::Horizontal</enum>
108 </property> 175 </property>
109 <property name="sizeHint" stdset="0"> 176 <property name="sizeHint" stdset="0">
110 <size> 177 <size>
111 <width>20</width> 178 <width>40</width>
112 <height>40</height> 179 <height>20</height>
113 </size> 180 </size>
114 </property> 181 </property>
115 </spacer> 182 </spacer>
116 </item> 183 </item>
117 </layout> 184 <item row="0" column="4">
118 </widget> 185 <spacer name="horizontalSpacer_2">
119 </item> 186 <property name="orientation">
120 <item row="0" column="0"> 187 <enum>Qt::Horizontal</enum>
121 <widget class="QGroupBox" name="faceButtons"> 188 </property>
122 <property name="title"> 189 <property name="sizeHint" stdset="0">
123 <string>Face Buttons</string> 190 <size>
124 </property> 191 <width>40</width>
125 <property name="flat"> 192 <height>20</height>
126 <bool>false</bool> 193 </size>
127 </property> 194 </property>
128 <property name="checkable"> 195 </spacer>
129 <bool>false</bool>
130 </property>
131 <layout class="QGridLayout" name="gridLayout">
132 <item row="0" column="0">
133 <layout class="QVBoxLayout" name="buttonFaceButtonsAVerticalLayout">
134 <item>
135 <widget class="QLabel" name="labelA">
136 <property name="text">
137 <string>A:</string>
138 </property>
139 </widget>
140 </item>
141 <item>
142 <widget class="QPushButton" name="buttonA">
143 <property name="text">
144 <string/>
145 </property>
146 </widget>
147 </item>
148 </layout>
149 </item> 196 </item>
150 <item row="0" column="1"> 197 <item row="1" column="1">
151 <layout class="QVBoxLayout" name="buttonFaceButtonsBVerticalLayout"> 198 <widget class="QLabel" name="label_3">
152 <item> 199 <property name="minimumSize">
153 <widget class="QLabel" name="labelB"> 200 <size>
154 <property name="text"> 201 <width>55</width>
155 <string>B:</string> 202 <height>0</height>
156 </property> 203 </size>
157 </widget> 204 </property>
158 </item> 205 <property name="text">
159 <item> 206 <string>Player 1</string>
160 <widget class="QPushButton" name="buttonB"> 207 </property>
161 <property name="text"> 208 </widget>
162 <string/>
163 </property>
164 </widget>
165 </item>
166 </layout>
167 </item> 209 </item>
168 <item row="1" column="0"> 210 <item row="2" column="1">
169 <layout class="QVBoxLayout" name="buttonFaceButtonsXVerticalLayout"> 211 <widget class="QLabel" name="label_4">
170 <item> 212 <property name="text">
171 <widget class="QLabel" name="labelX"> 213 <string>Player 2</string>
172 <property name="text"> 214 </property>
173 <string>X:</string> 215 </widget>
174 </property>
175 </widget>
176 </item>
177 <item>
178 <widget class="QPushButton" name="buttonX">
179 <property name="text">
180 <string/>
181 </property>
182 </widget>
183 </item>
184 </layout>
185 </item> 216 </item>
186 <item row="1" column="1"> 217 <item row="3" column="1">
187 <layout class="QVBoxLayout" name="buttonFaceButtonsYVerticalLayout"> 218 <widget class="QLabel" name="label_5">
188 <item> 219 <property name="text">
189 <widget class="QLabel" name="labelY"> 220 <string>Player 3</string>
190 <property name="text"> 221 </property>
191 <string>Y:</string> 222 </widget>
192 </property>
193 </widget>
194 </item>
195 <item>
196 <widget class="QPushButton" name="buttonY">
197 <property name="text">
198 <string/>
199 </property>
200 </widget>
201 </item>
202 </layout>
203 </item> 223 </item>
204 </layout> 224 <item row="4" column="1">
205 </widget> 225 <widget class="QLabel" name="label_6">
206 </item> 226 <property name="text">
207 <item row="0" column="1"> 227 <string>Player 4</string>
208 <widget class="QGroupBox" name="Dpad"> 228 </property>
209 <property name="title"> 229 </widget>
210 <string>Directional Pad</string>
211 </property>
212 <property name="flat">
213 <bool>false</bool>
214 </property>
215 <property name="checkable">
216 <bool>false</bool>
217 </property>
218 <layout class="QGridLayout" name="gridLayout_2">
219 <item row="1" column="0">
220 <layout class="QVBoxLayout" name="buttonDpadUpVerticalLayout">
221 <item>
222 <widget class="QLabel" name="labelDpadUp">
223 <property name="text">
224 <string>Up:</string>
225 </property>
226 </widget>
227 </item>
228 <item>
229 <widget class="QPushButton" name="buttonDpadUp">
230 <property name="text">
231 <string/>
232 </property>
233 </widget>
234 </item>
235 </layout>
236 </item> 230 </item>
237 <item row="1" column="1"> 231 <item row="5" column="1">
238 <layout class="QVBoxLayout" name="buttonDpadDownVerticalLayout"> 232 <widget class="QLabel" name="label_7">
239 <item> 233 <property name="text">
240 <widget class="QLabel" name="labelDpadDown"> 234 <string>Player 5</string>
241 <property name="text"> 235 </property>
242 <string>Down:</string> 236 </widget>
243 </property>
244 </widget>
245 </item>
246 <item>
247 <widget class="QPushButton" name="buttonDpadDown">
248 <property name="text">
249 <string/>
250 </property>
251 </widget>
252 </item>
253 </layout>
254 </item> 237 </item>
255 <item row="0" column="0"> 238 <item row="6" column="1">
256 <layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout"> 239 <widget class="QLabel" name="label_8">
257 <item> 240 <property name="text">
258 <widget class="QLabel" name="labelDpadLeft"> 241 <string>Player 6</string>
259 <property name="text"> 242 </property>
260 <string>Left:</string> 243 </widget>
261 </property>
262 </widget>
263 </item>
264 <item>
265 <widget class="QPushButton" name="buttonDpadLeft">
266 <property name="text">
267 <string/>
268 </property>
269 </widget>
270 </item>
271 </layout>
272 </item> 244 </item>
273 <item row="0" column="1"> 245 <item row="7" column="1">
274 <layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout"> 246 <widget class="QLabel" name="label_9">
275 <item> 247 <property name="text">
276 <widget class="QLabel" name="labelDpadRight"> 248 <string>Player 7</string>
277 <property name="text"> 249 </property>
278 <string>Right:</string> 250 </widget>
279 </property> 251 </item>
280 </widget> 252 <item row="8" column="1">
281 </item> 253 <widget class="QLabel" name="label_10">
282 <item> 254 <property name="text">
283 <widget class="QPushButton" name="buttonDpadRight"> 255 <string>Player 8</string>
284 <property name="text"> 256 </property>
285 <string/> 257 </widget>
286 </property>
287 </widget>
288 </item>
289 </layout>
290 </item> 258 </item>
291 </layout> 259 </layout>
292 </widget> 260 </widget>
293 </item> 261 </item>
294 <item row="3" column="0"> 262 <item>
295 <widget class="QGroupBox" name="shoulderButtons"> 263 <widget class="QGroupBox" name="gridGroupBox">
296 <property name="title"> 264 <property name="title">
297 <string>Shoulder Buttons</string> 265 <string>Handheld</string>
298 </property>
299 <property name="flat">
300 <bool>false</bool>
301 </property> 266 </property>
302 <property name="checkable"> 267 <layout class="QGridLayout" name="gridLayout_2">
303 <bool>false</bool> 268 <item row="1" column="2">
304 </property> 269 <spacer name="horizontalSpacer_5">
305 <layout class="QGridLayout" name="gridLayout_3"> 270 <property name="orientation">
306 <item row="0" column="0"> 271 <enum>Qt::Horizontal</enum>
307 <layout class="QVBoxLayout" name="buttonShoulderButtonsLVerticalLayout"> 272 </property>
308 <item> 273 <property name="sizeType">
309 <widget class="QLabel" name="labelL"> 274 <enum>QSizePolicy::Fixed</enum>
310 <property name="text"> 275 </property>
311 <string>L:</string> 276 <property name="sizeHint" stdset="0">
312 </property> 277 <size>
313 </widget> 278 <width>72</width>
314 </item> 279 <height>20</height>
315 <item> 280 </size>
316 <widget class="QPushButton" name="buttonL"> 281 </property>
317 <property name="text"> 282 </spacer>
318 <string/>
319 </property>
320 </widget>
321 </item>
322 </layout>
323 </item> 283 </item>
324 <item row="0" column="1"> 284 <item row="1" column="4">
325 <layout class="QVBoxLayout" name="buttonShoulderButtonsRVerticalLayout"> 285 <spacer name="horizontalSpacer_4">
326 <item> 286 <property name="orientation">
327 <widget class="QLabel" name="labelR"> 287 <enum>Qt::Horizontal</enum>
328 <property name="text"> 288 </property>
329 <string>R:</string> 289 <property name="sizeHint" stdset="0">
330 </property> 290 <size>
331 </widget> 291 <width>40</width>
332 </item> 292 <height>20</height>
333 <item> 293 </size>
334 <widget class="QPushButton" name="buttonR"> 294 </property>
335 <property name="text"> 295 </spacer>
336 <string/> 296 </item>
337 </property> 297 <item row="1" column="3">
338 </widget> 298 <widget class="QPushButton" name="handheld_configure">
339 </item> 299 <property name="text">
340 </layout> 300 <string>Configure</string>
301 </property>
302 </widget>
341 </item> 303 </item>
342 <item row="1" column="0"> 304 <item row="1" column="0">
343 <layout class="QVBoxLayout" name="buttonShoulderButtonsZLVerticalLayout"> 305 <spacer name="horizontalSpacer_3">
344 <item> 306 <property name="orientation">
345 <widget class="QLabel" name="labelZL"> 307 <enum>Qt::Horizontal</enum>
346 <property name="text"> 308 </property>
347 <string>ZL:</string> 309 <property name="sizeHint" stdset="0">
348 </property> 310 <size>
349 </widget> 311 <width>40</width>
350 </item> 312 <height>20</height>
351 <item> 313 </size>
352 <widget class="QPushButton" name="buttonZL"> 314 </property>
353 <property name="text"> 315 </spacer>
354 <string/>
355 </property>
356 </widget>
357 </item>
358 </layout>
359 </item> 316 </item>
360 <item row="1" column="1"> 317 <item row="1" column="1">
361 <layout class="QVBoxLayout" name="buttonShoulderButtonsZRVerticalLayout"> 318 <widget class="QCheckBox" name="handheld_connected">
362 <item> 319 <property name="text">
363 <widget class="QLabel" name="labelZR"> 320 <string>Joycons Docked</string>
364 <property name="text"> 321 </property>
365 <string>ZR:</string> 322 </widget>
366 </property>
367 </widget>
368 </item>
369 <item>
370 <widget class="QPushButton" name="buttonZR">
371 <property name="text">
372 <string/>
373 </property>
374 </widget>
375 </item>
376 </layout>
377 </item>
378 <item row="2" column="0">
379 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
380 <item>
381 <widget class="QLabel" name="labelSL">
382 <property name="text">
383 <string>SL:</string>
384 </property>
385 </widget>
386 </item>
387 <item>
388 <widget class="QPushButton" name="buttonSL">
389 <property name="text">
390 <string/>
391 </property>
392 </widget>
393 </item>
394 </layout>
395 </item> 323 </item>
396 <item row="2" column="1"> 324 <item row="0" column="1">
397 <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout"> 325 <widget class="QCheckBox" name="use_docked_mode">
398 <item> 326 <property name="text">
399 <widget class="QLabel" name="labelSR"> 327 <string>Use Docked Mode</string>
400 <property name="text"> 328 </property>
401 <string>SR:</string> 329 </widget>
402 </property>
403 </widget>
404 </item>
405 <item>
406 <widget class="QPushButton" name="buttonSR">
407 <property name="text">
408 <string/>
409 </property>
410 </widget>
411 </item>
412 </layout>
413 </item> 330 </item>
414 </layout> 331 </layout>
415 </widget> 332 </widget>
416 </item> 333 </item>
417 <item row="1" column="1"> 334 <item>
418 <widget class="QGroupBox" name="RStick"> 335 <widget class="QGroupBox" name="gridGroupBox">
419 <property name="title"> 336 <property name="title">
420 <string>Right Stick</string> 337 <string>Other</string>
421 </property>
422 <property name="alignment">
423 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
424 </property>
425 <property name="flat">
426 <bool>false</bool>
427 </property> 338 </property>
428 <property name="checkable"> 339 <layout class="QGridLayout" name="gridLayout_3">
429 <bool>false</bool>
430 </property>
431 <layout class="QGridLayout" name="gridLayout_5">
432 <item row="1" column="1"> 340 <item row="1" column="1">
433 <layout class="QVBoxLayout" name="buttonRStickDownVerticalLayout"> 341 <widget class="QCheckBox" name="keyboard_enabled">
434 <item> 342 <property name="minimumSize">
435 <widget class="QLabel" name="labelRStickDown"> 343 <size>
436 <property name="text"> 344 <width>0</width>
437 <string>Down:</string> 345 <height>23</height>
438 </property> 346 </size>
439 </widget> 347 </property>
440 </item>
441 <item>
442 <widget class="QPushButton" name="buttonRStickDown">
443 <property name="text">
444 <string/>
445 </property>
446 </widget>
447 </item>
448 </layout>
449 </item>
450 <item row="0" column="1">
451 <layout class="QVBoxLayout" name="buttonRStickRightVerticalLayout">
452 <item>
453 <widget class="QLabel" name="labelRStickRight">
454 <property name="text">
455 <string>Right:</string>
456 </property>
457 </widget>
458 </item>
459 <item>
460 <widget class="QPushButton" name="buttonRStickRight">
461 <property name="text">
462 <string/>
463 </property>
464 </widget>
465 </item>
466 </layout>
467 </item>
468 <item row="3" column="0" colspan="2">
469 <widget class="QPushButton" name="buttonRStickAnalog">
470 <property name="text"> 348 <property name="text">
471 <string>Set Analog Stick</string> 349 <string>Keyboard</string>
472 </property> 350 </property>
473 </widget> 351 </widget>
474 </item> 352 </item>
475 <item row="0" column="0">
476 <layout class="QVBoxLayout" name="buttonRStickLeftVerticalLayout">
477 <item>
478 <widget class="QLabel" name="labelRStickLeft">
479 <property name="text">
480 <string>Left:</string>
481 </property>
482 </widget>
483 </item>
484 <item>
485 <widget class="QPushButton" name="buttonRStickLeft">
486 <property name="text">
487 <string/>
488 </property>
489 </widget>
490 </item>
491 </layout>
492 </item>
493 <item row="1" column="0">
494 <layout class="QVBoxLayout" name="buttonRStickUpVerticalLayout">
495 <item>
496 <widget class="QLabel" name="labelRStickUp">
497 <property name="text">
498 <string>Up:</string>
499 </property>
500 </widget>
501 </item>
502 <item>
503 <widget class="QPushButton" name="buttonRStickUp">
504 <property name="text">
505 <string/>
506 </property>
507 </widget>
508 </item>
509 </layout>
510 </item>
511 <item row="2" column="0">
512 <layout class="QVBoxLayout" name="buttonRStickPressedVerticalLayout">
513 <item>
514 <widget class="QLabel" name="labelRStickPressed">
515 <property name="text">
516 <string>Pressed:</string>
517 </property>
518 </widget>
519 </item>
520 <item>
521 <widget class="QPushButton" name="buttonRStick">
522 <property name="text">
523 <string/>
524 </property>
525 </widget>
526 </item>
527 </layout>
528 </item>
529 <item row="2" column="1"> 353 <item row="2" column="1">
530 <layout class="QVBoxLayout" name="buttonRStickModVerticalLayout"> 354 <widget class="QCheckBox" name="debug_enabled">
531 <item> 355 <property name="text">
532 <widget class="QLabel" name="labelRStickMod"> 356 <string>Debug Controller</string>
533 <property name="text"> 357 </property>
534 <string>Modifier:</string> 358 </widget>
535 </property>
536 </widget>
537 </item>
538 <item>
539 <widget class="QPushButton" name="buttonRStickMod">
540 <property name="text">
541 <string/>
542 </property>
543 </widget>
544 </item>
545 </layout>
546 </item> 359 </item>
547 </layout> 360 <item row="3" column="1">
548 </widget> 361 <widget class="QCheckBox" name="touchscreen_enabled">
549 </item>
550 <item row="1" column="0">
551 <widget class="QGroupBox" name="LStick">
552 <property name="title">
553 <string>Left Stick</string>
554 </property>
555 <property name="flat">
556 <bool>false</bool>
557 </property>
558 <property name="checkable">
559 <bool>false</bool>
560 </property>
561 <layout class="QGridLayout" name="gridLayout_4">
562 <item row="1" column="1">
563 <layout class="QVBoxLayout" name="buttonLStickDownVerticalLayout">
564 <item>
565 <widget class="QLabel" name="labelLStickDown">
566 <property name="text">
567 <string>Down:</string>
568 </property>
569 </widget>
570 </item>
571 <item>
572 <widget class="QPushButton" name="buttonLStickDown">
573 <property name="text">
574 <string/>
575 </property>
576 </widget>
577 </item>
578 </layout>
579 </item>
580 <item row="4" column="0" colspan="2">
581 <widget class="QPushButton" name="buttonLStickAnalog">
582 <property name="text"> 362 <property name="text">
583 <string>Set Analog Stick</string> 363 <string>Touchscreen</string>
584 </property> 364 </property>
585 </widget> 365 </widget>
586 </item> 366 </item>
587 <item row="0" column="1"> 367 <item row="0" column="1">
588 <layout class="QVBoxLayout" name="buttonLStickRightVerticalLayout"> 368 <widget class="QCheckBox" name="mouse_enabled">
589 <item> 369 <property name="minimumSize">
590 <widget class="QLabel" name="labelLStickRight"> 370 <size>
591 <property name="text"> 371 <width>0</width>
592 <string>Right:</string> 372 <height>23</height>
593 </property> 373 </size>
594 </widget> 374 </property>
595 </item> 375 <property name="text">
596 <item> 376 <string>Mouse</string>
597 <widget class="QPushButton" name="buttonLStickRight"> 377 </property>
598 <property name="text"> 378 </widget>
599 <string/> 379 </item>
600 </property> 380 <item row="0" column="4">
601 </widget> 381 <spacer name="horizontalSpacer_7">
602 </item> 382 <property name="orientation">
603 </layout> 383 <enum>Qt::Horizontal</enum>
384 </property>
385 <property name="sizeHint" stdset="0">
386 <size>
387 <width>40</width>
388 <height>20</height>
389 </size>
390 </property>
391 </spacer>
392 </item>
393 <item row="0" column="2">
394 <spacer name="horizontalSpacer_8">
395 <property name="orientation">
396 <enum>Qt::Horizontal</enum>
397 </property>
398 <property name="sizeType">
399 <enum>QSizePolicy::Fixed</enum>
400 </property>
401 <property name="sizeHint" stdset="0">
402 <size>
403 <width>76</width>
404 <height>20</height>
405 </size>
406 </property>
407 </spacer>
604 </item> 408 </item>
605 <item row="0" column="0"> 409 <item row="0" column="0">
606 <layout class="QVBoxLayout" name="buttonLStickLeftVerticalLayout"> 410 <spacer name="horizontalSpacer_6">
607 <item> 411 <property name="orientation">
608 <widget class="QLabel" name="labelLStickLeft"> 412 <enum>Qt::Horizontal</enum>
609 <property name="text"> 413 </property>
610 <string>Left:</string> 414 <property name="sizeHint" stdset="0">
611 </property> 415 <size>
612 </widget> 416 <width>40</width>
613 </item> 417 <height>20</height>
614 <item> 418 </size>
615 <widget class="QPushButton" name="buttonLStickLeft"> 419 </property>
616 <property name="text"> 420 </spacer>
617 <string/>
618 </property>
619 </widget>
620 </item>
621 </layout>
622 </item> 421 </item>
623 <item row="1" column="0"> 422 <item row="3" column="3">
624 <layout class="QVBoxLayout" name="buttonLStickUpVerticalLayout"> 423 <widget class="QPushButton" name="touchscreen_advanced">
625 <item> 424 <property name="text">
626 <widget class="QLabel" name="labelLStickUp"> 425 <string>Advanced</string>
627 <property name="text"> 426 </property>
628 <string>Up:</string> 427 </widget>
629 </property>
630 </widget>
631 </item>
632 <item>
633 <widget class="QPushButton" name="buttonLStickUp">
634 <property name="text">
635 <string/>
636 </property>
637 </widget>
638 </item>
639 </layout>
640 </item>
641 <item row="3" column="0">
642 <layout class="QVBoxLayout" name="buttonLStickModVerticalLayout">
643 <item>
644 <widget class="QLabel" name="labelLStickMod">
645 <property name="text">
646 <string>Modifier:</string>
647 </property>
648 </widget>
649 </item>
650 <item>
651 <widget class="QPushButton" name="buttonLStickMod">
652 <property name="text">
653 <string/>
654 </property>
655 </widget>
656 </item>
657 </layout>
658 </item> 428 </item>
659 <item row="3" column="1"> 429 <item row="2" column="3">
660 <layout class="QVBoxLayout" name="buttonLStickPressedVerticalLayout" stretch="0,0"> 430 <widget class="QPushButton" name="debug_configure">
661 <item> 431 <property name="text">
662 <widget class="QLabel" name="labelLStickPressed"> 432 <string>Configure</string>
663 <property name="text"> 433 </property>
664 <string>Pressed:</string> 434 </widget>
665 </property> 435 </item>
666 </widget> 436 <item row="0" column="3">
667 </item> 437 <widget class="QPushButton" name="mouse_advanced">
668 <item> 438 <property name="text">
669 <widget class="QPushButton" name="buttonLStick"> 439 <string>Advanced</string>
670 <property name="text"> 440 </property>
671 <string/> 441 </widget>
672 </property>
673 </widget>
674 </item>
675 </layout>
676 </item> 442 </item>
677 </layout> 443 </layout>
678 </widget> 444 </widget>
679 </item> 445 </item>
680 </layout>
681 </item>
682 <item>
683 <layout class="QHBoxLayout" name="horizontalLayout">
684 <item> 446 <item>
685 <spacer name="horizontalSpacer"> 447 <spacer name="verticalSpacer">
686 <property name="orientation"> 448 <property name="orientation">
687 <enum>Qt::Horizontal</enum> 449 <enum>Qt::Vertical</enum>
688 </property> 450 </property>
689 <property name="sizeHint" stdset="0"> 451 <property name="sizeHint" stdset="0">
690 <size> 452 <size>
691 <width>40</width> 453 <width>20</width>
692 <height>20</height> 454 <height>40</height>
693 </size> 455 </size>
694 </property> 456 </property>
695 </spacer> 457 </spacer>
696 </item> 458 </item>
697 <item> 459 <item>
698 <widget class="QPushButton" name="buttonClearAll"> 460 <layout class="QHBoxLayout" name="horizontalLayout">
699 <property name="sizePolicy"> 461 <item>
700 <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> 462 <widget class="QPushButton" name="restore_defaults_button">
701 <horstretch>0</horstretch> 463 <property name="text">
702 <verstretch>0</verstretch> 464 <string>Restore Defaults</string>
703 </sizepolicy> 465 </property>
704 </property> 466 </widget>
705 <property name="sizeIncrement"> 467 </item>
706 <size> 468 <item>
707 <width>0</width> 469 <spacer name="horizontalSpacer_9">
708 <height>0</height> 470 <property name="orientation">
709 </size> 471 <enum>Qt::Horizontal</enum>
710 </property> 472 </property>
711 <property name="baseSize"> 473 <property name="sizeHint" stdset="0">
712 <size> 474 <size>
713 <width>0</width> 475 <width>40</width>
714 <height>0</height> 476 <height>20</height>
715 </size> 477 </size>
716 </property> 478 </property>
717 <property name="layoutDirection"> 479 </spacer>
718 <enum>Qt::LeftToRight</enum> 480 </item>
719 </property> 481 </layout>
720 <property name="text">
721 <string>Clear All</string>
722 </property>
723 </widget>
724 </item>
725 <item>
726 <widget class="QPushButton" name="buttonRestoreDefaults">
727 <property name="sizePolicy">
728 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
729 <horstretch>0</horstretch>
730 <verstretch>0</verstretch>
731 </sizepolicy>
732 </property>
733 <property name="sizeIncrement">
734 <size>
735 <width>0</width>
736 <height>0</height>
737 </size>
738 </property>
739 <property name="baseSize">
740 <size>
741 <width>0</width>
742 <height>0</height>
743 </size>
744 </property>
745 <property name="layoutDirection">
746 <enum>Qt::LeftToRight</enum>
747 </property>
748 <property name="text">
749 <string>Restore Defaults</string>
750 </property>
751 </widget>
752 </item> 482 </item>
753 </layout> 483 </layout>
754 </item> 484 </item>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
new file mode 100644
index 000000000..7dadd83c1
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -0,0 +1,500 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <memory>
7#include <utility>
8#include <QColorDialog>
9#include <QMenu>
10#include <QMessageBox>
11#include <QTimer>
12#include "common/assert.h"
13#include "common/param_package.h"
14#include "input_common/main.h"
15#include "ui_configure_input_player.h"
16#include "yuzu/configuration/config.h"
17#include "yuzu/configuration/configure_input_player.h"
18
19const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM>
20 ConfigureInputPlayer::analog_sub_buttons{{
21 "up",
22 "down",
23 "left",
24 "right",
25 "modifier",
26 }};
27
28static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) {
29 const int index1 = grid->indexOf(item);
30 const int index2 = grid->indexOf(onTopOf);
31 int row, column, rowSpan, columnSpan;
32 grid->getItemPosition(index2, &row, &column, &rowSpan, &columnSpan);
33 grid->takeAt(index1);
34 grid->addWidget(item, row, column, rowSpan, columnSpan);
35}
36
37static QString GetKeyName(int key_code) {
38 switch (key_code) {
39 case Qt::Key_Shift:
40 return QObject::tr("Shift");
41 case Qt::Key_Control:
42 return QObject::tr("Ctrl");
43 case Qt::Key_Alt:
44 return QObject::tr("Alt");
45 case Qt::Key_Meta:
46 return "";
47 default:
48 return QKeySequence(key_code).toString();
49 }
50}
51
52static void SetAnalogButton(const Common::ParamPackage& input_param,
53 Common::ParamPackage& analog_param, const std::string& button_name) {
54 if (analog_param.Get("engine", "") != "analog_from_button") {
55 analog_param = {
56 {"engine", "analog_from_button"},
57 {"modifier_scale", "0.5"},
58 };
59 }
60 analog_param.Set(button_name, input_param.Serialize());
61}
62
63static QString ButtonToText(const Common::ParamPackage& param) {
64 if (!param.Has("engine")) {
65 return QObject::tr("[not set]");
66 } else if (param.Get("engine", "") == "keyboard") {
67 return GetKeyName(param.Get("code", 0));
68 } else if (param.Get("engine", "") == "sdl") {
69 if (param.Has("hat")) {
70 return QString(QObject::tr("Hat %1 %2"))
71 .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
72 }
73 if (param.Has("axis")) {
74 return QString(QObject::tr("Axis %1%2"))
75 .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
76 }
77 if (param.Has("button")) {
78 return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
79 }
80 return QString();
81 } else {
82 return QObject::tr("[unknown]");
83 }
84};
85
86static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) {
87 if (!param.Has("engine")) {
88 return QObject::tr("[not set]");
89 } else if (param.Get("engine", "") == "analog_from_button") {
90 return ButtonToText(Common::ParamPackage{param.Get(dir, "")});
91 } else if (param.Get("engine", "") == "sdl") {
92 if (dir == "modifier") {
93 return QString(QObject::tr("[unused]"));
94 }
95
96 if (dir == "left" || dir == "right") {
97 return QString(QObject::tr("Axis %1")).arg(param.Get("axis_x", "").c_str());
98 } else if (dir == "up" || dir == "down") {
99 return QString(QObject::tr("Axis %1")).arg(param.Get("axis_y", "").c_str());
100 }
101 return QString();
102 } else {
103 return QObject::tr("[unknown]");
104 }
105};
106
107ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug)
108 : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
109 debug(debug), timeout_timer(std::make_unique<QTimer>()),
110 poll_timer(std::make_unique<QTimer>()) {
111 ui->setupUi(this);
112 setFocusPolicy(Qt::ClickFocus);
113
114 button_map = {
115 ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
116 ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
117 ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
118 ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
119 ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown,
120 ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown,
121 ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
122 };
123
124 analog_map_buttons = {{
125 {
126 ui->buttonLStickUp,
127 ui->buttonLStickDown,
128 ui->buttonLStickLeft,
129 ui->buttonLStickRight,
130 ui->buttonLStickMod,
131 },
132 {
133 ui->buttonRStickUp,
134 ui->buttonRStickDown,
135 ui->buttonRStickLeft,
136 ui->buttonRStickRight,
137 ui->buttonRStickMod,
138 },
139 }};
140
141 debug_hidden = {
142 ui->buttonSL, ui->labelSL,
143 ui->buttonSR, ui->labelSR,
144 ui->buttonLStick, ui->labelLStickPressed,
145 ui->buttonRStick, ui->labelRStickPressed,
146 ui->buttonHome, ui->labelHome,
147 ui->buttonScreenshot, ui->labelScreenshot,
148 };
149
150 auto layout = Settings::values.players[player_index].type;
151 if (debug)
152 layout = Settings::ControllerType::DualJoycon;
153
154 switch (layout) {
155 case Settings::ControllerType::ProController:
156 case Settings::ControllerType::DualJoycon:
157 layout_hidden = {
158 ui->buttonSL,
159 ui->labelSL,
160 ui->buttonSR,
161 ui->labelSR,
162 };
163 break;
164 case Settings::ControllerType::LeftJoycon:
165 layout_hidden = {
166 ui->right_body_button,
167 ui->right_buttons_button,
168 ui->right_body_label,
169 ui->right_buttons_label,
170 ui->buttonR,
171 ui->labelR,
172 ui->buttonZR,
173 ui->labelZR,
174 ui->labelHome,
175 ui->buttonHome,
176 ui->buttonPlus,
177 ui->labelPlus,
178 ui->RStick,
179 ui->faceButtons,
180 };
181 break;
182 case Settings::ControllerType::RightJoycon:
183 layout_hidden = {
184 ui->left_body_button, ui->left_buttons_button,
185 ui->left_body_label, ui->left_buttons_label,
186 ui->buttonL, ui->labelL,
187 ui->buttonZL, ui->labelZL,
188 ui->labelScreenshot, ui->buttonScreenshot,
189 ui->buttonMinus, ui->labelMinus,
190 ui->LStick, ui->Dpad,
191 };
192 break;
193 }
194
195 if (debug || layout == Settings::ControllerType::ProController) {
196 ui->controller_color->hide();
197 } else {
198 if (layout == Settings::ControllerType::LeftJoycon ||
199 layout == Settings::ControllerType::RightJoycon) {
200 ui->horizontalSpacer_4->setGeometry({0, 0, 0, 0});
201
202 LayerGridElements(ui->buttons, ui->shoulderButtons, ui->Dpad);
203 LayerGridElements(ui->buttons, ui->misc, ui->RStick);
204 LayerGridElements(ui->buttons, ui->Dpad, ui->faceButtons);
205 LayerGridElements(ui->buttons, ui->RStick, ui->LStick);
206 }
207 }
208
209 for (auto* widget : layout_hidden)
210 widget->setVisible(false);
211
212 analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
213
214 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
215 if (!button_map[button_id])
216 continue;
217 button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
218 connect(button_map[button_id], &QPushButton::released, [=]() {
219 handleClick(
220 button_map[button_id],
221 [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
222 InputCommon::Polling::DeviceType::Button);
223 });
224 connect(button_map[button_id], &QPushButton::customContextMenuRequested,
225 [=](const QPoint& menu_location) {
226 QMenu context_menu;
227 context_menu.addAction(tr("Clear"), [&] {
228 buttons_param[button_id].Clear();
229 button_map[button_id]->setText(tr("[not set]"));
230 });
231 context_menu.addAction(tr("Restore Default"), [&] {
232 buttons_param[button_id] = Common::ParamPackage{
233 InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
234 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
235 });
236 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
237 });
238 }
239
240 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
241 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
242 if (!analog_map_buttons[analog_id][sub_button_id])
243 continue;
244 analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
245 Qt::CustomContextMenu);
246 connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, [=]() {
247 handleClick(analog_map_buttons[analog_id][sub_button_id],
248 [=](const Common::ParamPackage& params) {
249 SetAnalogButton(params, analogs_param[analog_id],
250 analog_sub_buttons[sub_button_id]);
251 },
252 InputCommon::Polling::DeviceType::Button);
253 });
254 connect(analog_map_buttons[analog_id][sub_button_id],
255 &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
256 QMenu context_menu;
257 context_menu.addAction(tr("Clear"), [&] {
258 analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
259 analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
260 });
261 context_menu.addAction(tr("Restore Default"), [&] {
262 Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
263 Config::default_analogs[analog_id][sub_button_id])};
264 SetAnalogButton(params, analogs_param[analog_id],
265 analog_sub_buttons[sub_button_id]);
266 analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
267 analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
268 });
269 context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
270 menu_location));
271 });
272 }
273 connect(analog_map_stick[analog_id], &QPushButton::released, [=]() {
274 QMessageBox::information(this, tr("Information"),
275 tr("After pressing OK, first move your joystick horizontally, "
276 "and then vertically."));
277 handleClick(
278 analog_map_stick[analog_id],
279 [=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; },
280 InputCommon::Polling::DeviceType::Analog);
281 });
282 }
283
284 connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
285 connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
286
287 timeout_timer->setSingleShot(true);
288 connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); });
289
290 connect(poll_timer.get(), &QTimer::timeout, [this]() {
291 Common::ParamPackage params;
292 for (auto& poller : device_pollers) {
293 params = poller->GetNextInput();
294 if (params.Has("engine")) {
295 setPollingResult(params, false);
296 return;
297 }
298 }
299 });
300
301 controller_color_buttons = {
302 ui->left_body_button,
303 ui->left_buttons_button,
304 ui->right_body_button,
305 ui->right_buttons_button,
306 };
307
308 for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) {
309 connect(controller_color_buttons[i], &QPushButton::clicked, this,
310 [this, i] { OnControllerButtonClick(static_cast<int>(i)); });
311 }
312
313 this->loadConfiguration();
314 this->resize(0, 0);
315
316 // TODO(wwylele): enable this when we actually emulate it
317 ui->buttonHome->setEnabled(false);
318}
319
320ConfigureInputPlayer::~ConfigureInputPlayer() = default;
321
322void ConfigureInputPlayer::applyConfiguration() {
323 auto& buttons =
324 debug ? Settings::values.debug_pad_buttons : Settings::values.players[player_index].buttons;
325 auto& analogs =
326 debug ? Settings::values.debug_pad_analogs : Settings::values.players[player_index].analogs;
327
328 std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(),
329 [](const Common::ParamPackage& param) { return param.Serialize(); });
330 std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(),
331 [](const Common::ParamPackage& param) { return param.Serialize(); });
332
333 if (debug)
334 return;
335
336 std::array<u32, 4> colors{};
337 std::transform(controller_colors.begin(), controller_colors.end(), colors.begin(),
338 [](QColor color) { return color.rgb(); });
339
340 Settings::values.players[player_index].body_color_left = colors[0];
341 Settings::values.players[player_index].button_color_left = colors[1];
342 Settings::values.players[player_index].body_color_right = colors[2];
343 Settings::values.players[player_index].button_color_right = colors[3];
344}
345
346void ConfigureInputPlayer::OnControllerButtonClick(int i) {
347 const QColor new_bg_color = QColorDialog::getColor(controller_colors[i]);
348 if (!new_bg_color.isValid())
349 return;
350 controller_colors[i] = new_bg_color;
351 controller_color_buttons[i]->setStyleSheet(
352 QString("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
353}
354
355void ConfigureInputPlayer::loadConfiguration() {
356 if (debug) {
357 std::transform(Settings::values.debug_pad_buttons.begin(),
358 Settings::values.debug_pad_buttons.end(), buttons_param.begin(),
359 [](const std::string& str) { return Common::ParamPackage(str); });
360 std::transform(Settings::values.debug_pad_analogs.begin(),
361 Settings::values.debug_pad_analogs.end(), analogs_param.begin(),
362 [](const std::string& str) { return Common::ParamPackage(str); });
363 } else {
364 std::transform(Settings::values.players[player_index].buttons.begin(),
365 Settings::values.players[player_index].buttons.end(), buttons_param.begin(),
366 [](const std::string& str) { return Common::ParamPackage(str); });
367 std::transform(Settings::values.players[player_index].analogs.begin(),
368 Settings::values.players[player_index].analogs.end(), analogs_param.begin(),
369 [](const std::string& str) { return Common::ParamPackage(str); });
370 }
371
372 updateButtonLabels();
373
374 if (debug)
375 return;
376
377 std::array<u32, 4> colors = {
378 Settings::values.players[player_index].body_color_left,
379 Settings::values.players[player_index].button_color_left,
380 Settings::values.players[player_index].body_color_right,
381 Settings::values.players[player_index].button_color_right,
382 };
383
384 std::transform(colors.begin(), colors.end(), controller_colors.begin(),
385 [](u32 rgb) { return QColor::fromRgb(rgb); });
386
387 for (std::size_t i = 0; i < colors.size(); ++i) {
388 controller_color_buttons[i]->setStyleSheet(
389 QString("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
390 }
391}
392
393void ConfigureInputPlayer::restoreDefaults() {
394 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
395 buttons_param[button_id] = Common::ParamPackage{
396 InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
397 }
398
399 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
400 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
401 Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
402 Config::default_analogs[analog_id][sub_button_id])};
403 SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
404 }
405 }
406 updateButtonLabels();
407}
408
409void ConfigureInputPlayer::ClearAll() {
410 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
411 if (button_map[button_id] && button_map[button_id]->isEnabled())
412 buttons_param[button_id].Clear();
413 }
414 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
415 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
416 if (analog_map_buttons[analog_id][sub_button_id] &&
417 analog_map_buttons[analog_id][sub_button_id]->isEnabled())
418 analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
419 }
420 }
421
422 updateButtonLabels();
423}
424
425void ConfigureInputPlayer::updateButtonLabels() {
426 for (int button = 0; button < Settings::NativeButton::NumButtons; button++) {
427 button_map[button]->setText(ButtonToText(buttons_param[button]));
428 }
429
430 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
431 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
432 if (analog_map_buttons[analog_id][sub_button_id]) {
433 analog_map_buttons[analog_id][sub_button_id]->setText(
434 AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
435 }
436 }
437 analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
438 }
439}
440
441void ConfigureInputPlayer::handleClick(
442 QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
443 InputCommon::Polling::DeviceType type) {
444 button->setText(tr("[press key]"));
445 button->setFocus();
446
447 const auto iter = std::find(button_map.begin(), button_map.end(), button);
448 ASSERT(iter != button_map.end());
449 const auto index = std::distance(button_map.begin(), iter);
450 ASSERT(index < Settings::NativeButton::NumButtons && index >= 0);
451
452 input_setter = new_input_setter;
453
454 device_pollers = InputCommon::Polling::GetPollers(type);
455
456 // Keyboard keys can only be used as button devices
457 want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
458
459 for (auto& poller : device_pollers) {
460 poller->Start();
461 }
462
463 grabKeyboard();
464 grabMouse();
465 timeout_timer->start(5000); // Cancel after 5 seconds
466 poll_timer->start(200); // Check for new inputs every 200ms
467}
468
469void ConfigureInputPlayer::setPollingResult(const Common::ParamPackage& params, bool abort) {
470 releaseKeyboard();
471 releaseMouse();
472 timeout_timer->stop();
473 poll_timer->stop();
474 for (auto& poller : device_pollers) {
475 poller->Stop();
476 }
477
478 if (!abort) {
479 (*input_setter)(params);
480 }
481
482 updateButtonLabels();
483 input_setter = std::nullopt;
484}
485
486void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
487 if (!input_setter || !event)
488 return;
489
490 if (event->key() != Qt::Key_Escape) {
491 if (want_keyboard_keys) {
492 setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
493 false);
494 } else {
495 // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
496 return;
497 }
498 }
499 setPollingResult({}, true);
500}
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
new file mode 100644
index 000000000..7a53f6715
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -0,0 +1,104 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <functional>
9#include <memory>
10#include <optional>
11#include <string>
12
13#include <QDialog>
14#include <QKeyEvent>
15
16#include "common/param_package.h"
17#include "core/settings.h"
18#include "input_common/main.h"
19#include "ui_configure_input.h"
20
21class QPushButton;
22class QString;
23class QTimer;
24
25namespace Ui {
26class ConfigureInputPlayer;
27}
28
29class ConfigureInputPlayer : public QDialog {
30 Q_OBJECT
31
32public:
33 explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false);
34 ~ConfigureInputPlayer() override;
35
36 /// Save all button configurations to settings file
37 void applyConfiguration();
38
39private:
40 void OnControllerButtonClick(int i);
41
42 /// Load configuration settings.
43 void loadConfiguration();
44 /// Restore all buttons to their default values.
45 void restoreDefaults();
46 /// Clear all input configuration
47 void ClearAll();
48
49 /// Update UI to reflect current configuration.
50 void updateButtonLabels();
51
52 /// Called when the button was pressed.
53 void handleClick(QPushButton* button,
54 std::function<void(const Common::ParamPackage&)> new_input_setter,
55 InputCommon::Polling::DeviceType type);
56
57 /// Finish polling and configure input using the input_setter
58 void setPollingResult(const Common::ParamPackage& params, bool abort);
59
60 /// Handle key press events.
61 void keyPressEvent(QKeyEvent* event) override;
62
63 std::unique_ptr<Ui::ConfigureInputPlayer> ui;
64
65 std::size_t player_index;
66 bool debug;
67
68 std::unique_ptr<QTimer> timeout_timer;
69 std::unique_ptr<QTimer> poll_timer;
70
71 /// This will be the the setting function when an input is awaiting configuration.
72 std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
73
74 std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
75 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
76
77 static constexpr int ANALOG_SUB_BUTTONS_NUM = 5;
78
79 /// Each button input is represented by a QPushButton.
80 std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map;
81
82 std::vector<QWidget*> debug_hidden;
83 std::vector<QWidget*> layout_hidden;
84
85 /// A group of five QPushButtons represent one analog input. The buttons each represent up,
86 /// down, left, right, and modifier, respectively.
87 std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs>
88 analog_map_buttons;
89
90 /// Analog inputs are also represented each with a single button, used to configure with an
91 /// actual analog stick
92 std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick;
93
94 static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
95
96 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
97
98 /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
99 /// keyboard events are ignored.
100 bool want_keyboard_keys = false;
101
102 std::array<QPushButton*, 4> controller_color_buttons;
103 std::array<QColor, 4> controller_colors;
104};
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
new file mode 100644
index 000000000..42db020be
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -0,0 +1,1164 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureInputPlayer</class>
4 <widget class="QDialog" name="ConfigureInputPlayer">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>408</width>
10 <height>731</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Configure Input</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_5">
17 <item>
18 <layout class="QGridLayout" name="buttons">
19 <item row="1" column="1">
20 <widget class="QGroupBox" name="RStick">
21 <property name="title">
22 <string>Right Stick</string>
23 </property>
24 <property name="alignment">
25 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
26 </property>
27 <property name="flat">
28 <bool>false</bool>
29 </property>
30 <property name="checkable">
31 <bool>false</bool>
32 </property>
33 <layout class="QGridLayout" name="gridLayout_5">
34 <item row="1" column="1">
35 <layout class="QVBoxLayout" name="buttonRStickDownVerticalLayout">
36 <item>
37 <layout class="QHBoxLayout" name="buttonRStickDownHorizontalLayout">
38 <item>
39 <widget class="QLabel" name="labelRStickDown">
40 <property name="text">
41 <string>Down:</string>
42 </property>
43 </widget>
44 </item>
45 </layout>
46 </item>
47 <item>
48 <widget class="QPushButton" name="buttonRStickDown">
49 <property name="text">
50 <string/>
51 </property>
52 </widget>
53 </item>
54 </layout>
55 </item>
56 <item row="0" column="1">
57 <layout class="QVBoxLayout" name="buttonRStickRightVerticalLayout">
58 <item>
59 <layout class="QHBoxLayout" name="buttonRStickRightHorizontalLayout">
60 <item>
61 <widget class="QLabel" name="labelRStickRight">
62 <property name="text">
63 <string>Right:</string>
64 </property>
65 </widget>
66 </item>
67 </layout>
68 </item>
69 <item>
70 <widget class="QPushButton" name="buttonRStickRight">
71 <property name="text">
72 <string/>
73 </property>
74 </widget>
75 </item>
76 </layout>
77 </item>
78 <item row="3" column="0" colspan="2">
79 <widget class="QPushButton" name="buttonRStickAnalog">
80 <property name="text">
81 <string>Set Analog Stick</string>
82 </property>
83 </widget>
84 </item>
85 <item row="0" column="0">
86 <layout class="QVBoxLayout" name="buttonRStickLeftVerticalLayout">
87 <item>
88 <layout class="QHBoxLayout" name="buttonRStickLeftHorizontalLayout">
89 <item>
90 <widget class="QLabel" name="labelRStickLeft">
91 <property name="text">
92 <string>Left:</string>
93 </property>
94 </widget>
95 </item>
96 </layout>
97 </item>
98 <item>
99 <widget class="QPushButton" name="buttonRStickLeft">
100 <property name="text">
101 <string/>
102 </property>
103 </widget>
104 </item>
105 </layout>
106 </item>
107 <item row="1" column="0">
108 <layout class="QVBoxLayout" name="buttonRStickUpVerticalLayout">
109 <item>
110 <layout class="QHBoxLayout" name="buttonRStickUpHorizontalLayout">
111 <item>
112 <widget class="QLabel" name="labelRStickUp">
113 <property name="text">
114 <string>Up:</string>
115 </property>
116 </widget>
117 </item>
118 </layout>
119 </item>
120 <item>
121 <widget class="QPushButton" name="buttonRStickUp">
122 <property name="text">
123 <string/>
124 </property>
125 </widget>
126 </item>
127 </layout>
128 </item>
129 <item row="2" column="0">
130 <layout class="QVBoxLayout" name="buttonRStickPressedVerticalLayout">
131 <item>
132 <layout class="QHBoxLayout" name="buttonRStickPressedHorizontalLayout">
133 <item>
134 <widget class="QLabel" name="labelRStickPressed">
135 <property name="text">
136 <string>Pressed:</string>
137 </property>
138 </widget>
139 </item>
140 </layout>
141 </item>
142 <item>
143 <widget class="QPushButton" name="buttonRStick">
144 <property name="text">
145 <string/>
146 </property>
147 </widget>
148 </item>
149 </layout>
150 </item>
151 <item row="2" column="1">
152 <layout class="QVBoxLayout" name="buttonRStickModVerticalLayout">
153 <item>
154 <layout class="QHBoxLayout" name="buttonRStickModHorizontalLayout">
155 <item>
156 <widget class="QLabel" name="labelRStickMod">
157 <property name="text">
158 <string>Modifier:</string>
159 </property>
160 </widget>
161 </item>
162 </layout>
163 </item>
164 <item>
165 <widget class="QPushButton" name="buttonRStickMod">
166 <property name="text">
167 <string/>
168 </property>
169 </widget>
170 </item>
171 </layout>
172 </item>
173 </layout>
174 </widget>
175 </item>
176 <item row="0" column="1">
177 <widget class="QGroupBox" name="Dpad">
178 <property name="title">
179 <string>Directional Pad</string>
180 </property>
181 <property name="flat">
182 <bool>false</bool>
183 </property>
184 <property name="checkable">
185 <bool>false</bool>
186 </property>
187 <layout class="QGridLayout" name="gridLayout_2">
188 <item row="1" column="0">
189 <layout class="QVBoxLayout" name="buttonDpadUpVerticalLayout">
190 <item>
191 <layout class="QHBoxLayout" name="buttonDpadUpHorizontalLayout">
192 <item>
193 <widget class="QLabel" name="labelDpadUp">
194 <property name="text">
195 <string>Up:</string>
196 </property>
197 </widget>
198 </item>
199 </layout>
200 </item>
201 <item>
202 <widget class="QPushButton" name="buttonDpadUp">
203 <property name="text">
204 <string/>
205 </property>
206 </widget>
207 </item>
208 </layout>
209 </item>
210 <item row="1" column="1">
211 <layout class="QVBoxLayout" name="buttonDpadDownVerticalLayout">
212 <item>
213 <layout class="QHBoxLayout" name="buttonDpadDownHorizontalLayout">
214 <item>
215 <widget class="QLabel" name="labelDpadDown">
216 <property name="text">
217 <string>Down:</string>
218 </property>
219 </widget>
220 </item>
221 </layout>
222 </item>
223 <item>
224 <widget class="QPushButton" name="buttonDpadDown">
225 <property name="text">
226 <string/>
227 </property>
228 </widget>
229 </item>
230 </layout>
231 </item>
232 <item row="0" column="0">
233 <layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout">
234 <item>
235 <layout class="QHBoxLayout" name="buttonDpadLeftHorizontalLayout">
236 <item>
237 <widget class="QLabel" name="labelDpadLeft">
238 <property name="minimumSize">
239 <size>
240 <width>80</width>
241 <height>0</height>
242 </size>
243 </property>
244 <property name="text">
245 <string>Left:</string>
246 </property>
247 </widget>
248 </item>
249 </layout>
250 </item>
251 <item>
252 <widget class="QPushButton" name="buttonDpadLeft">
253 <property name="text">
254 <string/>
255 </property>
256 </widget>
257 </item>
258 </layout>
259 </item>
260 <item row="0" column="1">
261 <layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout">
262 <item>
263 <layout class="QHBoxLayout" name="buttonDpadRightHorizontalLayout">
264 <item>
265 <widget class="QLabel" name="labelDpadRight">
266 <property name="minimumSize">
267 <size>
268 <width>80</width>
269 <height>0</height>
270 </size>
271 </property>
272 <property name="text">
273 <string>Right:</string>
274 </property>
275 </widget>
276 </item>
277 </layout>
278 </item>
279 <item>
280 <widget class="QPushButton" name="buttonDpadRight">
281 <property name="text">
282 <string/>
283 </property>
284 </widget>
285 </item>
286 </layout>
287 </item>
288 </layout>
289 </widget>
290 </item>
291 <item row="0" column="0">
292 <widget class="QGroupBox" name="faceButtons">
293 <property name="title">
294 <string>Face Buttons</string>
295 </property>
296 <property name="flat">
297 <bool>false</bool>
298 </property>
299 <property name="checkable">
300 <bool>false</bool>
301 </property>
302 <layout class="QGridLayout" name="gridLayout">
303 <item row="0" column="0">
304 <layout class="QVBoxLayout" name="buttonFaceButtonsAVerticalLayout">
305 <item>
306 <layout class="QHBoxLayout" name="buttonFaceButtonsAHorizontalLayout">
307 <item>
308 <widget class="QLabel" name="labelA">
309 <property name="minimumSize">
310 <size>
311 <width>80</width>
312 <height>0</height>
313 </size>
314 </property>
315 <property name="text">
316 <string>A:</string>
317 </property>
318 </widget>
319 </item>
320 </layout>
321 </item>
322 <item>
323 <widget class="QPushButton" name="buttonA">
324 <property name="text">
325 <string/>
326 </property>
327 </widget>
328 </item>
329 </layout>
330 </item>
331 <item row="0" column="1">
332 <layout class="QVBoxLayout" name="buttonFaceButtonsBVerticalLayout">
333 <item>
334 <layout class="QHBoxLayout" name="buttonFaceButtonsBHorizontalLayout">
335 <item>
336 <widget class="QLabel" name="labelB">
337 <property name="minimumSize">
338 <size>
339 <width>80</width>
340 <height>0</height>
341 </size>
342 </property>
343 <property name="text">
344 <string>B:</string>
345 </property>
346 </widget>
347 </item>
348 </layout>
349 </item>
350 <item>
351 <widget class="QPushButton" name="buttonB">
352 <property name="text">
353 <string/>
354 </property>
355 </widget>
356 </item>
357 </layout>
358 </item>
359 <item row="1" column="0">
360 <layout class="QVBoxLayout" name="buttonFaceButtonsXVerticalLayout">
361 <item>
362 <layout class="QHBoxLayout" name="buttonFaceButtonsXHorizontalLayout">
363 <item>
364 <widget class="QLabel" name="labelX">
365 <property name="text">
366 <string>X:</string>
367 </property>
368 </widget>
369 </item>
370 </layout>
371 </item>
372 <item>
373 <widget class="QPushButton" name="buttonX">
374 <property name="text">
375 <string/>
376 </property>
377 </widget>
378 </item>
379 </layout>
380 </item>
381 <item row="1" column="1">
382 <layout class="QVBoxLayout" name="buttonFaceButtonsYVerticalLayout">
383 <item>
384 <layout class="QHBoxLayout" name="buttonFaceButtonsYHorizontalLayout">
385 <item>
386 <widget class="QLabel" name="labelY">
387 <property name="text">
388 <string>Y:</string>
389 </property>
390 </widget>
391 </item>
392 </layout>
393 </item>
394 <item>
395 <widget class="QPushButton" name="buttonY">
396 <property name="text">
397 <string/>
398 </property>
399 </widget>
400 </item>
401 </layout>
402 </item>
403 </layout>
404 </widget>
405 </item>
406 <item row="5" column="0" colspan="2">
407 <widget class="QGroupBox" name="controller_color">
408 <property name="title">
409 <string>Controller Color</string>
410 </property>
411 <layout class="QGridLayout" name="gridLayout_10" columnstretch="0,0,0,0,0,0,0">
412 <item row="0" column="0">
413 <spacer name="horizontalSpacer_2">
414 <property name="orientation">
415 <enum>Qt::Horizontal</enum>
416 </property>
417 <property name="sizeHint" stdset="0">
418 <size>
419 <width>40</width>
420 <height>20</height>
421 </size>
422 </property>
423 </spacer>
424 </item>
425 <item row="0" column="1">
426 <widget class="QLabel" name="left_body_label">
427 <property name="text">
428 <string>Left Body</string>
429 </property>
430 </widget>
431 </item>
432 <item row="0" column="6">
433 <spacer name="horizontalSpacer_3">
434 <property name="orientation">
435 <enum>Qt::Horizontal</enum>
436 </property>
437 <property name="sizeHint" stdset="0">
438 <size>
439 <width>40</width>
440 <height>20</height>
441 </size>
442 </property>
443 </spacer>
444 </item>
445 <item row="1" column="1">
446 <widget class="QLabel" name="left_buttons_label">
447 <property name="minimumSize">
448 <size>
449 <width>90</width>
450 <height>0</height>
451 </size>
452 </property>
453 <property name="text">
454 <string>Left Buttons</string>
455 </property>
456 </widget>
457 </item>
458 <item row="1" column="5">
459 <widget class="QPushButton" name="right_buttons_button">
460 <property name="sizePolicy">
461 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
462 <horstretch>0</horstretch>
463 <verstretch>0</verstretch>
464 </sizepolicy>
465 </property>
466 <property name="minimumSize">
467 <size>
468 <width>32</width>
469 <height>0</height>
470 </size>
471 </property>
472 <property name="maximumSize">
473 <size>
474 <width>40</width>
475 <height>16777215</height>
476 </size>
477 </property>
478 <property name="text">
479 <string/>
480 </property>
481 </widget>
482 </item>
483 <item row="0" column="4">
484 <widget class="QLabel" name="right_body_label">
485 <property name="text">
486 <string>Right Body</string>
487 </property>
488 </widget>
489 </item>
490 <item row="1" column="4">
491 <widget class="QLabel" name="right_buttons_label">
492 <property name="minimumSize">
493 <size>
494 <width>90</width>
495 <height>0</height>
496 </size>
497 </property>
498 <property name="text">
499 <string>Right Buttons</string>
500 </property>
501 </widget>
502 </item>
503 <item row="1" column="2">
504 <widget class="QPushButton" name="left_buttons_button">
505 <property name="sizePolicy">
506 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
507 <horstretch>0</horstretch>
508 <verstretch>0</verstretch>
509 </sizepolicy>
510 </property>
511 <property name="minimumSize">
512 <size>
513 <width>32</width>
514 <height>0</height>
515 </size>
516 </property>
517 <property name="maximumSize">
518 <size>
519 <width>40</width>
520 <height>16777215</height>
521 </size>
522 </property>
523 <property name="text">
524 <string/>
525 </property>
526 </widget>
527 </item>
528 <item row="0" column="2">
529 <widget class="QPushButton" name="left_body_button">
530 <property name="sizePolicy">
531 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
532 <horstretch>0</horstretch>
533 <verstretch>0</verstretch>
534 </sizepolicy>
535 </property>
536 <property name="minimumSize">
537 <size>
538 <width>32</width>
539 <height>0</height>
540 </size>
541 </property>
542 <property name="maximumSize">
543 <size>
544 <width>40</width>
545 <height>16777215</height>
546 </size>
547 </property>
548 <property name="text">
549 <string/>
550 </property>
551 </widget>
552 </item>
553 <item row="0" column="5">
554 <widget class="QPushButton" name="right_body_button">
555 <property name="sizePolicy">
556 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
557 <horstretch>0</horstretch>
558 <verstretch>0</verstretch>
559 </sizepolicy>
560 </property>
561 <property name="minimumSize">
562 <size>
563 <width>32</width>
564 <height>0</height>
565 </size>
566 </property>
567 <property name="maximumSize">
568 <size>
569 <width>40</width>
570 <height>16777215</height>
571 </size>
572 </property>
573 <property name="text">
574 <string/>
575 </property>
576 </widget>
577 </item>
578 <item row="0" column="3">
579 <spacer name="horizontalSpacer_4">
580 <property name="orientation">
581 <enum>Qt::Horizontal</enum>
582 </property>
583 <property name="sizeType">
584 <enum>QSizePolicy::Fixed</enum>
585 </property>
586 <property name="sizeHint" stdset="0">
587 <size>
588 <width>20</width>
589 <height>20</height>
590 </size>
591 </property>
592 </spacer>
593 </item>
594 </layout>
595 </widget>
596 </item>
597 <item row="1" column="0">
598 <widget class="QGroupBox" name="LStick">
599 <property name="title">
600 <string>Left Stick</string>
601 </property>
602 <property name="flat">
603 <bool>false</bool>
604 </property>
605 <property name="checkable">
606 <bool>false</bool>
607 </property>
608 <layout class="QGridLayout" name="gridLayout_4">
609 <item row="1" column="1">
610 <layout class="QVBoxLayout" name="buttonLStickUpVerticalLayout">
611 <item>
612 <layout class="QHBoxLayout" name="buttonLStickUpHorizontalLayout">
613 <item>
614 <widget class="QLabel" name="labelLStickUp">
615 <property name="text">
616 <string>Up:</string>
617 </property>
618 </widget>
619 </item>
620 </layout>
621 </item>
622 <item>
623 <widget class="QPushButton" name="buttonLStickUp">
624 <property name="text">
625 <string/>
626 </property>
627 </widget>
628 </item>
629 </layout>
630 </item>
631 <item row="0" column="2">
632 <layout class="QVBoxLayout" name="buttonLStickRightVerticalLayout">
633 <item>
634 <layout class="QHBoxLayout" name="buttonLStickRightHorizontalLayout">
635 <item>
636 <widget class="QLabel" name="labelLStickRight">
637 <property name="text">
638 <string>Right:</string>
639 </property>
640 </widget>
641 </item>
642 </layout>
643 </item>
644 <item>
645 <widget class="QPushButton" name="buttonLStickRight">
646 <property name="text">
647 <string/>
648 </property>
649 </widget>
650 </item>
651 </layout>
652 </item>
653 <item row="4" column="1" colspan="2">
654 <widget class="QPushButton" name="buttonLStickAnalog">
655 <property name="text">
656 <string>Set Analog Stick</string>
657 </property>
658 </widget>
659 </item>
660 <item row="0" column="1">
661 <layout class="QVBoxLayout" name="buttonLStickLeftVerticalLayout">
662 <item>
663 <layout class="QHBoxLayout" name="buttonLStickLeftHorizontalLayout_2">
664 <item>
665 <widget class="QLabel" name="labelLStickLeft">
666 <property name="text">
667 <string>Left:</string>
668 </property>
669 </widget>
670 </item>
671 </layout>
672 </item>
673 <item>
674 <widget class="QPushButton" name="buttonLStickLeft">
675 <property name="text">
676 <string/>
677 </property>
678 </widget>
679 </item>
680 </layout>
681 </item>
682 <item row="1" column="2">
683 <layout class="QVBoxLayout" name="buttonLStickDownVerticalLayout">
684 <item>
685 <layout class="QHBoxLayout" name="buttonLStickDownHorizontalLayout">
686 <item>
687 <widget class="QLabel" name="labelLStickDown">
688 <property name="text">
689 <string>Down:</string>
690 </property>
691 </widget>
692 </item>
693 </layout>
694 </item>
695 <item>
696 <widget class="QPushButton" name="buttonLStickDown">
697 <property name="text">
698 <string/>
699 </property>
700 </widget>
701 </item>
702 </layout>
703 </item>
704 <item row="3" column="2">
705 <layout class="QVBoxLayout" name="buttonLStickModVerticalLayout">
706 <item>
707 <layout class="QHBoxLayout" name="buttonLStickModHorizontalLayout">
708 <item>
709 <widget class="QLabel" name="labelLStickMod">
710 <property name="text">
711 <string>Modifier:</string>
712 </property>
713 </widget>
714 </item>
715 </layout>
716 </item>
717 <item>
718 <widget class="QPushButton" name="buttonLStickMod">
719 <property name="text">
720 <string/>
721 </property>
722 </widget>
723 </item>
724 </layout>
725 </item>
726 <item row="3" column="1">
727 <layout class="QVBoxLayout" name="buttonLStickPressedVerticalLayout" stretch="0,0">
728 <item>
729 <layout class="QHBoxLayout" name="buttonLStickPressedHorizontalLayout">
730 <item>
731 <widget class="QLabel" name="labelLStickPressed">
732 <property name="text">
733 <string>Pressed:</string>
734 </property>
735 </widget>
736 </item>
737 </layout>
738 </item>
739 <item>
740 <widget class="QPushButton" name="buttonLStick">
741 <property name="text">
742 <string/>
743 </property>
744 </widget>
745 </item>
746 </layout>
747 </item>
748 </layout>
749 </widget>
750 </item>
751 <item row="3" column="0">
752 <widget class="QGroupBox" name="shoulderButtons">
753 <property name="title">
754 <string>Shoulder Buttons</string>
755 </property>
756 <property name="flat">
757 <bool>false</bool>
758 </property>
759 <property name="checkable">
760 <bool>false</bool>
761 </property>
762 <layout class="QGridLayout" name="gridLayout_3">
763 <item row="3" column="0">
764 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
765 <item>
766 <layout class="QHBoxLayout" name="buttonShoulderButtonsSLHorizontalLayout">
767 <item>
768 <widget class="QLabel" name="labelSL">
769 <property name="text">
770 <string>SL:</string>
771 </property>
772 </widget>
773 </item>
774 </layout>
775 </item>
776 <item>
777 <widget class="QPushButton" name="buttonSL">
778 <property name="text">
779 <string/>
780 </property>
781 </widget>
782 </item>
783 </layout>
784 </item>
785 <item row="2" column="1">
786 <layout class="QVBoxLayout" name="buttonShoulderButtonsZRVerticalLayout">
787 <item>
788 <layout class="QHBoxLayout" name="buttonShoulderButtonsZRHorizontalLayout">
789 <item>
790 <widget class="QLabel" name="labelZR">
791 <property name="text">
792 <string>ZR:</string>
793 </property>
794 </widget>
795 </item>
796 </layout>
797 </item>
798 <item>
799 <widget class="QPushButton" name="buttonZR">
800 <property name="text">
801 <string/>
802 </property>
803 </widget>
804 </item>
805 </layout>
806 </item>
807 <item row="3" column="1">
808 <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout">
809 <item>
810 <layout class="QHBoxLayout" name="buttonShoulderButtonsSRHorizontalLayout">
811 <item>
812 <widget class="QLabel" name="labelSR">
813 <property name="text">
814 <string>SR:</string>
815 </property>
816 </widget>
817 </item>
818 </layout>
819 </item>
820 <item>
821 <widget class="QPushButton" name="buttonSR">
822 <property name="text">
823 <string/>
824 </property>
825 </widget>
826 </item>
827 </layout>
828 </item>
829 <item row="0" column="1">
830 <layout class="QVBoxLayout" name="buttonShoulderButtonsZLVerticalLayout">
831 <item>
832 <layout class="QHBoxLayout" name="buttonShoulderButtonsZLHorizontalLayout">
833 <item>
834 <widget class="QLabel" name="labelZL">
835 <property name="text">
836 <string>ZL:</string>
837 </property>
838 </widget>
839 </item>
840 </layout>
841 </item>
842 <item>
843 <widget class="QPushButton" name="buttonZL">
844 <property name="text">
845 <string/>
846 </property>
847 </widget>
848 </item>
849 </layout>
850 </item>
851 <item row="0" column="0">
852 <layout class="QVBoxLayout" name="buttonShoulderButtonsLVerticalLayout">
853 <item>
854 <layout class="QHBoxLayout" name="buttonShoulderButtonsLHorizontalLayout">
855 <item>
856 <widget class="QLabel" name="labelL">
857 <property name="text">
858 <string>L:</string>
859 </property>
860 </widget>
861 </item>
862 </layout>
863 </item>
864 <item>
865 <widget class="QPushButton" name="buttonL">
866 <property name="text">
867 <string/>
868 </property>
869 </widget>
870 </item>
871 </layout>
872 </item>
873 <item row="2" column="0">
874 <layout class="QVBoxLayout" name="buttonShoulderButtonsRVerticalLayout">
875 <item>
876 <layout class="QHBoxLayout" name="buttonShoulderButtonsRHorizontalLayout">
877 <item>
878 <widget class="QLabel" name="labelR">
879 <property name="text">
880 <string>R:</string>
881 </property>
882 </widget>
883 </item>
884 </layout>
885 </item>
886 <item>
887 <widget class="QPushButton" name="buttonR">
888 <property name="text">
889 <string/>
890 </property>
891 </widget>
892 </item>
893 </layout>
894 </item>
895 </layout>
896 </widget>
897 </item>
898 <item row="3" column="1">
899 <widget class="QGroupBox" name="misc">
900 <property name="title">
901 <string>Misc.</string>
902 </property>
903 <property name="flat">
904 <bool>false</bool>
905 </property>
906 <property name="checkable">
907 <bool>false</bool>
908 </property>
909 <layout class="QGridLayout" name="gridLayout_6">
910 <item row="1" column="0">
911 <layout class="QVBoxLayout" name="buttonMiscMinusVerticalLayout">
912 <item>
913 <layout class="QHBoxLayout" name="buttonMiscMinusHorizontalLayout">
914 <item>
915 <widget class="QLabel" name="labelMinus">
916 <property name="text">
917 <string>Minus:</string>
918 </property>
919 </widget>
920 </item>
921 </layout>
922 </item>
923 <item>
924 <widget class="QPushButton" name="buttonMinus">
925 <property name="text">
926 <string/>
927 </property>
928 </widget>
929 </item>
930 </layout>
931 </item>
932 <item row="3" column="1">
933 <spacer name="verticalSpacer_2">
934 <property name="orientation">
935 <enum>Qt::Vertical</enum>
936 </property>
937 <property name="sizeHint" stdset="0">
938 <size>
939 <width>20</width>
940 <height>40</height>
941 </size>
942 </property>
943 </spacer>
944 </item>
945 <item row="0" column="0">
946 <layout class="QVBoxLayout" name="buttonMiscPlusVerticalLayout">
947 <item>
948 <layout class="QHBoxLayout" name="buttonMiscPlusHorizontalLayout">
949 <item>
950 <widget class="QLabel" name="labelPlus">
951 <property name="text">
952 <string>Plus:</string>
953 </property>
954 </widget>
955 </item>
956 </layout>
957 </item>
958 <item>
959 <widget class="QPushButton" name="buttonPlus">
960 <property name="text">
961 <string/>
962 </property>
963 </widget>
964 </item>
965 </layout>
966 </item>
967 <item row="0" column="1">
968 <layout class="QVBoxLayout" name="buttonMiscHomeVerticalLayout">
969 <item>
970 <layout class="QHBoxLayout" name="buttonMiscHomeHorizontalLayout">
971 <item>
972 <widget class="QLabel" name="labelHome">
973 <property name="text">
974 <string>Home:</string>
975 </property>
976 </widget>
977 </item>
978 </layout>
979 </item>
980 <item>
981 <widget class="QPushButton" name="buttonHome">
982 <property name="text">
983 <string/>
984 </property>
985 </widget>
986 </item>
987 </layout>
988 </item>
989 <item row="1" column="1">
990 <layout class="QVBoxLayout" name="buttonMiscScrCapVerticalLayout">
991 <item>
992 <layout class="QHBoxLayout" name="buttonMiscScrCapHorizontalLayout">
993 <item>
994 <widget class="QLabel" name="labelScreenshot">
995 <property name="text">
996 <string>Screen Capture:</string>
997 </property>
998 <property name="wordWrap">
999 <bool>false</bool>
1000 </property>
1001 </widget>
1002 </item>
1003 </layout>
1004 </item>
1005 <item>
1006 <widget class="QPushButton" name="buttonScreenshot">
1007 <property name="sizePolicy">
1008 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1009 <horstretch>0</horstretch>
1010 <verstretch>0</verstretch>
1011 </sizepolicy>
1012 </property>
1013 <property name="maximumSize">
1014 <size>
1015 <width>80</width>
1016 <height>16777215</height>
1017 </size>
1018 </property>
1019 <property name="text">
1020 <string/>
1021 </property>
1022 </widget>
1023 </item>
1024 </layout>
1025 </item>
1026 </layout>
1027 </widget>
1028 </item>
1029 </layout>
1030 </item>
1031 <item>
1032 <spacer name="verticalSpacer">
1033 <property name="orientation">
1034 <enum>Qt::Vertical</enum>
1035 </property>
1036 <property name="sizeHint" stdset="0">
1037 <size>
1038 <width>20</width>
1039 <height>40</height>
1040 </size>
1041 </property>
1042 </spacer>
1043 </item>
1044 <item>
1045 <layout class="QHBoxLayout" name="horizontalLayout"/>
1046 </item>
1047 <item>
1048 <layout class="QHBoxLayout" name="horizontalLayout_2">
1049 <item>
1050 <widget class="QPushButton" name="buttonClearAll">
1051 <property name="sizePolicy">
1052 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
1053 <horstretch>0</horstretch>
1054 <verstretch>0</verstretch>
1055 </sizepolicy>
1056 </property>
1057 <property name="sizeIncrement">
1058 <size>
1059 <width>0</width>
1060 <height>0</height>
1061 </size>
1062 </property>
1063 <property name="baseSize">
1064 <size>
1065 <width>0</width>
1066 <height>0</height>
1067 </size>
1068 </property>
1069 <property name="layoutDirection">
1070 <enum>Qt::LeftToRight</enum>
1071 </property>
1072 <property name="text">
1073 <string>Clear All</string>
1074 </property>
1075 </widget>
1076 </item>
1077 <item>
1078 <widget class="QPushButton" name="buttonRestoreDefaults">
1079 <property name="sizePolicy">
1080 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
1081 <horstretch>0</horstretch>
1082 <verstretch>0</verstretch>
1083 </sizepolicy>
1084 </property>
1085 <property name="sizeIncrement">
1086 <size>
1087 <width>0</width>
1088 <height>0</height>
1089 </size>
1090 </property>
1091 <property name="baseSize">
1092 <size>
1093 <width>0</width>
1094 <height>0</height>
1095 </size>
1096 </property>
1097 <property name="layoutDirection">
1098 <enum>Qt::LeftToRight</enum>
1099 </property>
1100 <property name="text">
1101 <string>Restore Defaults</string>
1102 </property>
1103 </widget>
1104 </item>
1105 <item>
1106 <spacer name="horizontalSpacer">
1107 <property name="orientation">
1108 <enum>Qt::Horizontal</enum>
1109 </property>
1110 <property name="sizeHint" stdset="0">
1111 <size>
1112 <width>40</width>
1113 <height>20</height>
1114 </size>
1115 </property>
1116 </spacer>
1117 </item>
1118 <item>
1119 <widget class="QDialogButtonBox" name="buttonBox">
1120 <property name="standardButtons">
1121 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
1122 </property>
1123 </widget>
1124 </item>
1125 </layout>
1126 </item>
1127 </layout>
1128 </widget>
1129 <resources/>
1130 <connections>
1131 <connection>
1132 <sender>buttonBox</sender>
1133 <signal>accepted()</signal>
1134 <receiver>ConfigureInputPlayer</receiver>
1135 <slot>accept()</slot>
1136 <hints>
1137 <hint type="sourcelabel">
1138 <x>371</x>
1139 <y>730</y>
1140 </hint>
1141 <hint type="destinationlabel">
1142 <x>229</x>
1143 <y>375</y>
1144 </hint>
1145 </hints>
1146 </connection>
1147 <connection>
1148 <sender>buttonBox</sender>
1149 <signal>rejected()</signal>
1150 <receiver>ConfigureInputPlayer</receiver>
1151 <slot>reject()</slot>
1152 <hints>
1153 <hint type="sourcelabel">
1154 <x>371</x>
1155 <y>730</y>
1156 </hint>
1157 <hint type="destinationlabel">
1158 <x>229</x>
1159 <y>375</y>
1160 </hint>
1161 </hints>
1162 </connection>
1163 </connections>
1164</ui>
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
new file mode 100644
index 000000000..ef857035e
--- /dev/null
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -0,0 +1,213 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <memory>
7
8#include <QKeyEvent>
9#include <QMenu>
10#include <QTimer>
11
12#include "common/assert.h"
13#include "common/param_package.h"
14#include "input_common/main.h"
15#include "ui_configure_mouse_advanced.h"
16#include "yuzu/configuration/config.h"
17#include "yuzu/configuration/configure_mouse_advanced.h"
18
19static QString GetKeyName(int key_code) {
20 switch (key_code) {
21 case Qt::Key_Shift:
22 return QObject::tr("Shift");
23 case Qt::Key_Control:
24 return QObject::tr("Ctrl");
25 case Qt::Key_Alt:
26 return QObject::tr("Alt");
27 case Qt::Key_Meta:
28 return "";
29 default:
30 return QKeySequence(key_code).toString();
31 }
32}
33
34static QString ButtonToText(const Common::ParamPackage& param) {
35 if (!param.Has("engine")) {
36 return QObject::tr("[not set]");
37 } else if (param.Get("engine", "") == "keyboard") {
38 return GetKeyName(param.Get("code", 0));
39 } else if (param.Get("engine", "") == "sdl") {
40 if (param.Has("hat")) {
41 return QString(QObject::tr("Hat %1 %2"))
42 .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
43 }
44 if (param.Has("axis")) {
45 return QString(QObject::tr("Axis %1%2"))
46 .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
47 }
48 if (param.Has("button")) {
49 return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
50 }
51 return QString();
52 } else {
53 return QObject::tr("[unknown]");
54 }
55}
56
57ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
58 : QDialog(parent), ui(std::make_unique<Ui::ConfigureMouseAdvanced>()),
59 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
60 ui->setupUi(this);
61 setFocusPolicy(Qt::ClickFocus);
62
63 button_map = {
64 ui->left_button, ui->right_button, ui->middle_button, ui->forward_button, ui->back_button,
65 };
66
67 for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
68 if (!button_map[button_id])
69 continue;
70 button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
71 connect(button_map[button_id], &QPushButton::released, [=]() {
72 handleClick(
73 button_map[button_id],
74 [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
75 InputCommon::Polling::DeviceType::Button);
76 });
77 connect(button_map[button_id], &QPushButton::customContextMenuRequested,
78 [=](const QPoint& menu_location) {
79 QMenu context_menu;
80 context_menu.addAction(tr("Clear"), [&] {
81 buttons_param[button_id].Clear();
82 button_map[button_id]->setText(tr("[not set]"));
83 });
84 context_menu.addAction(tr("Restore Default"), [&] {
85 buttons_param[button_id] =
86 Common::ParamPackage{InputCommon::GenerateKeyboardParam(
87 Config::default_mouse_buttons[button_id])};
88 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
89 });
90 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
91 });
92 }
93
94 connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
95 connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
96
97 timeout_timer->setSingleShot(true);
98 connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); });
99
100 connect(poll_timer.get(), &QTimer::timeout, [this]() {
101 Common::ParamPackage params;
102 for (auto& poller : device_pollers) {
103 params = poller->GetNextInput();
104 if (params.Has("engine")) {
105 setPollingResult(params, false);
106 return;
107 }
108 }
109 });
110
111 loadConfiguration();
112 resize(0, 0);
113}
114
115ConfigureMouseAdvanced::~ConfigureMouseAdvanced() = default;
116
117void ConfigureMouseAdvanced::applyConfiguration() {
118 std::transform(buttons_param.begin(), buttons_param.end(),
119 Settings::values.mouse_buttons.begin(),
120 [](const Common::ParamPackage& param) { return param.Serialize(); });
121}
122
123void ConfigureMouseAdvanced::loadConfiguration() {
124 std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
125 buttons_param.begin(),
126 [](const std::string& str) { return Common::ParamPackage(str); });
127 updateButtonLabels();
128}
129
130void ConfigureMouseAdvanced::restoreDefaults() {
131 for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
132 buttons_param[button_id] = Common::ParamPackage{
133 InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])};
134 }
135
136 updateButtonLabels();
137}
138
139void ConfigureMouseAdvanced::ClearAll() {
140 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
141 if (button_map[i] && button_map[i]->isEnabled())
142 buttons_param[i].Clear();
143 }
144
145 updateButtonLabels();
146}
147
148void ConfigureMouseAdvanced::updateButtonLabels() {
149 for (int button = 0; button < Settings::NativeMouseButton::NumMouseButtons; button++) {
150 button_map[button]->setText(ButtonToText(buttons_param[button]));
151 }
152}
153
154void ConfigureMouseAdvanced::handleClick(
155 QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
156 InputCommon::Polling::DeviceType type) {
157 button->setText(tr("[press key]"));
158 button->setFocus();
159
160 const auto iter = std::find(button_map.begin(), button_map.end(), button);
161 ASSERT(iter != button_map.end());
162 const auto index = std::distance(button_map.begin(), iter);
163 ASSERT(index < Settings::NativeButton::NumButtons && index >= 0);
164
165 input_setter = new_input_setter;
166
167 device_pollers = InputCommon::Polling::GetPollers(type);
168
169 // Keyboard keys can only be used as button devices
170 want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
171
172 for (auto& poller : device_pollers) {
173 poller->Start();
174 }
175
176 grabKeyboard();
177 grabMouse();
178 timeout_timer->start(5000); // Cancel after 5 seconds
179 poll_timer->start(200); // Check for new inputs every 200ms
180}
181
182void ConfigureMouseAdvanced::setPollingResult(const Common::ParamPackage& params, bool abort) {
183 releaseKeyboard();
184 releaseMouse();
185 timeout_timer->stop();
186 poll_timer->stop();
187 for (auto& poller : device_pollers) {
188 poller->Stop();
189 }
190
191 if (!abort) {
192 (*input_setter)(params);
193 }
194
195 updateButtonLabels();
196 input_setter = std::nullopt;
197}
198
199void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) {
200 if (!input_setter || !event)
201 return;
202
203 if (event->key() != Qt::Key_Escape) {
204 if (want_keyboard_keys) {
205 setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
206 false);
207 } else {
208 // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
209 return;
210 }
211 }
212 setPollingResult({}, true);
213}
diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h
new file mode 100644
index 000000000..e04da4bf2
--- /dev/null
+++ b/src/yuzu/configuration/configure_mouse_advanced.h
@@ -0,0 +1,68 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <optional>
9#include <QDialog>
10
11#include "core/settings.h"
12
13class QCheckBox;
14class QPushButton;
15class QTimer;
16
17namespace Ui {
18class ConfigureMouseAdvanced;
19}
20
21class ConfigureMouseAdvanced : public QDialog {
22 Q_OBJECT
23
24public:
25 explicit ConfigureMouseAdvanced(QWidget* parent);
26 ~ConfigureMouseAdvanced() override;
27
28 void applyConfiguration();
29
30private:
31 /// Load configuration settings.
32 void loadConfiguration();
33 /// Restore all buttons to their default values.
34 void restoreDefaults();
35 /// Clear all input configuration
36 void ClearAll();
37
38 /// Update UI to reflect current configuration.
39 void updateButtonLabels();
40
41 /// Called when the button was pressed.
42 void handleClick(QPushButton* button,
43 std::function<void(const Common::ParamPackage&)> new_input_setter,
44 InputCommon::Polling::DeviceType type);
45
46 /// Finish polling and configure input using the input_setter
47 void setPollingResult(const Common::ParamPackage& params, bool abort);
48
49 /// Handle key press events.
50 void keyPressEvent(QKeyEvent* event) override;
51
52 std::unique_ptr<Ui::ConfigureMouseAdvanced> ui;
53
54 /// This will be the the setting function when an input is awaiting configuration.
55 std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
56
57 std::array<QPushButton*, Settings::NativeMouseButton::NumMouseButtons> button_map;
58 std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons> buttons_param;
59
60 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
61
62 std::unique_ptr<QTimer> timeout_timer;
63 std::unique_ptr<QTimer> poll_timer;
64
65 /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
66 /// keyboard events are ignored.
67 bool want_keyboard_keys = false;
68};
diff --git a/src/yuzu/configuration/configure_mouse_advanced.ui b/src/yuzu/configuration/configure_mouse_advanced.ui
new file mode 100644
index 000000000..08245ecf0
--- /dev/null
+++ b/src/yuzu/configuration/configure_mouse_advanced.ui
@@ -0,0 +1,261 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureMouseAdvanced</class>
4 <widget class="QDialog" name="ConfigureMouseAdvanced">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>250</width>
10 <height>261</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Configure Mouse</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <widget class="QGroupBox" name="gridGroupBox">
19 <property name="title">
20 <string>Mouse Buttons</string>
21 </property>
22 <layout class="QGridLayout" name="gridLayout">
23 <item row="0" column="4">
24 <spacer name="horizontalSpacer_2">
25 <property name="orientation">
26 <enum>Qt::Horizontal</enum>
27 </property>
28 <property name="sizeType">
29 <enum>QSizePolicy::Fixed</enum>
30 </property>
31 <property name="sizeHint" stdset="0">
32 <size>
33 <width>20</width>
34 <height>20</height>
35 </size>
36 </property>
37 </spacer>
38 </item>
39 <item row="0" column="3">
40 <layout class="QVBoxLayout" name="verticalLayout_4">
41 <item>
42 <layout class="QHBoxLayout" name="horizontalLayout_3">
43 <item>
44 <widget class="QLabel" name="label_3">
45 <property name="text">
46 <string>Right:</string>
47 </property>
48 </widget>
49 </item>
50 </layout>
51 </item>
52 <item>
53 <widget class="QPushButton" name="right_button">
54 <property name="minimumSize">
55 <size>
56 <width>75</width>
57 <height>0</height>
58 </size>
59 </property>
60 <property name="text">
61 <string/>
62 </property>
63 </widget>
64 </item>
65 </layout>
66 </item>
67 <item row="0" column="0">
68 <spacer name="horizontalSpacer">
69 <property name="orientation">
70 <enum>Qt::Horizontal</enum>
71 </property>
72 <property name="sizeType">
73 <enum>QSizePolicy::Fixed</enum>
74 </property>
75 <property name="sizeHint" stdset="0">
76 <size>
77 <width>20</width>
78 <height>20</height>
79 </size>
80 </property>
81 </spacer>
82 </item>
83 <item row="2" column="1">
84 <layout class="QVBoxLayout" name="verticalLayout_3">
85 <item>
86 <layout class="QHBoxLayout" name="horizontalLayout_2">
87 <item>
88 <widget class="QLabel" name="label_2">
89 <property name="text">
90 <string>Middle:</string>
91 </property>
92 </widget>
93 </item>
94 </layout>
95 </item>
96 <item>
97 <widget class="QPushButton" name="middle_button">
98 <property name="text">
99 <string/>
100 </property>
101 </widget>
102 </item>
103 </layout>
104 </item>
105 <item row="3" column="1">
106 <layout class="QVBoxLayout" name="verticalLayout_5">
107 <item>
108 <layout class="QHBoxLayout" name="horizontalLayout_4">
109 <item>
110 <widget class="QLabel" name="label_4">
111 <property name="minimumSize">
112 <size>
113 <width>54</width>
114 <height>0</height>
115 </size>
116 </property>
117 <property name="text">
118 <string>Back:</string>
119 </property>
120 </widget>
121 </item>
122 </layout>
123 </item>
124 <item>
125 <widget class="QPushButton" name="back_button">
126 <property name="text">
127 <string/>
128 </property>
129 </widget>
130 </item>
131 </layout>
132 </item>
133 <item row="0" column="1">
134 <layout class="QVBoxLayout" name="verticalLayout_2">
135 <item>
136 <layout class="QHBoxLayout" name="horizontalLayout">
137 <item>
138 <widget class="QLabel" name="label">
139 <property name="text">
140 <string>Left:</string>
141 </property>
142 </widget>
143 </item>
144 </layout>
145 </item>
146 <item>
147 <widget class="QPushButton" name="left_button">
148 <property name="minimumSize">
149 <size>
150 <width>75</width>
151 <height>0</height>
152 </size>
153 </property>
154 <property name="text">
155 <string/>
156 </property>
157 </widget>
158 </item>
159 </layout>
160 </item>
161 <item row="3" column="3">
162 <layout class="QVBoxLayout" name="verticalLayout_6">
163 <item>
164 <layout class="QHBoxLayout" name="horizontalLayout_5">
165 <item>
166 <widget class="QLabel" name="label_5">
167 <property name="text">
168 <string>Forward:</string>
169 </property>
170 </widget>
171 </item>
172 </layout>
173 </item>
174 <item>
175 <widget class="QPushButton" name="forward_button">
176 <property name="text">
177 <string/>
178 </property>
179 </widget>
180 </item>
181 </layout>
182 </item>
183 </layout>
184 </widget>
185 </item>
186 <item>
187 <layout class="QHBoxLayout" name="horizontalLayout_6">
188 <item>
189 <widget class="QPushButton" name="buttonClearAll">
190 <property name="text">
191 <string>Clear All</string>
192 </property>
193 </widget>
194 </item>
195 <item>
196 <widget class="QPushButton" name="buttonRestoreDefaults">
197 <property name="text">
198 <string>Restore Defaults</string>
199 </property>
200 </widget>
201 </item>
202 <item>
203 <spacer name="horizontalSpacer_3">
204 <property name="orientation">
205 <enum>Qt::Horizontal</enum>
206 </property>
207 <property name="sizeHint" stdset="0">
208 <size>
209 <width>40</width>
210 <height>20</height>
211 </size>
212 </property>
213 </spacer>
214 </item>
215 </layout>
216 </item>
217 <item>
218 <widget class="QDialogButtonBox" name="buttonBox">
219 <property name="standardButtons">
220 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
221 </property>
222 </widget>
223 </item>
224 </layout>
225 </widget>
226 <resources/>
227 <connections>
228 <connection>
229 <sender>buttonBox</sender>
230 <signal>accepted()</signal>
231 <receiver>ConfigureMouseAdvanced</receiver>
232 <slot>accept()</slot>
233 <hints>
234 <hint type="sourcelabel">
235 <x>124</x>
236 <y>266</y>
237 </hint>
238 <hint type="destinationlabel">
239 <x>124</x>
240 <y>143</y>
241 </hint>
242 </hints>
243 </connection>
244 <connection>
245 <sender>buttonBox</sender>
246 <signal>rejected()</signal>
247 <receiver>ConfigureMouseAdvanced</receiver>
248 <slot>reject()</slot>
249 <hints>
250 <hint type="sourcelabel">
251 <x>124</x>
252 <y>266</y>
253 </hint>
254 <hint type="destinationlabel">
255 <x>124</x>
256 <y>143</y>
257 </hint>
258 </hints>
259 </connection>
260 </connections>
261</ui>
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 4803d43bb..ab5d46492 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -137,6 +137,12 @@ ConfigureSystem::ConfigureSystem(QWidget* parent)
137 connect(ui->pm_remove, &QPushButton::pressed, this, &ConfigureSystem::DeleteUser); 137 connect(ui->pm_remove, &QPushButton::pressed, this, &ConfigureSystem::DeleteUser);
138 connect(ui->pm_set_image, &QPushButton::pressed, this, &ConfigureSystem::SetUserImage); 138 connect(ui->pm_set_image, &QPushButton::pressed, this, &ConfigureSystem::SetUserImage);
139 139
140 connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) {
141 ui->rng_seed_edit->setEnabled(checked);
142 if (!checked)
143 ui->rng_seed_edit->setText(QStringLiteral("00000000"));
144 });
145
140 scene = new QGraphicsScene; 146 scene = new QGraphicsScene;
141 ui->current_user_icon->setScene(scene); 147 ui->current_user_icon->setScene(scene);
142 148
@@ -155,6 +161,13 @@ void ConfigureSystem::setConfiguration() {
155 161
156 PopulateUserList(); 162 PopulateUserList();
157 UpdateCurrentUser(); 163 UpdateCurrentUser();
164
165 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value());
166 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value());
167
168 const auto rng_seed =
169 QString("%1").arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'}).toUpper();
170 ui->rng_seed_edit->setText(rng_seed);
158} 171}
159 172
160void ConfigureSystem::PopulateUserList() { 173void ConfigureSystem::PopulateUserList() {
@@ -195,6 +208,12 @@ void ConfigureSystem::applyConfiguration() {
195 return; 208 return;
196 209
197 Settings::values.language_index = ui->combo_language->currentIndex(); 210 Settings::values.language_index = ui->combo_language->currentIndex();
211
212 if (ui->rng_seed_checkbox->isChecked())
213 Settings::values.rng_seed = ui->rng_seed_edit->text().toULongLong(nullptr, 16);
214 else
215 Settings::values.rng_seed = std::nullopt;
216
198 Settings::Apply(); 217 Settings::Apply();
199} 218}
200 219
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index 020b32a37..a91580893 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -6,7 +6,7 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>360</width> 9 <width>366</width>
10 <height>483</height> 10 <height>483</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
@@ -22,98 +22,6 @@
22 <string>System Settings</string> 22 <string>System Settings</string>
23 </property> 23 </property>
24 <layout class="QGridLayout" name="gridLayout"> 24 <layout class="QGridLayout" name="gridLayout">
25 <item row="1" column="0">
26 <widget class="QLabel" name="label_language">
27 <property name="text">
28 <string>Language</string>
29 </property>
30 </widget>
31 </item>
32 <item row="0" column="0">
33 <widget class="QLabel" name="label_birthday">
34 <property name="text">
35 <string>Birthday</string>
36 </property>
37 </widget>
38 </item>
39 <item row="3" column="0">
40 <widget class="QLabel" name="label_console_id">
41 <property name="text">
42 <string>Console ID:</string>
43 </property>
44 </widget>
45 </item>
46 <item row="0" column="1">
47 <layout class="QHBoxLayout" name="horizontalLayout_birthday2">
48 <item>
49 <widget class="QComboBox" name="combo_birthmonth">
50 <item>
51 <property name="text">
52 <string>January</string>
53 </property>
54 </item>
55 <item>
56 <property name="text">
57 <string>February</string>
58 </property>
59 </item>
60 <item>
61 <property name="text">
62 <string>March</string>
63 </property>
64 </item>
65 <item>
66 <property name="text">
67 <string>April</string>
68 </property>
69 </item>
70 <item>
71 <property name="text">
72 <string>May</string>
73 </property>
74 </item>
75 <item>
76 <property name="text">
77 <string>June</string>
78 </property>
79 </item>
80 <item>
81 <property name="text">
82 <string>July</string>
83 </property>
84 </item>
85 <item>
86 <property name="text">
87 <string>August</string>
88 </property>
89 </item>
90 <item>
91 <property name="text">
92 <string>September</string>
93 </property>
94 </item>
95 <item>
96 <property name="text">
97 <string>October</string>
98 </property>
99 </item>
100 <item>
101 <property name="text">
102 <string>November</string>
103 </property>
104 </item>
105 <item>
106 <property name="text">
107 <string>December</string>
108 </property>
109 </item>
110 </widget>
111 </item>
112 <item>
113 <widget class="QComboBox" name="combo_birthday"/>
114 </item>
115 </layout>
116 </item>
117 <item row="1" column="1"> 25 <item row="1" column="1">
118 <widget class="QComboBox" name="combo_language"> 26 <widget class="QComboBox" name="combo_language">
119 <property name="toolTip"> 27 <property name="toolTip">
@@ -206,6 +114,13 @@
206 </item> 114 </item>
207 </widget> 115 </widget>
208 </item> 116 </item>
117 <item row="3" column="0">
118 <widget class="QLabel" name="label_console_id">
119 <property name="text">
120 <string>Console ID:</string>
121 </property>
122 </widget>
123 </item>
209 <item row="2" column="0"> 124 <item row="2" column="0">
210 <widget class="QLabel" name="label_sound"> 125 <widget class="QLabel" name="label_sound">
211 <property name="text"> 126 <property name="text">
@@ -213,6 +128,100 @@
213 </property> 128 </property>
214 </widget> 129 </widget>
215 </item> 130 </item>
131 <item row="0" column="0">
132 <widget class="QLabel" name="label_birthday">
133 <property name="text">
134 <string>Birthday</string>
135 </property>
136 </widget>
137 </item>
138 <item row="0" column="1">
139 <layout class="QHBoxLayout" name="horizontalLayout_birthday2">
140 <item>
141 <widget class="QComboBox" name="combo_birthmonth">
142 <item>
143 <property name="text">
144 <string>January</string>
145 </property>
146 </item>
147 <item>
148 <property name="text">
149 <string>February</string>
150 </property>
151 </item>
152 <item>
153 <property name="text">
154 <string>March</string>
155 </property>
156 </item>
157 <item>
158 <property name="text">
159 <string>April</string>
160 </property>
161 </item>
162 <item>
163 <property name="text">
164 <string>May</string>
165 </property>
166 </item>
167 <item>
168 <property name="text">
169 <string>June</string>
170 </property>
171 </item>
172 <item>
173 <property name="text">
174 <string>July</string>
175 </property>
176 </item>
177 <item>
178 <property name="text">
179 <string>August</string>
180 </property>
181 </item>
182 <item>
183 <property name="text">
184 <string>September</string>
185 </property>
186 </item>
187 <item>
188 <property name="text">
189 <string>October</string>
190 </property>
191 </item>
192 <item>
193 <property name="text">
194 <string>November</string>
195 </property>
196 </item>
197 <item>
198 <property name="text">
199 <string>December</string>
200 </property>
201 </item>
202 </widget>
203 </item>
204 <item>
205 <widget class="QComboBox" name="combo_birthday"/>
206 </item>
207 </layout>
208 </item>
209 <item row="3" column="1">
210 <widget class="QPushButton" name="button_regenerate_console_id">
211 <property name="sizePolicy">
212 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
213 <horstretch>0</horstretch>
214 <verstretch>0</verstretch>
215 </sizepolicy>
216 </property>
217 <property name="layoutDirection">
218 <enum>Qt::RightToLeft</enum>
219 </property>
220 <property name="text">
221 <string>Regenerate</string>
222 </property>
223 </widget>
224 </item>
216 <item row="2" column="1"> 225 <item row="2" column="1">
217 <widget class="QComboBox" name="combo_sound"> 226 <widget class="QComboBox" name="combo_sound">
218 <item> 227 <item>
@@ -232,19 +241,38 @@
232 </item> 241 </item>
233 </widget> 242 </widget>
234 </item> 243 </item>
235 <item row="3" column="1"> 244 <item row="1" column="0">
236 <widget class="QPushButton" name="button_regenerate_console_id"> 245 <widget class="QLabel" name="label_language">
246 <property name="text">
247 <string>Language</string>
248 </property>
249 </widget>
250 </item>
251 <item row="4" column="0">
252 <widget class="QCheckBox" name="rng_seed_checkbox">
253 <property name="text">
254 <string>RNG Seed</string>
255 </property>
256 </widget>
257 </item>
258 <item row="4" column="1">
259 <widget class="QLineEdit" name="rng_seed_edit">
237 <property name="sizePolicy"> 260 <property name="sizePolicy">
238 <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> 261 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
239 <horstretch>0</horstretch> 262 <horstretch>0</horstretch>
240 <verstretch>0</verstretch> 263 <verstretch>0</verstretch>
241 </sizepolicy> 264 </sizepolicy>
242 </property> 265 </property>
243 <property name="layoutDirection"> 266 <property name="font">
244 <enum>Qt::RightToLeft</enum> 267 <font>
268 <family>Lucida Console</family>
269 </font>
245 </property> 270 </property>
246 <property name="text"> 271 <property name="inputMask">
247 <string>Regenerate</string> 272 <string notr="true">HHHHHHHH</string>
273 </property>
274 <property name="maxLength">
275 <number>8</number>
248 </property> 276 </property>
249 </widget> 277 </widget>
250 </item> 278 </item>
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.cpp b/src/yuzu/configuration/configure_touchscreen_advanced.cpp
new file mode 100644
index 000000000..9c1561e9d
--- /dev/null
+++ b/src/yuzu/configuration/configure_touchscreen_advanced.cpp
@@ -0,0 +1,42 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <memory>
6#include "ui_configure_touchscreen_advanced.h"
7#include "yuzu/configuration/config.h"
8#include "yuzu/configuration/configure_touchscreen_advanced.h"
9
10ConfigureTouchscreenAdvanced::ConfigureTouchscreenAdvanced(QWidget* parent)
11 : QDialog(parent), ui(std::make_unique<Ui::ConfigureTouchscreenAdvanced>()) {
12 ui->setupUi(this);
13
14 connect(ui->restore_defaults_button, &QPushButton::pressed, this,
15 &ConfigureTouchscreenAdvanced::restoreDefaults);
16
17 loadConfiguration();
18 resize(0, 0);
19}
20
21ConfigureTouchscreenAdvanced::~ConfigureTouchscreenAdvanced() = default;
22
23void ConfigureTouchscreenAdvanced::applyConfiguration() {
24 Settings::values.touchscreen.finger = ui->finger_box->value();
25 Settings::values.touchscreen.diameter_x = ui->diameter_x_box->value();
26 Settings::values.touchscreen.diameter_y = ui->diameter_y_box->value();
27 Settings::values.touchscreen.rotation_angle = ui->angle_box->value();
28}
29
30void ConfigureTouchscreenAdvanced::loadConfiguration() {
31 ui->finger_box->setValue(Settings::values.touchscreen.finger);
32 ui->diameter_x_box->setValue(Settings::values.touchscreen.diameter_x);
33 ui->diameter_y_box->setValue(Settings::values.touchscreen.diameter_y);
34 ui->angle_box->setValue(Settings::values.touchscreen.rotation_angle);
35}
36
37void ConfigureTouchscreenAdvanced::restoreDefaults() {
38 ui->finger_box->setValue(0);
39 ui->diameter_x_box->setValue(15);
40 ui->diameter_y_box->setValue(15);
41 ui->angle_box->setValue(0);
42}
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.h b/src/yuzu/configuration/configure_touchscreen_advanced.h
new file mode 100644
index 000000000..41cd255fb
--- /dev/null
+++ b/src/yuzu/configuration/configure_touchscreen_advanced.h
@@ -0,0 +1,32 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QDialog>
9#include <QWidget>
10#include "yuzu/configuration/config.h"
11
12namespace Ui {
13class ConfigureTouchscreenAdvanced;
14}
15
16class ConfigureTouchscreenAdvanced : public QDialog {
17 Q_OBJECT
18
19public:
20 explicit ConfigureTouchscreenAdvanced(QWidget* parent);
21 ~ConfigureTouchscreenAdvanced() override;
22
23 void applyConfiguration();
24
25private:
26 /// Load configuration settings.
27 void loadConfiguration();
28 /// Restore all buttons to their default values.
29 void restoreDefaults();
30
31 std::unique_ptr<Ui::ConfigureTouchscreenAdvanced> ui;
32};
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.ui b/src/yuzu/configuration/configure_touchscreen_advanced.ui
new file mode 100644
index 000000000..1171c2dd1
--- /dev/null
+++ b/src/yuzu/configuration/configure_touchscreen_advanced.ui
@@ -0,0 +1,199 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureTouchscreenAdvanced</class>
4 <widget class="QDialog" name="ConfigureTouchscreenAdvanced">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>298</width>
10 <height>339</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Configure Touchscreen</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <widget class="QLabel" name="label_2">
19 <property name="minimumSize">
20 <size>
21 <width>280</width>
22 <height>0</height>
23 </size>
24 </property>
25 <property name="text">
26 <string>Warning: The settings in this page affect the inner workings of yuzu's emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</string>
27 </property>
28 <property name="wordWrap">
29 <bool>true</bool>
30 </property>
31 </widget>
32 </item>
33 <item>
34 <spacer name="verticalSpacer_2">
35 <property name="orientation">
36 <enum>Qt::Vertical</enum>
37 </property>
38 <property name="sizeType">
39 <enum>QSizePolicy::Fixed</enum>
40 </property>
41 <property name="sizeHint" stdset="0">
42 <size>
43 <width>20</width>
44 <height>20</height>
45 </size>
46 </property>
47 </spacer>
48 </item>
49 <item>
50 <widget class="QGroupBox" name="gridGroupBox">
51 <property name="title">
52 <string>Touch Parameters</string>
53 </property>
54 <layout class="QGridLayout" name="gridLayout">
55 <item row="0" column="0">
56 <spacer name="horizontalSpacer">
57 <property name="orientation">
58 <enum>Qt::Horizontal</enum>
59 </property>
60 <property name="sizeHint" stdset="0">
61 <size>
62 <width>40</width>
63 <height>20</height>
64 </size>
65 </property>
66 </spacer>
67 </item>
68 <item row="2" column="1">
69 <widget class="QLabel" name="label_4">
70 <property name="text">
71 <string>Touch Diameter Y</string>
72 </property>
73 </widget>
74 </item>
75 <item row="0" column="1">
76 <widget class="QLabel" name="label">
77 <property name="text">
78 <string>Finger</string>
79 </property>
80 </widget>
81 </item>
82 <item row="0" column="3">
83 <spacer name="horizontalSpacer_2">
84 <property name="orientation">
85 <enum>Qt::Horizontal</enum>
86 </property>
87 <property name="sizeHint" stdset="0">
88 <size>
89 <width>40</width>
90 <height>20</height>
91 </size>
92 </property>
93 </spacer>
94 </item>
95 <item row="1" column="1">
96 <widget class="QLabel" name="label_3">
97 <property name="text">
98 <string>Touch Diameter X</string>
99 </property>
100 </widget>
101 </item>
102 <item row="0" column="2">
103 <widget class="QSpinBox" name="finger_box">
104 <property name="minimumSize">
105 <size>
106 <width>80</width>
107 <height>0</height>
108 </size>
109 </property>
110 </widget>
111 </item>
112 <item row="3" column="1">
113 <widget class="QLabel" name="label_5">
114 <property name="text">
115 <string>Rotational Angle</string>
116 </property>
117 </widget>
118 </item>
119 <item row="1" column="2">
120 <widget class="QSpinBox" name="diameter_x_box"/>
121 </item>
122 <item row="2" column="2">
123 <widget class="QSpinBox" name="diameter_y_box"/>
124 </item>
125 <item row="3" column="2">
126 <widget class="QSpinBox" name="angle_box"/>
127 </item>
128 </layout>
129 </widget>
130 </item>
131 <item>
132 <spacer name="verticalSpacer">
133 <property name="orientation">
134 <enum>Qt::Vertical</enum>
135 </property>
136 <property name="sizeHint" stdset="0">
137 <size>
138 <width>20</width>
139 <height>40</height>
140 </size>
141 </property>
142 </spacer>
143 </item>
144 <item>
145 <layout class="QHBoxLayout" name="horizontalLayout">
146 <item>
147 <widget class="QPushButton" name="restore_defaults_button">
148 <property name="text">
149 <string>Restore Defaults</string>
150 </property>
151 </widget>
152 </item>
153 <item>
154 <widget class="QDialogButtonBox" name="buttonBox">
155 <property name="standardButtons">
156 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
157 </property>
158 </widget>
159 </item>
160 </layout>
161 </item>
162 </layout>
163 </widget>
164 <resources/>
165 <connections>
166 <connection>
167 <sender>buttonBox</sender>
168 <signal>accepted()</signal>
169 <receiver>ConfigureTouchscreenAdvanced</receiver>
170 <slot>accept()</slot>
171 <hints>
172 <hint type="sourcelabel">
173 <x>140</x>
174 <y>318</y>
175 </hint>
176 <hint type="destinationlabel">
177 <x>140</x>
178 <y>169</y>
179 </hint>
180 </hints>
181 </connection>
182 <connection>
183 <sender>buttonBox</sender>
184 <signal>rejected()</signal>
185 <receiver>ConfigureTouchscreenAdvanced</receiver>
186 <slot>reject()</slot>
187 <hints>
188 <hint type="sourcelabel">
189 <x>140</x>
190 <y>318</y>
191 </hint>
192 <hint type="destinationlabel">
193 <x>140</x>
194 <y>169</y>
195 </hint>
196 </hints>
197 </connection>
198 </connections>
199</ui>
diff --git a/src/yuzu/configuration/configure_web.h b/src/yuzu/configuration/configure_web.h
index 7741ab95d..7752ae4a1 100644
--- a/src/yuzu/configuration/configure_web.h
+++ b/src/yuzu/configuration/configure_web.h
@@ -17,18 +17,17 @@ class ConfigureWeb : public QWidget {
17 17
18public: 18public:
19 explicit ConfigureWeb(QWidget* parent = nullptr); 19 explicit ConfigureWeb(QWidget* parent = nullptr);
20 ~ConfigureWeb(); 20 ~ConfigureWeb() override;
21 21
22 void applyConfiguration(); 22 void applyConfiguration();
23 void retranslateUi(); 23 void retranslateUi();
24 24
25public slots: 25private:
26 void RefreshTelemetryID(); 26 void RefreshTelemetryID();
27 void OnLoginChanged(); 27 void OnLoginChanged();
28 void VerifyLogin(); 28 void VerifyLogin();
29 void OnLoginVerified(); 29 void OnLoginVerified();
30 30
31private:
32 void setConfiguration(); 31 void setConfiguration();
33 32
34 bool user_verified = true; 33 bool user_verified = true;
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 0c831c9f4..f9c18ede4 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -7,10 +7,10 @@
7 7
8#include "common/assert.h" 8#include "common/assert.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/handle_table.h" 10#include "core/hle/kernel/handle_table.h"
12#include "core/hle/kernel/mutex.h" 11#include "core/hle/kernel/mutex.h"
13#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/readable_event.h"
14#include "core/hle/kernel/scheduler.h" 14#include "core/hle/kernel/scheduler.h"
15#include "core/hle/kernel/thread.h" 15#include "core/hle/kernel/thread.h"
16#include "core/hle/kernel/timer.h" 16#include "core/hle/kernel/timer.h"
@@ -153,8 +153,8 @@ QString WaitTreeWaitObject::GetText() const {
153 153
154std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitObject& object) { 154std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitObject& object) {
155 switch (object.GetHandleType()) { 155 switch (object.GetHandleType()) {
156 case Kernel::HandleType::Event: 156 case Kernel::HandleType::ReadableEvent:
157 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::Event&>(object)); 157 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
158 case Kernel::HandleType::Timer: 158 case Kernel::HandleType::Timer:
159 return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object)); 159 return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object));
160 case Kernel::HandleType::Thread: 160 case Kernel::HandleType::Thread:
@@ -332,7 +332,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
332 return list; 332 return list;
333} 333}
334 334
335WaitTreeEvent::WaitTreeEvent(const Kernel::Event& object) : WaitTreeWaitObject(object) {} 335WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) : WaitTreeWaitObject(object) {}
336WaitTreeEvent::~WaitTreeEvent() = default; 336WaitTreeEvent::~WaitTreeEvent() = default;
337 337
338std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const { 338std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const {
@@ -340,7 +340,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const {
340 340
341 list.push_back(std::make_unique<WaitTreeText>( 341 list.push_back(std::make_unique<WaitTreeText>(
342 tr("reset type = %1") 342 tr("reset type = %1")
343 .arg(GetResetTypeQString(static_cast<const Kernel::Event&>(object).GetResetType())))); 343 .arg(GetResetTypeQString(
344 static_cast<const Kernel::ReadableEvent&>(object).GetResetType()))));
344 return list; 345 return list;
345} 346}
346 347
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index 331f89885..492fb6ac9 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -17,8 +17,8 @@
17class EmuThread; 17class EmuThread;
18 18
19namespace Kernel { 19namespace Kernel {
20class ReadableEvent;
20class WaitObject; 21class WaitObject;
21class Event;
22class Thread; 22class Thread;
23class Timer; 23class Timer;
24} // namespace Kernel 24} // namespace Kernel
@@ -144,7 +144,7 @@ public:
144class WaitTreeEvent : public WaitTreeWaitObject { 144class WaitTreeEvent : public WaitTreeWaitObject {
145 Q_OBJECT 145 Q_OBJECT
146public: 146public:
147 explicit WaitTreeEvent(const Kernel::Event& object); 147 explicit WaitTreeEvent(const Kernel::ReadableEvent& object);
148 ~WaitTreeEvent() override; 148 ~WaitTreeEvent() override;
149 149
150 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; 150 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index a5a4aa432..b52a50915 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -214,13 +214,20 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent)
214 tree_view->setEditTriggers(QHeaderView::NoEditTriggers); 214 tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
215 tree_view->setUniformRowHeights(true); 215 tree_view->setUniformRowHeights(true);
216 tree_view->setContextMenuPolicy(Qt::CustomContextMenu); 216 tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
217 tree_view->setStyleSheet("QTreeView{ border: none; }");
217 218
218 item_model->insertColumns(0, COLUMN_COUNT); 219 item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1);
219 item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name")); 220 item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
220 item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, tr("Compatibility")); 221 item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, tr("Compatibility"));
221 item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons")); 222
222 item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type")); 223 if (UISettings::values.show_add_ons) {
223 item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size")); 224 item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
225 item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
226 item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
227 } else {
228 item_model->setHeaderData(COLUMN_FILE_TYPE - 1, Qt::Horizontal, tr("File type"));
229 item_model->setHeaderData(COLUMN_SIZE - 1, Qt::Horizontal, tr("Size"));
230 }
224 231
225 connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry); 232 connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry);
226 connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu); 233 connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
@@ -394,6 +401,25 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
394 } 401 }
395 402
396 tree_view->setEnabled(false); 403 tree_view->setEnabled(false);
404
405 // Update the columns in case UISettings has changed
406 item_model->removeColumns(0, item_model->columnCount());
407 item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1);
408 item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
409 item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, tr("Compatibility"));
410
411 if (UISettings::values.show_add_ons) {
412 item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
413 item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
414 item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
415 } else {
416 item_model->setHeaderData(COLUMN_FILE_TYPE - 1, Qt::Horizontal, tr("File type"));
417 item_model->setHeaderData(COLUMN_SIZE - 1, Qt::Horizontal, tr("Size"));
418 item_model->removeColumns(COLUMN_COUNT - 1, 1);
419 }
420
421 LoadInterfaceLayout();
422
397 // Delete any rows that might already exist if we're repopulating 423 // Delete any rows that might already exist if we're repopulating
398 item_model->removeRows(0, item_model->rowCount()); 424 item_model->removeRows(0, item_model->rowCount());
399 425
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 3d865a12d..9fd074223 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -86,6 +86,35 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager,
86 out.chop(1); 86 out.chop(1);
87 return out; 87 return out;
88} 88}
89
90QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name,
91 const std::vector<u8>& icon, Loader::AppLoader& loader,
92 u64 program_id, const CompatibilityList& compatibility_list,
93 const FileSys::PatchManager& patch) {
94 const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
95
96 // The game list uses this as compatibility number for untested games
97 QString compatibility{"99"};
98 if (it != compatibility_list.end()) {
99 compatibility = it->second.first;
100 }
101
102 QList<QStandardItem*> list{
103 new GameListItemPath(
104 FormatGameName(path), icon, QString::fromStdString(name),
105 QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType())), program_id),
106 new GameListItemCompat(compatibility),
107 new GameListItem(QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType()))),
108 new GameListItemSize(FileUtil::GetSize(path)),
109 };
110
111 if (UISettings::values.show_add_ons) {
112 list.insert(
113 2, new GameListItem(FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable())));
114 }
115
116 return list;
117}
89} // Anonymous namespace 118} // Anonymous namespace
90 119
91GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan, 120GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan,
@@ -97,11 +126,11 @@ GameListWorker::~GameListWorker() = default;
97 126
98void GameListWorker::AddInstalledTitlesToGameList() { 127void GameListWorker::AddInstalledTitlesToGameList() {
99 const auto cache = Service::FileSystem::GetUnionContents(); 128 const auto cache = Service::FileSystem::GetUnionContents();
100 const auto installed_games = cache->ListEntriesFilter(FileSys::TitleType::Application, 129 const auto installed_games = cache.ListEntriesFilter(FileSys::TitleType::Application,
101 FileSys::ContentRecordType::Program); 130 FileSys::ContentRecordType::Program);
102 131
103 for (const auto& game : installed_games) { 132 for (const auto& game : installed_games) {
104 const auto file = cache->GetEntryUnparsed(game); 133 const auto file = cache.GetEntryUnparsed(game);
105 std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file); 134 std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file);
106 if (!loader) 135 if (!loader)
107 continue; 136 continue;
@@ -112,35 +141,19 @@ void GameListWorker::AddInstalledTitlesToGameList() {
112 loader->ReadProgramId(program_id); 141 loader->ReadProgramId(program_id);
113 142
114 const FileSys::PatchManager patch{program_id}; 143 const FileSys::PatchManager patch{program_id};
115 const auto control = cache->GetEntry(game.title_id, FileSys::ContentRecordType::Control); 144 const auto control = cache.GetEntry(game.title_id, FileSys::ContentRecordType::Control);
116 if (control != nullptr) 145 if (control != nullptr)
117 GetMetadataFromControlNCA(patch, *control, icon, name); 146 GetMetadataFromControlNCA(patch, *control, icon, name);
118 147
119 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); 148 emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, icon, *loader, program_id,
120 149 compatibility_list, patch));
121 // The game list uses this as compatibility number for untested games
122 QString compatibility("99");
123 if (it != compatibility_list.end())
124 compatibility = it->second.first;
125
126 emit EntryReady({
127 new GameListItemPath(
128 FormatGameName(file->GetFullPath()), icon, QString::fromStdString(name),
129 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
130 program_id),
131 new GameListItemCompat(compatibility),
132 new GameListItem(FormatPatchNameVersions(patch, *loader)),
133 new GameListItem(
134 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
135 new GameListItemSize(file->GetSize()),
136 });
137 } 150 }
138 151
139 const auto control_data = cache->ListEntriesFilter(FileSys::TitleType::Application, 152 const auto control_data = cache.ListEntriesFilter(FileSys::TitleType::Application,
140 FileSys::ContentRecordType::Control); 153 FileSys::ContentRecordType::Control);
141 154
142 for (const auto& entry : control_data) { 155 for (const auto& entry : control_data) {
143 auto nca = cache->GetEntry(entry); 156 auto nca = cache.GetEntry(entry);
144 if (nca != nullptr) { 157 if (nca != nullptr) {
145 nca_control_map.insert_or_assign(entry.title_id, std::move(nca)); 158 nca_control_map.insert_or_assign(entry.title_id, std::move(nca));
146 } 159 }
@@ -150,14 +163,14 @@ void GameListWorker::AddInstalledTitlesToGameList() {
150void GameListWorker::FillControlMap(const std::string& dir_path) { 163void GameListWorker::FillControlMap(const std::string& dir_path) {
151 const auto nca_control_callback = [this](u64* num_entries_out, const std::string& directory, 164 const auto nca_control_callback = [this](u64* num_entries_out, const std::string& directory,
152 const std::string& virtual_name) -> bool { 165 const std::string& virtual_name) -> bool {
153 std::string physical_name = directory + DIR_SEP + virtual_name; 166 if (stop_processing) {
154 167 // Breaks the callback loop
155 if (stop_processing) 168 return false;
156 return false; // Breaks the callback loop. 169 }
157 170
158 bool is_dir = FileUtil::IsDirectory(physical_name); 171 const std::string physical_name = directory + DIR_SEP + virtual_name;
159 QFileInfo file_info(physical_name.c_str()); 172 const QFileInfo file_info(QString::fromStdString(physical_name));
160 if (!is_dir && file_info.suffix().toStdString() == "nca") { 173 if (!file_info.isDir() && file_info.suffix() == QStringLiteral("nca")) {
161 auto nca = 174 auto nca =
162 std::make_unique<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read)); 175 std::make_unique<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read));
163 if (nca->GetType() == FileSys::NCAContentType::Control) { 176 if (nca->GetType() == FileSys::NCAContentType::Control) {
@@ -174,12 +187,13 @@ void GameListWorker::FillControlMap(const std::string& dir_path) {
174void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { 187void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) {
175 const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory, 188 const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory,
176 const std::string& virtual_name) -> bool { 189 const std::string& virtual_name) -> bool {
177 std::string physical_name = directory + DIR_SEP + virtual_name; 190 if (stop_processing) {
178 191 // Breaks the callback loop.
179 if (stop_processing) 192 return false;
180 return false; // Breaks the callback loop. 193 }
181 194
182 bool is_dir = FileUtil::IsDirectory(physical_name); 195 const std::string physical_name = directory + DIR_SEP + virtual_name;
196 const bool is_dir = FileUtil::IsDirectory(physical_name);
183 if (!is_dir && 197 if (!is_dir &&
184 (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { 198 (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
185 std::unique_ptr<Loader::AppLoader> loader = 199 std::unique_ptr<Loader::AppLoader> loader =
@@ -209,25 +223,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
209 } 223 }
210 } 224 }
211 225
212 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); 226 emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id,
213 227 compatibility_list, patch));
214 // The game list uses this as compatibility number for untested games
215 QString compatibility("99");
216 if (it != compatibility_list.end())
217 compatibility = it->second.first;
218
219 emit EntryReady({
220 new GameListItemPath(
221 FormatGameName(physical_name), icon, QString::fromStdString(name),
222 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
223 program_id),
224 new GameListItemCompat(compatibility),
225 new GameListItem(
226 FormatPatchNameVersions(patch, *loader, loader->IsRomFSUpdatable())),
227 new GameListItem(
228 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
229 new GameListItemSize(FileUtil::GetSize(physical_name)),
230 });
231 } else if (is_dir && recursion > 0) { 228 } else if (is_dir && recursion > 0) {
232 watch_list.append(QString::fromStdString(physical_name)); 229 watch_list.append(QString::fromStdString(physical_name));
233 AddFstEntriesToGameList(physical_name, recursion - 1); 230 AddFstEntriesToGameList(physical_name, recursion - 1);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 74a44be37..22c207a3a 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -8,11 +8,13 @@
8#include <thread> 8#include <thread>
9 9
10// VFS includes must be before glad as they will conflict with Windows file api, which uses defines. 10// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
11#include "applets/software_keyboard.h"
11#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
12#include "core/file_sys/vfs_real.h" 13#include "core/file_sys/vfs_real.h"
13#include "core/hle/service/acc/profile_manager.h" 14#include "core/hle/service/acc/profile_manager.h"
15#include "core/hle/service/am/applets/applets.h"
14 16
15// These are wrappers to avoid the calls to CreateDirectory and CreateFile becuase of the Windows 17// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
16// defines. 18// defines.
17static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper( 19static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper(
18 const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::Mode mode) { 20 const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::Mode mode) {
@@ -59,6 +61,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
59#include "core/file_sys/romfs.h" 61#include "core/file_sys/romfs.h"
60#include "core/file_sys/savedata_factory.h" 62#include "core/file_sys/savedata_factory.h"
61#include "core/file_sys/submission_package.h" 63#include "core/file_sys/submission_package.h"
64#include "core/frontend/applets/software_keyboard.h"
62#include "core/hle/kernel/process.h" 65#include "core/hle/kernel/process.h"
63#include "core/hle/service/filesystem/filesystem.h" 66#include "core/hle/service/filesystem/filesystem.h"
64#include "core/hle/service/filesystem/fsp_ldr.h" 67#include "core/hle/service/filesystem/fsp_ldr.h"
@@ -204,6 +207,27 @@ GMainWindow::~GMainWindow() {
204 delete render_window; 207 delete render_window;
205} 208}
206 209
210void GMainWindow::SoftwareKeyboardGetText(
211 const Core::Frontend::SoftwareKeyboardParameters& parameters) {
212 QtSoftwareKeyboardDialog dialog(this, parameters);
213 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
214 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
215 dialog.setWindowModality(Qt::WindowModal);
216 dialog.exec();
217
218 if (!dialog.GetStatus()) {
219 emit SoftwareKeyboardFinishedText(std::nullopt);
220 return;
221 }
222
223 emit SoftwareKeyboardFinishedText(dialog.GetText());
224}
225
226void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) {
227 QMessageBox::warning(this, tr("Text Check Failed"), QString::fromStdU16String(error_message));
228 emit SoftwareKeyboardFinishedCheckDialog();
229}
230
207void GMainWindow::InitializeWidgets() { 231void GMainWindow::InitializeWidgets() {
208#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING 232#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
209 ui.action_Report_Compatibility->setVisible(true); 233 ui.action_Report_Compatibility->setVisible(true);
@@ -308,6 +332,8 @@ void GMainWindow::InitializeHotkeys() {
308 Qt::ApplicationShortcut); 332 Qt::ApplicationShortcut);
309 hotkey_registry.RegisterHotkey("Main Window", "Decrease Speed Limit", QKeySequence("-"), 333 hotkey_registry.RegisterHotkey("Main Window", "Decrease Speed Limit", QKeySequence("-"),
310 Qt::ApplicationShortcut); 334 Qt::ApplicationShortcut);
335 hotkey_registry.RegisterHotkey("Main Window", "Load Amiibo", QKeySequence(Qt::Key_F2),
336 Qt::ApplicationShortcut);
311 hotkey_registry.LoadHotkeys(); 337 hotkey_registry.LoadHotkeys();
312 338
313 connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, 339 connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated,
@@ -361,6 +387,12 @@ void GMainWindow::InitializeHotkeys() {
361 UpdateStatusBar(); 387 UpdateStatusBar();
362 } 388 }
363 }); 389 });
390 connect(hotkey_registry.GetHotkey("Main Window", "Load Amiibo", this), &QShortcut::activated,
391 this, [&] {
392 if (ui.action_Load_Amiibo->isEnabled()) {
393 OnLoadAmiibo();
394 }
395 });
364} 396}
365 397
366void GMainWindow::SetDefaultUIGeometry() { 398void GMainWindow::SetDefaultUIGeometry() {
@@ -486,32 +518,20 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
486QStringList GMainWindow::GetUnsupportedGLExtensions() { 518QStringList GMainWindow::GetUnsupportedGLExtensions() {
487 QStringList unsupported_ext; 519 QStringList unsupported_ext;
488 520
489 if (!GLAD_GL_ARB_program_interface_query) 521 if (!GLAD_GL_ARB_direct_state_access)
490 unsupported_ext.append("ARB_program_interface_query"); 522 unsupported_ext.append("ARB_direct_state_access");
491 if (!GLAD_GL_ARB_separate_shader_objects)
492 unsupported_ext.append("ARB_separate_shader_objects");
493 if (!GLAD_GL_ARB_vertex_attrib_binding)
494 unsupported_ext.append("ARB_vertex_attrib_binding");
495 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) 523 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
496 unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev"); 524 unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev");
497 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) 525 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
498 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); 526 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge");
499 if (!GLAD_GL_ARB_base_instance)
500 unsupported_ext.append("ARB_base_instance");
501 if (!GLAD_GL_ARB_texture_storage)
502 unsupported_ext.append("ARB_texture_storage");
503 if (!GLAD_GL_ARB_multi_bind) 527 if (!GLAD_GL_ARB_multi_bind)
504 unsupported_ext.append("ARB_multi_bind"); 528 unsupported_ext.append("ARB_multi_bind");
505 if (!GLAD_GL_ARB_copy_image)
506 unsupported_ext.append("ARB_copy_image");
507 529
508 // Extensions required to support some texture formats. 530 // Extensions required to support some texture formats.
509 if (!GLAD_GL_EXT_texture_compression_s3tc) 531 if (!GLAD_GL_EXT_texture_compression_s3tc)
510 unsupported_ext.append("EXT_texture_compression_s3tc"); 532 unsupported_ext.append("EXT_texture_compression_s3tc");
511 if (!GLAD_GL_ARB_texture_compression_rgtc) 533 if (!GLAD_GL_ARB_texture_compression_rgtc)
512 unsupported_ext.append("ARB_texture_compression_rgtc"); 534 unsupported_ext.append("ARB_texture_compression_rgtc");
513 if (!GLAD_GL_ARB_texture_compression_bptc)
514 unsupported_ext.append("ARB_texture_compression_bptc");
515 if (!GLAD_GL_ARB_depth_buffer_float) 535 if (!GLAD_GL_ARB_depth_buffer_float)
516 unsupported_ext.append("ARB_depth_buffer_float"); 536 unsupported_ext.append("ARB_depth_buffer_float");
517 537
@@ -530,8 +550,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
530 render_window->MakeCurrent(); 550 render_window->MakeCurrent();
531 551
532 if (!gladLoadGL()) { 552 if (!gladLoadGL()) {
533 QMessageBox::critical(this, tr("Error while initializing OpenGL 3.3 Core!"), 553 QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3 Core!"),
534 tr("Your GPU may not support OpenGL 3.3, or you do not " 554 tr("Your GPU may not support OpenGL 4.3, or you do not "
535 "have the latest graphics driver.")); 555 "have the latest graphics driver."));
536 return false; 556 return false;
537 } 557 }
@@ -551,6 +571,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
551 571
552 system.SetGPUDebugContext(debug_context); 572 system.SetGPUDebugContext(debug_context);
553 573
574 system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this));
575
554 const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; 576 const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
555 577
556 const auto drd_callout = 578 const auto drd_callout =
@@ -885,7 +907,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
885 } 907 }
886 908
887 const auto installed = Service::FileSystem::GetUnionContents(); 909 const auto installed = Service::FileSystem::GetUnionContents();
888 auto romfs_title_id = SelectRomFSDumpTarget(*installed, program_id); 910 const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id);
889 911
890 if (!romfs_title_id) { 912 if (!romfs_title_id) {
891 failed(); 913 failed();
@@ -900,7 +922,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
900 if (*romfs_title_id == program_id) { 922 if (*romfs_title_id == program_id) {
901 romfs = file; 923 romfs = file;
902 } else { 924 } else {
903 romfs = installed->GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS(); 925 romfs = installed.GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS();
904 } 926 }
905 927
906 const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full); 928 const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
@@ -933,7 +955,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
933 const auto full = res == "Full"; 955 const auto full = res == "Full";
934 const auto entry_size = CalculateRomFSEntrySize(extracted, full); 956 const auto entry_size = CalculateRomFSEntrySize(extracted, full);
935 957
936 QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, entry_size, this); 958 QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0,
959 static_cast<s32>(entry_size), this);
937 progress.setWindowModality(Qt::WindowModal); 960 progress.setWindowModality(Qt::WindowModal);
938 progress.setMinimumDuration(100); 961 progress.setMinimumDuration(100);
939 962
@@ -1084,14 +1107,14 @@ void GMainWindow::OnMenuInstallToNAND() {
1084 return; 1107 return;
1085 } 1108 }
1086 const auto res = 1109 const auto res =
1087 Service::FileSystem::GetUserNANDContents()->InstallEntry(nsp, false, qt_raw_copy); 1110 Service::FileSystem::GetUserNANDContents()->InstallEntry(*nsp, false, qt_raw_copy);
1088 if (res == FileSys::InstallResult::Success) { 1111 if (res == FileSys::InstallResult::Success) {
1089 success(); 1112 success();
1090 } else { 1113 } else {
1091 if (res == FileSys::InstallResult::ErrorAlreadyExists) { 1114 if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1092 if (overwrite()) { 1115 if (overwrite()) {
1093 const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( 1116 const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
1094 nsp, true, qt_raw_copy); 1117 *nsp, true, qt_raw_copy);
1095 if (res2 == FileSys::InstallResult::Success) { 1118 if (res2 == FileSys::InstallResult::Success) {
1096 success(); 1119 success();
1097 } else { 1120 } else {
@@ -1146,10 +1169,10 @@ void GMainWindow::OnMenuInstallToNAND() {
1146 FileSys::InstallResult res; 1169 FileSys::InstallResult res;
1147 if (index >= static_cast<size_t>(FileSys::TitleType::Application)) { 1170 if (index >= static_cast<size_t>(FileSys::TitleType::Application)) {
1148 res = Service::FileSystem::GetUserNANDContents()->InstallEntry( 1171 res = Service::FileSystem::GetUserNANDContents()->InstallEntry(
1149 nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); 1172 *nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
1150 } else { 1173 } else {
1151 res = Service::FileSystem::GetSystemNANDContents()->InstallEntry( 1174 res = Service::FileSystem::GetSystemNANDContents()->InstallEntry(
1152 nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); 1175 *nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
1153 } 1176 }
1154 1177
1155 if (res == FileSys::InstallResult::Success) { 1178 if (res == FileSys::InstallResult::Success) {
@@ -1157,7 +1180,7 @@ void GMainWindow::OnMenuInstallToNAND() {
1157 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { 1180 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1158 if (overwrite()) { 1181 if (overwrite()) {
1159 const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( 1182 const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
1160 nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); 1183 *nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
1161 if (res2 == FileSys::InstallResult::Success) { 1184 if (res2 == FileSys::InstallResult::Success) {
1162 success(); 1185 success();
1163 } else { 1186 } else {
@@ -1219,8 +1242,13 @@ void GMainWindow::OnMenuRecentFile() {
1219 1242
1220void GMainWindow::OnStartGame() { 1243void GMainWindow::OnStartGame() {
1221 emu_thread->SetRunning(true); 1244 emu_thread->SetRunning(true);
1245
1246 qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
1247 "Core::Frontend::SoftwareKeyboardParameters");
1222 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); 1248 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
1223 qRegisterMetaType<std::string>("std::string"); 1249 qRegisterMetaType<std::string>("std::string");
1250 qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
1251
1224 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); 1252 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
1225 1253
1226 ui.action_Start->setEnabled(false); 1254 ui.action_Start->setEnabled(false);
@@ -1332,7 +1360,13 @@ void GMainWindow::OnConfigure() {
1332 UpdateUITheme(); 1360 UpdateUITheme();
1333 if (UISettings::values.enable_discord_presence != old_discord_presence) 1361 if (UISettings::values.enable_discord_presence != old_discord_presence)
1334 SetDiscordEnabled(UISettings::values.enable_discord_presence); 1362 SetDiscordEnabled(UISettings::values.enable_discord_presence);
1335 game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); 1363
1364 const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
1365 if (reload) {
1366 game_list->PopulateAsync(UISettings::values.gamedir,
1367 UISettings::values.gamedir_deepscan);
1368 }
1369
1336 config->Save(); 1370 config->Save();
1337 } 1371 }
1338} 1372}
@@ -1621,7 +1655,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
1621 return; 1655 return;
1622 } 1656 }
1623 1657
1624 if (ui.action_Fullscreen->isChecked()) { 1658 if (!ui.action_Fullscreen->isChecked()) {
1625 UISettings::values.geometry = saveGeometry(); 1659 UISettings::values.geometry = saveGeometry();
1626 UISettings::values.renderwindow_geometry = render_window->saveGeometry(); 1660 UISettings::values.renderwindow_geometry = render_window->saveGeometry();
1627 } 1661 }
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 929250e8c..674e73412 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -29,6 +29,10 @@ class ProfilerWidget;
29class WaitTreeWidget; 29class WaitTreeWidget;
30enum class GameListOpenTarget; 30enum class GameListOpenTarget;
31 31
32namespace Core::Frontend {
33struct SoftwareKeyboardParameters;
34} // namespace Core::Frontend
35
32namespace FileSys { 36namespace FileSys {
33class RegisteredCacheUnion; 37class RegisteredCacheUnion;
34class VfsFilesystem; 38class VfsFilesystem;
@@ -95,6 +99,13 @@ signals:
95 // Signal that tells widgets to update icons to use the current theme 99 // Signal that tells widgets to update icons to use the current theme
96 void UpdateThemedIcons(); 100 void UpdateThemedIcons();
97 101
102 void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
103 void SoftwareKeyboardFinishedCheckDialog();
104
105public slots:
106 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
107 void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
108
98private: 109private:
99 void InitializeWidgets(); 110 void InitializeWidgets();
100 void InitializeDebugWidgets(); 111 void InitializeDebugWidgets();
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 28cf269e7..75e96387f 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -70,6 +70,8 @@
70 <addaction name="separator"/> 70 <addaction name="separator"/>
71 <addaction name="action_Load_Amiibo"/> 71 <addaction name="action_Load_Amiibo"/>
72 <addaction name="separator"/> 72 <addaction name="separator"/>
73 <addaction name="action_Open_yuzu_Folder"/>
74 <addaction name="separator"/>
73 <addaction name="action_Exit"/> 75 <addaction name="action_Exit"/>
74 </widget> 76 </widget>
75 <widget class="QMenu" name="menu_Emulation"> 77 <widget class="QMenu" name="menu_Emulation">
@@ -110,7 +112,6 @@
110 <string>&amp;Help</string> 112 <string>&amp;Help</string>
111 </property> 113 </property>
112 <addaction name="action_Report_Compatibility"/> 114 <addaction name="action_Report_Compatibility"/>
113 <addaction name="action_Open_yuzu_Folder" />
114 <addaction name="separator"/> 115 <addaction name="separator"/>
115 <addaction name="action_About"/> 116 <addaction name="action_About"/>
116 </widget> 117 </widget>
diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h
index 2e617d52a..e80aebc0a 100644
--- a/src/yuzu/ui_settings.h
+++ b/src/yuzu/ui_settings.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <atomic>
8#include <vector> 9#include <vector>
9#include <QByteArray> 10#include <QByteArray>
10#include <QString> 11#include <QString>
@@ -59,9 +60,11 @@ struct Values {
59 60
60 // Game List 61 // Game List
61 bool show_unknown; 62 bool show_unknown;
63 bool show_add_ons;
62 uint32_t icon_size; 64 uint32_t icon_size;
63 uint8_t row_1_text_id; 65 uint8_t row_1_text_id;
64 uint8_t row_2_text_id; 66 uint8_t row_2_text_id;
67 std::atomic_bool is_game_list_reload_pending{false};
65}; 68};
66 69
67extern Values values; 70extern Values values;
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index b456266a6..097c1fbe3 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -65,30 +65,271 @@ static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs>
65 }, 65 },
66}}; 66}};
67 67
68static const std::array<int, Settings::NativeMouseButton::NumMouseButtons> default_mouse_buttons = {
69 SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_APOSTROPHE,
70 SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS,
71};
72
73static const std::array<int, 0x8A> keyboard_keys = {
74 0,
75 0,
76 0,
77 0,
78 SDL_SCANCODE_A,
79 SDL_SCANCODE_B,
80 SDL_SCANCODE_C,
81 SDL_SCANCODE_D,
82 SDL_SCANCODE_E,
83 SDL_SCANCODE_F,
84 SDL_SCANCODE_G,
85 SDL_SCANCODE_H,
86 SDL_SCANCODE_I,
87 SDL_SCANCODE_J,
88 SDL_SCANCODE_K,
89 SDL_SCANCODE_L,
90 SDL_SCANCODE_M,
91 SDL_SCANCODE_N,
92 SDL_SCANCODE_O,
93 SDL_SCANCODE_P,
94 SDL_SCANCODE_Q,
95 SDL_SCANCODE_R,
96 SDL_SCANCODE_S,
97 SDL_SCANCODE_T,
98 SDL_SCANCODE_U,
99 SDL_SCANCODE_V,
100 SDL_SCANCODE_W,
101 SDL_SCANCODE_X,
102 SDL_SCANCODE_Y,
103 SDL_SCANCODE_Z,
104 SDL_SCANCODE_1,
105 SDL_SCANCODE_2,
106 SDL_SCANCODE_3,
107 SDL_SCANCODE_4,
108 SDL_SCANCODE_5,
109 SDL_SCANCODE_6,
110 SDL_SCANCODE_7,
111 SDL_SCANCODE_8,
112 SDL_SCANCODE_9,
113 SDL_SCANCODE_0,
114 SDL_SCANCODE_RETURN,
115 SDL_SCANCODE_ESCAPE,
116 SDL_SCANCODE_BACKSPACE,
117 SDL_SCANCODE_TAB,
118 SDL_SCANCODE_SPACE,
119 SDL_SCANCODE_MINUS,
120 SDL_SCANCODE_EQUALS,
121 SDL_SCANCODE_LEFTBRACKET,
122 SDL_SCANCODE_RIGHTBRACKET,
123 SDL_SCANCODE_BACKSLASH,
124 0,
125 SDL_SCANCODE_SEMICOLON,
126 SDL_SCANCODE_APOSTROPHE,
127 SDL_SCANCODE_GRAVE,
128 SDL_SCANCODE_COMMA,
129 SDL_SCANCODE_PERIOD,
130 SDL_SCANCODE_SLASH,
131 SDL_SCANCODE_CAPSLOCK,
132
133 SDL_SCANCODE_F1,
134 SDL_SCANCODE_F2,
135 SDL_SCANCODE_F3,
136 SDL_SCANCODE_F4,
137 SDL_SCANCODE_F5,
138 SDL_SCANCODE_F6,
139 SDL_SCANCODE_F7,
140 SDL_SCANCODE_F8,
141 SDL_SCANCODE_F9,
142 SDL_SCANCODE_F10,
143 SDL_SCANCODE_F11,
144 SDL_SCANCODE_F12,
145
146 0,
147 SDL_SCANCODE_SCROLLLOCK,
148 SDL_SCANCODE_PAUSE,
149 SDL_SCANCODE_INSERT,
150 SDL_SCANCODE_HOME,
151 SDL_SCANCODE_PAGEUP,
152 SDL_SCANCODE_DELETE,
153 SDL_SCANCODE_END,
154 SDL_SCANCODE_PAGEDOWN,
155 SDL_SCANCODE_RIGHT,
156 SDL_SCANCODE_LEFT,
157 SDL_SCANCODE_DOWN,
158 SDL_SCANCODE_UP,
159
160 SDL_SCANCODE_NUMLOCKCLEAR,
161 SDL_SCANCODE_KP_DIVIDE,
162 SDL_SCANCODE_KP_MULTIPLY,
163 SDL_SCANCODE_KP_MINUS,
164 SDL_SCANCODE_KP_PLUS,
165 SDL_SCANCODE_KP_ENTER,
166 SDL_SCANCODE_KP_1,
167 SDL_SCANCODE_KP_2,
168 SDL_SCANCODE_KP_3,
169 SDL_SCANCODE_KP_4,
170 SDL_SCANCODE_KP_5,
171 SDL_SCANCODE_KP_6,
172 SDL_SCANCODE_KP_7,
173 SDL_SCANCODE_KP_8,
174 SDL_SCANCODE_KP_9,
175 SDL_SCANCODE_KP_0,
176 SDL_SCANCODE_KP_PERIOD,
177
178 0,
179 0,
180 SDL_SCANCODE_POWER,
181 SDL_SCANCODE_KP_EQUALS,
182
183 SDL_SCANCODE_F13,
184 SDL_SCANCODE_F14,
185 SDL_SCANCODE_F15,
186 SDL_SCANCODE_F16,
187 SDL_SCANCODE_F17,
188 SDL_SCANCODE_F18,
189 SDL_SCANCODE_F19,
190 SDL_SCANCODE_F20,
191 SDL_SCANCODE_F21,
192 SDL_SCANCODE_F22,
193 SDL_SCANCODE_F23,
194 SDL_SCANCODE_F24,
195
196 0,
197 SDL_SCANCODE_HELP,
198 SDL_SCANCODE_MENU,
199 0,
200 0,
201 0,
202 0,
203 0,
204 0,
205 0,
206 0,
207 0,
208 0,
209 0,
210 0,
211 SDL_SCANCODE_KP_COMMA,
212 SDL_SCANCODE_KP_LEFTPAREN,
213 SDL_SCANCODE_KP_RIGHTPAREN,
214 0,
215 0,
216 0,
217 0,
218};
219
220static const std::array<int, 8> keyboard_mods{
221 SDL_SCANCODE_LCTRL, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_LALT, SDL_SCANCODE_LGUI,
222 SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI,
223};
224
68void Config::ReadValues() { 225void Config::ReadValues() {
69 // Controls 226 // Controls
227 for (std::size_t p = 0; p < Settings::values.players.size(); ++p) {
228 const auto group = fmt::format("ControlsP{}", p);
229 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
230 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
231 Settings::values.players[p].buttons[i] =
232 sdl2_config->Get(group, Settings::NativeButton::mapping[i], default_param);
233 if (Settings::values.players[p].buttons[i].empty())
234 Settings::values.players[p].buttons[i] = default_param;
235 }
236
237 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
238 std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
239 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
240 default_analogs[i][3], default_analogs[i][4], 0.5f);
241 Settings::values.players[p].analogs[i] =
242 sdl2_config->Get(group, Settings::NativeAnalog::mapping[i], default_param);
243 if (Settings::values.players[p].analogs[i].empty())
244 Settings::values.players[p].analogs[i] = default_param;
245 }
246 }
247
248 Settings::values.mouse_enabled =
249 sdl2_config->GetBoolean("ControlsGeneral", "mouse_enabled", false);
250 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
251 std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
252 Settings::values.mouse_buttons[i] = sdl2_config->Get(
253 "ControlsGeneral", std::string("mouse_") + Settings::NativeMouseButton::mapping[i],
254 default_param);
255 if (Settings::values.mouse_buttons[i].empty())
256 Settings::values.mouse_buttons[i] = default_param;
257 }
258
259 Settings::values.motion_device = sdl2_config->Get(
260 "ControlsGeneral", "motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01");
261
262 Settings::values.keyboard_enabled =
263 sdl2_config->GetBoolean("ControlsGeneral", "keyboard_enabled", false);
264
265 Settings::values.debug_pad_enabled =
266 sdl2_config->GetBoolean("ControlsGeneral", "debug_pad_enabled", false);
70 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { 267 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
71 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); 268 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
72 Settings::values.buttons[i] = 269 Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
73 sdl2_config->Get("Controls", Settings::NativeButton::mapping[i], default_param); 270 "ControlsGeneral", std::string("debug_pad_") + Settings::NativeButton::mapping[i],
74 if (Settings::values.buttons[i].empty()) 271 default_param);
75 Settings::values.buttons[i] = default_param; 272 if (Settings::values.debug_pad_buttons[i].empty())
273 Settings::values.debug_pad_buttons[i] = default_param;
76 } 274 }
77 275
78 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { 276 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
79 std::string default_param = InputCommon::GenerateAnalogParamFromKeys( 277 std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
80 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], 278 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
81 default_analogs[i][3], default_analogs[i][4], 0.5f); 279 default_analogs[i][3], default_analogs[i][4], 0.5f);
82 Settings::values.analogs[i] = 280 Settings::values.debug_pad_analogs[i] = sdl2_config->Get(
83 sdl2_config->Get("Controls", Settings::NativeAnalog::mapping[i], default_param); 281 "ControlsGeneral", std::string("debug_pad_") + Settings::NativeAnalog::mapping[i],
84 if (Settings::values.analogs[i].empty()) 282 default_param);
85 Settings::values.analogs[i] = default_param; 283 if (Settings::values.debug_pad_analogs[i].empty())
284 Settings::values.debug_pad_analogs[i] = default_param;
86 } 285 }
87 286
88 Settings::values.motion_device = sdl2_config->Get( 287 Settings::values.touchscreen.enabled =
89 "Controls", "motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01"); 288 sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
90 Settings::values.touch_device = 289 Settings::values.touchscreen.device =
91 sdl2_config->Get("Controls", "touch_device", "engine:emu_window"); 290 sdl2_config->Get("ControlsGeneral", "touch_device", "engine:emu_window");
291 Settings::values.touchscreen.finger =
292 sdl2_config->GetInteger("ControlsGeneral", "touch_finger", 0);
293 Settings::values.touchscreen.rotation_angle =
294 sdl2_config->GetInteger("ControlsGeneral", "touch_angle", 0);
295 Settings::values.touchscreen.diameter_x =
296 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
297 Settings::values.touchscreen.diameter_y =
298 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
299
300 std::transform(keyboard_keys.begin(), keyboard_keys.end(),
301 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
302 std::transform(keyboard_mods.begin(), keyboard_mods.end(),
303 Settings::values.keyboard_keys.begin() +
304 Settings::NativeKeyboard::LeftControlKey,
305 InputCommon::GenerateKeyboardParam);
306 std::transform(keyboard_mods.begin(), keyboard_mods.end(),
307 Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
308
309 // Data Storage
310 Settings::values.use_virtual_sd =
311 sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
312 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir,
313 sdl2_config->Get("Data Storage", "nand_directory",
314 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)));
315 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir,
316 sdl2_config->Get("Data Storage", "sdmc_directory",
317 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
318
319 // System
320 Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
321 Settings::values.enable_nfc = sdl2_config->GetBoolean("System", "enable_nfc", true);
322 const auto size = sdl2_config->GetInteger("System", "users_size", 0);
323
324 Settings::values.current_user = std::clamp<int>(
325 sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1);
326
327 const auto enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
328 if (enabled) {
329 Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0);
330 } else {
331 Settings::values.rng_seed = std::nullopt;
332 }
92 333
93 // Core 334 // Core
94 Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); 335 Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true);
@@ -114,23 +355,7 @@ void Config::ReadValues() {
114 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto"); 355 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
115 Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1); 356 Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1);
116 357
117 // Data Storage 358 Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1);
118 Settings::values.use_virtual_sd =
119 sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
120 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir,
121 sdl2_config->Get("Data Storage", "nand_directory",
122 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)));
123 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir,
124 sdl2_config->Get("Data Storage", "sdmc_directory",
125 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
126
127 // System
128 Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
129 Settings::values.enable_nfc = sdl2_config->GetBoolean("System", "enable_nfc", true);
130 const auto size = sdl2_config->GetInteger("System", "users_size", 0);
131
132 Settings::values.current_user = std::clamp<int>(
133 sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1);
134 359
135 // Miscellaneous 360 // Miscellaneous
136 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); 361 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
@@ -141,6 +366,8 @@ void Config::ReadValues() {
141 Settings::values.gdbstub_port = 366 Settings::values.gdbstub_port =
142 static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689)); 367 static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689));
143 Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", ""); 368 Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", "");
369 Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false);
370 Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false);
144 371
145 // Web Service 372 // Web Service
146 Settings::values.enable_telemetry = 373 Settings::values.enable_telemetry =
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index e0b223cd6..d73669f36 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -178,6 +178,11 @@ use_docked_mode =
178# 1 (default): Yes, 0 : No 178# 1 (default): Yes, 0 : No
179enable_nfc = 179enable_nfc =
180 180
181# Sets the seed for the RNG generator built into the switch
182# rng_seed will be ignored and randomly generated if rng_seed_enabled is false
183rng_seed_enabled =
184rng_seed =
185
181# Sets the account username, max length is 32 characters 186# Sets the account username, max length is 32 characters
182# yuzu (default) 187# yuzu (default)
183username = yuzu 188username = yuzu
@@ -201,6 +206,10 @@ log_filter = *:Trace
201# Port for listening to GDB connections. 206# Port for listening to GDB connections.
202use_gdbstub=false 207use_gdbstub=false
203gdbstub_port=24689 208gdbstub_port=24689
209# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them
210dump_exefs=false
211# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them
212dump_nso=false
204 213
205[WebService] 214[WebService]
206# Whether or not to enable telemetry 215# Whether or not to enable telemetry
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index a9ad92a80..a557f2884 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -111,32 +111,20 @@ void EmuWindow_SDL2::Fullscreen() {
111bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { 111bool EmuWindow_SDL2::SupportsRequiredGLExtensions() {
112 std::vector<std::string> unsupported_ext; 112 std::vector<std::string> unsupported_ext;
113 113
114 if (!GLAD_GL_ARB_program_interface_query) 114 if (!GLAD_GL_ARB_direct_state_access)
115 unsupported_ext.push_back("ARB_program_interface_query"); 115 unsupported_ext.push_back("ARB_direct_state_access");
116 if (!GLAD_GL_ARB_separate_shader_objects)
117 unsupported_ext.push_back("ARB_separate_shader_objects");
118 if (!GLAD_GL_ARB_vertex_attrib_binding)
119 unsupported_ext.push_back("ARB_vertex_attrib_binding");
120 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) 116 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
121 unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); 117 unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev");
122 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) 118 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
123 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); 119 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge");
124 if (!GLAD_GL_ARB_base_instance)
125 unsupported_ext.push_back("ARB_base_instance");
126 if (!GLAD_GL_ARB_texture_storage)
127 unsupported_ext.push_back("ARB_texture_storage");
128 if (!GLAD_GL_ARB_multi_bind) 120 if (!GLAD_GL_ARB_multi_bind)
129 unsupported_ext.push_back("ARB_multi_bind"); 121 unsupported_ext.push_back("ARB_multi_bind");
130 if (!GLAD_GL_ARB_copy_image)
131 unsupported_ext.push_back("ARB_copy_image");
132 122
133 // Extensions required to support some texture formats. 123 // Extensions required to support some texture formats.
134 if (!GLAD_GL_EXT_texture_compression_s3tc) 124 if (!GLAD_GL_EXT_texture_compression_s3tc)
135 unsupported_ext.push_back("EXT_texture_compression_s3tc"); 125 unsupported_ext.push_back("EXT_texture_compression_s3tc");
136 if (!GLAD_GL_ARB_texture_compression_rgtc) 126 if (!GLAD_GL_ARB_texture_compression_rgtc)
137 unsupported_ext.push_back("ARB_texture_compression_rgtc"); 127 unsupported_ext.push_back("ARB_texture_compression_rgtc");
138 if (!GLAD_GL_ARB_texture_compression_bptc)
139 unsupported_ext.push_back("ARB_texture_compression_bptc");
140 if (!GLAD_GL_ARB_depth_buffer_float) 128 if (!GLAD_GL_ARB_depth_buffer_float)
141 unsupported_ext.push_back("ARB_depth_buffer_float"); 129 unsupported_ext.push_back("ARB_depth_buffer_float");
142 130
@@ -157,7 +145,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
157 exit(1); 145 exit(1);
158 } 146 }
159 147
160 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 148 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
161 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 149 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
162 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 150 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
163 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 151 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);