summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.gitmodules9
-rw-r--r--CMakeLists.txt18
-rw-r--r--CMakeModules/CopyYuzuQt5Deps.cmake3
-rw-r--r--appveyor.yml4
-rw-r--r--dist/qt_themes/qdarkstyle/LICENSE.md183
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss607
-rw-r--r--externals/CMakeLists.txt16
m---------externals/catch0
m---------externals/cubeb0
m---------externals/dynarmic0
-rw-r--r--externals/glad/include/glad/glad.h23
-rw-r--r--externals/glad/src/glad.c6385
m---------externals/mbedtls0
m---------externals/opus0
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/audio_core/CMakeLists.txt31
-rw-r--r--src/audio_core/algorithm/filter.cpp79
-rw-r--r--src/audio_core/algorithm/filter.h62
-rw-r--r--src/audio_core/algorithm/interpolate.cpp71
-rw-r--r--src/audio_core/algorithm/interpolate.h43
-rw-r--r--src/audio_core/audio_out.cpp58
-rw-r--r--src/audio_core/audio_out.h43
-rw-r--r--src/audio_core/audio_renderer.cpp249
-rw-r--r--src/audio_core/audio_renderer.h211
-rw-r--r--src/audio_core/buffer.h45
-rw-r--r--src/audio_core/codec.cpp77
-rw-r--r--src/audio_core/codec.h44
-rw-r--r--src/audio_core/cubeb_sink.cpp206
-rw-r--r--src/audio_core/cubeb_sink.h32
-rw-r--r--src/audio_core/null_sink.h27
-rw-r--r--src/audio_core/sink.h31
-rw-r--r--src/audio_core/sink_details.cpp44
-rw-r--r--src/audio_core/sink_details.h35
-rw-r--r--src/audio_core/sink_stream.h32
-rw-r--r--src/audio_core/stream.cpp127
-rw-r--r--src/audio_core/stream.h102
-rw-r--r--src/common/CMakeLists.txt4
-rw-r--r--src/common/alignment.h4
-rw-r--r--src/common/bit_set.h2
-rw-r--r--src/common/break_points.cpp90
-rw-r--r--src/common/break_points.h49
-rw-r--r--src/common/color.h50
-rw-r--r--src/common/common_funcs.h4
-rw-r--r--src/common/common_paths.h1
-rw-r--r--src/common/file_util.cpp36
-rw-r--r--src/common/file_util.h35
-rw-r--r--src/common/hash.h4
-rw-r--r--src/common/hex_util.cpp31
-rw-r--r--src/common/hex_util.h41
-rw-r--r--src/common/logging/backend.cpp30
-rw-r--r--src/common/logging/log.h25
-rw-r--r--src/common/logging/text_formatter.h1
-rw-r--r--src/common/math_util.h10
-rw-r--r--src/common/misc.cpp2
-rw-r--r--src/common/string_util.cpp8
-rw-r--r--src/common/swap.h2
-rw-r--r--src/common/thread_queue_list.h10
-rw-r--r--src/common/threadsafe_queue.h32
-rw-r--r--src/common/timer.cpp95
-rw-r--r--src/common/timer.h17
-rw-r--r--src/common/vector_math.h362
-rw-r--r--src/common/x64/xbyak_abi.h20
-rw-r--r--src/common/x64/xbyak_util.h8
-rw-r--r--src/core/CMakeLists.txt112
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp36
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp2
-rw-r--r--src/core/core.cpp89
-rw-r--r--src/core/core.h91
-rw-r--r--src/core/core_cpu.cpp5
-rw-r--r--src/core/core_cpu.h2
-rw-r--r--src/core/core_timing.cpp26
-rw-r--r--src/core/core_timing.h12
-rw-r--r--src/core/crypto/aes_util.cpp115
-rw-r--r--src/core/crypto/aes_util.h64
-rw-r--r--src/core/crypto/ctr_encryption_layer.cpp56
-rw-r--r--src/core/crypto/ctr_encryption_layer.h33
-rw-r--r--src/core/crypto/encryption_layer.cpp42
-rw-r--r--src/core/crypto/encryption_layer.h33
-rw-r--r--src/core/crypto/key_manager.cpp177
-rw-r--r--src/core/crypto/key_manager.h117
-rw-r--r--src/core/crypto/sha_util.cpp5
-rw-r--r--src/core/crypto/sha_util.h20
-rw-r--r--src/core/file_sys/bis_factory.cpp31
-rw-r--r--src/core/file_sys/bis_factory.h30
-rw-r--r--src/core/file_sys/card_image.cpp162
-rw-r--r--src/core/file_sys/card_image.h97
-rw-r--r--src/core/file_sys/content_archive.cpp296
-rw-r--r--src/core/file_sys/content_archive.h33
-rw-r--r--src/core/file_sys/control_metadata.cpp2
-rw-r--r--src/core/file_sys/control_metadata.h8
-rw-r--r--src/core/file_sys/directory.h12
-rw-r--r--src/core/file_sys/nca_metadata.cpp131
-rw-r--r--src/core/file_sys/nca_metadata.h111
-rw-r--r--src/core/file_sys/partition_filesystem.cpp13
-rw-r--r--src/core/file_sys/partition_filesystem.h2
-rw-r--r--src/core/file_sys/program_metadata.cpp12
-rw-r--r--src/core/file_sys/program_metadata.h2
-rw-r--r--src/core/file_sys/registered_cache.cpp478
-rw-r--r--src/core/file_sys/registered_cache.h124
-rw-r--r--src/core/file_sys/romfs.cpp124
-rw-r--r--src/core/file_sys/romfs.h35
-rw-r--r--src/core/file_sys/savedata_factory.h1
-rw-r--r--src/core/file_sys/vfs.cpp191
-rw-r--r--src/core/file_sys/vfs.h103
-rw-r--r--src/core/file_sys/vfs_concat.cpp94
-rw-r--r--src/core/file_sys/vfs_concat.h41
-rw-r--r--src/core/file_sys/vfs_offset.cpp7
-rw-r--r--src/core/file_sys/vfs_offset.h6
-rw-r--r--src/core/file_sys/vfs_real.cpp353
-rw-r--r--src/core/file_sys/vfs_real.h58
-rw-r--r--src/core/file_sys/vfs_vector.cpp86
-rw-r--r--src/core/file_sys/vfs_vector.h45
-rw-r--r--src/core/frontend/emu_window.cpp4
-rw-r--r--src/core/frontend/emu_window.h10
-rw-r--r--src/core/gdbstub/gdbstub.cpp175
-rw-r--r--src/core/gdbstub/gdbstub.h8
-rw-r--r--src/core/hle/ipc_helpers.h7
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp38
-rw-r--r--src/core/hle/kernel/address_arbiter.h4
-rw-r--r--src/core/hle/kernel/client_port.cpp17
-rw-r--r--src/core/hle/kernel/client_port.h16
-rw-r--r--src/core/hle/kernel/client_session.cpp2
-rw-r--r--src/core/hle/kernel/client_session.h2
-rw-r--r--src/core/hle/kernel/event.cpp4
-rw-r--r--src/core/hle/kernel/event.h14
-rw-r--r--src/core/hle/kernel/handle_table.cpp1
-rw-r--r--src/core/hle/kernel/handle_table.h2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp9
-rw-r--r--src/core/hle/kernel/hle_ipc.h5
-rw-r--r--src/core/hle/kernel/kernel.cpp10
-rw-r--r--src/core/hle/kernel/kernel.h112
-rw-r--r--src/core/hle/kernel/memory.cpp92
-rw-r--r--src/core/hle/kernel/memory.h31
-rw-r--r--src/core/hle/kernel/mutex.cpp7
-rw-r--r--src/core/hle/kernel/mutex.h8
-rw-r--r--src/core/hle/kernel/object.cpp35
-rw-r--r--src/core/hle/kernel/object.h101
-rw-r--r--src/core/hle/kernel/object_address_table.cpp36
-rw-r--r--src/core/hle/kernel/object_address_table.h62
-rw-r--r--src/core/hle/kernel/process.cpp84
-rw-r--r--src/core/hle/kernel/process.h64
-rw-r--r--src/core/hle/kernel/resource_limit.h2
-rw-r--r--src/core/hle/kernel/scheduler.cpp6
-rw-r--r--src/core/hle/kernel/scheduler.h6
-rw-r--r--src/core/hle/kernel/server_port.cpp2
-rw-r--r--src/core/hle/kernel/server_port.h3
-rw-r--r--src/core/hle/kernel/server_session.cpp14
-rw-r--r--src/core/hle/kernel/server_session.h13
-rw-r--r--src/core/hle/kernel/session.h2
-rw-r--r--src/core/hle/kernel/shared_memory.cpp37
-rw-r--r--src/core/hle/kernel/shared_memory.h8
-rw-r--r--src/core/hle/kernel/svc.cpp17
-rw-r--r--src/core/hle/kernel/thread.cpp90
-rw-r--r--src/core/hle/kernel/thread.h15
-rw-r--r--src/core/hle/kernel/timer.cpp2
-rw-r--r--src/core/hle/kernel/timer.h24
-rw-r--r--src/core/hle/kernel/vm_manager.cpp36
-rw-r--r--src/core/hle/kernel/vm_manager.h8
-rw-r--r--src/core/hle/kernel/wait_object.cpp5
-rw-r--r--src/core/hle/kernel/wait_object.h2
-rw-r--r--src/core/hle/romfs.cpp102
-rw-r--r--src/core/hle/romfs.h22
-rw-r--r--src/core/hle/service/acc/acc.cpp60
-rw-r--r--src/core/hle/service/acc/acc.h1
-rw-r--r--src/core/hle/service/acc/acc_su.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp52
-rw-r--r--src/core/hle/service/am/am.h5
-rw-r--r--src/core/hle/service/am/idle.cpp24
-rw-r--r--src/core/hle/service/am/idle.h16
-rw-r--r--src/core/hle/service/am/omm.cpp42
-rw-r--r--src/core/hle/service/am/omm.h16
-rw-r--r--src/core/hle/service/am/spsm.cpp30
-rw-r--r--src/core/hle/service/am/spsm.h16
-rw-r--r--src/core/hle/service/apm/apm.cpp1
-rw-r--r--src/core/hle/service/apm/interface.cpp25
-rw-r--r--src/core/hle/service/apm/interface.h8
-rw-r--r--src/core/hle/service/arp/arp.cpp75
-rw-r--r--src/core/hle/service/arp/arp.h16
-rw-r--r--src/core/hle/service/audio/audctl.cpp45
-rw-r--r--src/core/hle/service/audio/audctl.h16
-rw-r--r--src/core/hle/service/audio/auddbg.cpp20
-rw-r--r--src/core/hle/service/audio/auddbg.h16
-rw-r--r--src/core/hle/service/audio/audin_a.cpp22
-rw-r--r--src/core/hle/service/audio/audin_a.h16
-rw-r--r--src/core/hle/service/audio/audio.cpp16
-rw-r--r--src/core/hle/service/audio/audout_a.cpp24
-rw-r--r--src/core/hle/service/audio/audout_a.h16
-rw-r--r--src/core/hle/service/audio/audout_u.cpp199
-rw-r--r--src/core/hle/service/audio/audout_u.h24
-rw-r--r--src/core/hle/service/audio/audrec_a.cpp20
-rw-r--r--src/core/hle/service/audio/audrec_a.h16
-rw-r--r--src/core/hle/service/audio/audren_a.cpp26
-rw-r--r--src/core/hle/service/audio/audren_a.h16
-rw-r--r--src/core/hle/service/audio/audren_u.cpp250
-rw-r--r--src/core/hle/service/audio/audren_u.h20
-rw-r--r--src/core/hle/service/audio/hwopus.cpp135
-rw-r--r--src/core/hle/service/audio/hwopus.h1
-rw-r--r--src/core/hle/service/bpc/bpc.cpp57
-rw-r--r--src/core/hle/service/bpc/bpc.h15
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp72
-rw-r--r--src/core/hle/service/btdrv/btdrv.h16
-rw-r--r--src/core/hle/service/btm/btm.cpp121
-rw-r--r--src/core/hle/service/btm/btm.h15
-rw-r--r--src/core/hle/service/caps/caps.cpp152
-rw-r--r--src/core/hle/service/caps/caps.h15
-rw-r--r--src/core/hle/service/fgm/fgm.cpp75
-rw-r--r--src/core/hle/service/fgm/fgm.h15
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp39
-rw-r--r--src/core/hle/service/filesystem/filesystem.h10
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.cpp22
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.h16
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.cpp23
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.h16
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp9
-rw-r--r--src/core/hle/service/friend/friend.cpp104
-rw-r--r--src/core/hle/service/grc/grc.cpp31
-rw-r--r--src/core/hle/service/grc/grc.h15
-rw-r--r--src/core/hle/service/hid/hid.cpp261
-rw-r--r--src/core/hle/service/hid/irs.cpp49
-rw-r--r--src/core/hle/service/hid/irs.h21
-rw-r--r--src/core/hle/service/hid/xcd.cpp37
-rw-r--r--src/core/hle/service/hid/xcd.h16
-rw-r--r--src/core/hle/service/lbl/lbl.cpp90
-rw-r--r--src/core/hle/service/lbl/lbl.h15
-rw-r--r--src/core/hle/service/ldn/ldn.cpp142
-rw-r--r--src/core/hle/service/ldn/ldn.h16
-rw-r--r--src/core/hle/service/lm/lm.cpp30
-rw-r--r--src/core/hle/service/mig/mig.cpp34
-rw-r--r--src/core/hle/service/mig/mig.h15
-rw-r--r--src/core/hle/service/mii/mii.cpp107
-rw-r--r--src/core/hle/service/mii/mii.h15
-rw-r--r--src/core/hle/service/mm/mm_u.cpp83
-rw-r--r--src/core/hle/service/mm/mm_u.h15
-rw-r--r--src/core/hle/service/ncm/ncm.cpp59
-rw-r--r--src/core/hle/service/ncm/ncm.h15
-rw-r--r--src/core/hle/service/nfc/nfc.cpp222
-rw-r--r--src/core/hle/service/nfc/nfc.h15
-rw-r--r--src/core/hle/service/nim/nim.cpp124
-rw-r--r--src/core/hle/service/nim/nim.h15
-rw-r--r--src/core/hle/service/ns/ns.cpp447
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp17
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp34
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h36
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp34
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h36
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp2
-rw-r--r--src/core/hle/service/nvdrv/interface.h1
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp13
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h8
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp7
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp20
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h17
-rw-r--r--src/core/hle/service/pcie/pcie.cpp64
-rw-r--r--src/core/hle/service/pcie/pcie.h15
-rw-r--r--src/core/hle/service/pcv/pcv.cpp84
-rw-r--r--src/core/hle/service/pcv/pcv.h15
-rw-r--r--src/core/hle/service/psc/psc.cpp77
-rw-r--r--src/core/hle/service/psc/psc.h15
-rw-r--r--src/core/hle/service/service.cpp48
-rw-r--r--src/core/hle/service/service.h10
-rw-r--r--src/core/hle/service/set/set.cpp15
-rw-r--r--src/core/hle/service/set/set.h2
-rw-r--r--src/core/hle/service/sm/controller.cpp4
-rw-r--r--src/core/hle/service/sm/sm.h8
-rw-r--r--src/core/hle/service/sockets/bsd.cpp22
-rw-r--r--src/core/hle/service/sockets/bsd.h5
-rw-r--r--src/core/hle/service/sockets/ethc.cpp38
-rw-r--r--src/core/hle/service/sockets/ethc.h21
-rw-r--r--src/core/hle/service/sockets/sockets.cpp7
-rw-r--r--src/core/hle/service/time/time.cpp4
-rw-r--r--src/core/hle/service/usb/usb.cpp238
-rw-r--r--src/core/hle/service/usb/usb.h15
-rw-r--r--src/core/hle/service/wlan/wlan.cpp172
-rw-r--r--src/core/hle/service/wlan/wlan.h15
-rw-r--r--src/core/hw/aes/ccm.cpp28
-rw-r--r--src/core/hw/hw.cpp96
-rw-r--r--src/core/hw/hw.h50
-rw-r--r--src/core/hw/lcd.cpp67
-rw-r--r--src/core/hw/lcd.h86
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp86
-rw-r--r--src/core/loader/deconstructed_rom_directory.h13
-rw-r--r--src/core/loader/elf.cpp9
-rw-r--r--src/core/loader/loader.cpp68
-rw-r--r--src/core/loader/loader.h67
-rw-r--r--src/core/loader/nca.cpp81
-rw-r--r--src/core/loader/nca.h19
-rw-r--r--src/core/loader/nro.cpp13
-rw-r--r--src/core/loader/nro.h2
-rw-r--r--src/core/loader/nso.cpp3
-rw-r--r--src/core/loader/nso.h2
-rw-r--r--src/core/loader/xci.cpp100
-rw-r--r--src/core/loader/xci.h53
-rw-r--r--src/core/memory.cpp146
-rw-r--r--src/core/memory.h111
-rw-r--r--src/core/perf_stats.cpp17
-rw-r--r--src/core/perf_stats.h8
-rw-r--r--src/core/settings.cpp14
-rw-r--r--src/core/settings.h9
-rw-r--r--src/input_common/keyboard.cpp5
-rw-r--r--src/input_common/motion_emu.cpp2
-rw-r--r--src/input_common/sdl/sdl.cpp20
-rw-r--r--src/tests/CMakeLists.txt1
-rw-r--r--src/tests/common/param_package.cpp2
-rw-r--r--src/tests/core/core_timing.cpp2
-rw-r--r--src/tests/core/memory/memory.cpp56
-rw-r--r--src/tests/glad.cpp2
-rw-r--r--src/tests/tests.cpp2
-rw-r--r--src/video_core/command_processor.cpp8
-rw-r--r--src/video_core/command_processor.h3
-rw-r--r--src/video_core/engines/maxwell_3d.cpp39
-rw-r--r--src/video_core/engines/maxwell_3d.h39
-rw-r--r--src/video_core/engines/shader_bytecode.h54
-rw-r--r--src/video_core/gpu.cpp57
-rw-r--r--src/video_core/gpu.h34
-rw-r--r--src/video_core/macro_interpreter.cpp4
-rw-r--r--src/video_core/macro_interpreter.h4
-rw-r--r--src/video_core/memory_manager.cpp36
-rw-r--r--src/video_core/renderer_base.cpp29
-rw-r--r--src/video_core/renderer_base.h45
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp243
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h31
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp239
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h425
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp296
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp24
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h11
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_state.h15
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp201
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.h42
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h50
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp38
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h19
-rw-r--r--src/video_core/textures/decoders.cpp88
-rw-r--r--src/video_core/textures/decoders.h4
-rw-r--r--src/video_core/video_core.cpp30
-rw-r--r--src/video_core/video_core.h31
-rw-r--r--src/yuzu/CMakeLists.txt6
-rw-r--r--src/yuzu/about_dialog.cpp7
-rw-r--r--src/yuzu/about_dialog.h2
-rw-r--r--src/yuzu/aboutdialog.ui4
-rw-r--r--src/yuzu/bootmanager.h4
-rw-r--r--src/yuzu/configuration/config.cpp33
-rw-r--r--src/yuzu/configuration/configure.ui32
-rw-r--r--src/yuzu/configuration/configure_audio.cpp90
-rw-r--r--src/yuzu/configuration/configure_audio.h31
-rw-r--r--src/yuzu/configuration/configure_audio.ui130
-rw-r--r--src/yuzu/configuration/configure_debug.cpp3
-rw-r--r--src/yuzu/configuration/configure_debug.ui7
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp9
-rw-r--r--src/yuzu/configuration/configure_dialog.h4
-rw-r--r--src/yuzu/configuration/configure_gamelist.cpp63
-rw-r--r--src/yuzu/configuration/configure_gamelist.h28
-rw-r--r--src/yuzu/configuration/configure_gamelist.ui126
-rw-r--r--src/yuzu/configuration/configure_general.cpp7
-rw-r--r--src/yuzu/configuration/configure_general.h4
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp3
-rw-r--r--src/yuzu/configuration/configure_input.cpp2
-rw-r--r--src/yuzu/configuration/configure_system.cpp10
-rw-r--r--src/yuzu/configuration/configure_system.ui29
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp6
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoint_observer.h8
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints.cpp26
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints.h11
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints_p.h1
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp43
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.h15
-rw-r--r--src/yuzu/debugger/wait_tree.cpp10
-rw-r--r--src/yuzu/debugger/wait_tree.h6
-rw-r--r--src/yuzu/game_list.cpp175
-rw-r--r--src/yuzu/game_list.h3
-rw-r--r--src/yuzu/game_list_p.h66
-rw-r--r--src/yuzu/hotkeys.cpp67
-rw-r--r--src/yuzu/hotkeys.h107
-rw-r--r--src/yuzu/main.cpp327
-rw-r--r--src/yuzu/main.h9
-rw-r--r--src/yuzu/main.ui7
-rw-r--r--src/yuzu/ui_settings.h6
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/default_ini.h24
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h2
-rw-r--r--src/yuzu_cmd/yuzu.cpp29
397 files changed, 17535 insertions, 7573 deletions
diff --git a/.gitignore b/.gitignore
index 5ec0d110b..f704edeb8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,7 +11,7 @@ src/common/scm_rev.cpp
.idea/
.vs/
.vscode/
-CMakeLists.txt.user
+CMakeLists.txt.user*
# *nix related
# Common convention for backup or temporary files
diff --git a/.gitmodules b/.gitmodules
index a08850c1a..4f4e8690b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,6 +7,9 @@
[submodule "catch"]
path = externals/catch
url = https://github.com/philsquared/Catch.git
+[submodule "cubeb"]
+ path = externals/cubeb
+ url = https://github.com/kinetiknz/cubeb.git
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/MerryMage/dynarmic.git
@@ -22,3 +25,9 @@
[submodule "unicorn"]
path = externals/unicorn
url = https://github.com/yuzu-emu/unicorn
+[submodule "mbedtls"]
+ path = externals/mbedtls
+ url = https://github.com/DarkLordZach/mbedtls
+[submodule "opus"]
+ path = externals/opus
+ url = https://github.com/ogniK5377/opus.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 86d2423ed..59c610732 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
-# CMake 3.6 required for FindBoost to define IMPORTED libs properly on unknown Boost versions
-cmake_minimum_required(VERSION 3.6)
+cmake_minimum_required(VERSION 3.7)
+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
include(DownloadExternals)
@@ -17,6 +17,8 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "EN
option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON)
+option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
+
if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit)
message(STATUS "Copying pre-commit hook")
file(COPY hooks/pre-commit
@@ -64,10 +66,12 @@ if (NOT ENABLE_GENERIC)
detect_architecture("_M_AMD64" x86_64)
detect_architecture("_M_IX86" x86)
detect_architecture("_M_ARM" ARM)
+ detect_architecture("_M_ARM64" ARM64)
else()
detect_architecture("__x86_64__" x86_64)
detect_architecture("__i386__" x86)
detect_architecture("__arm__" ARM)
+ detect_architecture("__aarch64__" ARM64)
endif()
endif()
@@ -185,8 +189,8 @@ find_package(Threads REQUIRED)
if (ENABLE_SDL2)
if (YUZU_USE_BUNDLED_SDL2)
# Detect toolchain and platform
- if (MSVC14 AND ARCHITECTURE_x86_64)
- set(SDL2_VER "SDL2-2.0.5")
+ if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
+ set(SDL2_VER "SDL2-2.0.8")
else()
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
endif()
@@ -218,7 +222,7 @@ if (YUZU_USE_BUNDLED_UNICORN)
if (MSVC)
message(STATUS "unicorn not found, falling back to bundled")
# Detect toolchain and platform
- if (MSVC14 AND ARCHITECTURE_x86_64)
+ if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
set(UNICORN_VER "unicorn-yuzu")
else()
message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
@@ -277,7 +281,7 @@ endif()
if (ENABLE_QT)
if (YUZU_USE_BUNDLED_QT)
- if (MSVC14 AND ARCHITECTURE_x86_64)
+ if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
set(QT_VER qt-5.10.0-msvc2015_64)
else()
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
@@ -301,7 +305,7 @@ endif()
# ======================================
IF (APPLE)
- FIND_LIBRARY(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related
+ find_library(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
if (CMAKE_CXX_COMPILER_ID STREQUAL Clang)
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake
index e4a9796c8..aaf80b77b 100644
--- a/CMakeModules/CopyYuzuQt5Deps.cmake
+++ b/CMakeModules/CopyYuzuQt5Deps.cmake
@@ -4,8 +4,10 @@ function(copy_yuzu_Qt5_deps target_dir)
set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
+ set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")
set(PLATFORMS ${DLL_DEST}platforms/)
set(STYLES ${DLL_DEST}styles/)
+ set(IMAGEFORMATS ${DLL_DEST}imageformats/)
windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
icudt*.dll
icuin*.dll
@@ -17,4 +19,5 @@ function(copy_yuzu_Qt5_deps target_dir)
)
windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
+ windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*)
endfunction(copy_yuzu_Qt5_deps)
diff --git a/appveyor.yml b/appveyor.yml
index 1e1e63ad7..436d98fa1 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -117,6 +117,7 @@ after_build:
mkdir $RELEASE_DIST
mkdir $RELEASE_DIST/platforms
mkdir $RELEASE_DIST/styles
+ mkdir $RELEASE_DIST/imageformats
# copy the compiled binaries and other release files to the release folder
Get-ChildItem "$CMAKE_BINARY_DIR" -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
@@ -140,6 +141,9 @@ after_build:
# copy the qt windows vista style dll to platforms
Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/styles/qwindowsvistastyle.dll" -force -destination "$RELEASE_DIST/styles"
+ # copy the qt jpeg imageformat dll to platforms
+ Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/imageformats/qjpeg.dll" -force -destination "$RELEASE_DIST/imageformats"
+
7z a -tzip $MINGW_BUILD_ZIP $RELEASE_DIST\*
7z a $MINGW_SEVENZIP $RELEASE_DIST
}
diff --git a/dist/qt_themes/qdarkstyle/LICENSE.md b/dist/qt_themes/qdarkstyle/LICENSE.md
new file mode 100644
index 000000000..d8910aea5
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle/LICENSE.md
@@ -0,0 +1,183 @@
+# License
+
+## The MIT License (MIT) - Code
+
+Copyright (c) 2013-2018 Colin Duquesnoy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+## Creative Commons Attribution International 4.0 - Images
+
+QDarkStyle (c) 2013-2018 Colin Duquesnoy
+
+Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.
+
+### Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses.
+
+* __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors).
+
+* __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees).
+
+## Creative Commons Attribution 4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
+
+### Section 1 – Definitions
+
+a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
+
+b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
+
+c. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
+
+d. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
+
+e. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
+
+f. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
+
+g. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
+
+h. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License.
+
+i. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
+
+j. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
+
+k. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
+
+### Section 2 – Scope
+
+a. ___License grant.___
+
+ 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
+
+ A. reproduce and Share the Licensed Material, in whole or in part; and
+
+ B. produce, reproduce, and Share Adapted Material.
+
+ 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
+
+ 3. __Term.__ The term of this Public License is specified in Section 6(a).
+
+ 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
+
+ 5. __Downstream recipients.__
+
+ A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
+
+ B. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
+
+ 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
+
+b. ___Other rights.___
+
+ 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this Public License.
+
+ 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties.
+
+### Section 3 – License Conditions
+
+Your exercise of the Licensed Rights is expressly made subject to the following conditions.
+
+a. ___Attribution.___
+
+ 1. If You Share the Licensed Material (including in modified form), You must:
+
+ A. retain the following if it is supplied by the Licensor with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
+
+ B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
+
+ C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
+
+ 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
+
+ 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License.
+
+### Section 4 – Sui Generis Database Rights
+
+Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
+
+a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database;
+
+b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and
+
+c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
+
+### Section 5 – Disclaimer of Warranties and Limitation of Liability
+
+a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__
+
+b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__
+
+c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
+
+### Section 6 – Term and Termination
+
+a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
+
+b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
+
+c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
+
+d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
+
+### Section 7 – Other Terms and Conditions
+
+a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
+
+b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
+
+### Section 8 – Interpretation
+
+a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
+
+b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
+
+c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
+
+d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
+
+> Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.
+>
+> Creative Commons may be contacted at creativecommons.org \ No newline at end of file
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index c8e50312a..399c38dce 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -1,40 +1,15 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) <2013-2014> <Colin Duquesnoy>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-QToolTip
-{
+QToolTip {
border: 1px solid #76797C;
- background-color: rgb(90, 102, 117);;
+ background-color: #5A7566;
color: white;
- padding: 5px;
+ padding: 0px; /*remove padding, for fix combobox tooltip.*/
opacity: 200;
}
-QWidget
-{
+QWidget {
color: #eff0f1;
background-color: #31363b;
- selection-background-color:#3daee9;
+ selection-background-color: #3daee9;
selection-color: #eff0f1;
background-clip: border;
border-image: none;
@@ -42,43 +17,38 @@ QWidget
outline: 0;
}
-QWidget:item:hover
-{
+QWidget:item:hover {
background-color: #18465d;
color: #eff0f1;
}
-QWidget:item:selected
-{
+QWidget:item:selected {
background-color: #18465d;
}
-QCheckBox
-{
+QCheckBox {
spacing: 5px;
outline: none;
color: #eff0f1;
margin-bottom: 2px;
}
-QCheckBox:disabled
-{
+QCheckBox:disabled {
color: #76797C;
}
QCheckBox::indicator,
-QGroupBox::indicator
-{
+QGroupBox::indicator {
width: 18px;
height: 18px;
}
-QGroupBox::indicator
-{
+
+QGroupBox::indicator {
margin-left: 2px;
}
-QCheckBox::indicator:unchecked
-{
+QCheckBox::indicator:unchecked,
+QGroupBox::indicator:unchecked {
image: url(:/qss_icons/rc/checkbox_unchecked.png);
}
@@ -87,14 +57,13 @@ QCheckBox::indicator:unchecked:focus,
QCheckBox::indicator:unchecked:pressed,
QGroupBox::indicator:unchecked:hover,
QGroupBox::indicator:unchecked:focus,
-QGroupBox::indicator:unchecked:pressed
-{
- border: none;
+QGroupBox::indicator:unchecked:pressed {
+ border: none;
image: url(:/qss_icons/rc/checkbox_unchecked_focus.png);
}
-QCheckBox::indicator:checked
-{
+QCheckBox::indicator:checked,
+QGroupBox::indicator:checked {
image: url(:/qss_icons/rc/checkbox_checked.png);
}
@@ -103,72 +72,60 @@ QCheckBox::indicator:checked:focus,
QCheckBox::indicator:checked:pressed,
QGroupBox::indicator:checked:hover,
QGroupBox::indicator:checked:focus,
-QGroupBox::indicator:checked:pressed
-{
- border: none;
+QGroupBox::indicator:checked:pressed {
+ border: none;
image: url(:/qss_icons/rc/checkbox_checked_focus.png);
}
-
-QCheckBox::indicator:indeterminate
-{
+QCheckBox::indicator:indeterminate {
image: url(:/qss_icons/rc/checkbox_indeterminate.png);
}
QCheckBox::indicator:indeterminate:focus,
QCheckBox::indicator:indeterminate:hover,
-QCheckBox::indicator:indeterminate:pressed
-{
+QCheckBox::indicator:indeterminate:pressed {
image: url(:/qss_icons/rc/checkbox_indeterminate_focus.png);
}
QCheckBox::indicator:checked:disabled,
-QGroupBox::indicator:checked:disabled
-{
+QGroupBox::indicator:checked:disabled {
image: url(:/qss_icons/rc/checkbox_checked_disabled.png);
}
QCheckBox::indicator:unchecked:disabled,
-QGroupBox::indicator:unchecked:disabled
-{
+QGroupBox::indicator:unchecked:disabled {
image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png);
}
-QRadioButton
-{
+QRadioButton {
spacing: 5px;
outline: none;
color: #eff0f1;
margin-bottom: 2px;
}
-QRadioButton:disabled
-{
+QRadioButton:disabled {
color: #76797C;
}
-QRadioButton::indicator
-{
+
+QRadioButton::indicator {
width: 21px;
height: 21px;
}
-QRadioButton::indicator:unchecked
-{
+QRadioButton::indicator:unchecked {
image: url(:/qss_icons/rc/radio_unchecked.png);
}
-
QRadioButton::indicator:unchecked:hover,
QRadioButton::indicator:unchecked:focus,
-QRadioButton::indicator:unchecked:pressed
-{
+QRadioButton::indicator:unchecked:pressed {
border: none;
outline: none;
image: url(:/qss_icons/rc/radio_unchecked_focus.png);
}
-QRadioButton::indicator:checked
-{
+QRadioButton::indicator:checked {
border: none;
outline: none;
image: url(:/qss_icons/rc/radio_checked.png);
@@ -176,72 +133,60 @@ QRadioButton::indicator:checked
QRadioButton::indicator:checked:hover,
QRadioButton::indicator:checked:focus,
-QRadioButton::indicator:checked:pressed
-{
+QRadioButton::indicator:checked:pressed {
border: none;
outline: none;
image: url(:/qss_icons/rc/radio_checked_focus.png);
}
-QRadioButton::indicator:checked:disabled
-{
+QRadioButton::indicator:checked:disabled {
outline: none;
image: url(:/qss_icons/rc/radio_checked_disabled.png);
}
-QRadioButton::indicator:unchecked:disabled
-{
+QRadioButton::indicator:unchecked:disabled {
image: url(:/qss_icons/rc/radio_unchecked_disabled.png);
}
-
-QMenuBar
-{
+QMenuBar {
background-color: #31363b;
color: #eff0f1;
}
-QMenuBar::item
-{
+QMenuBar::item {
background: transparent;
}
-QMenuBar::item:selected
-{
+QMenuBar::item:selected {
background: transparent;
border: 1px solid #76797C;
}
-QMenuBar::item:pressed
-{
+QMenuBar::item:pressed {
border: 1px solid #76797C;
background-color: #3daee9;
color: #eff0f1;
- margin-bottom:-1px;
- padding-bottom:1px;
+ margin-bottom: -1px;
+ padding-bottom: 1px;
}
-QMenu
-{
+QMenu {
border: 1px solid #76797C;
color: #eff0f1;
margin: 2px;
}
-QMenu::icon
-{
+QMenu::icon {
margin: 5px;
}
-QMenu::item
-{
+QMenu::item {
padding: 5px 30px 5px 30px;
- margin-left: 5px;
- border: 1px solid transparent; /* reserve space for selection border */
+ border: 1px solid transparent;
+ /* reserve space for selection border */
}
-QMenu::item:selected
-{
+QMenu::item:selected {
color: #eff0f1;
}
@@ -257,8 +202,10 @@ QMenu::indicator {
height: 18px;
}
+
/* non-exclusive indicator = check box style indicator
(see QActionGroup::setExclusive) */
+
QMenu::indicator:non-exclusive:unchecked {
image: url(:/qss_icons/rc/checkbox_unchecked.png);
}
@@ -275,7 +222,9 @@ QMenu::indicator:non-exclusive:checked:selected {
image: url(:/qss_icons/rc/checkbox_checked_disabled.png);
}
+
/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */
+
QMenu::indicator:exclusive:unchecked {
image: url(:/qss_icons/rc/radio_unchecked.png);
}
@@ -297,33 +246,31 @@ QMenu::right-arrow {
image: url(:/qss_icons/rc/right_arrow.png)
}
-
-QWidget:disabled
-{
+QWidget:disabled {
color: #454545;
background-color: #31363b;
}
-QAbstractItemView
-{
+QAbstractItemView {
alternate-background-color: #31363b;
color: #eff0f1;
- border: 1px solid 3A3939;
+ border: 1px solid #3A3939;
border-radius: 2px;
}
-QWidget:focus, QMenuBar:focus
-{
+QWidget:focus,
+QMenuBar:focus {
border: 1px solid #3daee9;
}
-QTabWidget:focus, QCheckBox:focus, QRadioButton:focus, QSlider:focus
-{
+QTabWidget:focus,
+QCheckBox:focus,
+QRadioButton:focus,
+QSlider:focus {
border: none;
}
-QLineEdit
-{
+QLineEdit {
background-color: #232629;
padding: 5px;
border-style: solid;
@@ -332,13 +279,12 @@ QLineEdit
color: #eff0f1;
}
-QAbstractItemView QLineEdit
-{
+QAbstractItemView QLineEdit {
padding: 0;
}
QGroupBox {
- border:1px solid #76797C;
+ border: 1px solid #76797C;
border-radius: 2px;
margin-top: 20px;
}
@@ -351,15 +297,13 @@ QGroupBox::title {
padding-top: 10px;
}
-QAbstractScrollArea
-{
+QAbstractScrollArea {
border-radius: 2px;
border: 1px solid #76797C;
background-color: transparent;
}
-QScrollBar:horizontal
-{
+QScrollBar:horizontal {
height: 15px;
margin: 3px 15px 3px 15px;
border: 1px transparent #2A2929;
@@ -367,15 +311,13 @@ QScrollBar:horizontal
background-color: #2A2929;
}
-QScrollBar::handle:horizontal
-{
+QScrollBar::handle:horizontal {
background-color: #605F5F;
min-width: 5px;
border-radius: 4px;
}
-QScrollBar::add-line:horizontal
-{
+QScrollBar::add-line:horizontal {
margin: 0px 3px 0px 3px;
border-image: url(:/qss_icons/rc/right_arrow_disabled.png);
width: 10px;
@@ -384,8 +326,7 @@ QScrollBar::add-line:horizontal
subcontrol-origin: margin;
}
-QScrollBar::sub-line:horizontal
-{
+QScrollBar::sub-line:horizontal {
margin: 0px 3px 0px 3px;
border-image: url(:/qss_icons/rc/left_arrow_disabled.png);
height: 10px;
@@ -394,8 +335,8 @@ QScrollBar::sub-line:horizontal
subcontrol-origin: margin;
}
-QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on
-{
+QScrollBar::add-line:horizontal:hover,
+QScrollBar::add-line:horizontal:on {
border-image: url(:/qss_icons/rc/right_arrow.png);
height: 10px;
width: 10px;
@@ -403,9 +344,8 @@ QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on
subcontrol-origin: margin;
}
-
-QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on
-{
+QScrollBar::sub-line:horizontal:hover,
+QScrollBar::sub-line:horizontal:on {
border-image: url(:/qss_icons/rc/left_arrow.png);
height: 10px;
width: 10px;
@@ -413,19 +353,17 @@ QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on
subcontrol-origin: margin;
}
-QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal
-{
+QScrollBar::up-arrow:horizontal,
+QScrollBar::down-arrow:horizontal {
background: none;
}
-
-QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
-{
+QScrollBar::add-page:horizontal,
+QScrollBar::sub-page:horizontal {
background: none;
}
-QScrollBar:vertical
-{
+QScrollBar:vertical {
background-color: #2A2929;
width: 15px;
margin: 15px 3px 15px 3px;
@@ -433,15 +371,13 @@ QScrollBar:vertical
border-radius: 4px;
}
-QScrollBar::handle:vertical
-{
+QScrollBar::handle:vertical {
background-color: #605F5F;
min-height: 5px;
border-radius: 4px;
}
-QScrollBar::sub-line:vertical
-{
+QScrollBar::sub-line:vertical {
margin: 3px 0px 3px 0px;
border-image: url(:/qss_icons/rc/up_arrow_disabled.png);
height: 10px;
@@ -450,8 +386,7 @@ QScrollBar::sub-line:vertical
subcontrol-origin: margin;
}
-QScrollBar::add-line:vertical
-{
+QScrollBar::add-line:vertical {
margin: 3px 0px 3px 0px;
border-image: url(:/qss_icons/rc/down_arrow_disabled.png);
height: 10px;
@@ -460,9 +395,8 @@ QScrollBar::add-line:vertical
subcontrol-origin: margin;
}
-QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on
-{
-
+QScrollBar::sub-line:vertical:hover,
+QScrollBar::sub-line:vertical:on {
border-image: url(:/qss_icons/rc/up_arrow.png);
height: 10px;
width: 10px;
@@ -470,9 +404,8 @@ QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on
subcontrol-origin: margin;
}
-
-QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on
-{
+QScrollBar::add-line:vertical:hover,
+QScrollBar::add-line:vertical:on {
border-image: url(:/qss_icons/rc/down_arrow.png);
height: 10px;
width: 10px;
@@ -480,34 +413,31 @@ QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on
subcontrol-origin: margin;
}
-QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical
-{
+QScrollBar::up-arrow:vertical,
+QScrollBar::down-arrow:vertical {
background: none;
}
-
-QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical
-{
+QScrollBar::add-page:vertical,
+QScrollBar::sub-page:vertical {
background: none;
}
-QTextEdit
-{
+QTextEdit {
background-color: #232629;
color: #eff0f1;
border: 1px solid #76797C;
}
-QPlainTextEdit
-{
- background-color: #232629;;
+QPlainTextEdit {
+ background-color: #232629;
+ ;
color: #eff0f1;
border-radius: 2px;
border: 1px solid #76797C;
}
-QHeaderView::section
-{
+QHeaderView::section {
background-color: #76797C;
color: #eff0f1;
padding: 5px;
@@ -520,9 +450,7 @@ QSizeGrip {
height: 12px;
}
-
-QMainWindow::separator
-{
+QMainWindow::separator {
background-color: #31363b;
color: white;
padding-left: 4px;
@@ -530,9 +458,7 @@ QMainWindow::separator
border: 1px dashed #76797C;
}
-QMainWindow::separator:hover
-{
-
+QMainWindow::separator:hover {
background-color: #787876;
color: white;
padding-left: 4px;
@@ -540,9 +466,7 @@ QMainWindow::separator:hover
spacing: 2px;
}
-
-QMenu::separator
-{
+QMenu::separator {
height: 1px;
background-color: #76797C;
color: white;
@@ -551,21 +475,17 @@ QMenu::separator
margin-right: 5px;
}
-
-QFrame
-{
+QFrame {
border-radius: 2px;
border: 1px solid #76797C;
}
-QFrame[frameShape="0"]
-{
+QFrame[frameShape="0"] {
border-radius: 2px;
border: 1px transparent #76797C;
}
-QStackedWidget
-{
+QStackedWidget {
border: 1px transparent black;
}
@@ -578,21 +498,24 @@ QToolBar {
QToolBar::handle:horizontal {
image: url(:/qss_icons/rc/Hmovetoolbar.png);
}
+
QToolBar::handle:vertical {
image: url(:/qss_icons/rc/Vmovetoolbar.png);
}
+
QToolBar::separator:horizontal {
image: url(:/qss_icons/rc/Hsepartoolbar.png);
}
+
QToolBar::separator:vertical {
image: url(:/qss_icons/rc/Vsepartoolbar.png);
}
+
QToolButton#qt_toolbar_ext_button {
background: #58595a
}
-QPushButton
-{
+QPushButton {
color: #eff0f1;
background-color: #31363b;
border-width: 1px;
@@ -603,8 +526,7 @@ QPushButton
outline: none;
}
-QPushButton:disabled
-{
+QPushButton:disabled {
background-color: #31363b;
border-width: 1px;
border-color: #454545;
@@ -622,15 +544,13 @@ QPushButton:focus {
color: white;
}
-QPushButton:pressed
-{
+QPushButton:pressed {
background-color: #3daee9;
padding-top: -15px;
padding-bottom: -17px;
}
-QComboBox
-{
+QComboBox {
selection-background-color: #3daee9;
border-style: solid;
border: 1px solid #76797C;
@@ -639,38 +559,40 @@ QComboBox
min-width: 75px;
}
-QPushButton:checked{
+QPushButton:checked {
background-color: #76797C;
border-color: #6A6969;
}
-QComboBox:hover,QPushButton:hover,QAbstractSpinBox:hover,QLineEdit:hover,QTextEdit:hover,QPlainTextEdit:hover,QAbstractView:hover,QTreeView:hover
-{
+QComboBox:hover,
+QPushButton:hover,
+QAbstractSpinBox:hover,
+QLineEdit:hover,
+QTextEdit:hover,
+QPlainTextEdit:hover,
+QAbstractView:hover,
+QTreeView:hover {
border: 1px solid #3daee9;
color: #eff0f1;
}
-QComboBox:on
-{
+QComboBox:on {
padding-top: 3px;
padding-left: 4px;
selection-background-color: #4a4a4a;
}
-QComboBox QAbstractItemView
-{
+QComboBox QAbstractItemView {
background-color: #232629;
border-radius: 2px;
border: 1px solid #76797C;
selection-background-color: #18465d;
}
-QComboBox::drop-down
-{
+QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
-
border-left-width: 0px;
border-left-color: darkgray;
border-left-style: solid;
@@ -678,14 +600,13 @@ QComboBox::drop-down
border-bottom-right-radius: 3px;
}
-QComboBox::down-arrow
-{
+QComboBox::down-arrow {
image: url(:/qss_icons/rc/down_arrow_disabled.png);
}
-QComboBox::down-arrow:on, QComboBox::down-arrow:hover,
-QComboBox::down-arrow:focus
-{
+QComboBox::down-arrow:on,
+QComboBox::down-arrow:hover,
+QComboBox::down-arrow:focus {
image: url(:/qss_icons/rc/down_arrow.png);
}
@@ -698,49 +619,47 @@ QAbstractSpinBox {
min-width: 75px;
}
-QAbstractSpinBox:up-button
-{
+QAbstractSpinBox:up-button {
background-color: transparent;
subcontrol-origin: border;
subcontrol-position: center right;
}
-QAbstractSpinBox:down-button
-{
+QAbstractSpinBox:down-button {
background-color: transparent;
subcontrol-origin: border;
subcontrol-position: center left;
}
-QAbstractSpinBox::up-arrow,QAbstractSpinBox::up-arrow:disabled,QAbstractSpinBox::up-arrow:off {
+QAbstractSpinBox::up-arrow,
+QAbstractSpinBox::up-arrow:disabled,
+QAbstractSpinBox::up-arrow:off {
image: url(:/qss_icons/rc/up_arrow_disabled.png);
width: 10px;
height: 10px;
}
-QAbstractSpinBox::up-arrow:hover
-{
+
+QAbstractSpinBox::up-arrow:hover {
image: url(:/qss_icons/rc/up_arrow.png);
}
-
-QAbstractSpinBox::down-arrow,QAbstractSpinBox::down-arrow:disabled,QAbstractSpinBox::down-arrow:off
-{
+QAbstractSpinBox::down-arrow,
+QAbstractSpinBox::down-arrow:disabled,
+QAbstractSpinBox::down-arrow:off {
image: url(:/qss_icons/rc/down_arrow_disabled.png);
width: 10px;
height: 10px;
}
-QAbstractSpinBox::down-arrow:hover
-{
+
+QAbstractSpinBox::down-arrow:hover {
image: url(:/qss_icons/rc/down_arrow.png);
}
-
-QLabel
-{
+QLabel {
border: 0px solid black;
}
-QTabWidget{
+QTabWidget {
border: 0px transparent black;
}
@@ -751,27 +670,24 @@ QTabWidget::pane {
}
QTabWidget::tab-bar {
- left: 5px; /* move to the right by 5px */
+ /* left: 5px; move to the right by 5px */
}
-QTabBar
-{
+QTabBar {
qproperty-drawBase: 0;
border-radius: 3px;
}
-QTabBar:focus
-{
+QTabBar:focus {
border: 0px transparent black;
}
-QTabBar::close-button {
+QTabBar::close-button {
image: url(:/qss_icons/rc/close.png);
background: transparent;
}
-QTabBar::close-button:hover
-{
+QTabBar::close-button:hover {
image: url(:/qss_icons/rc/close-hover.png);
background: transparent;
}
@@ -781,7 +697,9 @@ QTabBar::close-button:pressed {
background: transparent;
}
+
/* TOP TABS */
+
QTabBar::tab:top {
color: #eff0f1;
border: 1px solid #76797C;
@@ -793,12 +711,11 @@ QTabBar::tab:top {
border-top-right-radius: 2px;
}
-QTabBar::tab:top:!selected
-{
+QTabBar::tab:top:selected {
color: #eff0f1;
background-color: #54575B;
border: 1px solid #76797C;
- border-bottom: 1px transparent black;
+ border-bottom: 2px solid #3daee9;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
@@ -807,7 +724,9 @@ QTabBar::tab:top:!selected:hover {
background-color: #3daee9;
}
+
/* BOTTOM TABS */
+
QTabBar::tab:bottom {
color: #eff0f1;
border: 1px solid #76797C;
@@ -819,12 +738,11 @@ QTabBar::tab:bottom {
min-width: 50px;
}
-QTabBar::tab:bottom:!selected
-{
+QTabBar::tab:bottom:selected {
color: #eff0f1;
background-color: #54575B;
border: 1px solid #76797C;
- border-top: 1px transparent black;
+ border-top: 2px solid #3daee9;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
@@ -833,7 +751,9 @@ QTabBar::tab:bottom:!selected:hover {
background-color: #3daee9;
}
+
/* LEFT TABS */
+
QTabBar::tab:left {
color: #eff0f1;
border: 1px solid #76797C;
@@ -845,12 +765,11 @@ QTabBar::tab:left {
min-height: 50px;
}
-QTabBar::tab:left:!selected
-{
+QTabBar::tab:left:selected {
color: #eff0f1;
background-color: #54575B;
border: 1px solid #76797C;
- border-left: 1px transparent black;
+ border-left: 2px solid #3daee9;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
@@ -861,6 +780,7 @@ QTabBar::tab:left:!selected:hover {
/* RIGHT TABS */
+
QTabBar::tab:right {
color: #eff0f1;
border: 1px solid #76797C;
@@ -872,12 +792,11 @@ QTabBar::tab:right {
min-height: 50px;
}
-QTabBar::tab:right:!selected
-{
+QTabBar::tab:right:selected {
color: #eff0f1;
background-color: #54575B;
border: 1px solid #76797C;
- border-right: 1px transparent black;
+ border-right: 2px solid #3daee9;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
}
@@ -887,21 +806,20 @@ QTabBar::tab:right:!selected:hover {
}
QTabBar QToolButton::right-arrow:enabled {
- image: url(:/qss_icons/rc/right_arrow.png);
- }
+ image: url(:/qss_icons/rc/right_arrow.png);
+}
- QTabBar QToolButton::left-arrow:enabled {
- image: url(:/qss_icons/rc/left_arrow.png);
- }
+QTabBar QToolButton::left-arrow:enabled {
+ image: url(:/qss_icons/rc/left_arrow.png);
+}
QTabBar QToolButton::right-arrow:disabled {
- image: url(:/qss_icons/rc/right_arrow_disabled.png);
- }
-
- QTabBar QToolButton::left-arrow:disabled {
- image: url(:/qss_icons/rc/left_arrow_disabled.png);
- }
+ image: url(:/qss_icons/rc/right_arrow_disabled.png);
+}
+QTabBar QToolButton::left-arrow:disabled {
+ image: url(:/qss_icons/rc/left_arrow_disabled.png);
+}
QDockWidget {
background: #31363b;
@@ -910,29 +828,32 @@ QDockWidget {
titlebar-normal-icon: url(:/qss_icons/rc/undock.png);
}
-QDockWidget::close-button, QDockWidget::float-button {
+QDockWidget::close-button,
+QDockWidget::float-button {
border: 1px solid transparent;
border-radius: 2px;
background: transparent;
}
-QDockWidget::close-button:hover, QDockWidget::float-button:hover {
+QDockWidget::close-button:hover,
+QDockWidget::float-button:hover {
background: rgba(255, 255, 255, 10);
}
-QDockWidget::close-button:pressed, QDockWidget::float-button:pressed {
+QDockWidget::close-button:pressed,
+QDockWidget::float-button:pressed {
padding: 1px -1px -1px 1px;
background: rgba(255, 255, 255, 10);
}
-QTreeView, QListView
-{
+QTreeView,
+QListView {
border: 1px solid #76797C;
background-color: #232629;
}
-QTreeView:branch:selected, QTreeView:branch:hover
-{
+QTreeView:branch:selected,
+QTreeView:branch:hover {
background: url(:/qss_icons/rc/transparent.png);
}
@@ -954,31 +875,75 @@ QTreeView::branch:closed:has-children:has-siblings {
}
QTreeView::branch:open:has-children:!has-siblings,
-QTreeView::branch:open:has-children:has-siblings {
+QTreeView::branch:open:has-children:has-siblings {
image: url(:/qss_icons/rc/branch_open.png);
}
QTreeView::branch:has-children:!has-siblings:closed:hover,
QTreeView::branch:closed:has-children:has-siblings:hover {
image: url(:/qss_icons/rc/branch_closed-on.png);
- }
+}
QTreeView::branch:open:has-children:!has-siblings:hover,
-QTreeView::branch:open:has-children:has-siblings:hover {
+QTreeView::branch:open:has-children:has-siblings:hover {
image: url(:/qss_icons/rc/branch_open-on.png);
- }
+}
-QListView::item:!selected:hover, QTreeView::item:!selected:hover {
+QListView::item:!selected:hover,
+QTreeView::item:!selected:hover {
background: #18465d;
outline: 0;
color: #eff0f1
}
-QListView::item:selected:hover, QTreeView::item:selected:hover {
+QListView::item:selected:hover,
+QTreeView::item:selected:hover {
background: #287399;
color: #eff0f1;
}
+QTreeView::indicator:checked,
+QListView::indicator:checked {
+ image: url(:/qss_icons/rc/checkbox_checked.png);
+}
+
+QTreeView::indicator:unchecked,
+QListView::indicator:unchecked {
+ image: url(:/qss_icons/rc/checkbox_unchecked.png);
+}
+
+QTreeView::indicator:indeterminate,
+QListView::indicator:indeterminate {
+ image: url(:/qss_icons/rc/checkbox_indeterminate.png);
+}
+
+QTreeView::indicator:checked:hover,
+QTreeView::indicator:checked:focus,
+QTreeView::indicator:checked:pressed,
+QListView::indicator:checked:hover,
+QListView::indicator:checked:focus,
+QListView::indicator:checked:pressed {
+ image: url(:/qss_icons/rc/checkbox_checked_focus.png);
+}
+
+QTreeView::indicator:unchecked:hover,
+QTreeView::indicator:unchecked:focus,
+QTreeView::indicator:unchecked:pressed,
+QListView::indicator:unchecked:hover,
+QListView::indicator:unchecked:focus,
+QListView::indicator:unchecked:pressed {
+ image: url(:/qss_icons/rc/checkbox_unchecked_focus.png);
+}
+
+QTreeView::indicator:indeterminate:hover,
+QTreeView::indicator:indeterminate:focus,
+QTreeView::indicator:indeterminate:pressed,
+QListView::indicator:indeterminate:hover,
+QListView::indicator:indeterminate:focus,
+QListView::indicator:indeterminate:pressed {
+ image: url(:/qss_icons/rc/checkbox_indeterminate_focus.png);
+}
+
QSlider::groove:horizontal {
border: 1px solid #565a5e;
height: 4px;
@@ -1021,38 +986,49 @@ QToolButton {
padding: 5px;
}
-QToolButton[popupMode="1"] { /* only for MenuButtonPopup */
- padding-right: 20px; /* make way for the popup button */
- border: 1px #76797C;
- border-radius: 5px;
+QToolButton[popupMode="1"] {
+ /* only for MenuButtonPopup */
+ padding-right: 20px;
+ /* make way for the popup button */
+ border: 1px #76797C;
+ border-radius: 5px;
}
-QToolButton[popupMode="2"] { /* only for InstantPopup */
- padding-right: 10px; /* make way for the popup button */
- border: 1px #76797C;
+QToolButton[popupMode="2"] {
+ /* only for InstantPopup */
+ padding-right: 10px;
+ /* make way for the popup button */
+ border: 1px #76797C;
}
-
-QToolButton:hover, QToolButton::menu-button:hover {
+QToolButton:hover,
+QToolButton::menu-button:hover {
background-color: transparent;
border: 1px solid #3daee9;
padding: 5px;
}
-QToolButton:checked, QToolButton:pressed,
- QToolButton::menu-button:pressed {
+QToolButton:checked,
+QToolButton:pressed,
+QToolButton::menu-button:pressed {
background-color: #3daee9;
border: 1px solid #3daee9;
padding: 5px;
}
+
/* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */
+
QToolButton::menu-indicator {
image: url(:/qss_icons/rc/down_arrow.png);
- top: -7px; left: -2px; /* shift it a bit */
+ top: -7px;
+ left: -2px;
+ /* shift it a bit */
}
+
/* the subcontrols below are used only in the MenuButtonPopup mode */
+
QToolButton::menu-button {
border: 1px transparent #76797C;
border-top-right-radius: 6px;
@@ -1070,47 +1046,46 @@ QToolButton::menu-arrow:open {
border: 1px solid #76797C;
}
-QPushButton::menu-indicator {
+QPushButton::menu-indicator {
subcontrol-origin: padding;
subcontrol-position: bottom right;
left: 8px;
}
-QTableView
-{
+QTableView {
border: 1px solid #76797C;
gridline-color: #31363b;
background-color: #232629;
}
-
-QTableView, QHeaderView
-{
+QTableView,
+QHeaderView {
border-radius: 0px;
}
-QTableView::item:pressed, QListView::item:pressed, QTreeView::item:pressed {
+QTableView::item:pressed,
+QListView::item:pressed,
+QTreeView::item:pressed {
background: #18465d;
color: #eff0f1;
}
-QTableView::item:selected:active, QTreeView::item:selected:active, QListView::item:selected:active {
+QTableView::item:selected:active,
+QTreeView::item:selected:active,
+QListView::item:selected:active {
background: #287399;
color: #eff0f1;
}
-
-QHeaderView
-{
+QHeaderView {
background-color: #31363b;
border: 1px transparent;
border-radius: 0px;
margin: 0px;
padding: 0px;
-
}
-QHeaderView::section {
+QHeaderView::section {
background-color: #31363b;
color: #eff0f1;
padding: 5px;
@@ -1119,34 +1094,32 @@ QHeaderView::section {
text-align: center;
}
-QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one
-{
+QHeaderView::section::vertical::first,
+QHeaderView::section::vertical::only-one {
border-top: 1px solid #76797C;
}
-QHeaderView::section::vertical
-{
+QHeaderView::section::vertical {
border-top: transparent;
}
-QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one
-{
+QHeaderView::section::horizontal::first,
+QHeaderView::section::horizontal::only-one {
border-left: 1px solid #76797C;
}
-QHeaderView::section::horizontal
-{
+QHeaderView::section::horizontal {
border-left: transparent;
}
-
-QHeaderView::section:checked
- {
+QHeaderView::section:checked {
color: white;
background-color: #334e5e;
- }
+}
+
+
+/* style the sort indicator */
- /* style the sort indicator */
QHeaderView::down-arrow {
image: url(:/qss_icons/rc/down_arrow.png);
}
@@ -1155,14 +1128,13 @@ QHeaderView::up-arrow {
image: url(:/qss_icons/rc/up_arrow.png);
}
-
QTableCornerButton::section {
background-color: #31363b;
border: 1px transparent #76797C;
border-radius: 0px;
}
-QToolBox {
+QToolBox {
padding: 5px;
border: 1px transparent black;
}
@@ -1176,22 +1148,22 @@ QToolBox::tab {
border-top-right-radius: 5px;
}
-QToolBox::tab:selected { /* italicize selected tabs */
+QToolBox::tab:selected {
+ /* italicize selected tabs */
font: italic;
background-color: #31363b;
border-color: #3daee9;
- }
+}
QStatusBar::item {
border: 0px transparent dark;
- }
-
+}
-QFrame[height="3"], QFrame[width="3"] {
+QFrame[height="3"],
+QFrame[width="3"] {
background-color: #76797C;
}
-
QSplitter::handle {
border: 1px dashed #76797C;
}
@@ -1219,8 +1191,7 @@ QProgressBar::chunk {
background-color: #05B8CC;
}
-QDateEdit
-{
+QDateEdit {
selection-background-color: #3daee9;
border-style: solid;
border: 1px solid #3375A3;
@@ -1229,23 +1200,20 @@ QDateEdit
min-width: 75px;
}
-QDateEdit:on
-{
+QDateEdit:on {
padding-top: 3px;
padding-left: 4px;
selection-background-color: #4a4a4a;
}
-QDateEdit QAbstractItemView
-{
+QDateEdit QAbstractItemView {
background-color: #232629;
border-radius: 2px;
border: 1px solid #3375A3;
selection-background-color: #3daee9;
}
-QDateEdit::drop-down
-{
+QDateEdit::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
@@ -1256,13 +1224,12 @@ QDateEdit::drop-down
border-bottom-right-radius: 3px;
}
-QDateEdit::down-arrow
-{
+QDateEdit::down-arrow {
image: url(:/qss_icons/rc/down_arrow_disabled.png);
}
-QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover,
-QDateEdit::down-arrow:focus
-{
+QDateEdit::down-arrow:on,
+QDateEdit::down-arrow:hover,
+QDateEdit::down-arrow:focus {
image: url(:/qss_icons/rc/down_arrow.png);
}
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index d2b0652a5..b6eb36f20 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -32,9 +32,13 @@ add_subdirectory(inih)
# lz4
set(LZ4_BUNDLED_MODE ON)
-add_subdirectory(lz4/contrib/cmake_unofficial)
+add_subdirectory(lz4/contrib/cmake_unofficial EXCLUDE_FROM_ALL)
target_include_directories(lz4_static INTERFACE ./lz4/lib)
+# mbedtls
+add_subdirectory(mbedtls EXCLUDE_FROM_ALL)
+target_include_directories(mbedtls PUBLIC ./mbedtls/include)
+
# MicroProfile
add_library(microprofile INTERFACE)
target_include_directories(microprofile INTERFACE ./microprofile)
@@ -50,3 +54,13 @@ if (ARCHITECTURE_x86_64)
target_include_directories(xbyak INTERFACE ./xbyak/xbyak)
target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
endif()
+
+# Opus
+add_subdirectory(opus)
+target_include_directories(opus INTERFACE ./opus/include)
+
+# Cubeb
+if(ENABLE_CUBEB)
+ set(BUILD_TESTS OFF CACHE BOOL "")
+ add_subdirectory(cubeb EXCLUDE_FROM_ALL)
+endif()
diff --git a/externals/catch b/externals/catch
-Subproject d2a130f2433aeaca070e3e4d6298a80049d21cf
+Subproject 15cf3caaceb21172ea42a24e595a2eb58c3ec96
diff --git a/externals/cubeb b/externals/cubeb
new file mode 160000
+Subproject 12b78c0edfa40007e41dbdcd9dfe367fbb98d01
diff --git a/externals/dynarmic b/externals/dynarmic
-Subproject 98e23801297167db1fd266696484a49096e734c
+Subproject 550d662f0ece868209f0f760dddc8b2ad4698b1
diff --git a/externals/glad/include/glad/glad.h b/externals/glad/include/glad/glad.h
index 5f4b962d9..fd41dc702 100644
--- a/externals/glad/include/glad/glad.h
+++ b/externals/glad/include/glad/glad.h
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.25 on Fri Jul 20 07:59:28 2018.
+ OpenGL loader generated by glad 0.1.26 on Tue Aug 7 08:21:50 2018.
Language/Generator: C/C++
Specification: gl
@@ -15,6 +15,7 @@
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,
@@ -600,7 +601,7 @@
Omit khrplatform: False
Commandline:
- --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_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"
+ --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"
Online:
Too many extensions
*/
@@ -1409,7 +1410,6 @@ typedef void (APIENTRY *GLVULKANPROCNV)(void);
#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
#define GL_MAX_SAMPLES 0x8D57
-#define GL_INDEX 0x8222
#define GL_FRAMEBUFFER_SRGB 0x8DB9
#define GL_HALF_FLOAT 0x140B
#define GL_MAP_READ_BIT 0x0001
@@ -2780,6 +2780,12 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150
#define GL_DEPTH_CLAMP_NEAR_AMD 0x901E
#define GL_DEPTH_CLAMP_FAR_AMD 0x901F
+#define GL_RENDERBUFFER_STORAGE_SAMPLES_AMD 0x91B2
+#define GL_MAX_COLOR_FRAMEBUFFER_SAMPLES_AMD 0x91B3
+#define GL_MAX_COLOR_FRAMEBUFFER_STORAGE_SAMPLES_AMD 0x91B4
+#define GL_MAX_DEPTH_STENCIL_FRAMEBUFFER_SAMPLES_AMD 0x91B5
+#define GL_NUM_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B6
+#define GL_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B7
#define GL_SUBSAMPLE_DISTANCE_AMD 0x883F
#define GL_PIXELS_PER_SAMPLE_PATTERN_X_AMD 0x91AE
#define GL_PIXELS_PER_SAMPLE_PATTERN_Y_AMD 0x91AF
@@ -3157,6 +3163,7 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316
#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317
#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318
+#define GL_INDEX 0x8222
#define GL_LINES_ADJACENCY_ARB 0x000A
#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B
#define GL_TRIANGLES_ADJACENCY_ARB 0x000C
@@ -6433,6 +6440,16 @@ typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC)(GLuint buf, GL
GLAPI PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC glad_glBlendEquationSeparateIndexedAMD;
#define glBlendEquationSeparateIndexedAMD glad_glBlendEquationSeparateIndexedAMD
#endif
+#ifndef GL_AMD_framebuffer_multisample_advanced
+#define GL_AMD_framebuffer_multisample_advanced 1
+GLAPI int GLAD_GL_AMD_framebuffer_multisample_advanced;
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC)(GLenum target, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC glad_glRenderbufferStorageMultisampleAdvancedAMD;
+#define glRenderbufferStorageMultisampleAdvancedAMD glad_glRenderbufferStorageMultisampleAdvancedAMD
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC)(GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC glad_glNamedRenderbufferStorageMultisampleAdvancedAMD;
+#define glNamedRenderbufferStorageMultisampleAdvancedAMD glad_glNamedRenderbufferStorageMultisampleAdvancedAMD
+#endif
#ifndef GL_AMD_framebuffer_sample_positions
#define GL_AMD_framebuffer_sample_positions 1
GLAPI int GLAD_GL_AMD_framebuffer_sample_positions;
diff --git a/externals/glad/src/glad.c b/externals/glad/src/glad.c
index 13607e449..1cf0890b9 100644
--- a/externals/glad/src/glad.c
+++ b/externals/glad/src/glad.c
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.25 on Fri Jul 20 07:59:28 2018.
+ OpenGL loader generated by glad 0.1.26 on Tue Aug 7 08:21:50 2018.
Language/Generator: C/C++
Specification: gl
@@ -15,6 +15,7 @@
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,
@@ -600,7 +601,7 @@
Omit khrplatform: False
Commandline:
- --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_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"
+ --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"
Online:
Too many extensions
*/
@@ -739,7 +740,7 @@ int gladLoadGL(void) {
return status;
}
-struct gladGLversionStruct GLVersion;
+struct gladGLversionStruct GLVersion = { 0, 0 };
#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
#define _GLAD_IS_SOME_NEW_VERSION 1
@@ -838,3190 +839,3193 @@ static int has_ext(const char *ext) {
return 0;
}
-int GLAD_GL_VERSION_1_0;
-int GLAD_GL_VERSION_1_1;
-int GLAD_GL_VERSION_1_2;
-int GLAD_GL_VERSION_1_3;
-int GLAD_GL_VERSION_1_4;
-int GLAD_GL_VERSION_1_5;
-int GLAD_GL_VERSION_2_0;
-int GLAD_GL_VERSION_2_1;
-int GLAD_GL_VERSION_3_0;
-int GLAD_GL_VERSION_3_1;
-int GLAD_GL_VERSION_3_2;
-int GLAD_GL_VERSION_3_3;
-PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;
-PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;
-PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
-PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
-PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;
-PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv;
-PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;
-PFNGLBINDSAMPLERPROC glad_glBindSampler;
-PFNGLLINEWIDTHPROC glad_glLineWidth;
-PFNGLCOLORP3UIVPROC glad_glColorP3uiv;
-PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;
-PFNGLCOMPILESHADERPROC glad_glCompileShader;
-PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;
-PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;
-PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui;
-PFNGLVERTEXP4UIPROC glad_glVertexP4ui;
-PFNGLENABLEIPROC glad_glEnablei;
-PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;
-PFNGLCREATESHADERPROC glad_glCreateShader;
-PFNGLISBUFFERPROC glad_glIsBuffer;
-PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;
-PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
-PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
-PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
-PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
-PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
-PFNGLHINTPROC glad_glHint;
-PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;
-PFNGLSAMPLEMASKIPROC glad_glSampleMaski;
-PFNGLVERTEXP2UIPROC glad_glVertexP2ui;
-PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;
-PFNGLPOINTSIZEPROC glad_glPointSize;
-PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;
-PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
-PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;
-PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
-PFNGLWAITSYNCPROC glad_glWaitSync;
-PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;
-PFNGLUNIFORM3IPROC glad_glUniform3i;
-PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;
-PFNGLUNIFORM3FPROC glad_glUniform3f;
-PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;
-PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
-PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui;
-PFNGLCOLORMASKIPROC glad_glColorMaski;
-PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;
-PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;
-PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui;
-PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;
-PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;
-PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;
-PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;
-PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui;
-PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
-PFNGLDRAWARRAYSPROC glad_glDrawArrays;
-PFNGLUNIFORM1UIPROC glad_glUniform1ui;
-PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;
-PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui;
-PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;
-PFNGLCLEARPROC glad_glClear;
-PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;
-PFNGLISENABLEDPROC glad_glIsEnabled;
-PFNGLSTENCILOPPROC glad_glStencilOp;
-PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
-PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
-PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;
-PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;
-PFNGLTEXIMAGE1DPROC glad_glTexImage1D;
-PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
-PFNGLGETTEXIMAGEPROC glad_glGetTexImage;
-PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;
-PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
-PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
-PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
-PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;
-PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;
-PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
-PFNGLGETQUERYIVPROC glad_glGetQueryiv;
-PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;
-PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;
-PFNGLISSHADERPROC glad_glIsShader;
-PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;
-PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;
-PFNGLENABLEPROC glad_glEnable;
-PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;
-PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
-PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;
-PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv;
-PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;
-PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
-PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;
-PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;
-PFNGLDRAWBUFFERPROC glad_glDrawBuffer;
-PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;
-PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;
-PFNGLFLUSHPROC glad_glFlush;
-PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
-PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
-PFNGLFENCESYNCPROC glad_glFenceSync;
-PFNGLCOLORP3UIPROC glad_glColorP3ui;
-PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;
-PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;
-PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;
-PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv;
-PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
-PFNGLGENSAMPLERSPROC glad_glGenSamplers;
-PFNGLCLAMPCOLORPROC glad_glClampColor;
-PFNGLUNIFORM4IVPROC glad_glUniform4iv;
-PFNGLCLEARSTENCILPROC glad_glClearStencil;
-PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv;
-PFNGLGENTEXTURESPROC glad_glGenTextures;
-PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;
-PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;
-PFNGLISSYNCPROC glad_glIsSync;
-PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;
-PFNGLUNIFORM2IPROC glad_glUniform2i;
-PFNGLUNIFORM2FPROC glad_glUniform2f;
-PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui;
-PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
-PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
-PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;
-PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;
-PFNGLGENQUERIESPROC glad_glGenQueries;
-PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;
-PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;
-PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;
-PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;
-PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
-PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;
-PFNGLISENABLEDIPROC glad_glIsEnabledi;
-PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui;
-PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;
-PFNGLUNIFORM2IVPROC glad_glUniform2iv;
-PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
-PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;
-PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;
-PFNGLGETSHADERIVPROC glad_glGetShaderiv;
-PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;
-PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
-PFNGLGETDOUBLEVPROC glad_glGetDoublev;
-PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;
-PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
-PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv;
-PFNGLUNIFORM3FVPROC glad_glUniform3fv;
-PFNGLDEPTHRANGEPROC glad_glDepthRange;
-PFNGLMAPBUFFERPROC glad_glMapBuffer;
-PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;
-PFNGLDELETESYNCPROC glad_glDeleteSync;
-PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;
-PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
-PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;
-PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
-PFNGLUNIFORM3IVPROC glad_glUniform3iv;
-PFNGLPOLYGONMODEPROC glad_glPolygonMode;
-PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;
-PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;
-PFNGLUSEPROGRAMPROC glad_glUseProgram;
-PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
-PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;
-PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
-PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;
-PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;
-PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;
-PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;
-PFNGLFINISHPROC glad_glFinish;
-PFNGLDELETESHADERPROC glad_glDeleteShader;
-PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;
-PFNGLVIEWPORTPROC glad_glViewport;
-PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;
-PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;
-PFNGLUNIFORM2UIPROC glad_glUniform2ui;
-PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;
-PFNGLCLEARDEPTHPROC glad_glClearDepth;
-PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;
-PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
-PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
-PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
-PFNGLTEXBUFFERPROC glad_glTexBuffer;
-PFNGLPIXELSTOREIPROC glad_glPixelStorei;
-PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
-PFNGLPIXELSTOREFPROC glad_glPixelStoref;
-PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;
-PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv;
-PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;
-PFNGLLINKPROGRAMPROC glad_glLinkProgram;
-PFNGLBINDTEXTUREPROC glad_glBindTexture;
-PFNGLGETSTRINGPROC glad_glGetString;
-PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;
-PFNGLDETACHSHADERPROC glad_glDetachShader;
-PFNGLENDQUERYPROC glad_glEndQuery;
-PFNGLNORMALP3UIPROC glad_glNormalP3ui;
-PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;
-PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
-PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
-PFNGLDELETEQUERIESPROC glad_glDeleteQueries;
-PFNGLNORMALP3UIVPROC glad_glNormalP3uiv;
-PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
-PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;
-PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
-PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;
-PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;
-PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
-PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;
-PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;
-PFNGLUNIFORM1FPROC glad_glUniform1f;
-PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
-PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;
-PFNGLUNIFORM1IPROC glad_glUniform1i;
-PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
-PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
-PFNGLDISABLEPROC glad_glDisable;
-PFNGLLOGICOPPROC glad_glLogicOp;
-PFNGLUNIFORM4UIPROC glad_glUniform4ui;
-PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
-PFNGLCULLFACEPROC glad_glCullFace;
-PFNGLGETSTRINGIPROC glad_glGetStringi;
-PFNGLATTACHSHADERPROC glad_glAttachShader;
-PFNGLQUERYCOUNTERPROC glad_glQueryCounter;
-PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;
-PFNGLDRAWELEMENTSPROC glad_glDrawElements;
-PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;
-PFNGLUNIFORM1IVPROC glad_glUniform1iv;
-PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;
-PFNGLREADBUFFERPROC glad_glReadBuffer;
-PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;
-PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;
-PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
-PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;
-PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
-PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;
-PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;
-PFNGLBLENDCOLORPROC glad_glBlendColor;
-PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;
-PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;
-PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;
-PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;
-PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
-PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;
-PFNGLISPROGRAMPROC glad_glIsProgram;
-PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;
-PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
-PFNGLUNIFORM4IPROC glad_glUniform4i;
-PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
-PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
-PFNGLREADPIXELSPROC glad_glReadPixels;
-PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;
-PFNGLUNIFORM4FPROC glad_glUniform4f;
-PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
-PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
-PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;
-PFNGLSTENCILFUNCPROC glad_glStencilFunc;
-PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;
-PFNGLCOLORP4UIPROC glad_glColorP4ui;
-PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;
-PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
-PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;
-PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;
-PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
-PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;
-PFNGLGENBUFFERSPROC glad_glGenBuffers;
-PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;
-PFNGLBLENDFUNCPROC glad_glBlendFunc;
-PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
-PFNGLTEXIMAGE3DPROC glad_glTexImage3D;
-PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
-PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;
-PFNGLGETINTEGER64VPROC glad_glGetInteger64v;
-PFNGLSCISSORPROC glad_glScissor;
-PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv;
-PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
-PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv;
-PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;
-PFNGLCLEARCOLORPROC glad_glClearColor;
-PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;
-PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;
-PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;
-PFNGLCOLORP4UIVPROC glad_glColorP4uiv;
-PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;
-PFNGLUNIFORM3UIPROC glad_glUniform3ui;
-PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;
-PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;
-PFNGLUNIFORM2FVPROC glad_glUniform2fv;
-PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;
-PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;
-PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;
-PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;
-PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;
-PFNGLDEPTHFUNCPROC glad_glDepthFunc;
-PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
-PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;
-PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
-PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui;
-PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;
-PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;
-PFNGLCOLORMASKPROC glad_glColorMask;
-PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;
-PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
-PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
-PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;
-PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;
-PFNGLUNIFORM4FVPROC glad_glUniform4fv;
-PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;
-PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;
-PFNGLISSAMPLERPROC glad_glIsSampler;
-PFNGLVERTEXP3UIPROC glad_glVertexP3ui;
-PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;
-PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;
-PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;
-PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;
-PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
-PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;
-PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv;
-PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
-PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;
-PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;
-PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;
-PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;
-PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;
-PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
-PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;
-PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;
-PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;
-PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;
-PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv;
-PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;
-PFNGLDISABLEIPROC glad_glDisablei;
-PFNGLSHADERSOURCEPROC glad_glShaderSource;
-PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
-PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;
-PFNGLGETSYNCIVPROC glad_glGetSynciv;
-PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv;
-PFNGLBEGINQUERYPROC glad_glBeginQuery;
-PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
-PFNGLBINDBUFFERPROC glad_glBindBuffer;
-PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
-PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;
-PFNGLBUFFERDATAPROC glad_glBufferData;
-PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;
-PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui;
-PFNGLGETERRORPROC glad_glGetError;
-PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;
-PFNGLGETFLOATVPROC glad_glGetFloatv;
-PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;
-PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
-PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;
-PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;
-PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;
-PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
-PFNGLGETINTEGERVPROC glad_glGetIntegerv;
-PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;
-PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;
-PFNGLISQUERYPROC glad_glIsQuery;
-PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;
-PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
-PFNGLSTENCILMASKPROC glad_glStencilMask;
-PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;
-PFNGLISTEXTUREPROC glad_glIsTexture;
-PFNGLUNIFORM1FVPROC glad_glUniform1fv;
-PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;
-PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
-PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;
-PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;
-PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;
-PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;
-PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
-PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;
-PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;
-PFNGLDEPTHMASKPROC glad_glDepthMask;
-PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;
-PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;
-PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;
-PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;
-PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
-PFNGLFRONTFACEPROC glad_glFrontFace;
-int GLAD_GL_SGIX_pixel_tiles;
-int GLAD_GL_EXT_post_depth_coverage;
-int GLAD_GL_APPLE_element_array;
-int GLAD_GL_AMD_multi_draw_indirect;
-int GLAD_GL_EXT_blend_subtract;
-int GLAD_GL_SGIX_tag_sample_buffer;
-int GLAD_GL_NV_point_sprite;
-int GLAD_GL_IBM_texture_mirrored_repeat;
-int GLAD_GL_APPLE_transform_hint;
-int GLAD_GL_ATI_separate_stencil;
-int GLAD_GL_NV_shader_atomic_int64;
-int GLAD_GL_EXT_semaphore_win32;
-int GLAD_GL_NV_vertex_program2_option;
-int GLAD_GL_EXT_texture_buffer_object;
-int GLAD_GL_ARB_vertex_blend;
-int GLAD_GL_OVR_multiview;
-int GLAD_GL_AMD_shader_gpu_shader_half_float_fetch;
-int GLAD_GL_NV_vertex_program2;
-int GLAD_GL_ARB_program_interface_query;
-int GLAD_GL_EXT_misc_attribute;
-int GLAD_GL_NV_multisample_coverage;
-int GLAD_GL_ARB_shading_language_packing;
-int GLAD_GL_EXT_texture_cube_map;
-int GLAD_GL_NV_viewport_array2;
-int GLAD_GL_ARB_texture_stencil8;
-int GLAD_GL_EXT_index_func;
-int GLAD_GL_EXT_memory_object_fd;
-int GLAD_GL_OES_compressed_paletted_texture;
-int GLAD_GL_MESA_shader_integer_functions;
-int GLAD_GL_NV_shader_buffer_load;
-int GLAD_GL_EXT_color_subtable;
-int GLAD_GL_SUNX_constant_data;
-int GLAD_GL_EXT_texture_compression_s3tc;
-int GLAD_GL_EXT_multi_draw_arrays;
-int GLAD_GL_ARB_shader_atomic_counters;
-int GLAD_GL_ARB_arrays_of_arrays;
-int GLAD_GL_NV_conditional_render;
-int GLAD_GL_EXT_texture_env_combine;
-int GLAD_GL_NV_fog_distance;
-int GLAD_GL_SGIX_async_histogram;
-int GLAD_GL_MESA_resize_buffers;
-int GLAD_GL_NV_light_max_exponent;
-int GLAD_GL_NV_texture_env_combine4;
-int GLAD_GL_ARB_spirv_extensions;
-int GLAD_GL_ARB_texture_view;
-int GLAD_GL_ARB_texture_env_combine;
-int GLAD_GL_ARB_map_buffer_range;
-int GLAD_GL_EXT_convolution;
-int GLAD_GL_NV_compute_program5;
-int GLAD_GL_NV_vertex_attrib_integer_64bit;
-int GLAD_GL_EXT_paletted_texture;
-int GLAD_GL_ARB_texture_buffer_object;
-int GLAD_GL_ATI_pn_triangles;
-int GLAD_GL_SGIX_resample;
-int GLAD_GL_SGIX_flush_raster;
-int GLAD_GL_EXT_light_texture;
-int GLAD_GL_ARB_point_sprite;
-int GLAD_GL_SUN_convolution_border_modes;
-int GLAD_GL_EXT_semaphore_fd;
-int GLAD_GL_NV_parameter_buffer_object2;
-int GLAD_GL_ARB_half_float_pixel;
-int GLAD_GL_NV_tessellation_program5;
-int GLAD_GL_REND_screen_coordinates;
-int GLAD_GL_EXT_shared_texture_palette;
-int GLAD_GL_EXT_packed_float;
-int GLAD_GL_OML_subsample;
-int GLAD_GL_SGIX_vertex_preclip;
-int GLAD_GL_SGIX_texture_scale_bias;
-int GLAD_GL_AMD_draw_buffers_blend;
-int GLAD_GL_APPLE_texture_range;
-int GLAD_GL_EXT_texture_array;
-int GLAD_GL_NV_texture_barrier;
-int GLAD_GL_ARB_texture_query_levels;
-int GLAD_GL_NV_texgen_emboss;
-int GLAD_GL_EXT_texture_swizzle;
-int GLAD_GL_ARB_texture_rg;
-int GLAD_GL_ARB_vertex_type_2_10_10_10_rev;
-int GLAD_GL_ARB_fragment_shader;
-int GLAD_GL_3DFX_tbuffer;
-int GLAD_GL_GREMEDY_frame_terminator;
-int GLAD_GL_IBM_cull_vertex;
-int GLAD_GL_EXT_separate_shader_objects;
-int GLAD_GL_NV_texture_multisample;
-int GLAD_GL_ARB_shader_objects;
-int GLAD_GL_ARB_framebuffer_object;
-int GLAD_GL_EXT_external_buffer;
-int GLAD_GL_ATI_envmap_bumpmap;
-int GLAD_GL_AMD_shader_explicit_vertex_parameter;
-int GLAD_GL_ARB_robust_buffer_access_behavior;
-int GLAD_GL_ARB_shader_stencil_export;
-int GLAD_GL_NV_texture_rectangle;
-int GLAD_GL_ARB_enhanced_layouts;
-int GLAD_GL_ARB_texture_rectangle;
-int GLAD_GL_SGI_texture_color_table;
-int GLAD_GL_NV_viewport_swizzle;
-int GLAD_GL_ATI_map_object_buffer;
-int GLAD_GL_ARB_robustness;
-int GLAD_GL_NV_pixel_data_range;
-int GLAD_GL_EXT_framebuffer_blit;
-int GLAD_GL_ARB_gpu_shader_fp64;
-int GLAD_GL_NV_command_list;
-int GLAD_GL_SGIX_depth_texture;
-int GLAD_GL_AMD_framebuffer_sample_positions;
-int GLAD_GL_GREMEDY_string_marker;
-int GLAD_GL_ARB_texture_compression_bptc;
-int GLAD_GL_EXT_subtexture;
-int GLAD_GL_EXT_pixel_transform_color_table;
-int GLAD_GL_EXT_texture_compression_rgtc;
-int GLAD_GL_ARB_shader_atomic_counter_ops;
-int GLAD_GL_SGIX_depth_pass_instrument;
-int GLAD_GL_EXT_gpu_program_parameters;
-int GLAD_GL_NV_evaluators;
-int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent;
-int GLAD_GL_SGIS_texture_filter4;
-int GLAD_GL_AMD_performance_monitor;
-int GLAD_GL_NV_geometry_shader4;
-int GLAD_GL_EXT_stencil_clear_tag;
-int GLAD_GL_NV_vertex_program1_1;
-int GLAD_GL_NV_present_video;
-int GLAD_GL_ARB_texture_compression_rgtc;
-int GLAD_GL_HP_convolution_border_modes;
-int GLAD_GL_EXT_shader_integer_mix;
-int GLAD_GL_SGIX_framezoom;
-int GLAD_GL_ARB_stencil_texturing;
-int GLAD_GL_ARB_shader_clock;
-int GLAD_GL_NV_shader_atomic_fp16_vector;
-int GLAD_GL_SGIX_fog_offset;
-int GLAD_GL_ARB_draw_elements_base_vertex;
-int GLAD_GL_INGR_interlace_read;
-int GLAD_GL_NV_transform_feedback;
-int GLAD_GL_NV_fragment_program;
-int GLAD_GL_AMD_stencil_operation_extended;
-int GLAD_GL_ARB_seamless_cubemap_per_texture;
-int GLAD_GL_ARB_instanced_arrays;
-int GLAD_GL_ARB_get_texture_sub_image;
-int GLAD_GL_NV_vertex_array_range2;
-int GLAD_GL_KHR_robustness;
-int GLAD_GL_AMD_sparse_texture;
-int GLAD_GL_ARB_clip_control;
-int GLAD_GL_NV_fragment_coverage_to_color;
-int GLAD_GL_NV_fence;
-int GLAD_GL_ARB_texture_buffer_range;
-int GLAD_GL_SUN_mesh_array;
-int GLAD_GL_ARB_vertex_attrib_binding;
-int GLAD_GL_ARB_framebuffer_no_attachments;
-int GLAD_GL_ARB_cl_event;
-int GLAD_GL_EXT_vertex_weighting;
-int GLAD_GL_ARB_derivative_control;
-int GLAD_GL_NV_packed_depth_stencil;
-int GLAD_GL_OES_single_precision;
-int GLAD_GL_NV_primitive_restart;
-int GLAD_GL_SUN_global_alpha;
-int GLAD_GL_ARB_fragment_shader_interlock;
-int GLAD_GL_EXT_texture_object;
-int GLAD_GL_AMD_name_gen_delete;
-int GLAD_GL_NV_texture_compression_vtc;
-int GLAD_GL_NV_sample_mask_override_coverage;
-int GLAD_GL_NV_texture_shader3;
-int GLAD_GL_MESA_tile_raster_order;
-int GLAD_GL_ARB_texture_filter_anisotropic;
-int GLAD_GL_EXT_texture;
-int GLAD_GL_ARB_buffer_storage;
-int GLAD_GL_AMD_shader_atomic_counter_ops;
-int GLAD_GL_APPLE_vertex_program_evaluators;
-int GLAD_GL_AMD_texture_gather_bias_lod;
-int GLAD_GL_NV_texgen_reflection;
-int GLAD_GL_ARB_explicit_uniform_location;
-int GLAD_GL_ARB_depth_buffer_float;
-int GLAD_GL_NV_path_rendering_shared_edge;
-int GLAD_GL_SGIX_shadow_ambient;
-int GLAD_GL_ARB_texture_cube_map;
-int GLAD_GL_AMD_vertex_shader_viewport_index;
-int GLAD_GL_SGIX_list_priority;
-int GLAD_GL_NV_vertex_buffer_unified_memory;
-int GLAD_GL_NV_uniform_buffer_unified_memory;
-int GLAD_GL_ARB_clear_texture;
-int GLAD_GL_ATI_texture_env_combine3;
-int GLAD_GL_NV_depth_clamp;
-int GLAD_GL_ARB_map_buffer_alignment;
-int GLAD_GL_EXT_memory_object;
-int GLAD_GL_NV_blend_equation_advanced;
-int GLAD_GL_SGIS_sharpen_texture;
-int GLAD_GL_KHR_robust_buffer_access_behavior;
-int GLAD_GL_ARB_pipeline_statistics_query;
-int GLAD_GL_ARB_vertex_program;
-int GLAD_GL_ARB_texture_rgb10_a2ui;
-int GLAD_GL_OML_interlace;
-int GLAD_GL_ATI_pixel_format_float;
-int GLAD_GL_NV_clip_space_w_scaling;
-int GLAD_GL_ARB_vertex_buffer_object;
-int GLAD_GL_EXT_shadow_funcs;
-int GLAD_GL_ATI_text_fragment_shader;
-int GLAD_GL_NV_vertex_array_range;
-int GLAD_GL_SGIX_fragment_lighting;
-int GLAD_GL_AMD_shader_ballot;
-int GLAD_GL_NV_texture_expand_normal;
-int GLAD_GL_NV_framebuffer_multisample_coverage;
-int GLAD_GL_EXT_timer_query;
-int GLAD_GL_EXT_vertex_array_bgra;
-int GLAD_GL_NV_bindless_texture;
-int GLAD_GL_KHR_debug;
-int GLAD_GL_SGIS_texture_border_clamp;
-int GLAD_GL_ATI_vertex_attrib_array_object;
-int GLAD_GL_SGIX_clipmap;
-int GLAD_GL_EXT_geometry_shader4;
-int GLAD_GL_ARB_shader_texture_image_samples;
-int GLAD_GL_MESA_ycbcr_texture;
-int GLAD_GL_MESAX_texture_stack;
-int GLAD_GL_AMD_seamless_cubemap_per_texture;
-int GLAD_GL_EXT_bindable_uniform;
-int GLAD_GL_KHR_texture_compression_astc_hdr;
-int GLAD_GL_ARB_shader_ballot;
-int GLAD_GL_KHR_blend_equation_advanced;
-int GLAD_GL_ARB_fragment_program_shadow;
-int GLAD_GL_ATI_element_array;
-int GLAD_GL_AMD_texture_texture4;
-int GLAD_GL_SGIX_reference_plane;
-int GLAD_GL_EXT_stencil_two_side;
-int GLAD_GL_ARB_transform_feedback_overflow_query;
-int GLAD_GL_SGIX_texture_lod_bias;
-int GLAD_GL_KHR_no_error;
-int GLAD_GL_NV_explicit_multisample;
-int GLAD_GL_NV_stereo_view_rendering;
-int GLAD_GL_IBM_static_data;
-int GLAD_GL_EXT_clip_volume_hint;
-int GLAD_GL_EXT_texture_perturb_normal;
-int GLAD_GL_NV_fragment_program2;
-int GLAD_GL_NV_fragment_program4;
-int GLAD_GL_EXT_point_parameters;
-int GLAD_GL_PGI_misc_hints;
-int GLAD_GL_EXT_EGL_image_storage;
-int GLAD_GL_SGIX_subsample;
-int GLAD_GL_AMD_shader_stencil_export;
-int GLAD_GL_ARB_shader_texture_lod;
-int GLAD_GL_ARB_vertex_shader;
-int GLAD_GL_ARB_depth_clamp;
-int GLAD_GL_SGIS_texture_select;
-int GLAD_GL_NV_texture_shader;
-int GLAD_GL_ARB_tessellation_shader;
-int GLAD_GL_EXT_draw_buffers2;
-int GLAD_GL_ARB_vertex_attrib_64bit;
-int GLAD_GL_EXT_texture_filter_minmax;
-int GLAD_GL_NV_query_resource;
-int GLAD_GL_AMD_interleaved_elements;
-int GLAD_GL_ARB_fragment_program;
-int GLAD_GL_OML_resample;
-int GLAD_GL_APPLE_ycbcr_422;
-int GLAD_GL_SGIX_texture_add_env;
-int GLAD_GL_ARB_shadow_ambient;
-int GLAD_GL_ARB_texture_storage;
-int GLAD_GL_EXT_pixel_buffer_object;
-int GLAD_GL_ARB_copy_image;
-int GLAD_GL_SGIS_pixel_texture;
-int GLAD_GL_SGIS_generate_mipmap;
-int GLAD_GL_SGIX_instruments;
-int GLAD_GL_ARB_fragment_layer_viewport;
-int GLAD_GL_ARB_shader_storage_buffer_object;
-int GLAD_GL_EXT_sparse_texture2;
-int GLAD_GL_EXT_blend_minmax;
-int GLAD_GL_MESA_pack_invert;
-int GLAD_GL_ARB_base_instance;
-int GLAD_GL_SGIX_convolution_accuracy;
-int GLAD_GL_PGI_vertex_hints;
-int GLAD_GL_AMD_transform_feedback4;
-int GLAD_GL_ARB_ES3_1_compatibility;
-int GLAD_GL_EXT_memory_object_win32;
-int GLAD_GL_EXT_texture_integer;
-int GLAD_GL_ARB_texture_multisample;
-int GLAD_GL_ATI_vertex_streams;
-int GLAD_GL_AMD_gpu_shader_int64;
-int GLAD_GL_S3_s3tc;
-int GLAD_GL_ARB_query_buffer_object;
-int GLAD_GL_AMD_vertex_shader_tessellator;
-int GLAD_GL_ARB_invalidate_subdata;
-int GLAD_GL_NV_draw_vulkan_image;
-int GLAD_GL_EXT_index_material;
-int GLAD_GL_NVX_linked_gpu_multicast;
-int GLAD_GL_NV_blend_equation_advanced_coherent;
-int GLAD_GL_KHR_texture_compression_astc_sliced_3d;
-int GLAD_GL_INTEL_parallel_arrays;
-int GLAD_GL_ATI_draw_buffers;
-int GLAD_GL_WIN_specular_fog;
-int GLAD_GL_EXT_cmyka;
-int GLAD_GL_SGIX_pixel_texture;
-int GLAD_GL_APPLE_specular_vector;
-int GLAD_GL_ARB_compatibility;
-int GLAD_GL_ARB_timer_query;
-int GLAD_GL_SGIX_interlace;
-int GLAD_GL_NV_parameter_buffer_object;
-int GLAD_GL_AMD_shader_trinary_minmax;
-int GLAD_GL_ARB_direct_state_access;
-int GLAD_GL_EXT_rescale_normal;
-int GLAD_GL_ARB_pixel_buffer_object;
-int GLAD_GL_ARB_uniform_buffer_object;
-int GLAD_GL_ARB_vertex_type_10f_11f_11f_rev;
-int GLAD_GL_ARB_texture_swizzle;
-int GLAD_GL_NV_transform_feedback2;
-int GLAD_GL_SGIX_async_pixel;
-int GLAD_GL_NV_fragment_program_option;
-int GLAD_GL_ARB_explicit_attrib_location;
-int GLAD_GL_EXT_blend_color;
-int GLAD_GL_NV_shader_thread_group;
-int GLAD_GL_EXT_stencil_wrap;
-int GLAD_GL_EXT_index_array_formats;
-int GLAD_GL_OVR_multiview2;
-int GLAD_GL_EXT_histogram;
-int GLAD_GL_EXT_polygon_offset;
-int GLAD_GL_SGIS_point_parameters;
-int GLAD_GL_SGIX_ycrcb;
-int GLAD_GL_EXT_direct_state_access;
-int GLAD_GL_ARB_cull_distance;
-int GLAD_GL_AMD_sample_positions;
-int GLAD_GL_NV_vertex_program;
-int GLAD_GL_NV_shader_thread_shuffle;
-int GLAD_GL_ARB_shader_precision;
-int GLAD_GL_EXT_vertex_shader;
-int GLAD_GL_EXT_blend_func_separate;
-int GLAD_GL_APPLE_fence;
-int GLAD_GL_NV_query_resource_tag;
-int GLAD_GL_OES_byte_coordinates;
-int GLAD_GL_ARB_transpose_matrix;
-int GLAD_GL_ARB_provoking_vertex;
-int GLAD_GL_EXT_fog_coord;
-int GLAD_GL_EXT_vertex_array;
-int GLAD_GL_ARB_half_float_vertex;
-int GLAD_GL_EXT_blend_equation_separate;
-int GLAD_GL_NV_framebuffer_mixed_samples;
-int GLAD_GL_NVX_conditional_render;
-int GLAD_GL_ARB_multi_draw_indirect;
-int GLAD_GL_EXT_raster_multisample;
-int GLAD_GL_NV_copy_image;
-int GLAD_GL_HP_texture_lighting;
-int GLAD_GL_INTEL_framebuffer_CMAA;
-int GLAD_GL_ARB_transform_feedback2;
-int GLAD_GL_ARB_transform_feedback3;
-int GLAD_GL_SGIX_ycrcba;
-int GLAD_GL_EXT_debug_marker;
-int GLAD_GL_EXT_bgra;
-int GLAD_GL_ARB_sparse_texture_clamp;
-int GLAD_GL_EXT_pixel_transform;
-int GLAD_GL_ARB_conservative_depth;
-int GLAD_GL_ATI_fragment_shader;
-int GLAD_GL_ARB_vertex_array_object;
-int GLAD_GL_SUN_triangle_list;
-int GLAD_GL_EXT_texture_env_add;
-int GLAD_GL_EXT_packed_depth_stencil;
-int GLAD_GL_EXT_texture_mirror_clamp;
-int GLAD_GL_NV_multisample_filter_hint;
-int GLAD_GL_APPLE_float_pixels;
-int GLAD_GL_ARB_transform_feedback_instanced;
-int GLAD_GL_SGIX_async;
-int GLAD_GL_EXT_texture_compression_latc;
-int GLAD_GL_NV_robustness_video_memory_purge;
-int GLAD_GL_ARB_shading_language_100;
-int GLAD_GL_INTEL_performance_query;
-int GLAD_GL_ARB_texture_mirror_clamp_to_edge;
-int GLAD_GL_NV_gpu_shader5;
-int GLAD_GL_NV_bindless_multi_draw_indirect_count;
-int GLAD_GL_ARB_ES2_compatibility;
-int GLAD_GL_ARB_indirect_parameters;
-int GLAD_GL_EXT_window_rectangles;
-int GLAD_GL_NV_half_float;
-int GLAD_GL_ARB_ES3_2_compatibility;
-int GLAD_GL_ATI_texture_mirror_once;
-int GLAD_GL_IBM_rasterpos_clip;
-int GLAD_GL_EXT_semaphore;
-int GLAD_GL_SGIX_shadow;
-int GLAD_GL_EXT_polygon_offset_clamp;
-int GLAD_GL_NV_deep_texture3D;
-int GLAD_GL_ARB_shader_draw_parameters;
-int GLAD_GL_SGIX_calligraphic_fragment;
-int GLAD_GL_ARB_shader_bit_encoding;
-int GLAD_GL_EXT_compiled_vertex_array;
-int GLAD_GL_NV_depth_buffer_float;
-int GLAD_GL_NV_occlusion_query;
-int GLAD_GL_APPLE_flush_buffer_range;
-int GLAD_GL_ARB_imaging;
-int GLAD_GL_NV_shader_atomic_float;
-int GLAD_GL_ARB_draw_buffers_blend;
-int GLAD_GL_AMD_gcn_shader;
-int GLAD_GL_AMD_blend_minmax_factor;
-int GLAD_GL_EXT_texture_sRGB_decode;
-int GLAD_GL_ARB_shading_language_420pack;
-int GLAD_GL_ARB_shader_viewport_layer_array;
-int GLAD_GL_ATI_meminfo;
-int GLAD_GL_EXT_abgr;
-int GLAD_GL_AMD_pinned_memory;
-int GLAD_GL_EXT_texture_snorm;
-int GLAD_GL_SGIX_texture_coordinate_clamp;
-int GLAD_GL_ARB_clear_buffer_object;
-int GLAD_GL_ARB_multisample;
-int GLAD_GL_EXT_debug_label;
-int GLAD_GL_ARB_sample_shading;
-int GLAD_GL_NV_internalformat_sample_query;
-int GLAD_GL_INTEL_map_texture;
-int GLAD_GL_ARB_texture_env_crossbar;
-int GLAD_GL_EXT_422_pixels;
-int GLAD_GL_NV_blend_minmax_factor;
-int GLAD_GL_NV_conservative_raster_pre_snap_triangles;
-int GLAD_GL_ARB_compute_shader;
-int GLAD_GL_EXT_blend_logic_op;
-int GLAD_GL_ARB_blend_func_extended;
-int GLAD_GL_IBM_vertex_array_lists;
-int GLAD_GL_ARB_color_buffer_float;
-int GLAD_GL_ARB_bindless_texture;
-int GLAD_GL_ARB_window_pos;
-int GLAD_GL_ARB_internalformat_query;
-int GLAD_GL_ARB_shadow;
-int GLAD_GL_ARB_texture_mirrored_repeat;
-int GLAD_GL_EXT_shader_image_load_store;
-int GLAD_GL_EXT_copy_texture;
-int GLAD_GL_NV_register_combiners2;
-int GLAD_GL_SGIX_ycrcb_subsample;
-int GLAD_GL_NV_alpha_to_coverage_dither_control;
-int GLAD_GL_SGIX_ir_instrument1;
-int GLAD_GL_NV_draw_texture;
-int GLAD_GL_EXT_texture_shared_exponent;
-int GLAD_GL_NV_texture_shader2;
-int GLAD_GL_EXT_draw_instanced;
-int GLAD_GL_NV_copy_depth_to_color;
-int GLAD_GL_ARB_viewport_array;
-int GLAD_GL_ARB_separate_shader_objects;
-int GLAD_GL_NV_conservative_raster_pre_snap;
-int GLAD_GL_EXT_depth_bounds_test;
-int GLAD_GL_HP_image_transform;
-int GLAD_GL_ARB_texture_env_add;
-int GLAD_GL_NV_video_capture;
-int GLAD_GL_ARB_sampler_objects;
-int GLAD_GL_ARB_matrix_palette;
-int GLAD_GL_SGIS_texture_color_mask;
-int GLAD_GL_EXT_packed_pixels;
-int GLAD_GL_EXT_coordinate_frame;
-int GLAD_GL_ARB_texture_compression;
-int GLAD_GL_ARB_multi_bind;
-int GLAD_GL_APPLE_aux_depth_stencil;
-int GLAD_GL_ARB_shader_subroutine;
-int GLAD_GL_EXT_framebuffer_sRGB;
-int GLAD_GL_ARB_texture_storage_multisample;
-int GLAD_GL_KHR_blend_equation_advanced_coherent;
-int GLAD_GL_EXT_vertex_attrib_64bit;
-int GLAD_GL_NV_shader_atomic_float64;
-int GLAD_GL_ARB_depth_texture;
-int GLAD_GL_NV_shader_buffer_store;
-int GLAD_GL_OES_query_matrix;
-int GLAD_GL_MESA_window_pos;
-int GLAD_GL_NV_fill_rectangle;
-int GLAD_GL_NV_shader_storage_buffer_object;
-int GLAD_GL_ARB_texture_query_lod;
-int GLAD_GL_ARB_copy_buffer;
-int GLAD_GL_ARB_shader_image_size;
-int GLAD_GL_NV_shader_atomic_counters;
-int GLAD_GL_APPLE_object_purgeable;
-int GLAD_GL_ARB_occlusion_query;
-int GLAD_GL_INGR_color_clamp;
-int GLAD_GL_SGI_color_table;
-int GLAD_GL_NV_gpu_program5_mem_extended;
-int GLAD_GL_ARB_texture_cube_map_array;
-int GLAD_GL_SGIX_scalebias_hint;
-int GLAD_GL_EXT_gpu_shader4;
-int GLAD_GL_NV_geometry_program4;
-int GLAD_GL_EXT_framebuffer_multisample_blit_scaled;
-int GLAD_GL_AMD_debug_output;
-int GLAD_GL_ARB_texture_border_clamp;
-int GLAD_GL_EXT_win32_keyed_mutex;
-int GLAD_GL_ARB_fragment_coord_conventions;
-int GLAD_GL_ARB_multitexture;
-int GLAD_GL_SGIX_polynomial_ffd;
-int GLAD_GL_EXT_texture_env_dot3;
-int GLAD_GL_EXT_provoking_vertex;
-int GLAD_GL_ARB_point_parameters;
-int GLAD_GL_ARB_shader_image_load_store;
-int GLAD_GL_ARB_conditional_render_inverted;
-int GLAD_GL_HP_occlusion_test;
-int GLAD_GL_ARB_ES3_compatibility;
-int GLAD_GL_ARB_texture_barrier;
-int GLAD_GL_ARB_texture_buffer_object_rgb32;
-int GLAD_GL_NV_bindless_multi_draw_indirect;
-int GLAD_GL_SGIX_texture_multi_buffer;
-int GLAD_GL_INTEL_blackhole_render;
-int GLAD_GL_AMD_shader_image_load_store_lod;
-int GLAD_GL_KHR_texture_compression_astc_ldr;
-int GLAD_GL_3DFX_multisample;
-int GLAD_GL_INTEL_fragment_shader_ordering;
-int GLAD_GL_ARB_texture_env_dot3;
-int GLAD_GL_NV_gpu_program4;
-int GLAD_GL_NV_gpu_program5;
-int GLAD_GL_NV_float_buffer;
-int GLAD_GL_SGIS_texture_edge_clamp;
-int GLAD_GL_ARB_framebuffer_sRGB;
-int GLAD_GL_SUN_slice_accum;
-int GLAD_GL_EXT_index_texture;
-int GLAD_GL_EXT_shader_image_load_formatted;
-int GLAD_GL_ARB_geometry_shader4;
-int GLAD_GL_EXT_separate_specular_color;
-int GLAD_GL_AMD_depth_clamp_separate;
-int GLAD_GL_NV_conservative_raster;
-int GLAD_GL_ARB_sparse_texture2;
-int GLAD_GL_SGIX_sprite;
-int GLAD_GL_ARB_get_program_binary;
-int GLAD_GL_AMD_occlusion_query_event;
-int GLAD_GL_SGIS_multisample;
-int GLAD_GL_EXT_framebuffer_object;
-int GLAD_GL_ARB_robustness_isolation;
-int GLAD_GL_ARB_vertex_array_bgra;
-int GLAD_GL_APPLE_vertex_array_range;
-int GLAD_GL_AMD_query_buffer_object;
-int GLAD_GL_NV_register_combiners;
-int GLAD_GL_ARB_draw_buffers;
-int GLAD_GL_NVX_blend_equation_advanced_multi_draw_buffers;
-int GLAD_GL_AMD_gpu_shader_int16;
-int GLAD_GL_ARB_debug_output;
-int GLAD_GL_EXT_shader_framebuffer_fetch;
-int GLAD_GL_SGI_color_matrix;
-int GLAD_GL_EXT_cull_vertex;
-int GLAD_GL_EXT_texture_sRGB;
-int GLAD_GL_APPLE_row_bytes;
-int GLAD_GL_NV_conservative_raster_underestimation;
-int GLAD_GL_IBM_multimode_draw_arrays;
-int GLAD_GL_KHR_parallel_shader_compile;
-int GLAD_GL_APPLE_vertex_array_object;
-int GLAD_GL_3DFX_texture_compression_FXT1;
-int GLAD_GL_NV_fragment_shader_interlock;
-int GLAD_GL_AMD_conservative_depth;
-int GLAD_GL_ARB_texture_float;
-int GLAD_GL_ARB_compressed_texture_pixel_storage;
-int GLAD_GL_SGIS_detail_texture;
-int GLAD_GL_NV_geometry_shader_passthrough;
-int GLAD_GL_ARB_draw_instanced;
-int GLAD_GL_OES_read_format;
-int GLAD_GL_ATI_texture_float;
-int GLAD_GL_ARB_texture_gather;
-int GLAD_GL_AMD_vertex_shader_layer;
-int GLAD_GL_ARB_shading_language_include;
-int GLAD_GL_APPLE_client_storage;
-int GLAD_GL_WIN_phong_shading;
-int GLAD_GL_INGR_blend_func_separate;
-int GLAD_GL_NV_path_rendering;
-int GLAD_GL_NV_conservative_raster_dilate;
-int GLAD_GL_AMD_gpu_shader_half_float;
-int GLAD_GL_ARB_post_depth_coverage;
-int GLAD_GL_ARB_texture_non_power_of_two;
-int GLAD_GL_APPLE_rgb_422;
-int GLAD_GL_EXT_texture_lod_bias;
-int GLAD_GL_ARB_gpu_shader_int64;
-int GLAD_GL_ARB_seamless_cube_map;
-int GLAD_GL_ARB_shader_group_vote;
-int GLAD_GL_NV_vdpau_interop;
-int GLAD_GL_ARB_occlusion_query2;
-int GLAD_GL_ARB_internalformat_query2;
-int GLAD_GL_EXT_texture_filter_anisotropic;
-int GLAD_GL_SUN_vertex;
-int GLAD_GL_EXT_transform_feedback;
-int GLAD_GL_SGIX_igloo_interface;
-int GLAD_GL_SGIS_texture_lod;
-int GLAD_GL_NV_vertex_program3;
-int GLAD_GL_ARB_draw_indirect;
-int GLAD_GL_NV_vertex_program4;
-int GLAD_GL_AMD_transform_feedback3_lines_triangles;
-int GLAD_GL_SGIS_fog_function;
-int GLAD_GL_EXT_x11_sync_object;
-int GLAD_GL_ARB_sync;
-int GLAD_GL_NV_texture_rectangle_compressed;
-int GLAD_GL_NV_sample_locations;
-int GLAD_GL_NV_gpu_multicast;
-int GLAD_GL_ARB_gl_spirv;
-int GLAD_GL_ARB_compute_variable_group_size;
-int GLAD_GL_OES_fixed_point;
-int GLAD_GL_MESA_program_binary_formats;
-int GLAD_GL_NV_blend_square;
-int GLAD_GL_EXT_framebuffer_multisample;
-int GLAD_GL_ARB_gpu_shader5;
-int GLAD_GL_SGIS_texture4D;
-int GLAD_GL_EXT_texture3D;
-int GLAD_GL_EXT_multisample;
-int GLAD_GL_EXT_secondary_color;
-int GLAD_GL_INTEL_conservative_rasterization;
-int GLAD_GL_ARB_texture_filter_minmax;
-int GLAD_GL_ATI_vertex_array_object;
-int GLAD_GL_ARB_parallel_shader_compile;
-int GLAD_GL_NVX_gpu_memory_info;
-int GLAD_GL_ARB_sparse_texture;
-int GLAD_GL_SGIS_point_line_texgen;
-int GLAD_GL_ARB_sample_locations;
-int GLAD_GL_ARB_sparse_buffer;
-int GLAD_GL_ARB_polygon_offset_clamp;
-int GLAD_GL_EXT_draw_range_elements;
-int GLAD_GL_SGIX_blend_alpha_minmax;
-int GLAD_GL_KHR_context_flush_control;
-PFNGLTBUFFERMASK3DFXPROC glad_glTbufferMask3DFX;
-PFNGLDEBUGMESSAGEENABLEAMDPROC glad_glDebugMessageEnableAMD;
-PFNGLDEBUGMESSAGEINSERTAMDPROC glad_glDebugMessageInsertAMD;
-PFNGLDEBUGMESSAGECALLBACKAMDPROC glad_glDebugMessageCallbackAMD;
-PFNGLGETDEBUGMESSAGELOGAMDPROC glad_glGetDebugMessageLogAMD;
-PFNGLBLENDFUNCINDEXEDAMDPROC glad_glBlendFuncIndexedAMD;
-PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC glad_glBlendFuncSeparateIndexedAMD;
-PFNGLBLENDEQUATIONINDEXEDAMDPROC glad_glBlendEquationIndexedAMD;
-PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC glad_glBlendEquationSeparateIndexedAMD;
-PFNGLFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC glad_glFramebufferSamplePositionsfvAMD;
-PFNGLNAMEDFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC glad_glNamedFramebufferSamplePositionsfvAMD;
-PFNGLGETFRAMEBUFFERPARAMETERFVAMDPROC glad_glGetFramebufferParameterfvAMD;
-PFNGLGETNAMEDFRAMEBUFFERPARAMETERFVAMDPROC glad_glGetNamedFramebufferParameterfvAMD;
-PFNGLUNIFORM1I64NVPROC glad_glUniform1i64NV;
-PFNGLUNIFORM2I64NVPROC glad_glUniform2i64NV;
-PFNGLUNIFORM3I64NVPROC glad_glUniform3i64NV;
-PFNGLUNIFORM4I64NVPROC glad_glUniform4i64NV;
-PFNGLUNIFORM1I64VNVPROC glad_glUniform1i64vNV;
-PFNGLUNIFORM2I64VNVPROC glad_glUniform2i64vNV;
-PFNGLUNIFORM3I64VNVPROC glad_glUniform3i64vNV;
-PFNGLUNIFORM4I64VNVPROC glad_glUniform4i64vNV;
-PFNGLUNIFORM1UI64NVPROC glad_glUniform1ui64NV;
-PFNGLUNIFORM2UI64NVPROC glad_glUniform2ui64NV;
-PFNGLUNIFORM3UI64NVPROC glad_glUniform3ui64NV;
-PFNGLUNIFORM4UI64NVPROC glad_glUniform4ui64NV;
-PFNGLUNIFORM1UI64VNVPROC glad_glUniform1ui64vNV;
-PFNGLUNIFORM2UI64VNVPROC glad_glUniform2ui64vNV;
-PFNGLUNIFORM3UI64VNVPROC glad_glUniform3ui64vNV;
-PFNGLUNIFORM4UI64VNVPROC glad_glUniform4ui64vNV;
-PFNGLGETUNIFORMI64VNVPROC glad_glGetUniformi64vNV;
-PFNGLGETUNIFORMUI64VNVPROC glad_glGetUniformui64vNV;
-PFNGLPROGRAMUNIFORM1I64NVPROC glad_glProgramUniform1i64NV;
-PFNGLPROGRAMUNIFORM2I64NVPROC glad_glProgramUniform2i64NV;
-PFNGLPROGRAMUNIFORM3I64NVPROC glad_glProgramUniform3i64NV;
-PFNGLPROGRAMUNIFORM4I64NVPROC glad_glProgramUniform4i64NV;
-PFNGLPROGRAMUNIFORM1I64VNVPROC glad_glProgramUniform1i64vNV;
-PFNGLPROGRAMUNIFORM2I64VNVPROC glad_glProgramUniform2i64vNV;
-PFNGLPROGRAMUNIFORM3I64VNVPROC glad_glProgramUniform3i64vNV;
-PFNGLPROGRAMUNIFORM4I64VNVPROC glad_glProgramUniform4i64vNV;
-PFNGLPROGRAMUNIFORM1UI64NVPROC glad_glProgramUniform1ui64NV;
-PFNGLPROGRAMUNIFORM2UI64NVPROC glad_glProgramUniform2ui64NV;
-PFNGLPROGRAMUNIFORM3UI64NVPROC glad_glProgramUniform3ui64NV;
-PFNGLPROGRAMUNIFORM4UI64NVPROC glad_glProgramUniform4ui64NV;
-PFNGLPROGRAMUNIFORM1UI64VNVPROC glad_glProgramUniform1ui64vNV;
-PFNGLPROGRAMUNIFORM2UI64VNVPROC glad_glProgramUniform2ui64vNV;
-PFNGLPROGRAMUNIFORM3UI64VNVPROC glad_glProgramUniform3ui64vNV;
-PFNGLPROGRAMUNIFORM4UI64VNVPROC glad_glProgramUniform4ui64vNV;
-PFNGLVERTEXATTRIBPARAMETERIAMDPROC glad_glVertexAttribParameteriAMD;
-PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC glad_glMultiDrawArraysIndirectAMD;
-PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC glad_glMultiDrawElementsIndirectAMD;
-PFNGLGENNAMESAMDPROC glad_glGenNamesAMD;
-PFNGLDELETENAMESAMDPROC glad_glDeleteNamesAMD;
-PFNGLISNAMEAMDPROC glad_glIsNameAMD;
-PFNGLQUERYOBJECTPARAMETERUIAMDPROC glad_glQueryObjectParameteruiAMD;
-PFNGLGETPERFMONITORGROUPSAMDPROC glad_glGetPerfMonitorGroupsAMD;
-PFNGLGETPERFMONITORCOUNTERSAMDPROC glad_glGetPerfMonitorCountersAMD;
-PFNGLGETPERFMONITORGROUPSTRINGAMDPROC glad_glGetPerfMonitorGroupStringAMD;
-PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC glad_glGetPerfMonitorCounterStringAMD;
-PFNGLGETPERFMONITORCOUNTERINFOAMDPROC glad_glGetPerfMonitorCounterInfoAMD;
-PFNGLGENPERFMONITORSAMDPROC glad_glGenPerfMonitorsAMD;
-PFNGLDELETEPERFMONITORSAMDPROC glad_glDeletePerfMonitorsAMD;
-PFNGLSELECTPERFMONITORCOUNTERSAMDPROC glad_glSelectPerfMonitorCountersAMD;
-PFNGLBEGINPERFMONITORAMDPROC glad_glBeginPerfMonitorAMD;
-PFNGLENDPERFMONITORAMDPROC glad_glEndPerfMonitorAMD;
-PFNGLGETPERFMONITORCOUNTERDATAAMDPROC glad_glGetPerfMonitorCounterDataAMD;
-PFNGLSETMULTISAMPLEFVAMDPROC glad_glSetMultisamplefvAMD;
-PFNGLTEXSTORAGESPARSEAMDPROC glad_glTexStorageSparseAMD;
-PFNGLTEXTURESTORAGESPARSEAMDPROC glad_glTextureStorageSparseAMD;
-PFNGLSTENCILOPVALUEAMDPROC glad_glStencilOpValueAMD;
-PFNGLTESSELLATIONFACTORAMDPROC glad_glTessellationFactorAMD;
-PFNGLTESSELLATIONMODEAMDPROC glad_glTessellationModeAMD;
-PFNGLELEMENTPOINTERAPPLEPROC glad_glElementPointerAPPLE;
-PFNGLDRAWELEMENTARRAYAPPLEPROC glad_glDrawElementArrayAPPLE;
-PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC glad_glDrawRangeElementArrayAPPLE;
-PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC glad_glMultiDrawElementArrayAPPLE;
-PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC glad_glMultiDrawRangeElementArrayAPPLE;
-PFNGLGENFENCESAPPLEPROC glad_glGenFencesAPPLE;
-PFNGLDELETEFENCESAPPLEPROC glad_glDeleteFencesAPPLE;
-PFNGLSETFENCEAPPLEPROC glad_glSetFenceAPPLE;
-PFNGLISFENCEAPPLEPROC glad_glIsFenceAPPLE;
-PFNGLTESTFENCEAPPLEPROC glad_glTestFenceAPPLE;
-PFNGLFINISHFENCEAPPLEPROC glad_glFinishFenceAPPLE;
-PFNGLTESTOBJECTAPPLEPROC glad_glTestObjectAPPLE;
-PFNGLFINISHOBJECTAPPLEPROC glad_glFinishObjectAPPLE;
-PFNGLBUFFERPARAMETERIAPPLEPROC glad_glBufferParameteriAPPLE;
-PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glad_glFlushMappedBufferRangeAPPLE;
-PFNGLOBJECTPURGEABLEAPPLEPROC glad_glObjectPurgeableAPPLE;
-PFNGLOBJECTUNPURGEABLEAPPLEPROC glad_glObjectUnpurgeableAPPLE;
-PFNGLGETOBJECTPARAMETERIVAPPLEPROC glad_glGetObjectParameterivAPPLE;
-PFNGLTEXTURERANGEAPPLEPROC glad_glTextureRangeAPPLE;
-PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC glad_glGetTexParameterPointervAPPLE;
-PFNGLBINDVERTEXARRAYAPPLEPROC glad_glBindVertexArrayAPPLE;
-PFNGLDELETEVERTEXARRAYSAPPLEPROC glad_glDeleteVertexArraysAPPLE;
-PFNGLGENVERTEXARRAYSAPPLEPROC glad_glGenVertexArraysAPPLE;
-PFNGLISVERTEXARRAYAPPLEPROC glad_glIsVertexArrayAPPLE;
-PFNGLVERTEXARRAYRANGEAPPLEPROC glad_glVertexArrayRangeAPPLE;
-PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC glad_glFlushVertexArrayRangeAPPLE;
-PFNGLVERTEXARRAYPARAMETERIAPPLEPROC glad_glVertexArrayParameteriAPPLE;
-PFNGLENABLEVERTEXATTRIBAPPLEPROC glad_glEnableVertexAttribAPPLE;
-PFNGLDISABLEVERTEXATTRIBAPPLEPROC glad_glDisableVertexAttribAPPLE;
-PFNGLISVERTEXATTRIBENABLEDAPPLEPROC glad_glIsVertexAttribEnabledAPPLE;
-PFNGLMAPVERTEXATTRIB1DAPPLEPROC glad_glMapVertexAttrib1dAPPLE;
-PFNGLMAPVERTEXATTRIB1FAPPLEPROC glad_glMapVertexAttrib1fAPPLE;
-PFNGLMAPVERTEXATTRIB2DAPPLEPROC glad_glMapVertexAttrib2dAPPLE;
-PFNGLMAPVERTEXATTRIB2FAPPLEPROC glad_glMapVertexAttrib2fAPPLE;
-PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;
-PFNGLSHADERBINARYPROC glad_glShaderBinary;
-PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;
-PFNGLDEPTHRANGEFPROC glad_glDepthRangef;
-PFNGLCLEARDEPTHFPROC glad_glClearDepthf;
-PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion;
-PFNGLPRIMITIVEBOUNDINGBOXARBPROC glad_glPrimitiveBoundingBoxARB;
-PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance;
-PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance;
-PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance;
-PFNGLGETTEXTUREHANDLEARBPROC glad_glGetTextureHandleARB;
-PFNGLGETTEXTURESAMPLERHANDLEARBPROC glad_glGetTextureSamplerHandleARB;
-PFNGLMAKETEXTUREHANDLERESIDENTARBPROC glad_glMakeTextureHandleResidentARB;
-PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC glad_glMakeTextureHandleNonResidentARB;
-PFNGLGETIMAGEHANDLEARBPROC glad_glGetImageHandleARB;
-PFNGLMAKEIMAGEHANDLERESIDENTARBPROC glad_glMakeImageHandleResidentARB;
-PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC glad_glMakeImageHandleNonResidentARB;
-PFNGLUNIFORMHANDLEUI64ARBPROC glad_glUniformHandleui64ARB;
-PFNGLUNIFORMHANDLEUI64VARBPROC glad_glUniformHandleui64vARB;
-PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC glad_glProgramUniformHandleui64ARB;
-PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC glad_glProgramUniformHandleui64vARB;
-PFNGLISTEXTUREHANDLERESIDENTARBPROC glad_glIsTextureHandleResidentARB;
-PFNGLISIMAGEHANDLERESIDENTARBPROC glad_glIsImageHandleResidentARB;
-PFNGLVERTEXATTRIBL1UI64ARBPROC glad_glVertexAttribL1ui64ARB;
-PFNGLVERTEXATTRIBL1UI64VARBPROC glad_glVertexAttribL1ui64vARB;
-PFNGLGETVERTEXATTRIBLUI64VARBPROC glad_glGetVertexAttribLui64vARB;
-PFNGLBUFFERSTORAGEPROC glad_glBufferStorage;
-PFNGLCREATESYNCFROMCLEVENTARBPROC glad_glCreateSyncFromCLeventARB;
-PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData;
-PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData;
-PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage;
-PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage;
-PFNGLCLIPCONTROLPROC glad_glClipControl;
-PFNGLCLAMPCOLORARBPROC glad_glClampColorARB;
-PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute;
-PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect;
-PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC glad_glDispatchComputeGroupSizeARB;
-PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData;
-PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB;
-PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB;
-PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB;
-PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB;
-PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks;
-PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase;
-PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange;
-PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv;
-PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v;
-PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v;
-PFNGLCREATEBUFFERSPROC glad_glCreateBuffers;
-PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage;
-PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData;
-PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData;
-PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData;
-PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData;
-PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData;
-PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer;
-PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange;
-PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer;
-PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange;
-PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv;
-PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v;
-PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv;
-PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData;
-PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers;
-PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer;
-PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri;
-PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture;
-PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer;
-PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer;
-PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers;
-PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer;
-PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData;
-PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData;
-PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv;
-PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv;
-PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv;
-PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi;
-PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer;
-PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus;
-PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv;
-PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv;
-PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers;
-PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage;
-PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample;
-PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv;
-PFNGLCREATETEXTURESPROC glad_glCreateTextures;
-PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer;
-PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange;
-PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D;
-PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D;
-PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D;
-PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample;
-PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample;
-PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D;
-PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D;
-PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D;
-PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D;
-PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D;
-PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D;
-PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D;
-PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D;
-PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D;
-PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf;
-PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv;
-PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri;
-PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv;
-PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv;
-PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv;
-PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap;
-PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit;
-PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage;
-PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage;
-PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv;
-PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv;
-PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv;
-PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv;
-PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv;
-PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv;
-PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays;
-PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib;
-PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib;
-PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer;
-PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer;
-PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers;
-PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding;
-PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat;
-PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat;
-PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat;
-PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor;
-PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv;
-PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv;
-PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv;
-PFNGLCREATESAMPLERSPROC glad_glCreateSamplers;
-PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines;
-PFNGLCREATEQUERIESPROC glad_glCreateQueries;
-PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v;
-PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv;
-PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v;
-PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv;
-PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB;
-PFNGLBLENDEQUATIONIARBPROC glad_glBlendEquationiARB;
-PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB;
-PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB;
-PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB;
-PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect;
-PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect;
-PFNGLDRAWARRAYSINSTANCEDARBPROC glad_glDrawArraysInstancedARB;
-PFNGLDRAWELEMENTSINSTANCEDARBPROC glad_glDrawElementsInstancedARB;
-PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB;
-PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB;
-PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB;
-PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB;
-PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB;
-PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB;
-PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB;
-PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB;
-PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB;
-PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB;
-PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB;
-PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB;
-PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB;
-PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB;
-PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB;
-PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB;
-PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB;
-PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB;
-PFNGLISPROGRAMARBPROC glad_glIsProgramARB;
-PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri;
-PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv;
-PFNGLPROGRAMPARAMETERIARBPROC glad_glProgramParameteriARB;
-PFNGLFRAMEBUFFERTEXTUREARBPROC glad_glFramebufferTextureARB;
-PFNGLFRAMEBUFFERTEXTURELAYERARBPROC glad_glFramebufferTextureLayerARB;
-PFNGLFRAMEBUFFERTEXTUREFACEARBPROC glad_glFramebufferTextureFaceARB;
-PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary;
-PFNGLPROGRAMBINARYPROC glad_glProgramBinary;
-PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri;
-PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage;
-PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage;
-PFNGLSPECIALIZESHADERARBPROC glad_glSpecializeShaderARB;
-PFNGLUNIFORM1DPROC glad_glUniform1d;
-PFNGLUNIFORM2DPROC glad_glUniform2d;
-PFNGLUNIFORM3DPROC glad_glUniform3d;
-PFNGLUNIFORM4DPROC glad_glUniform4d;
-PFNGLUNIFORM1DVPROC glad_glUniform1dv;
-PFNGLUNIFORM2DVPROC glad_glUniform2dv;
-PFNGLUNIFORM3DVPROC glad_glUniform3dv;
-PFNGLUNIFORM4DVPROC glad_glUniform4dv;
-PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv;
-PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv;
-PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv;
-PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv;
-PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv;
-PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv;
-PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv;
-PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv;
-PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv;
-PFNGLGETUNIFORMDVPROC glad_glGetUniformdv;
-PFNGLUNIFORM1I64ARBPROC glad_glUniform1i64ARB;
-PFNGLUNIFORM2I64ARBPROC glad_glUniform2i64ARB;
-PFNGLUNIFORM3I64ARBPROC glad_glUniform3i64ARB;
-PFNGLUNIFORM4I64ARBPROC glad_glUniform4i64ARB;
-PFNGLUNIFORM1I64VARBPROC glad_glUniform1i64vARB;
-PFNGLUNIFORM2I64VARBPROC glad_glUniform2i64vARB;
-PFNGLUNIFORM3I64VARBPROC glad_glUniform3i64vARB;
-PFNGLUNIFORM4I64VARBPROC glad_glUniform4i64vARB;
-PFNGLUNIFORM1UI64ARBPROC glad_glUniform1ui64ARB;
-PFNGLUNIFORM2UI64ARBPROC glad_glUniform2ui64ARB;
-PFNGLUNIFORM3UI64ARBPROC glad_glUniform3ui64ARB;
-PFNGLUNIFORM4UI64ARBPROC glad_glUniform4ui64ARB;
-PFNGLUNIFORM1UI64VARBPROC glad_glUniform1ui64vARB;
-PFNGLUNIFORM2UI64VARBPROC glad_glUniform2ui64vARB;
-PFNGLUNIFORM3UI64VARBPROC glad_glUniform3ui64vARB;
-PFNGLUNIFORM4UI64VARBPROC glad_glUniform4ui64vARB;
-PFNGLGETUNIFORMI64VARBPROC glad_glGetUniformi64vARB;
-PFNGLGETUNIFORMUI64VARBPROC glad_glGetUniformui64vARB;
-PFNGLGETNUNIFORMI64VARBPROC glad_glGetnUniformi64vARB;
-PFNGLGETNUNIFORMUI64VARBPROC glad_glGetnUniformui64vARB;
-PFNGLPROGRAMUNIFORM1I64ARBPROC glad_glProgramUniform1i64ARB;
-PFNGLPROGRAMUNIFORM2I64ARBPROC glad_glProgramUniform2i64ARB;
-PFNGLPROGRAMUNIFORM3I64ARBPROC glad_glProgramUniform3i64ARB;
-PFNGLPROGRAMUNIFORM4I64ARBPROC glad_glProgramUniform4i64ARB;
-PFNGLPROGRAMUNIFORM1I64VARBPROC glad_glProgramUniform1i64vARB;
-PFNGLPROGRAMUNIFORM2I64VARBPROC glad_glProgramUniform2i64vARB;
-PFNGLPROGRAMUNIFORM3I64VARBPROC glad_glProgramUniform3i64vARB;
-PFNGLPROGRAMUNIFORM4I64VARBPROC glad_glProgramUniform4i64vARB;
-PFNGLPROGRAMUNIFORM1UI64ARBPROC glad_glProgramUniform1ui64ARB;
-PFNGLPROGRAMUNIFORM2UI64ARBPROC glad_glProgramUniform2ui64ARB;
-PFNGLPROGRAMUNIFORM3UI64ARBPROC glad_glProgramUniform3ui64ARB;
-PFNGLPROGRAMUNIFORM4UI64ARBPROC glad_glProgramUniform4ui64ARB;
-PFNGLPROGRAMUNIFORM1UI64VARBPROC glad_glProgramUniform1ui64vARB;
-PFNGLPROGRAMUNIFORM2UI64VARBPROC glad_glProgramUniform2ui64vARB;
-PFNGLPROGRAMUNIFORM3UI64VARBPROC glad_glProgramUniform3ui64vARB;
-PFNGLPROGRAMUNIFORM4UI64VARBPROC glad_glProgramUniform4ui64vARB;
-PFNGLCOLORTABLEPROC glad_glColorTable;
-PFNGLCOLORTABLEPARAMETERFVPROC glad_glColorTableParameterfv;
-PFNGLCOLORTABLEPARAMETERIVPROC glad_glColorTableParameteriv;
-PFNGLCOPYCOLORTABLEPROC glad_glCopyColorTable;
-PFNGLGETCOLORTABLEPROC glad_glGetColorTable;
-PFNGLGETCOLORTABLEPARAMETERFVPROC glad_glGetColorTableParameterfv;
-PFNGLGETCOLORTABLEPARAMETERIVPROC glad_glGetColorTableParameteriv;
-PFNGLCOLORSUBTABLEPROC glad_glColorSubTable;
-PFNGLCOPYCOLORSUBTABLEPROC glad_glCopyColorSubTable;
-PFNGLCONVOLUTIONFILTER1DPROC glad_glConvolutionFilter1D;
-PFNGLCONVOLUTIONFILTER2DPROC glad_glConvolutionFilter2D;
-PFNGLCONVOLUTIONPARAMETERFPROC glad_glConvolutionParameterf;
-PFNGLCONVOLUTIONPARAMETERFVPROC glad_glConvolutionParameterfv;
-PFNGLCONVOLUTIONPARAMETERIPROC glad_glConvolutionParameteri;
-PFNGLCONVOLUTIONPARAMETERIVPROC glad_glConvolutionParameteriv;
-PFNGLCOPYCONVOLUTIONFILTER1DPROC glad_glCopyConvolutionFilter1D;
-PFNGLCOPYCONVOLUTIONFILTER2DPROC glad_glCopyConvolutionFilter2D;
-PFNGLGETCONVOLUTIONFILTERPROC glad_glGetConvolutionFilter;
-PFNGLGETCONVOLUTIONPARAMETERFVPROC glad_glGetConvolutionParameterfv;
-PFNGLGETCONVOLUTIONPARAMETERIVPROC glad_glGetConvolutionParameteriv;
-PFNGLGETSEPARABLEFILTERPROC glad_glGetSeparableFilter;
-PFNGLSEPARABLEFILTER2DPROC glad_glSeparableFilter2D;
-PFNGLGETHISTOGRAMPROC glad_glGetHistogram;
-PFNGLGETHISTOGRAMPARAMETERFVPROC glad_glGetHistogramParameterfv;
-PFNGLGETHISTOGRAMPARAMETERIVPROC glad_glGetHistogramParameteriv;
-PFNGLGETMINMAXPROC glad_glGetMinmax;
-PFNGLGETMINMAXPARAMETERFVPROC glad_glGetMinmaxParameterfv;
-PFNGLGETMINMAXPARAMETERIVPROC glad_glGetMinmaxParameteriv;
-PFNGLHISTOGRAMPROC glad_glHistogram;
-PFNGLMINMAXPROC glad_glMinmax;
-PFNGLRESETHISTOGRAMPROC glad_glResetHistogram;
-PFNGLRESETMINMAXPROC glad_glResetMinmax;
-PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC glad_glMultiDrawArraysIndirectCountARB;
-PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC glad_glMultiDrawElementsIndirectCountARB;
-PFNGLVERTEXATTRIBDIVISORARBPROC glad_glVertexAttribDivisorARB;
-PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ;
-PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v;
-PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage;
-PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage;
-PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData;
-PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData;
-PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer;
-PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer;
-PFNGLCURRENTPALETTEMATRIXARBPROC glad_glCurrentPaletteMatrixARB;
-PFNGLMATRIXINDEXUBVARBPROC glad_glMatrixIndexubvARB;
-PFNGLMATRIXINDEXUSVARBPROC glad_glMatrixIndexusvARB;
-PFNGLMATRIXINDEXUIVARBPROC glad_glMatrixIndexuivARB;
-PFNGLMATRIXINDEXPOINTERARBPROC glad_glMatrixIndexPointerARB;
-PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase;
-PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange;
-PFNGLBINDTEXTURESPROC glad_glBindTextures;
-PFNGLBINDSAMPLERSPROC glad_glBindSamplers;
-PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures;
-PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers;
-PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect;
-PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect;
-PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB;
-PFNGLACTIVETEXTUREARBPROC glad_glActiveTextureARB;
-PFNGLCLIENTACTIVETEXTUREARBPROC glad_glClientActiveTextureARB;
-PFNGLMULTITEXCOORD1DARBPROC glad_glMultiTexCoord1dARB;
-PFNGLMULTITEXCOORD1DVARBPROC glad_glMultiTexCoord1dvARB;
-PFNGLMULTITEXCOORD1FARBPROC glad_glMultiTexCoord1fARB;
-PFNGLMULTITEXCOORD1FVARBPROC glad_glMultiTexCoord1fvARB;
-PFNGLMULTITEXCOORD1IARBPROC glad_glMultiTexCoord1iARB;
-PFNGLMULTITEXCOORD1IVARBPROC glad_glMultiTexCoord1ivARB;
-PFNGLMULTITEXCOORD1SARBPROC glad_glMultiTexCoord1sARB;
-PFNGLMULTITEXCOORD1SVARBPROC glad_glMultiTexCoord1svARB;
-PFNGLMULTITEXCOORD2DARBPROC glad_glMultiTexCoord2dARB;
-PFNGLMULTITEXCOORD2DVARBPROC glad_glMultiTexCoord2dvARB;
-PFNGLMULTITEXCOORD2FARBPROC glad_glMultiTexCoord2fARB;
-PFNGLMULTITEXCOORD2FVARBPROC glad_glMultiTexCoord2fvARB;
-PFNGLMULTITEXCOORD2IARBPROC glad_glMultiTexCoord2iARB;
-PFNGLMULTITEXCOORD2IVARBPROC glad_glMultiTexCoord2ivARB;
-PFNGLMULTITEXCOORD2SARBPROC glad_glMultiTexCoord2sARB;
-PFNGLMULTITEXCOORD2SVARBPROC glad_glMultiTexCoord2svARB;
-PFNGLMULTITEXCOORD3DARBPROC glad_glMultiTexCoord3dARB;
-PFNGLMULTITEXCOORD3DVARBPROC glad_glMultiTexCoord3dvARB;
-PFNGLMULTITEXCOORD3FARBPROC glad_glMultiTexCoord3fARB;
-PFNGLMULTITEXCOORD3FVARBPROC glad_glMultiTexCoord3fvARB;
-PFNGLMULTITEXCOORD3IARBPROC glad_glMultiTexCoord3iARB;
-PFNGLMULTITEXCOORD3IVARBPROC glad_glMultiTexCoord3ivARB;
-PFNGLMULTITEXCOORD3SARBPROC glad_glMultiTexCoord3sARB;
-PFNGLMULTITEXCOORD3SVARBPROC glad_glMultiTexCoord3svARB;
-PFNGLMULTITEXCOORD4DARBPROC glad_glMultiTexCoord4dARB;
-PFNGLMULTITEXCOORD4DVARBPROC glad_glMultiTexCoord4dvARB;
-PFNGLMULTITEXCOORD4FARBPROC glad_glMultiTexCoord4fARB;
-PFNGLMULTITEXCOORD4FVARBPROC glad_glMultiTexCoord4fvARB;
-PFNGLMULTITEXCOORD4IARBPROC glad_glMultiTexCoord4iARB;
-PFNGLMULTITEXCOORD4IVARBPROC glad_glMultiTexCoord4ivARB;
-PFNGLMULTITEXCOORD4SARBPROC glad_glMultiTexCoord4sARB;
-PFNGLMULTITEXCOORD4SVARBPROC glad_glMultiTexCoord4svARB;
-PFNGLGENQUERIESARBPROC glad_glGenQueriesARB;
-PFNGLDELETEQUERIESARBPROC glad_glDeleteQueriesARB;
-PFNGLISQUERYARBPROC glad_glIsQueryARB;
-PFNGLBEGINQUERYARBPROC glad_glBeginQueryARB;
-PFNGLENDQUERYARBPROC glad_glEndQueryARB;
-PFNGLGETQUERYIVARBPROC glad_glGetQueryivARB;
-PFNGLGETQUERYOBJECTIVARBPROC glad_glGetQueryObjectivARB;
-PFNGLGETQUERYOBJECTUIVARBPROC glad_glGetQueryObjectuivARB;
-PFNGLMAXSHADERCOMPILERTHREADSARBPROC glad_glMaxShaderCompilerThreadsARB;
-PFNGLPOINTPARAMETERFARBPROC glad_glPointParameterfARB;
-PFNGLPOINTPARAMETERFVARBPROC glad_glPointParameterfvARB;
-PFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp;
-PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv;
-PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex;
-PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName;
-PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv;
-PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation;
-PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex;
-PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB;
-PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB;
-PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB;
-PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB;
-PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB;
-PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB;
-PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB;
-PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB;
-PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB;
-PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB;
-PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB;
-PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB;
-PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB;
-PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB;
-PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB;
-PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB;
-PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB;
-PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB;
-PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB;
-PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB;
-PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glFramebufferSampleLocationsfvARB;
-PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB;
-PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB;
-PFNGLMINSAMPLESHADINGARBPROC glad_glMinSampleShadingARB;
-PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages;
-PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram;
-PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv;
-PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline;
-PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines;
-PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines;
-PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline;
-PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv;
-PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i;
-PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv;
-PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f;
-PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv;
-PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d;
-PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv;
-PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui;
-PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv;
-PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i;
-PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv;
-PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f;
-PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv;
-PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d;
-PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv;
-PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui;
-PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv;
-PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i;
-PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv;
-PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f;
-PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv;
-PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d;
-PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv;
-PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui;
-PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv;
-PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i;
-PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv;
-PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f;
-PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv;
-PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d;
-PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv;
-PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui;
-PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv;
-PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv;
-PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv;
-PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv;
-PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv;
-PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv;
-PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv;
-PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv;
-PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv;
-PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv;
-PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv;
-PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv;
-PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv;
-PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv;
-PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv;
-PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv;
-PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv;
-PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv;
-PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv;
-PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline;
-PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog;
-PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv;
-PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture;
-PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier;
-PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB;
-PFNGLGETHANDLEARBPROC glad_glGetHandleARB;
-PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB;
-PFNGLCREATESHADEROBJECTARBPROC glad_glCreateShaderObjectARB;
-PFNGLSHADERSOURCEARBPROC glad_glShaderSourceARB;
-PFNGLCOMPILESHADERARBPROC glad_glCompileShaderARB;
-PFNGLCREATEPROGRAMOBJECTARBPROC glad_glCreateProgramObjectARB;
-PFNGLATTACHOBJECTARBPROC glad_glAttachObjectARB;
-PFNGLLINKPROGRAMARBPROC glad_glLinkProgramARB;
-PFNGLUSEPROGRAMOBJECTARBPROC glad_glUseProgramObjectARB;
-PFNGLVALIDATEPROGRAMARBPROC glad_glValidateProgramARB;
-PFNGLUNIFORM1FARBPROC glad_glUniform1fARB;
-PFNGLUNIFORM2FARBPROC glad_glUniform2fARB;
-PFNGLUNIFORM3FARBPROC glad_glUniform3fARB;
-PFNGLUNIFORM4FARBPROC glad_glUniform4fARB;
-PFNGLUNIFORM1IARBPROC glad_glUniform1iARB;
-PFNGLUNIFORM2IARBPROC glad_glUniform2iARB;
-PFNGLUNIFORM3IARBPROC glad_glUniform3iARB;
-PFNGLUNIFORM4IARBPROC glad_glUniform4iARB;
-PFNGLUNIFORM1FVARBPROC glad_glUniform1fvARB;
-PFNGLUNIFORM2FVARBPROC glad_glUniform2fvARB;
-PFNGLUNIFORM3FVARBPROC glad_glUniform3fvARB;
-PFNGLUNIFORM4FVARBPROC glad_glUniform4fvARB;
-PFNGLUNIFORM1IVARBPROC glad_glUniform1ivARB;
-PFNGLUNIFORM2IVARBPROC glad_glUniform2ivARB;
-PFNGLUNIFORM3IVARBPROC glad_glUniform3ivARB;
-PFNGLUNIFORM4IVARBPROC glad_glUniform4ivARB;
-PFNGLUNIFORMMATRIX2FVARBPROC glad_glUniformMatrix2fvARB;
-PFNGLUNIFORMMATRIX3FVARBPROC glad_glUniformMatrix3fvARB;
-PFNGLUNIFORMMATRIX4FVARBPROC glad_glUniformMatrix4fvARB;
-PFNGLGETOBJECTPARAMETERFVARBPROC glad_glGetObjectParameterfvARB;
-PFNGLGETOBJECTPARAMETERIVARBPROC glad_glGetObjectParameterivARB;
-PFNGLGETINFOLOGARBPROC glad_glGetInfoLogARB;
-PFNGLGETATTACHEDOBJECTSARBPROC glad_glGetAttachedObjectsARB;
-PFNGLGETUNIFORMLOCATIONARBPROC glad_glGetUniformLocationARB;
-PFNGLGETACTIVEUNIFORMARBPROC glad_glGetActiveUniformARB;
-PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB;
-PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB;
-PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB;
-PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding;
-PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation;
-PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex;
-PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv;
-PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName;
-PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName;
-PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv;
-PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv;
-PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv;
-PFNGLNAMEDSTRINGARBPROC glad_glNamedStringARB;
-PFNGLDELETENAMEDSTRINGARBPROC glad_glDeleteNamedStringARB;
-PFNGLCOMPILESHADERINCLUDEARBPROC glad_glCompileShaderIncludeARB;
-PFNGLISNAMEDSTRINGARBPROC glad_glIsNamedStringARB;
-PFNGLGETNAMEDSTRINGARBPROC glad_glGetNamedStringARB;
-PFNGLGETNAMEDSTRINGIVARBPROC glad_glGetNamedStringivARB;
-PFNGLBUFFERPAGECOMMITMENTARBPROC glad_glBufferPageCommitmentARB;
-PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC glad_glNamedBufferPageCommitmentEXT;
-PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC glad_glNamedBufferPageCommitmentARB;
-PFNGLTEXPAGECOMMITMENTARBPROC glad_glTexPageCommitmentARB;
-PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri;
-PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv;
-PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier;
-PFNGLTEXBUFFERARBPROC glad_glTexBufferARB;
-PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange;
-PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB;
-PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB;
-PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB;
-PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB;
-PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB;
-PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB;
-PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB;
-PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D;
-PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D;
-PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D;
-PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample;
-PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample;
-PFNGLTEXTUREVIEWPROC glad_glTextureView;
-PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback;
-PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks;
-PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks;
-PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback;
-PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback;
-PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback;
-PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback;
-PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream;
-PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed;
-PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed;
-PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv;
-PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced;
-PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced;
-PFNGLLOADTRANSPOSEMATRIXFARBPROC glad_glLoadTransposeMatrixfARB;
-PFNGLLOADTRANSPOSEMATRIXDARBPROC glad_glLoadTransposeMatrixdARB;
-PFNGLMULTTRANSPOSEMATRIXFARBPROC glad_glMultTransposeMatrixfARB;
-PFNGLMULTTRANSPOSEMATRIXDARBPROC glad_glMultTransposeMatrixdARB;
-PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d;
-PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d;
-PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d;
-PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d;
-PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv;
-PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv;
-PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv;
-PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv;
-PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer;
-PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv;
-PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer;
-PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat;
-PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat;
-PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat;
-PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding;
-PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor;
-PFNGLWEIGHTBVARBPROC glad_glWeightbvARB;
-PFNGLWEIGHTSVARBPROC glad_glWeightsvARB;
-PFNGLWEIGHTIVARBPROC glad_glWeightivARB;
-PFNGLWEIGHTFVARBPROC glad_glWeightfvARB;
-PFNGLWEIGHTDVARBPROC glad_glWeightdvARB;
-PFNGLWEIGHTUBVARBPROC glad_glWeightubvARB;
-PFNGLWEIGHTUSVARBPROC glad_glWeightusvARB;
-PFNGLWEIGHTUIVARBPROC glad_glWeightuivARB;
-PFNGLWEIGHTPOINTERARBPROC glad_glWeightPointerARB;
-PFNGLVERTEXBLENDARBPROC glad_glVertexBlendARB;
-PFNGLBINDBUFFERARBPROC glad_glBindBufferARB;
-PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB;
-PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB;
-PFNGLISBUFFERARBPROC glad_glIsBufferARB;
-PFNGLBUFFERDATAARBPROC glad_glBufferDataARB;
-PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB;
-PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB;
-PFNGLMAPBUFFERARBPROC glad_glMapBufferARB;
-PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB;
-PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB;
-PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB;
-PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB;
-PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB;
-PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB;
-PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB;
-PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB;
-PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB;
-PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB;
-PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB;
-PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB;
-PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB;
-PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB;
-PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB;
-PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB;
-PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB;
-PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB;
-PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB;
-PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB;
-PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB;
-PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB;
-PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB;
-PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB;
-PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB;
-PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB;
-PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB;
-PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB;
-PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB;
-PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB;
-PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB;
-PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB;
-PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB;
-PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB;
-PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB;
-PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB;
-PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB;
-PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB;
-PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB;
-PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB;
-PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB;
-PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB;
-PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB;
-PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB;
-PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB;
-PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB;
-PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB;
-PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB;
-PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB;
-PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv;
-PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf;
-PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv;
-PFNGLSCISSORARRAYVPROC glad_glScissorArrayv;
-PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed;
-PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv;
-PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv;
-PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed;
-PFNGLGETFLOATI_VPROC glad_glGetFloati_v;
-PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v;
-PFNGLWINDOWPOS2DARBPROC glad_glWindowPos2dARB;
-PFNGLWINDOWPOS2DVARBPROC glad_glWindowPos2dvARB;
-PFNGLWINDOWPOS2FARBPROC glad_glWindowPos2fARB;
-PFNGLWINDOWPOS2FVARBPROC glad_glWindowPos2fvARB;
-PFNGLWINDOWPOS2IARBPROC glad_glWindowPos2iARB;
-PFNGLWINDOWPOS2IVARBPROC glad_glWindowPos2ivARB;
-PFNGLWINDOWPOS2SARBPROC glad_glWindowPos2sARB;
-PFNGLWINDOWPOS2SVARBPROC glad_glWindowPos2svARB;
-PFNGLWINDOWPOS3DARBPROC glad_glWindowPos3dARB;
-PFNGLWINDOWPOS3DVARBPROC glad_glWindowPos3dvARB;
-PFNGLWINDOWPOS3FARBPROC glad_glWindowPos3fARB;
-PFNGLWINDOWPOS3FVARBPROC glad_glWindowPos3fvARB;
-PFNGLWINDOWPOS3IARBPROC glad_glWindowPos3iARB;
-PFNGLWINDOWPOS3IVARBPROC glad_glWindowPos3ivARB;
-PFNGLWINDOWPOS3SARBPROC glad_glWindowPos3sARB;
-PFNGLWINDOWPOS3SVARBPROC glad_glWindowPos3svARB;
-PFNGLDRAWBUFFERSATIPROC glad_glDrawBuffersATI;
-PFNGLELEMENTPOINTERATIPROC glad_glElementPointerATI;
-PFNGLDRAWELEMENTARRAYATIPROC glad_glDrawElementArrayATI;
-PFNGLDRAWRANGEELEMENTARRAYATIPROC glad_glDrawRangeElementArrayATI;
-PFNGLTEXBUMPPARAMETERIVATIPROC glad_glTexBumpParameterivATI;
-PFNGLTEXBUMPPARAMETERFVATIPROC glad_glTexBumpParameterfvATI;
-PFNGLGETTEXBUMPPARAMETERIVATIPROC glad_glGetTexBumpParameterivATI;
-PFNGLGETTEXBUMPPARAMETERFVATIPROC glad_glGetTexBumpParameterfvATI;
-PFNGLGENFRAGMENTSHADERSATIPROC glad_glGenFragmentShadersATI;
-PFNGLBINDFRAGMENTSHADERATIPROC glad_glBindFragmentShaderATI;
-PFNGLDELETEFRAGMENTSHADERATIPROC glad_glDeleteFragmentShaderATI;
-PFNGLBEGINFRAGMENTSHADERATIPROC glad_glBeginFragmentShaderATI;
-PFNGLENDFRAGMENTSHADERATIPROC glad_glEndFragmentShaderATI;
-PFNGLPASSTEXCOORDATIPROC glad_glPassTexCoordATI;
-PFNGLSAMPLEMAPATIPROC glad_glSampleMapATI;
-PFNGLCOLORFRAGMENTOP1ATIPROC glad_glColorFragmentOp1ATI;
-PFNGLCOLORFRAGMENTOP2ATIPROC glad_glColorFragmentOp2ATI;
-PFNGLCOLORFRAGMENTOP3ATIPROC glad_glColorFragmentOp3ATI;
-PFNGLALPHAFRAGMENTOP1ATIPROC glad_glAlphaFragmentOp1ATI;
-PFNGLALPHAFRAGMENTOP2ATIPROC glad_glAlphaFragmentOp2ATI;
-PFNGLALPHAFRAGMENTOP3ATIPROC glad_glAlphaFragmentOp3ATI;
-PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glad_glSetFragmentShaderConstantATI;
-PFNGLMAPOBJECTBUFFERATIPROC glad_glMapObjectBufferATI;
-PFNGLUNMAPOBJECTBUFFERATIPROC glad_glUnmapObjectBufferATI;
-PFNGLPNTRIANGLESIATIPROC glad_glPNTrianglesiATI;
-PFNGLPNTRIANGLESFATIPROC glad_glPNTrianglesfATI;
-PFNGLSTENCILOPSEPARATEATIPROC glad_glStencilOpSeparateATI;
-PFNGLSTENCILFUNCSEPARATEATIPROC glad_glStencilFuncSeparateATI;
-PFNGLNEWOBJECTBUFFERATIPROC glad_glNewObjectBufferATI;
-PFNGLISOBJECTBUFFERATIPROC glad_glIsObjectBufferATI;
-PFNGLUPDATEOBJECTBUFFERATIPROC glad_glUpdateObjectBufferATI;
-PFNGLGETOBJECTBUFFERFVATIPROC glad_glGetObjectBufferfvATI;
-PFNGLGETOBJECTBUFFERIVATIPROC glad_glGetObjectBufferivATI;
-PFNGLFREEOBJECTBUFFERATIPROC glad_glFreeObjectBufferATI;
-PFNGLARRAYOBJECTATIPROC glad_glArrayObjectATI;
-PFNGLGETARRAYOBJECTFVATIPROC glad_glGetArrayObjectfvATI;
-PFNGLGETARRAYOBJECTIVATIPROC glad_glGetArrayObjectivATI;
-PFNGLVARIANTARRAYOBJECTATIPROC glad_glVariantArrayObjectATI;
-PFNGLGETVARIANTARRAYOBJECTFVATIPROC glad_glGetVariantArrayObjectfvATI;
-PFNGLGETVARIANTARRAYOBJECTIVATIPROC glad_glGetVariantArrayObjectivATI;
-PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glad_glVertexAttribArrayObjectATI;
-PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC glad_glGetVertexAttribArrayObjectfvATI;
-PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC glad_glGetVertexAttribArrayObjectivATI;
-PFNGLVERTEXSTREAM1SATIPROC glad_glVertexStream1sATI;
-PFNGLVERTEXSTREAM1SVATIPROC glad_glVertexStream1svATI;
-PFNGLVERTEXSTREAM1IATIPROC glad_glVertexStream1iATI;
-PFNGLVERTEXSTREAM1IVATIPROC glad_glVertexStream1ivATI;
-PFNGLVERTEXSTREAM1FATIPROC glad_glVertexStream1fATI;
-PFNGLVERTEXSTREAM1FVATIPROC glad_glVertexStream1fvATI;
-PFNGLVERTEXSTREAM1DATIPROC glad_glVertexStream1dATI;
-PFNGLVERTEXSTREAM1DVATIPROC glad_glVertexStream1dvATI;
-PFNGLVERTEXSTREAM2SATIPROC glad_glVertexStream2sATI;
-PFNGLVERTEXSTREAM2SVATIPROC glad_glVertexStream2svATI;
-PFNGLVERTEXSTREAM2IATIPROC glad_glVertexStream2iATI;
-PFNGLVERTEXSTREAM2IVATIPROC glad_glVertexStream2ivATI;
-PFNGLVERTEXSTREAM2FATIPROC glad_glVertexStream2fATI;
-PFNGLVERTEXSTREAM2FVATIPROC glad_glVertexStream2fvATI;
-PFNGLVERTEXSTREAM2DATIPROC glad_glVertexStream2dATI;
-PFNGLVERTEXSTREAM2DVATIPROC glad_glVertexStream2dvATI;
-PFNGLVERTEXSTREAM3SATIPROC glad_glVertexStream3sATI;
-PFNGLVERTEXSTREAM3SVATIPROC glad_glVertexStream3svATI;
-PFNGLVERTEXSTREAM3IATIPROC glad_glVertexStream3iATI;
-PFNGLVERTEXSTREAM3IVATIPROC glad_glVertexStream3ivATI;
-PFNGLVERTEXSTREAM3FATIPROC glad_glVertexStream3fATI;
-PFNGLVERTEXSTREAM3FVATIPROC glad_glVertexStream3fvATI;
-PFNGLVERTEXSTREAM3DATIPROC glad_glVertexStream3dATI;
-PFNGLVERTEXSTREAM3DVATIPROC glad_glVertexStream3dvATI;
-PFNGLVERTEXSTREAM4SATIPROC glad_glVertexStream4sATI;
-PFNGLVERTEXSTREAM4SVATIPROC glad_glVertexStream4svATI;
-PFNGLVERTEXSTREAM4IATIPROC glad_glVertexStream4iATI;
-PFNGLVERTEXSTREAM4IVATIPROC glad_glVertexStream4ivATI;
-PFNGLVERTEXSTREAM4FATIPROC glad_glVertexStream4fATI;
-PFNGLVERTEXSTREAM4FVATIPROC glad_glVertexStream4fvATI;
-PFNGLVERTEXSTREAM4DATIPROC glad_glVertexStream4dATI;
-PFNGLVERTEXSTREAM4DVATIPROC glad_glVertexStream4dvATI;
-PFNGLNORMALSTREAM3BATIPROC glad_glNormalStream3bATI;
-PFNGLNORMALSTREAM3BVATIPROC glad_glNormalStream3bvATI;
-PFNGLNORMALSTREAM3SATIPROC glad_glNormalStream3sATI;
-PFNGLNORMALSTREAM3SVATIPROC glad_glNormalStream3svATI;
-PFNGLNORMALSTREAM3IATIPROC glad_glNormalStream3iATI;
-PFNGLNORMALSTREAM3IVATIPROC glad_glNormalStream3ivATI;
-PFNGLNORMALSTREAM3FATIPROC glad_glNormalStream3fATI;
-PFNGLNORMALSTREAM3FVATIPROC glad_glNormalStream3fvATI;
-PFNGLNORMALSTREAM3DATIPROC glad_glNormalStream3dATI;
-PFNGLNORMALSTREAM3DVATIPROC glad_glNormalStream3dvATI;
-PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC glad_glClientActiveVertexStreamATI;
-PFNGLVERTEXBLENDENVIATIPROC glad_glVertexBlendEnviATI;
-PFNGLVERTEXBLENDENVFATIPROC glad_glVertexBlendEnvfATI;
-PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC glad_glEGLImageTargetTexStorageEXT;
-PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC glad_glEGLImageTargetTextureStorageEXT;
-PFNGLUNIFORMBUFFEREXTPROC glad_glUniformBufferEXT;
-PFNGLGETUNIFORMBUFFERSIZEEXTPROC glad_glGetUniformBufferSizeEXT;
-PFNGLGETUNIFORMOFFSETEXTPROC glad_glGetUniformOffsetEXT;
-PFNGLBLENDCOLOREXTPROC glad_glBlendColorEXT;
-PFNGLBLENDEQUATIONSEPARATEEXTPROC glad_glBlendEquationSeparateEXT;
-PFNGLBLENDFUNCSEPARATEEXTPROC glad_glBlendFuncSeparateEXT;
-PFNGLBLENDEQUATIONEXTPROC glad_glBlendEquationEXT;
-PFNGLCOLORSUBTABLEEXTPROC glad_glColorSubTableEXT;
-PFNGLCOPYCOLORSUBTABLEEXTPROC glad_glCopyColorSubTableEXT;
-PFNGLLOCKARRAYSEXTPROC glad_glLockArraysEXT;
-PFNGLUNLOCKARRAYSEXTPROC glad_glUnlockArraysEXT;
-PFNGLCONVOLUTIONFILTER1DEXTPROC glad_glConvolutionFilter1DEXT;
-PFNGLCONVOLUTIONFILTER2DEXTPROC glad_glConvolutionFilter2DEXT;
-PFNGLCONVOLUTIONPARAMETERFEXTPROC glad_glConvolutionParameterfEXT;
-PFNGLCONVOLUTIONPARAMETERFVEXTPROC glad_glConvolutionParameterfvEXT;
-PFNGLCONVOLUTIONPARAMETERIEXTPROC glad_glConvolutionParameteriEXT;
-PFNGLCONVOLUTIONPARAMETERIVEXTPROC glad_glConvolutionParameterivEXT;
-PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC glad_glCopyConvolutionFilter1DEXT;
-PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC glad_glCopyConvolutionFilter2DEXT;
-PFNGLGETCONVOLUTIONFILTEREXTPROC glad_glGetConvolutionFilterEXT;
-PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC glad_glGetConvolutionParameterfvEXT;
-PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC glad_glGetConvolutionParameterivEXT;
-PFNGLGETSEPARABLEFILTEREXTPROC glad_glGetSeparableFilterEXT;
-PFNGLSEPARABLEFILTER2DEXTPROC glad_glSeparableFilter2DEXT;
-PFNGLTANGENT3BEXTPROC glad_glTangent3bEXT;
-PFNGLTANGENT3BVEXTPROC glad_glTangent3bvEXT;
-PFNGLTANGENT3DEXTPROC glad_glTangent3dEXT;
-PFNGLTANGENT3DVEXTPROC glad_glTangent3dvEXT;
-PFNGLTANGENT3FEXTPROC glad_glTangent3fEXT;
-PFNGLTANGENT3FVEXTPROC glad_glTangent3fvEXT;
-PFNGLTANGENT3IEXTPROC glad_glTangent3iEXT;
-PFNGLTANGENT3IVEXTPROC glad_glTangent3ivEXT;
-PFNGLTANGENT3SEXTPROC glad_glTangent3sEXT;
-PFNGLTANGENT3SVEXTPROC glad_glTangent3svEXT;
-PFNGLBINORMAL3BEXTPROC glad_glBinormal3bEXT;
-PFNGLBINORMAL3BVEXTPROC glad_glBinormal3bvEXT;
-PFNGLBINORMAL3DEXTPROC glad_glBinormal3dEXT;
-PFNGLBINORMAL3DVEXTPROC glad_glBinormal3dvEXT;
-PFNGLBINORMAL3FEXTPROC glad_glBinormal3fEXT;
-PFNGLBINORMAL3FVEXTPROC glad_glBinormal3fvEXT;
-PFNGLBINORMAL3IEXTPROC glad_glBinormal3iEXT;
-PFNGLBINORMAL3IVEXTPROC glad_glBinormal3ivEXT;
-PFNGLBINORMAL3SEXTPROC glad_glBinormal3sEXT;
-PFNGLBINORMAL3SVEXTPROC glad_glBinormal3svEXT;
-PFNGLTANGENTPOINTEREXTPROC glad_glTangentPointerEXT;
-PFNGLBINORMALPOINTEREXTPROC glad_glBinormalPointerEXT;
-PFNGLCOPYTEXIMAGE1DEXTPROC glad_glCopyTexImage1DEXT;
-PFNGLCOPYTEXIMAGE2DEXTPROC glad_glCopyTexImage2DEXT;
-PFNGLCOPYTEXSUBIMAGE1DEXTPROC glad_glCopyTexSubImage1DEXT;
-PFNGLCOPYTEXSUBIMAGE2DEXTPROC glad_glCopyTexSubImage2DEXT;
-PFNGLCOPYTEXSUBIMAGE3DEXTPROC glad_glCopyTexSubImage3DEXT;
-PFNGLCULLPARAMETERDVEXTPROC glad_glCullParameterdvEXT;
-PFNGLCULLPARAMETERFVEXTPROC glad_glCullParameterfvEXT;
-PFNGLLABELOBJECTEXTPROC glad_glLabelObjectEXT;
-PFNGLGETOBJECTLABELEXTPROC glad_glGetObjectLabelEXT;
-PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT;
-PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT;
-PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT;
-PFNGLDEPTHBOUNDSEXTPROC glad_glDepthBoundsEXT;
-PFNGLMATRIXLOADFEXTPROC glad_glMatrixLoadfEXT;
-PFNGLMATRIXLOADDEXTPROC glad_glMatrixLoaddEXT;
-PFNGLMATRIXMULTFEXTPROC glad_glMatrixMultfEXT;
-PFNGLMATRIXMULTDEXTPROC glad_glMatrixMultdEXT;
-PFNGLMATRIXLOADIDENTITYEXTPROC glad_glMatrixLoadIdentityEXT;
-PFNGLMATRIXROTATEFEXTPROC glad_glMatrixRotatefEXT;
-PFNGLMATRIXROTATEDEXTPROC glad_glMatrixRotatedEXT;
-PFNGLMATRIXSCALEFEXTPROC glad_glMatrixScalefEXT;
-PFNGLMATRIXSCALEDEXTPROC glad_glMatrixScaledEXT;
-PFNGLMATRIXTRANSLATEFEXTPROC glad_glMatrixTranslatefEXT;
-PFNGLMATRIXTRANSLATEDEXTPROC glad_glMatrixTranslatedEXT;
-PFNGLMATRIXFRUSTUMEXTPROC glad_glMatrixFrustumEXT;
-PFNGLMATRIXORTHOEXTPROC glad_glMatrixOrthoEXT;
-PFNGLMATRIXPOPEXTPROC glad_glMatrixPopEXT;
-PFNGLMATRIXPUSHEXTPROC glad_glMatrixPushEXT;
-PFNGLCLIENTATTRIBDEFAULTEXTPROC glad_glClientAttribDefaultEXT;
-PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC glad_glPushClientAttribDefaultEXT;
-PFNGLTEXTUREPARAMETERFEXTPROC glad_glTextureParameterfEXT;
-PFNGLTEXTUREPARAMETERFVEXTPROC glad_glTextureParameterfvEXT;
-PFNGLTEXTUREPARAMETERIEXTPROC glad_glTextureParameteriEXT;
-PFNGLTEXTUREPARAMETERIVEXTPROC glad_glTextureParameterivEXT;
-PFNGLTEXTUREIMAGE1DEXTPROC glad_glTextureImage1DEXT;
-PFNGLTEXTUREIMAGE2DEXTPROC glad_glTextureImage2DEXT;
-PFNGLTEXTURESUBIMAGE1DEXTPROC glad_glTextureSubImage1DEXT;
-PFNGLTEXTURESUBIMAGE2DEXTPROC glad_glTextureSubImage2DEXT;
-PFNGLCOPYTEXTUREIMAGE1DEXTPROC glad_glCopyTextureImage1DEXT;
-PFNGLCOPYTEXTUREIMAGE2DEXTPROC glad_glCopyTextureImage2DEXT;
-PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC glad_glCopyTextureSubImage1DEXT;
-PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC glad_glCopyTextureSubImage2DEXT;
-PFNGLGETTEXTUREIMAGEEXTPROC glad_glGetTextureImageEXT;
-PFNGLGETTEXTUREPARAMETERFVEXTPROC glad_glGetTextureParameterfvEXT;
-PFNGLGETTEXTUREPARAMETERIVEXTPROC glad_glGetTextureParameterivEXT;
-PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC glad_glGetTextureLevelParameterfvEXT;
-PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC glad_glGetTextureLevelParameterivEXT;
-PFNGLTEXTUREIMAGE3DEXTPROC glad_glTextureImage3DEXT;
-PFNGLTEXTURESUBIMAGE3DEXTPROC glad_glTextureSubImage3DEXT;
-PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC glad_glCopyTextureSubImage3DEXT;
-PFNGLBINDMULTITEXTUREEXTPROC glad_glBindMultiTextureEXT;
-PFNGLMULTITEXCOORDPOINTEREXTPROC glad_glMultiTexCoordPointerEXT;
-PFNGLMULTITEXENVFEXTPROC glad_glMultiTexEnvfEXT;
-PFNGLMULTITEXENVFVEXTPROC glad_glMultiTexEnvfvEXT;
-PFNGLMULTITEXENVIEXTPROC glad_glMultiTexEnviEXT;
-PFNGLMULTITEXENVIVEXTPROC glad_glMultiTexEnvivEXT;
-PFNGLMULTITEXGENDEXTPROC glad_glMultiTexGendEXT;
-PFNGLMULTITEXGENDVEXTPROC glad_glMultiTexGendvEXT;
-PFNGLMULTITEXGENFEXTPROC glad_glMultiTexGenfEXT;
-PFNGLMULTITEXGENFVEXTPROC glad_glMultiTexGenfvEXT;
-PFNGLMULTITEXGENIEXTPROC glad_glMultiTexGeniEXT;
-PFNGLMULTITEXGENIVEXTPROC glad_glMultiTexGenivEXT;
-PFNGLGETMULTITEXENVFVEXTPROC glad_glGetMultiTexEnvfvEXT;
-PFNGLGETMULTITEXENVIVEXTPROC glad_glGetMultiTexEnvivEXT;
-PFNGLGETMULTITEXGENDVEXTPROC glad_glGetMultiTexGendvEXT;
-PFNGLGETMULTITEXGENFVEXTPROC glad_glGetMultiTexGenfvEXT;
-PFNGLGETMULTITEXGENIVEXTPROC glad_glGetMultiTexGenivEXT;
-PFNGLMULTITEXPARAMETERIEXTPROC glad_glMultiTexParameteriEXT;
-PFNGLMULTITEXPARAMETERIVEXTPROC glad_glMultiTexParameterivEXT;
-PFNGLMULTITEXPARAMETERFEXTPROC glad_glMultiTexParameterfEXT;
-PFNGLMULTITEXPARAMETERFVEXTPROC glad_glMultiTexParameterfvEXT;
-PFNGLMULTITEXIMAGE1DEXTPROC glad_glMultiTexImage1DEXT;
-PFNGLMULTITEXIMAGE2DEXTPROC glad_glMultiTexImage2DEXT;
-PFNGLMULTITEXSUBIMAGE1DEXTPROC glad_glMultiTexSubImage1DEXT;
-PFNGLMULTITEXSUBIMAGE2DEXTPROC glad_glMultiTexSubImage2DEXT;
-PFNGLCOPYMULTITEXIMAGE1DEXTPROC glad_glCopyMultiTexImage1DEXT;
-PFNGLCOPYMULTITEXIMAGE2DEXTPROC glad_glCopyMultiTexImage2DEXT;
-PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC glad_glCopyMultiTexSubImage1DEXT;
-PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC glad_glCopyMultiTexSubImage2DEXT;
-PFNGLGETMULTITEXIMAGEEXTPROC glad_glGetMultiTexImageEXT;
-PFNGLGETMULTITEXPARAMETERFVEXTPROC glad_glGetMultiTexParameterfvEXT;
-PFNGLGETMULTITEXPARAMETERIVEXTPROC glad_glGetMultiTexParameterivEXT;
-PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC glad_glGetMultiTexLevelParameterfvEXT;
-PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC glad_glGetMultiTexLevelParameterivEXT;
-PFNGLMULTITEXIMAGE3DEXTPROC glad_glMultiTexImage3DEXT;
-PFNGLMULTITEXSUBIMAGE3DEXTPROC glad_glMultiTexSubImage3DEXT;
-PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC glad_glCopyMultiTexSubImage3DEXT;
-PFNGLENABLECLIENTSTATEINDEXEDEXTPROC glad_glEnableClientStateIndexedEXT;
-PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC glad_glDisableClientStateIndexedEXT;
-PFNGLGETFLOATINDEXEDVEXTPROC glad_glGetFloatIndexedvEXT;
-PFNGLGETDOUBLEINDEXEDVEXTPROC glad_glGetDoubleIndexedvEXT;
-PFNGLGETPOINTERINDEXEDVEXTPROC glad_glGetPointerIndexedvEXT;
-PFNGLENABLEINDEXEDEXTPROC glad_glEnableIndexedEXT;
-PFNGLDISABLEINDEXEDEXTPROC glad_glDisableIndexedEXT;
-PFNGLISENABLEDINDEXEDEXTPROC glad_glIsEnabledIndexedEXT;
-PFNGLGETINTEGERINDEXEDVEXTPROC glad_glGetIntegerIndexedvEXT;
-PFNGLGETBOOLEANINDEXEDVEXTPROC glad_glGetBooleanIndexedvEXT;
-PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC glad_glCompressedTextureImage3DEXT;
-PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC glad_glCompressedTextureImage2DEXT;
-PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC glad_glCompressedTextureImage1DEXT;
-PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC glad_glCompressedTextureSubImage3DEXT;
-PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC glad_glCompressedTextureSubImage2DEXT;
-PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC glad_glCompressedTextureSubImage1DEXT;
-PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC glad_glGetCompressedTextureImageEXT;
-PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC glad_glCompressedMultiTexImage3DEXT;
-PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC glad_glCompressedMultiTexImage2DEXT;
-PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC glad_glCompressedMultiTexImage1DEXT;
-PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC glad_glCompressedMultiTexSubImage3DEXT;
-PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC glad_glCompressedMultiTexSubImage2DEXT;
-PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC glad_glCompressedMultiTexSubImage1DEXT;
-PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC glad_glGetCompressedMultiTexImageEXT;
-PFNGLMATRIXLOADTRANSPOSEFEXTPROC glad_glMatrixLoadTransposefEXT;
-PFNGLMATRIXLOADTRANSPOSEDEXTPROC glad_glMatrixLoadTransposedEXT;
-PFNGLMATRIXMULTTRANSPOSEFEXTPROC glad_glMatrixMultTransposefEXT;
-PFNGLMATRIXMULTTRANSPOSEDEXTPROC glad_glMatrixMultTransposedEXT;
-PFNGLNAMEDBUFFERDATAEXTPROC glad_glNamedBufferDataEXT;
-PFNGLNAMEDBUFFERSUBDATAEXTPROC glad_glNamedBufferSubDataEXT;
-PFNGLMAPNAMEDBUFFEREXTPROC glad_glMapNamedBufferEXT;
-PFNGLUNMAPNAMEDBUFFEREXTPROC glad_glUnmapNamedBufferEXT;
-PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC glad_glGetNamedBufferParameterivEXT;
-PFNGLGETNAMEDBUFFERPOINTERVEXTPROC glad_glGetNamedBufferPointervEXT;
-PFNGLGETNAMEDBUFFERSUBDATAEXTPROC glad_glGetNamedBufferSubDataEXT;
-PFNGLPROGRAMUNIFORM1FEXTPROC glad_glProgramUniform1fEXT;
-PFNGLPROGRAMUNIFORM2FEXTPROC glad_glProgramUniform2fEXT;
-PFNGLPROGRAMUNIFORM3FEXTPROC glad_glProgramUniform3fEXT;
-PFNGLPROGRAMUNIFORM4FEXTPROC glad_glProgramUniform4fEXT;
-PFNGLPROGRAMUNIFORM1IEXTPROC glad_glProgramUniform1iEXT;
-PFNGLPROGRAMUNIFORM2IEXTPROC glad_glProgramUniform2iEXT;
-PFNGLPROGRAMUNIFORM3IEXTPROC glad_glProgramUniform3iEXT;
-PFNGLPROGRAMUNIFORM4IEXTPROC glad_glProgramUniform4iEXT;
-PFNGLPROGRAMUNIFORM1FVEXTPROC glad_glProgramUniform1fvEXT;
-PFNGLPROGRAMUNIFORM2FVEXTPROC glad_glProgramUniform2fvEXT;
-PFNGLPROGRAMUNIFORM3FVEXTPROC glad_glProgramUniform3fvEXT;
-PFNGLPROGRAMUNIFORM4FVEXTPROC glad_glProgramUniform4fvEXT;
-PFNGLPROGRAMUNIFORM1IVEXTPROC glad_glProgramUniform1ivEXT;
-PFNGLPROGRAMUNIFORM2IVEXTPROC glad_glProgramUniform2ivEXT;
-PFNGLPROGRAMUNIFORM3IVEXTPROC glad_glProgramUniform3ivEXT;
-PFNGLPROGRAMUNIFORM4IVEXTPROC glad_glProgramUniform4ivEXT;
-PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC glad_glProgramUniformMatrix2fvEXT;
-PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC glad_glProgramUniformMatrix3fvEXT;
-PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC glad_glProgramUniformMatrix4fvEXT;
-PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC glad_glProgramUniformMatrix2x3fvEXT;
-PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC glad_glProgramUniformMatrix3x2fvEXT;
-PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC glad_glProgramUniformMatrix2x4fvEXT;
-PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC glad_glProgramUniformMatrix4x2fvEXT;
-PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC glad_glProgramUniformMatrix3x4fvEXT;
-PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC glad_glProgramUniformMatrix4x3fvEXT;
-PFNGLTEXTUREBUFFEREXTPROC glad_glTextureBufferEXT;
-PFNGLMULTITEXBUFFEREXTPROC glad_glMultiTexBufferEXT;
-PFNGLTEXTUREPARAMETERIIVEXTPROC glad_glTextureParameterIivEXT;
-PFNGLTEXTUREPARAMETERIUIVEXTPROC glad_glTextureParameterIuivEXT;
-PFNGLGETTEXTUREPARAMETERIIVEXTPROC glad_glGetTextureParameterIivEXT;
-PFNGLGETTEXTUREPARAMETERIUIVEXTPROC glad_glGetTextureParameterIuivEXT;
-PFNGLMULTITEXPARAMETERIIVEXTPROC glad_glMultiTexParameterIivEXT;
-PFNGLMULTITEXPARAMETERIUIVEXTPROC glad_glMultiTexParameterIuivEXT;
-PFNGLGETMULTITEXPARAMETERIIVEXTPROC glad_glGetMultiTexParameterIivEXT;
-PFNGLGETMULTITEXPARAMETERIUIVEXTPROC glad_glGetMultiTexParameterIuivEXT;
-PFNGLPROGRAMUNIFORM1UIEXTPROC glad_glProgramUniform1uiEXT;
-PFNGLPROGRAMUNIFORM2UIEXTPROC glad_glProgramUniform2uiEXT;
-PFNGLPROGRAMUNIFORM3UIEXTPROC glad_glProgramUniform3uiEXT;
-PFNGLPROGRAMUNIFORM4UIEXTPROC glad_glProgramUniform4uiEXT;
-PFNGLPROGRAMUNIFORM1UIVEXTPROC glad_glProgramUniform1uivEXT;
-PFNGLPROGRAMUNIFORM2UIVEXTPROC glad_glProgramUniform2uivEXT;
-PFNGLPROGRAMUNIFORM3UIVEXTPROC glad_glProgramUniform3uivEXT;
-PFNGLPROGRAMUNIFORM4UIVEXTPROC glad_glProgramUniform4uivEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC glad_glNamedProgramLocalParameters4fvEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC glad_glNamedProgramLocalParameterI4iEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC glad_glNamedProgramLocalParameterI4ivEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC glad_glNamedProgramLocalParametersI4ivEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC glad_glNamedProgramLocalParameterI4uiEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC glad_glNamedProgramLocalParameterI4uivEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC glad_glNamedProgramLocalParametersI4uivEXT;
-PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC glad_glGetNamedProgramLocalParameterIivEXT;
-PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC glad_glGetNamedProgramLocalParameterIuivEXT;
-PFNGLENABLECLIENTSTATEIEXTPROC glad_glEnableClientStateiEXT;
-PFNGLDISABLECLIENTSTATEIEXTPROC glad_glDisableClientStateiEXT;
-PFNGLGETFLOATI_VEXTPROC glad_glGetFloati_vEXT;
-PFNGLGETDOUBLEI_VEXTPROC glad_glGetDoublei_vEXT;
-PFNGLGETPOINTERI_VEXTPROC glad_glGetPointeri_vEXT;
-PFNGLNAMEDPROGRAMSTRINGEXTPROC glad_glNamedProgramStringEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC glad_glNamedProgramLocalParameter4dEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC glad_glNamedProgramLocalParameter4dvEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC glad_glNamedProgramLocalParameter4fEXT;
-PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC glad_glNamedProgramLocalParameter4fvEXT;
-PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC glad_glGetNamedProgramLocalParameterdvEXT;
-PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC glad_glGetNamedProgramLocalParameterfvEXT;
-PFNGLGETNAMEDPROGRAMIVEXTPROC glad_glGetNamedProgramivEXT;
-PFNGLGETNAMEDPROGRAMSTRINGEXTPROC glad_glGetNamedProgramStringEXT;
-PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC glad_glNamedRenderbufferStorageEXT;
-PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC glad_glGetNamedRenderbufferParameterivEXT;
-PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glNamedRenderbufferStorageMultisampleEXT;
-PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC glad_glNamedRenderbufferStorageMultisampleCoverageEXT;
-PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC glad_glCheckNamedFramebufferStatusEXT;
-PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC glad_glNamedFramebufferTexture1DEXT;
-PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC glad_glNamedFramebufferTexture2DEXT;
-PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC glad_glNamedFramebufferTexture3DEXT;
-PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC glad_glNamedFramebufferRenderbufferEXT;
-PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetNamedFramebufferAttachmentParameterivEXT;
-PFNGLGENERATETEXTUREMIPMAPEXTPROC glad_glGenerateTextureMipmapEXT;
-PFNGLGENERATEMULTITEXMIPMAPEXTPROC glad_glGenerateMultiTexMipmapEXT;
-PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC glad_glFramebufferDrawBufferEXT;
-PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC glad_glFramebufferDrawBuffersEXT;
-PFNGLFRAMEBUFFERREADBUFFEREXTPROC glad_glFramebufferReadBufferEXT;
-PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC glad_glGetFramebufferParameterivEXT;
-PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC glad_glNamedCopyBufferSubDataEXT;
-PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC glad_glNamedFramebufferTextureEXT;
-PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC glad_glNamedFramebufferTextureLayerEXT;
-PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC glad_glNamedFramebufferTextureFaceEXT;
-PFNGLTEXTURERENDERBUFFEREXTPROC glad_glTextureRenderbufferEXT;
-PFNGLMULTITEXRENDERBUFFEREXTPROC glad_glMultiTexRenderbufferEXT;
-PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC glad_glVertexArrayVertexOffsetEXT;
-PFNGLVERTEXARRAYCOLOROFFSETEXTPROC glad_glVertexArrayColorOffsetEXT;
-PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC glad_glVertexArrayEdgeFlagOffsetEXT;
-PFNGLVERTEXARRAYINDEXOFFSETEXTPROC glad_glVertexArrayIndexOffsetEXT;
-PFNGLVERTEXARRAYNORMALOFFSETEXTPROC glad_glVertexArrayNormalOffsetEXT;
-PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC glad_glVertexArrayTexCoordOffsetEXT;
-PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC glad_glVertexArrayMultiTexCoordOffsetEXT;
-PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC glad_glVertexArrayFogCoordOffsetEXT;
-PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC glad_glVertexArraySecondaryColorOffsetEXT;
-PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC glad_glVertexArrayVertexAttribOffsetEXT;
-PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC glad_glVertexArrayVertexAttribIOffsetEXT;
-PFNGLENABLEVERTEXARRAYEXTPROC glad_glEnableVertexArrayEXT;
-PFNGLDISABLEVERTEXARRAYEXTPROC glad_glDisableVertexArrayEXT;
-PFNGLENABLEVERTEXARRAYATTRIBEXTPROC glad_glEnableVertexArrayAttribEXT;
-PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC glad_glDisableVertexArrayAttribEXT;
-PFNGLGETVERTEXARRAYINTEGERVEXTPROC glad_glGetVertexArrayIntegervEXT;
-PFNGLGETVERTEXARRAYPOINTERVEXTPROC glad_glGetVertexArrayPointervEXT;
-PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC glad_glGetVertexArrayIntegeri_vEXT;
-PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC glad_glGetVertexArrayPointeri_vEXT;
-PFNGLMAPNAMEDBUFFERRANGEEXTPROC glad_glMapNamedBufferRangeEXT;
-PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC glad_glFlushMappedNamedBufferRangeEXT;
-PFNGLNAMEDBUFFERSTORAGEEXTPROC glad_glNamedBufferStorageEXT;
-PFNGLCLEARNAMEDBUFFERDATAEXTPROC glad_glClearNamedBufferDataEXT;
-PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC glad_glClearNamedBufferSubDataEXT;
-PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC glad_glNamedFramebufferParameteriEXT;
-PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC glad_glGetNamedFramebufferParameterivEXT;
-PFNGLPROGRAMUNIFORM1DEXTPROC glad_glProgramUniform1dEXT;
-PFNGLPROGRAMUNIFORM2DEXTPROC glad_glProgramUniform2dEXT;
-PFNGLPROGRAMUNIFORM3DEXTPROC glad_glProgramUniform3dEXT;
-PFNGLPROGRAMUNIFORM4DEXTPROC glad_glProgramUniform4dEXT;
-PFNGLPROGRAMUNIFORM1DVEXTPROC glad_glProgramUniform1dvEXT;
-PFNGLPROGRAMUNIFORM2DVEXTPROC glad_glProgramUniform2dvEXT;
-PFNGLPROGRAMUNIFORM3DVEXTPROC glad_glProgramUniform3dvEXT;
-PFNGLPROGRAMUNIFORM4DVEXTPROC glad_glProgramUniform4dvEXT;
-PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC glad_glProgramUniformMatrix2dvEXT;
-PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC glad_glProgramUniformMatrix3dvEXT;
-PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC glad_glProgramUniformMatrix4dvEXT;
-PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC glad_glProgramUniformMatrix2x3dvEXT;
-PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC glad_glProgramUniformMatrix2x4dvEXT;
-PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC glad_glProgramUniformMatrix3x2dvEXT;
-PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC glad_glProgramUniformMatrix3x4dvEXT;
-PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC glad_glProgramUniformMatrix4x2dvEXT;
-PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC glad_glProgramUniformMatrix4x3dvEXT;
-PFNGLTEXTUREBUFFERRANGEEXTPROC glad_glTextureBufferRangeEXT;
-PFNGLTEXTURESTORAGE1DEXTPROC glad_glTextureStorage1DEXT;
-PFNGLTEXTURESTORAGE2DEXTPROC glad_glTextureStorage2DEXT;
-PFNGLTEXTURESTORAGE3DEXTPROC glad_glTextureStorage3DEXT;
-PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC glad_glTextureStorage2DMultisampleEXT;
-PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC glad_glTextureStorage3DMultisampleEXT;
-PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC glad_glVertexArrayBindVertexBufferEXT;
-PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC glad_glVertexArrayVertexAttribFormatEXT;
-PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC glad_glVertexArrayVertexAttribIFormatEXT;
-PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC glad_glVertexArrayVertexAttribLFormatEXT;
-PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC glad_glVertexArrayVertexAttribBindingEXT;
-PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC glad_glVertexArrayVertexBindingDivisorEXT;
-PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC glad_glVertexArrayVertexAttribLOffsetEXT;
-PFNGLTEXTUREPAGECOMMITMENTEXTPROC glad_glTexturePageCommitmentEXT;
-PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC glad_glVertexArrayVertexAttribDivisorEXT;
-PFNGLCOLORMASKINDEXEDEXTPROC glad_glColorMaskIndexedEXT;
-PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT;
-PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT;
-PFNGLDRAWRANGEELEMENTSEXTPROC glad_glDrawRangeElementsEXT;
-PFNGLBUFFERSTORAGEEXTERNALEXTPROC glad_glBufferStorageExternalEXT;
-PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC glad_glNamedBufferStorageExternalEXT;
-PFNGLFOGCOORDFEXTPROC glad_glFogCoordfEXT;
-PFNGLFOGCOORDFVEXTPROC glad_glFogCoordfvEXT;
-PFNGLFOGCOORDDEXTPROC glad_glFogCoorddEXT;
-PFNGLFOGCOORDDVEXTPROC glad_glFogCoorddvEXT;
-PFNGLFOGCOORDPOINTEREXTPROC glad_glFogCoordPointerEXT;
-PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT;
-PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT;
-PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT;
-PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT;
-PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT;
-PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT;
-PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT;
-PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT;
-PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT;
-PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT;
-PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT;
-PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT;
-PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT;
-PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT;
-PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT;
-PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT;
-PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT;
-PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT;
-PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT;
-PFNGLPROGRAMPARAMETERIEXTPROC glad_glProgramParameteriEXT;
-PFNGLPROGRAMENVPARAMETERS4FVEXTPROC glad_glProgramEnvParameters4fvEXT;
-PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC glad_glProgramLocalParameters4fvEXT;
-PFNGLGETUNIFORMUIVEXTPROC glad_glGetUniformuivEXT;
-PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT;
-PFNGLGETFRAGDATALOCATIONEXTPROC glad_glGetFragDataLocationEXT;
-PFNGLUNIFORM1UIEXTPROC glad_glUniform1uiEXT;
-PFNGLUNIFORM2UIEXTPROC glad_glUniform2uiEXT;
-PFNGLUNIFORM3UIEXTPROC glad_glUniform3uiEXT;
-PFNGLUNIFORM4UIEXTPROC glad_glUniform4uiEXT;
-PFNGLUNIFORM1UIVEXTPROC glad_glUniform1uivEXT;
-PFNGLUNIFORM2UIVEXTPROC glad_glUniform2uivEXT;
-PFNGLUNIFORM3UIVEXTPROC glad_glUniform3uivEXT;
-PFNGLUNIFORM4UIVEXTPROC glad_glUniform4uivEXT;
-PFNGLGETHISTOGRAMEXTPROC glad_glGetHistogramEXT;
-PFNGLGETHISTOGRAMPARAMETERFVEXTPROC glad_glGetHistogramParameterfvEXT;
-PFNGLGETHISTOGRAMPARAMETERIVEXTPROC glad_glGetHistogramParameterivEXT;
-PFNGLGETMINMAXEXTPROC glad_glGetMinmaxEXT;
-PFNGLGETMINMAXPARAMETERFVEXTPROC glad_glGetMinmaxParameterfvEXT;
-PFNGLGETMINMAXPARAMETERIVEXTPROC glad_glGetMinmaxParameterivEXT;
-PFNGLHISTOGRAMEXTPROC glad_glHistogramEXT;
-PFNGLMINMAXEXTPROC glad_glMinmaxEXT;
-PFNGLRESETHISTOGRAMEXTPROC glad_glResetHistogramEXT;
-PFNGLRESETMINMAXEXTPROC glad_glResetMinmaxEXT;
-PFNGLINDEXFUNCEXTPROC glad_glIndexFuncEXT;
-PFNGLINDEXMATERIALEXTPROC glad_glIndexMaterialEXT;
-PFNGLAPPLYTEXTUREEXTPROC glad_glApplyTextureEXT;
-PFNGLTEXTURELIGHTEXTPROC glad_glTextureLightEXT;
-PFNGLTEXTUREMATERIALEXTPROC glad_glTextureMaterialEXT;
-PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT;
-PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT;
-PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT;
-PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT;
-PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT;
-PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT;
-PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT;
-PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT;
-PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT;
-PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT;
-PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT;
-PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT;
-PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT;
-PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT;
-PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT;
-PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT;
-PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT;
-PFNGLTEXSTORAGEMEM1DEXTPROC glad_glTexStorageMem1DEXT;
-PFNGLTEXTURESTORAGEMEM1DEXTPROC glad_glTextureStorageMem1DEXT;
-PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT;
-PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC glad_glImportMemoryWin32HandleEXT;
-PFNGLIMPORTMEMORYWIN32NAMEEXTPROC glad_glImportMemoryWin32NameEXT;
-PFNGLMULTIDRAWARRAYSEXTPROC glad_glMultiDrawArraysEXT;
-PFNGLMULTIDRAWELEMENTSEXTPROC glad_glMultiDrawElementsEXT;
-PFNGLSAMPLEMASKEXTPROC glad_glSampleMaskEXT;
-PFNGLSAMPLEPATTERNEXTPROC glad_glSamplePatternEXT;
-PFNGLCOLORTABLEEXTPROC glad_glColorTableEXT;
-PFNGLGETCOLORTABLEEXTPROC glad_glGetColorTableEXT;
-PFNGLGETCOLORTABLEPARAMETERIVEXTPROC glad_glGetColorTableParameterivEXT;
-PFNGLGETCOLORTABLEPARAMETERFVEXTPROC glad_glGetColorTableParameterfvEXT;
-PFNGLPIXELTRANSFORMPARAMETERIEXTPROC glad_glPixelTransformParameteriEXT;
-PFNGLPIXELTRANSFORMPARAMETERFEXTPROC glad_glPixelTransformParameterfEXT;
-PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC glad_glPixelTransformParameterivEXT;
-PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC glad_glPixelTransformParameterfvEXT;
-PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC glad_glGetPixelTransformParameterivEXT;
-PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC glad_glGetPixelTransformParameterfvEXT;
-PFNGLPOINTPARAMETERFEXTPROC glad_glPointParameterfEXT;
-PFNGLPOINTPARAMETERFVEXTPROC glad_glPointParameterfvEXT;
-PFNGLPOLYGONOFFSETEXTPROC glad_glPolygonOffsetEXT;
-PFNGLPOLYGONOFFSETCLAMPEXTPROC glad_glPolygonOffsetClampEXT;
-PFNGLPROVOKINGVERTEXEXTPROC glad_glProvokingVertexEXT;
-PFNGLRASTERSAMPLESEXTPROC glad_glRasterSamplesEXT;
-PFNGLSECONDARYCOLOR3BEXTPROC glad_glSecondaryColor3bEXT;
-PFNGLSECONDARYCOLOR3BVEXTPROC glad_glSecondaryColor3bvEXT;
-PFNGLSECONDARYCOLOR3DEXTPROC glad_glSecondaryColor3dEXT;
-PFNGLSECONDARYCOLOR3DVEXTPROC glad_glSecondaryColor3dvEXT;
-PFNGLSECONDARYCOLOR3FEXTPROC glad_glSecondaryColor3fEXT;
-PFNGLSECONDARYCOLOR3FVEXTPROC glad_glSecondaryColor3fvEXT;
-PFNGLSECONDARYCOLOR3IEXTPROC glad_glSecondaryColor3iEXT;
-PFNGLSECONDARYCOLOR3IVEXTPROC glad_glSecondaryColor3ivEXT;
-PFNGLSECONDARYCOLOR3SEXTPROC glad_glSecondaryColor3sEXT;
-PFNGLSECONDARYCOLOR3SVEXTPROC glad_glSecondaryColor3svEXT;
-PFNGLSECONDARYCOLOR3UBEXTPROC glad_glSecondaryColor3ubEXT;
-PFNGLSECONDARYCOLOR3UBVEXTPROC glad_glSecondaryColor3ubvEXT;
-PFNGLSECONDARYCOLOR3UIEXTPROC glad_glSecondaryColor3uiEXT;
-PFNGLSECONDARYCOLOR3UIVEXTPROC glad_glSecondaryColor3uivEXT;
-PFNGLSECONDARYCOLOR3USEXTPROC glad_glSecondaryColor3usEXT;
-PFNGLSECONDARYCOLOR3USVEXTPROC glad_glSecondaryColor3usvEXT;
-PFNGLSECONDARYCOLORPOINTEREXTPROC glad_glSecondaryColorPointerEXT;
-PFNGLGENSEMAPHORESEXTPROC glad_glGenSemaphoresEXT;
-PFNGLDELETESEMAPHORESEXTPROC glad_glDeleteSemaphoresEXT;
-PFNGLISSEMAPHOREEXTPROC glad_glIsSemaphoreEXT;
-PFNGLSEMAPHOREPARAMETERUI64VEXTPROC glad_glSemaphoreParameterui64vEXT;
-PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC glad_glGetSemaphoreParameterui64vEXT;
-PFNGLWAITSEMAPHOREEXTPROC glad_glWaitSemaphoreEXT;
-PFNGLSIGNALSEMAPHOREEXTPROC glad_glSignalSemaphoreEXT;
-PFNGLIMPORTSEMAPHOREFDEXTPROC glad_glImportSemaphoreFdEXT;
-PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC glad_glImportSemaphoreWin32HandleEXT;
-PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC glad_glImportSemaphoreWin32NameEXT;
-PFNGLUSESHADERPROGRAMEXTPROC glad_glUseShaderProgramEXT;
-PFNGLACTIVEPROGRAMEXTPROC glad_glActiveProgramEXT;
-PFNGLCREATESHADERPROGRAMEXTPROC glad_glCreateShaderProgramEXT;
-PFNGLACTIVESHADERPROGRAMEXTPROC glad_glActiveShaderProgramEXT;
-PFNGLBINDPROGRAMPIPELINEEXTPROC glad_glBindProgramPipelineEXT;
-PFNGLCREATESHADERPROGRAMVEXTPROC glad_glCreateShaderProgramvEXT;
-PFNGLDELETEPROGRAMPIPELINESEXTPROC glad_glDeleteProgramPipelinesEXT;
-PFNGLGENPROGRAMPIPELINESEXTPROC glad_glGenProgramPipelinesEXT;
-PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC glad_glGetProgramPipelineInfoLogEXT;
-PFNGLGETPROGRAMPIPELINEIVEXTPROC glad_glGetProgramPipelineivEXT;
-PFNGLISPROGRAMPIPELINEEXTPROC glad_glIsProgramPipelineEXT;
-PFNGLUSEPROGRAMSTAGESEXTPROC glad_glUseProgramStagesEXT;
-PFNGLVALIDATEPROGRAMPIPELINEEXTPROC glad_glValidateProgramPipelineEXT;
-PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC glad_glFramebufferFetchBarrierEXT;
-PFNGLBINDIMAGETEXTUREEXTPROC glad_glBindImageTextureEXT;
-PFNGLMEMORYBARRIEREXTPROC glad_glMemoryBarrierEXT;
-PFNGLSTENCILCLEARTAGEXTPROC glad_glStencilClearTagEXT;
-PFNGLACTIVESTENCILFACEEXTPROC glad_glActiveStencilFaceEXT;
-PFNGLTEXSUBIMAGE1DEXTPROC glad_glTexSubImage1DEXT;
-PFNGLTEXSUBIMAGE2DEXTPROC glad_glTexSubImage2DEXT;
-PFNGLTEXIMAGE3DEXTPROC glad_glTexImage3DEXT;
-PFNGLTEXSUBIMAGE3DEXTPROC glad_glTexSubImage3DEXT;
-PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glad_glFramebufferTextureLayerEXT;
-PFNGLTEXBUFFEREXTPROC glad_glTexBufferEXT;
-PFNGLTEXPARAMETERIIVEXTPROC glad_glTexParameterIivEXT;
-PFNGLTEXPARAMETERIUIVEXTPROC glad_glTexParameterIuivEXT;
-PFNGLGETTEXPARAMETERIIVEXTPROC glad_glGetTexParameterIivEXT;
-PFNGLGETTEXPARAMETERIUIVEXTPROC glad_glGetTexParameterIuivEXT;
-PFNGLCLEARCOLORIIEXTPROC glad_glClearColorIiEXT;
-PFNGLCLEARCOLORIUIEXTPROC glad_glClearColorIuiEXT;
-PFNGLARETEXTURESRESIDENTEXTPROC glad_glAreTexturesResidentEXT;
-PFNGLBINDTEXTUREEXTPROC glad_glBindTextureEXT;
-PFNGLDELETETEXTURESEXTPROC glad_glDeleteTexturesEXT;
-PFNGLGENTEXTURESEXTPROC glad_glGenTexturesEXT;
-PFNGLISTEXTUREEXTPROC glad_glIsTextureEXT;
-PFNGLPRIORITIZETEXTURESEXTPROC glad_glPrioritizeTexturesEXT;
-PFNGLTEXTURENORMALEXTPROC glad_glTextureNormalEXT;
-PFNGLGETQUERYOBJECTI64VEXTPROC glad_glGetQueryObjecti64vEXT;
-PFNGLGETQUERYOBJECTUI64VEXTPROC glad_glGetQueryObjectui64vEXT;
-PFNGLBEGINTRANSFORMFEEDBACKEXTPROC glad_glBeginTransformFeedbackEXT;
-PFNGLENDTRANSFORMFEEDBACKEXTPROC glad_glEndTransformFeedbackEXT;
-PFNGLBINDBUFFERRANGEEXTPROC glad_glBindBufferRangeEXT;
-PFNGLBINDBUFFEROFFSETEXTPROC glad_glBindBufferOffsetEXT;
-PFNGLBINDBUFFERBASEEXTPROC glad_glBindBufferBaseEXT;
-PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC glad_glTransformFeedbackVaryingsEXT;
-PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC glad_glGetTransformFeedbackVaryingEXT;
-PFNGLARRAYELEMENTEXTPROC glad_glArrayElementEXT;
-PFNGLCOLORPOINTEREXTPROC glad_glColorPointerEXT;
-PFNGLDRAWARRAYSEXTPROC glad_glDrawArraysEXT;
-PFNGLEDGEFLAGPOINTEREXTPROC glad_glEdgeFlagPointerEXT;
-PFNGLGETPOINTERVEXTPROC glad_glGetPointervEXT;
-PFNGLINDEXPOINTEREXTPROC glad_glIndexPointerEXT;
-PFNGLNORMALPOINTEREXTPROC glad_glNormalPointerEXT;
-PFNGLTEXCOORDPOINTEREXTPROC glad_glTexCoordPointerEXT;
-PFNGLVERTEXPOINTEREXTPROC glad_glVertexPointerEXT;
-PFNGLVERTEXATTRIBL1DEXTPROC glad_glVertexAttribL1dEXT;
-PFNGLVERTEXATTRIBL2DEXTPROC glad_glVertexAttribL2dEXT;
-PFNGLVERTEXATTRIBL3DEXTPROC glad_glVertexAttribL3dEXT;
-PFNGLVERTEXATTRIBL4DEXTPROC glad_glVertexAttribL4dEXT;
-PFNGLVERTEXATTRIBL1DVEXTPROC glad_glVertexAttribL1dvEXT;
-PFNGLVERTEXATTRIBL2DVEXTPROC glad_glVertexAttribL2dvEXT;
-PFNGLVERTEXATTRIBL3DVEXTPROC glad_glVertexAttribL3dvEXT;
-PFNGLVERTEXATTRIBL4DVEXTPROC glad_glVertexAttribL4dvEXT;
-PFNGLVERTEXATTRIBLPOINTEREXTPROC glad_glVertexAttribLPointerEXT;
-PFNGLGETVERTEXATTRIBLDVEXTPROC glad_glGetVertexAttribLdvEXT;
-PFNGLBEGINVERTEXSHADEREXTPROC glad_glBeginVertexShaderEXT;
-PFNGLENDVERTEXSHADEREXTPROC glad_glEndVertexShaderEXT;
-PFNGLBINDVERTEXSHADEREXTPROC glad_glBindVertexShaderEXT;
-PFNGLGENVERTEXSHADERSEXTPROC glad_glGenVertexShadersEXT;
-PFNGLDELETEVERTEXSHADEREXTPROC glad_glDeleteVertexShaderEXT;
-PFNGLSHADEROP1EXTPROC glad_glShaderOp1EXT;
-PFNGLSHADEROP2EXTPROC glad_glShaderOp2EXT;
-PFNGLSHADEROP3EXTPROC glad_glShaderOp3EXT;
-PFNGLSWIZZLEEXTPROC glad_glSwizzleEXT;
-PFNGLWRITEMASKEXTPROC glad_glWriteMaskEXT;
-PFNGLINSERTCOMPONENTEXTPROC glad_glInsertComponentEXT;
-PFNGLEXTRACTCOMPONENTEXTPROC glad_glExtractComponentEXT;
-PFNGLGENSYMBOLSEXTPROC glad_glGenSymbolsEXT;
-PFNGLSETINVARIANTEXTPROC glad_glSetInvariantEXT;
-PFNGLSETLOCALCONSTANTEXTPROC glad_glSetLocalConstantEXT;
-PFNGLVARIANTBVEXTPROC glad_glVariantbvEXT;
-PFNGLVARIANTSVEXTPROC glad_glVariantsvEXT;
-PFNGLVARIANTIVEXTPROC glad_glVariantivEXT;
-PFNGLVARIANTFVEXTPROC glad_glVariantfvEXT;
-PFNGLVARIANTDVEXTPROC glad_glVariantdvEXT;
-PFNGLVARIANTUBVEXTPROC glad_glVariantubvEXT;
-PFNGLVARIANTUSVEXTPROC glad_glVariantusvEXT;
-PFNGLVARIANTUIVEXTPROC glad_glVariantuivEXT;
-PFNGLVARIANTPOINTEREXTPROC glad_glVariantPointerEXT;
-PFNGLENABLEVARIANTCLIENTSTATEEXTPROC glad_glEnableVariantClientStateEXT;
-PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC glad_glDisableVariantClientStateEXT;
-PFNGLBINDLIGHTPARAMETEREXTPROC glad_glBindLightParameterEXT;
-PFNGLBINDMATERIALPARAMETEREXTPROC glad_glBindMaterialParameterEXT;
-PFNGLBINDTEXGENPARAMETEREXTPROC glad_glBindTexGenParameterEXT;
-PFNGLBINDTEXTUREUNITPARAMETEREXTPROC glad_glBindTextureUnitParameterEXT;
-PFNGLBINDPARAMETEREXTPROC glad_glBindParameterEXT;
-PFNGLISVARIANTENABLEDEXTPROC glad_glIsVariantEnabledEXT;
-PFNGLGETVARIANTBOOLEANVEXTPROC glad_glGetVariantBooleanvEXT;
-PFNGLGETVARIANTINTEGERVEXTPROC glad_glGetVariantIntegervEXT;
-PFNGLGETVARIANTFLOATVEXTPROC glad_glGetVariantFloatvEXT;
-PFNGLGETVARIANTPOINTERVEXTPROC glad_glGetVariantPointervEXT;
-PFNGLGETINVARIANTBOOLEANVEXTPROC glad_glGetInvariantBooleanvEXT;
-PFNGLGETINVARIANTINTEGERVEXTPROC glad_glGetInvariantIntegervEXT;
-PFNGLGETINVARIANTFLOATVEXTPROC glad_glGetInvariantFloatvEXT;
-PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC glad_glGetLocalConstantBooleanvEXT;
-PFNGLGETLOCALCONSTANTINTEGERVEXTPROC glad_glGetLocalConstantIntegervEXT;
-PFNGLGETLOCALCONSTANTFLOATVEXTPROC glad_glGetLocalConstantFloatvEXT;
-PFNGLVERTEXWEIGHTFEXTPROC glad_glVertexWeightfEXT;
-PFNGLVERTEXWEIGHTFVEXTPROC glad_glVertexWeightfvEXT;
-PFNGLVERTEXWEIGHTPOINTEREXTPROC glad_glVertexWeightPointerEXT;
-PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC glad_glAcquireKeyedMutexWin32EXT;
-PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC glad_glReleaseKeyedMutexWin32EXT;
-PFNGLWINDOWRECTANGLESEXTPROC glad_glWindowRectanglesEXT;
-PFNGLIMPORTSYNCEXTPROC glad_glImportSyncEXT;
-PFNGLFRAMETERMINATORGREMEDYPROC glad_glFrameTerminatorGREMEDY;
-PFNGLSTRINGMARKERGREMEDYPROC glad_glStringMarkerGREMEDY;
-PFNGLIMAGETRANSFORMPARAMETERIHPPROC glad_glImageTransformParameteriHP;
-PFNGLIMAGETRANSFORMPARAMETERFHPPROC glad_glImageTransformParameterfHP;
-PFNGLIMAGETRANSFORMPARAMETERIVHPPROC glad_glImageTransformParameterivHP;
-PFNGLIMAGETRANSFORMPARAMETERFVHPPROC glad_glImageTransformParameterfvHP;
-PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC glad_glGetImageTransformParameterivHP;
-PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC glad_glGetImageTransformParameterfvHP;
-PFNGLMULTIMODEDRAWARRAYSIBMPROC glad_glMultiModeDrawArraysIBM;
-PFNGLMULTIMODEDRAWELEMENTSIBMPROC glad_glMultiModeDrawElementsIBM;
-PFNGLFLUSHSTATICDATAIBMPROC glad_glFlushStaticDataIBM;
-PFNGLCOLORPOINTERLISTIBMPROC glad_glColorPointerListIBM;
-PFNGLSECONDARYCOLORPOINTERLISTIBMPROC glad_glSecondaryColorPointerListIBM;
-PFNGLEDGEFLAGPOINTERLISTIBMPROC glad_glEdgeFlagPointerListIBM;
-PFNGLFOGCOORDPOINTERLISTIBMPROC glad_glFogCoordPointerListIBM;
-PFNGLINDEXPOINTERLISTIBMPROC glad_glIndexPointerListIBM;
-PFNGLNORMALPOINTERLISTIBMPROC glad_glNormalPointerListIBM;
-PFNGLTEXCOORDPOINTERLISTIBMPROC glad_glTexCoordPointerListIBM;
-PFNGLVERTEXPOINTERLISTIBMPROC glad_glVertexPointerListIBM;
-PFNGLBLENDFUNCSEPARATEINGRPROC glad_glBlendFuncSeparateINGR;
-PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC glad_glApplyFramebufferAttachmentCMAAINTEL;
-PFNGLSYNCTEXTUREINTELPROC glad_glSyncTextureINTEL;
-PFNGLUNMAPTEXTURE2DINTELPROC glad_glUnmapTexture2DINTEL;
-PFNGLMAPTEXTURE2DINTELPROC glad_glMapTexture2DINTEL;
-PFNGLVERTEXPOINTERVINTELPROC glad_glVertexPointervINTEL;
-PFNGLNORMALPOINTERVINTELPROC glad_glNormalPointervINTEL;
-PFNGLCOLORPOINTERVINTELPROC glad_glColorPointervINTEL;
-PFNGLTEXCOORDPOINTERVINTELPROC glad_glTexCoordPointervINTEL;
-PFNGLBEGINPERFQUERYINTELPROC glad_glBeginPerfQueryINTEL;
-PFNGLCREATEPERFQUERYINTELPROC glad_glCreatePerfQueryINTEL;
-PFNGLDELETEPERFQUERYINTELPROC glad_glDeletePerfQueryINTEL;
-PFNGLENDPERFQUERYINTELPROC glad_glEndPerfQueryINTEL;
-PFNGLGETFIRSTPERFQUERYIDINTELPROC glad_glGetFirstPerfQueryIdINTEL;
-PFNGLGETNEXTPERFQUERYIDINTELPROC glad_glGetNextPerfQueryIdINTEL;
-PFNGLGETPERFCOUNTERINFOINTELPROC glad_glGetPerfCounterInfoINTEL;
-PFNGLGETPERFQUERYDATAINTELPROC glad_glGetPerfQueryDataINTEL;
-PFNGLGETPERFQUERYIDBYNAMEINTELPROC glad_glGetPerfQueryIdByNameINTEL;
-PFNGLGETPERFQUERYINFOINTELPROC glad_glGetPerfQueryInfoINTEL;
-PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR;
-PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl;
-PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert;
-PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback;
-PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog;
-PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup;
-PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup;
-PFNGLOBJECTLABELPROC glad_glObjectLabel;
-PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel;
-PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel;
-PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel;
-PFNGLGETPOINTERVPROC glad_glGetPointerv;
-PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR;
-PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR;
-PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR;
-PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR;
-PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR;
-PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR;
-PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR;
-PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR;
-PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR;
-PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR;
-PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR;
-PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glad_glMaxShaderCompilerThreadsKHR;
-PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus;
-PFNGLREADNPIXELSPROC glad_glReadnPixels;
-PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv;
-PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv;
-PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;
-PFNGLGETGRAPHICSRESETSTATUSKHRPROC glad_glGetGraphicsResetStatusKHR;
-PFNGLREADNPIXELSKHRPROC glad_glReadnPixelsKHR;
-PFNGLGETNUNIFORMFVKHRPROC glad_glGetnUniformfvKHR;
-PFNGLGETNUNIFORMIVKHRPROC glad_glGetnUniformivKHR;
-PFNGLGETNUNIFORMUIVKHRPROC glad_glGetnUniformuivKHR;
-PFNGLRESIZEBUFFERSMESAPROC glad_glResizeBuffersMESA;
-PFNGLWINDOWPOS2DMESAPROC glad_glWindowPos2dMESA;
-PFNGLWINDOWPOS2DVMESAPROC glad_glWindowPos2dvMESA;
-PFNGLWINDOWPOS2FMESAPROC glad_glWindowPos2fMESA;
-PFNGLWINDOWPOS2FVMESAPROC glad_glWindowPos2fvMESA;
-PFNGLWINDOWPOS2IMESAPROC glad_glWindowPos2iMESA;
-PFNGLWINDOWPOS2IVMESAPROC glad_glWindowPos2ivMESA;
-PFNGLWINDOWPOS2SMESAPROC glad_glWindowPos2sMESA;
-PFNGLWINDOWPOS2SVMESAPROC glad_glWindowPos2svMESA;
-PFNGLWINDOWPOS3DMESAPROC glad_glWindowPos3dMESA;
-PFNGLWINDOWPOS3DVMESAPROC glad_glWindowPos3dvMESA;
-PFNGLWINDOWPOS3FMESAPROC glad_glWindowPos3fMESA;
-PFNGLWINDOWPOS3FVMESAPROC glad_glWindowPos3fvMESA;
-PFNGLWINDOWPOS3IMESAPROC glad_glWindowPos3iMESA;
-PFNGLWINDOWPOS3IVMESAPROC glad_glWindowPos3ivMESA;
-PFNGLWINDOWPOS3SMESAPROC glad_glWindowPos3sMESA;
-PFNGLWINDOWPOS3SVMESAPROC glad_glWindowPos3svMESA;
-PFNGLWINDOWPOS4DMESAPROC glad_glWindowPos4dMESA;
-PFNGLWINDOWPOS4DVMESAPROC glad_glWindowPos4dvMESA;
-PFNGLWINDOWPOS4FMESAPROC glad_glWindowPos4fMESA;
-PFNGLWINDOWPOS4FVMESAPROC glad_glWindowPos4fvMESA;
-PFNGLWINDOWPOS4IMESAPROC glad_glWindowPos4iMESA;
-PFNGLWINDOWPOS4IVMESAPROC glad_glWindowPos4ivMESA;
-PFNGLWINDOWPOS4SMESAPROC glad_glWindowPos4sMESA;
-PFNGLWINDOWPOS4SVMESAPROC glad_glWindowPos4svMESA;
-PFNGLBEGINCONDITIONALRENDERNVXPROC glad_glBeginConditionalRenderNVX;
-PFNGLENDCONDITIONALRENDERNVXPROC glad_glEndConditionalRenderNVX;
-PFNGLLGPUNAMEDBUFFERSUBDATANVXPROC glad_glLGPUNamedBufferSubDataNVX;
-PFNGLLGPUCOPYIMAGESUBDATANVXPROC glad_glLGPUCopyImageSubDataNVX;
-PFNGLLGPUINTERLOCKNVXPROC glad_glLGPUInterlockNVX;
-PFNGLALPHATOCOVERAGEDITHERCONTROLNVPROC glad_glAlphaToCoverageDitherControlNV;
-PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC glad_glMultiDrawArraysIndirectBindlessNV;
-PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC glad_glMultiDrawElementsIndirectBindlessNV;
-PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC glad_glMultiDrawArraysIndirectBindlessCountNV;
-PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC glad_glMultiDrawElementsIndirectBindlessCountNV;
-PFNGLGETTEXTUREHANDLENVPROC glad_glGetTextureHandleNV;
-PFNGLGETTEXTURESAMPLERHANDLENVPROC glad_glGetTextureSamplerHandleNV;
-PFNGLMAKETEXTUREHANDLERESIDENTNVPROC glad_glMakeTextureHandleResidentNV;
-PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC glad_glMakeTextureHandleNonResidentNV;
-PFNGLGETIMAGEHANDLENVPROC glad_glGetImageHandleNV;
-PFNGLMAKEIMAGEHANDLERESIDENTNVPROC glad_glMakeImageHandleResidentNV;
-PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC glad_glMakeImageHandleNonResidentNV;
-PFNGLUNIFORMHANDLEUI64NVPROC glad_glUniformHandleui64NV;
-PFNGLUNIFORMHANDLEUI64VNVPROC glad_glUniformHandleui64vNV;
-PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC glad_glProgramUniformHandleui64NV;
-PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC glad_glProgramUniformHandleui64vNV;
-PFNGLISTEXTUREHANDLERESIDENTNVPROC glad_glIsTextureHandleResidentNV;
-PFNGLISIMAGEHANDLERESIDENTNVPROC glad_glIsImageHandleResidentNV;
-PFNGLBLENDPARAMETERINVPROC glad_glBlendParameteriNV;
-PFNGLBLENDBARRIERNVPROC glad_glBlendBarrierNV;
-PFNGLVIEWPORTPOSITIONWSCALENVPROC glad_glViewportPositionWScaleNV;
-PFNGLCREATESTATESNVPROC glad_glCreateStatesNV;
-PFNGLDELETESTATESNVPROC glad_glDeleteStatesNV;
-PFNGLISSTATENVPROC glad_glIsStateNV;
-PFNGLSTATECAPTURENVPROC glad_glStateCaptureNV;
-PFNGLGETCOMMANDHEADERNVPROC glad_glGetCommandHeaderNV;
-PFNGLGETSTAGEINDEXNVPROC glad_glGetStageIndexNV;
-PFNGLDRAWCOMMANDSNVPROC glad_glDrawCommandsNV;
-PFNGLDRAWCOMMANDSADDRESSNVPROC glad_glDrawCommandsAddressNV;
-PFNGLDRAWCOMMANDSSTATESNVPROC glad_glDrawCommandsStatesNV;
-PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC glad_glDrawCommandsStatesAddressNV;
-PFNGLCREATECOMMANDLISTSNVPROC glad_glCreateCommandListsNV;
-PFNGLDELETECOMMANDLISTSNVPROC glad_glDeleteCommandListsNV;
-PFNGLISCOMMANDLISTNVPROC glad_glIsCommandListNV;
-PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC glad_glListDrawCommandsStatesClientNV;
-PFNGLCOMMANDLISTSEGMENTSNVPROC glad_glCommandListSegmentsNV;
-PFNGLCOMPILECOMMANDLISTNVPROC glad_glCompileCommandListNV;
-PFNGLCALLCOMMANDLISTNVPROC glad_glCallCommandListNV;
-PFNGLBEGINCONDITIONALRENDERNVPROC glad_glBeginConditionalRenderNV;
-PFNGLENDCONDITIONALRENDERNVPROC glad_glEndConditionalRenderNV;
-PFNGLSUBPIXELPRECISIONBIASNVPROC glad_glSubpixelPrecisionBiasNV;
-PFNGLCONSERVATIVERASTERPARAMETERFNVPROC glad_glConservativeRasterParameterfNV;
-PFNGLCONSERVATIVERASTERPARAMETERINVPROC glad_glConservativeRasterParameteriNV;
-PFNGLCOPYIMAGESUBDATANVPROC glad_glCopyImageSubDataNV;
-PFNGLDEPTHRANGEDNVPROC glad_glDepthRangedNV;
-PFNGLCLEARDEPTHDNVPROC glad_glClearDepthdNV;
-PFNGLDEPTHBOUNDSDNVPROC glad_glDepthBoundsdNV;
-PFNGLDRAWTEXTURENVPROC glad_glDrawTextureNV;
-PFNGLDRAWVKIMAGENVPROC glad_glDrawVkImageNV;
-PFNGLGETVKPROCADDRNVPROC glad_glGetVkProcAddrNV;
-PFNGLWAITVKSEMAPHORENVPROC glad_glWaitVkSemaphoreNV;
-PFNGLSIGNALVKSEMAPHORENVPROC glad_glSignalVkSemaphoreNV;
-PFNGLSIGNALVKFENCENVPROC glad_glSignalVkFenceNV;
-PFNGLMAPCONTROLPOINTSNVPROC glad_glMapControlPointsNV;
-PFNGLMAPPARAMETERIVNVPROC glad_glMapParameterivNV;
-PFNGLMAPPARAMETERFVNVPROC glad_glMapParameterfvNV;
-PFNGLGETMAPCONTROLPOINTSNVPROC glad_glGetMapControlPointsNV;
-PFNGLGETMAPPARAMETERIVNVPROC glad_glGetMapParameterivNV;
-PFNGLGETMAPPARAMETERFVNVPROC glad_glGetMapParameterfvNV;
-PFNGLGETMAPATTRIBPARAMETERIVNVPROC glad_glGetMapAttribParameterivNV;
-PFNGLGETMAPATTRIBPARAMETERFVNVPROC glad_glGetMapAttribParameterfvNV;
-PFNGLEVALMAPSNVPROC glad_glEvalMapsNV;
-PFNGLGETMULTISAMPLEFVNVPROC glad_glGetMultisamplefvNV;
-PFNGLSAMPLEMASKINDEXEDNVPROC glad_glSampleMaskIndexedNV;
-PFNGLTEXRENDERBUFFERNVPROC glad_glTexRenderbufferNV;
-PFNGLDELETEFENCESNVPROC glad_glDeleteFencesNV;
-PFNGLGENFENCESNVPROC glad_glGenFencesNV;
-PFNGLISFENCENVPROC glad_glIsFenceNV;
-PFNGLTESTFENCENVPROC glad_glTestFenceNV;
-PFNGLGETFENCEIVNVPROC glad_glGetFenceivNV;
-PFNGLFINISHFENCENVPROC glad_glFinishFenceNV;
-PFNGLSETFENCENVPROC glad_glSetFenceNV;
-PFNGLFRAGMENTCOVERAGECOLORNVPROC glad_glFragmentCoverageColorNV;
-PFNGLPROGRAMNAMEDPARAMETER4FNVPROC glad_glProgramNamedParameter4fNV;
-PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC glad_glProgramNamedParameter4fvNV;
-PFNGLPROGRAMNAMEDPARAMETER4DNVPROC glad_glProgramNamedParameter4dNV;
-PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC glad_glProgramNamedParameter4dvNV;
-PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC glad_glGetProgramNamedParameterfvNV;
-PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC glad_glGetProgramNamedParameterdvNV;
-PFNGLCOVERAGEMODULATIONTABLENVPROC glad_glCoverageModulationTableNV;
-PFNGLGETCOVERAGEMODULATIONTABLENVPROC glad_glGetCoverageModulationTableNV;
-PFNGLCOVERAGEMODULATIONNVPROC glad_glCoverageModulationNV;
-PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC glad_glRenderbufferStorageMultisampleCoverageNV;
-PFNGLPROGRAMVERTEXLIMITNVPROC glad_glProgramVertexLimitNV;
-PFNGLFRAMEBUFFERTEXTUREEXTPROC glad_glFramebufferTextureEXT;
-PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC glad_glFramebufferTextureFaceEXT;
-PFNGLRENDERGPUMASKNVPROC glad_glRenderGpuMaskNV;
-PFNGLMULTICASTBUFFERSUBDATANVPROC glad_glMulticastBufferSubDataNV;
-PFNGLMULTICASTCOPYBUFFERSUBDATANVPROC glad_glMulticastCopyBufferSubDataNV;
-PFNGLMULTICASTCOPYIMAGESUBDATANVPROC glad_glMulticastCopyImageSubDataNV;
-PFNGLMULTICASTBLITFRAMEBUFFERNVPROC glad_glMulticastBlitFramebufferNV;
-PFNGLMULTICASTFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glMulticastFramebufferSampleLocationsfvNV;
-PFNGLMULTICASTBARRIERNVPROC glad_glMulticastBarrierNV;
-PFNGLMULTICASTWAITSYNCNVPROC glad_glMulticastWaitSyncNV;
-PFNGLMULTICASTGETQUERYOBJECTIVNVPROC glad_glMulticastGetQueryObjectivNV;
-PFNGLMULTICASTGETQUERYOBJECTUIVNVPROC glad_glMulticastGetQueryObjectuivNV;
-PFNGLMULTICASTGETQUERYOBJECTI64VNVPROC glad_glMulticastGetQueryObjecti64vNV;
-PFNGLMULTICASTGETQUERYOBJECTUI64VNVPROC glad_glMulticastGetQueryObjectui64vNV;
-PFNGLPROGRAMLOCALPARAMETERI4INVPROC glad_glProgramLocalParameterI4iNV;
-PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC glad_glProgramLocalParameterI4ivNV;
-PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC glad_glProgramLocalParametersI4ivNV;
-PFNGLPROGRAMLOCALPARAMETERI4UINVPROC glad_glProgramLocalParameterI4uiNV;
-PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC glad_glProgramLocalParameterI4uivNV;
-PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC glad_glProgramLocalParametersI4uivNV;
-PFNGLPROGRAMENVPARAMETERI4INVPROC glad_glProgramEnvParameterI4iNV;
-PFNGLPROGRAMENVPARAMETERI4IVNVPROC glad_glProgramEnvParameterI4ivNV;
-PFNGLPROGRAMENVPARAMETERSI4IVNVPROC glad_glProgramEnvParametersI4ivNV;
-PFNGLPROGRAMENVPARAMETERI4UINVPROC glad_glProgramEnvParameterI4uiNV;
-PFNGLPROGRAMENVPARAMETERI4UIVNVPROC glad_glProgramEnvParameterI4uivNV;
-PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC glad_glProgramEnvParametersI4uivNV;
-PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC glad_glGetProgramLocalParameterIivNV;
-PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC glad_glGetProgramLocalParameterIuivNV;
-PFNGLGETPROGRAMENVPARAMETERIIVNVPROC glad_glGetProgramEnvParameterIivNV;
-PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC glad_glGetProgramEnvParameterIuivNV;
-PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC glad_glProgramSubroutineParametersuivNV;
-PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC glad_glGetProgramSubroutineParameteruivNV;
-PFNGLVERTEX2HNVPROC glad_glVertex2hNV;
-PFNGLVERTEX2HVNVPROC glad_glVertex2hvNV;
-PFNGLVERTEX3HNVPROC glad_glVertex3hNV;
-PFNGLVERTEX3HVNVPROC glad_glVertex3hvNV;
-PFNGLVERTEX4HNVPROC glad_glVertex4hNV;
-PFNGLVERTEX4HVNVPROC glad_glVertex4hvNV;
-PFNGLNORMAL3HNVPROC glad_glNormal3hNV;
-PFNGLNORMAL3HVNVPROC glad_glNormal3hvNV;
-PFNGLCOLOR3HNVPROC glad_glColor3hNV;
-PFNGLCOLOR3HVNVPROC glad_glColor3hvNV;
-PFNGLCOLOR4HNVPROC glad_glColor4hNV;
-PFNGLCOLOR4HVNVPROC glad_glColor4hvNV;
-PFNGLTEXCOORD1HNVPROC glad_glTexCoord1hNV;
-PFNGLTEXCOORD1HVNVPROC glad_glTexCoord1hvNV;
-PFNGLTEXCOORD2HNVPROC glad_glTexCoord2hNV;
-PFNGLTEXCOORD2HVNVPROC glad_glTexCoord2hvNV;
-PFNGLTEXCOORD3HNVPROC glad_glTexCoord3hNV;
-PFNGLTEXCOORD3HVNVPROC glad_glTexCoord3hvNV;
-PFNGLTEXCOORD4HNVPROC glad_glTexCoord4hNV;
-PFNGLTEXCOORD4HVNVPROC glad_glTexCoord4hvNV;
-PFNGLMULTITEXCOORD1HNVPROC glad_glMultiTexCoord1hNV;
-PFNGLMULTITEXCOORD1HVNVPROC glad_glMultiTexCoord1hvNV;
-PFNGLMULTITEXCOORD2HNVPROC glad_glMultiTexCoord2hNV;
-PFNGLMULTITEXCOORD2HVNVPROC glad_glMultiTexCoord2hvNV;
-PFNGLMULTITEXCOORD3HNVPROC glad_glMultiTexCoord3hNV;
-PFNGLMULTITEXCOORD3HVNVPROC glad_glMultiTexCoord3hvNV;
-PFNGLMULTITEXCOORD4HNVPROC glad_glMultiTexCoord4hNV;
-PFNGLMULTITEXCOORD4HVNVPROC glad_glMultiTexCoord4hvNV;
-PFNGLFOGCOORDHNVPROC glad_glFogCoordhNV;
-PFNGLFOGCOORDHVNVPROC glad_glFogCoordhvNV;
-PFNGLSECONDARYCOLOR3HNVPROC glad_glSecondaryColor3hNV;
-PFNGLSECONDARYCOLOR3HVNVPROC glad_glSecondaryColor3hvNV;
-PFNGLVERTEXWEIGHTHNVPROC glad_glVertexWeighthNV;
-PFNGLVERTEXWEIGHTHVNVPROC glad_glVertexWeighthvNV;
-PFNGLVERTEXATTRIB1HNVPROC glad_glVertexAttrib1hNV;
-PFNGLVERTEXATTRIB1HVNVPROC glad_glVertexAttrib1hvNV;
-PFNGLVERTEXATTRIB2HNVPROC glad_glVertexAttrib2hNV;
-PFNGLVERTEXATTRIB2HVNVPROC glad_glVertexAttrib2hvNV;
-PFNGLVERTEXATTRIB3HNVPROC glad_glVertexAttrib3hNV;
-PFNGLVERTEXATTRIB3HVNVPROC glad_glVertexAttrib3hvNV;
-PFNGLVERTEXATTRIB4HNVPROC glad_glVertexAttrib4hNV;
-PFNGLVERTEXATTRIB4HVNVPROC glad_glVertexAttrib4hvNV;
-PFNGLVERTEXATTRIBS1HVNVPROC glad_glVertexAttribs1hvNV;
-PFNGLVERTEXATTRIBS2HVNVPROC glad_glVertexAttribs2hvNV;
-PFNGLVERTEXATTRIBS3HVNVPROC glad_glVertexAttribs3hvNV;
-PFNGLVERTEXATTRIBS4HVNVPROC glad_glVertexAttribs4hvNV;
-PFNGLGETINTERNALFORMATSAMPLEIVNVPROC glad_glGetInternalformatSampleivNV;
-PFNGLGENOCCLUSIONQUERIESNVPROC glad_glGenOcclusionQueriesNV;
-PFNGLDELETEOCCLUSIONQUERIESNVPROC glad_glDeleteOcclusionQueriesNV;
-PFNGLISOCCLUSIONQUERYNVPROC glad_glIsOcclusionQueryNV;
-PFNGLBEGINOCCLUSIONQUERYNVPROC glad_glBeginOcclusionQueryNV;
-PFNGLENDOCCLUSIONQUERYNVPROC glad_glEndOcclusionQueryNV;
-PFNGLGETOCCLUSIONQUERYIVNVPROC glad_glGetOcclusionQueryivNV;
-PFNGLGETOCCLUSIONQUERYUIVNVPROC glad_glGetOcclusionQueryuivNV;
-PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC glad_glProgramBufferParametersfvNV;
-PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC glad_glProgramBufferParametersIivNV;
-PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC glad_glProgramBufferParametersIuivNV;
-PFNGLGENPATHSNVPROC glad_glGenPathsNV;
-PFNGLDELETEPATHSNVPROC glad_glDeletePathsNV;
-PFNGLISPATHNVPROC glad_glIsPathNV;
-PFNGLPATHCOMMANDSNVPROC glad_glPathCommandsNV;
-PFNGLPATHCOORDSNVPROC glad_glPathCoordsNV;
-PFNGLPATHSUBCOMMANDSNVPROC glad_glPathSubCommandsNV;
-PFNGLPATHSUBCOORDSNVPROC glad_glPathSubCoordsNV;
-PFNGLPATHSTRINGNVPROC glad_glPathStringNV;
-PFNGLPATHGLYPHSNVPROC glad_glPathGlyphsNV;
-PFNGLPATHGLYPHRANGENVPROC glad_glPathGlyphRangeNV;
-PFNGLWEIGHTPATHSNVPROC glad_glWeightPathsNV;
-PFNGLCOPYPATHNVPROC glad_glCopyPathNV;
-PFNGLINTERPOLATEPATHSNVPROC glad_glInterpolatePathsNV;
-PFNGLTRANSFORMPATHNVPROC glad_glTransformPathNV;
-PFNGLPATHPARAMETERIVNVPROC glad_glPathParameterivNV;
-PFNGLPATHPARAMETERINVPROC glad_glPathParameteriNV;
-PFNGLPATHPARAMETERFVNVPROC glad_glPathParameterfvNV;
-PFNGLPATHPARAMETERFNVPROC glad_glPathParameterfNV;
-PFNGLPATHDASHARRAYNVPROC glad_glPathDashArrayNV;
-PFNGLPATHSTENCILFUNCNVPROC glad_glPathStencilFuncNV;
-PFNGLPATHSTENCILDEPTHOFFSETNVPROC glad_glPathStencilDepthOffsetNV;
-PFNGLSTENCILFILLPATHNVPROC glad_glStencilFillPathNV;
-PFNGLSTENCILSTROKEPATHNVPROC glad_glStencilStrokePathNV;
-PFNGLSTENCILFILLPATHINSTANCEDNVPROC glad_glStencilFillPathInstancedNV;
-PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC glad_glStencilStrokePathInstancedNV;
-PFNGLPATHCOVERDEPTHFUNCNVPROC glad_glPathCoverDepthFuncNV;
-PFNGLCOVERFILLPATHNVPROC glad_glCoverFillPathNV;
-PFNGLCOVERSTROKEPATHNVPROC glad_glCoverStrokePathNV;
-PFNGLCOVERFILLPATHINSTANCEDNVPROC glad_glCoverFillPathInstancedNV;
-PFNGLCOVERSTROKEPATHINSTANCEDNVPROC glad_glCoverStrokePathInstancedNV;
-PFNGLGETPATHPARAMETERIVNVPROC glad_glGetPathParameterivNV;
-PFNGLGETPATHPARAMETERFVNVPROC glad_glGetPathParameterfvNV;
-PFNGLGETPATHCOMMANDSNVPROC glad_glGetPathCommandsNV;
-PFNGLGETPATHCOORDSNVPROC glad_glGetPathCoordsNV;
-PFNGLGETPATHDASHARRAYNVPROC glad_glGetPathDashArrayNV;
-PFNGLGETPATHMETRICSNVPROC glad_glGetPathMetricsNV;
-PFNGLGETPATHMETRICRANGENVPROC glad_glGetPathMetricRangeNV;
-PFNGLGETPATHSPACINGNVPROC glad_glGetPathSpacingNV;
-PFNGLISPOINTINFILLPATHNVPROC glad_glIsPointInFillPathNV;
-PFNGLISPOINTINSTROKEPATHNVPROC glad_glIsPointInStrokePathNV;
-PFNGLGETPATHLENGTHNVPROC glad_glGetPathLengthNV;
-PFNGLPOINTALONGPATHNVPROC glad_glPointAlongPathNV;
-PFNGLMATRIXLOAD3X2FNVPROC glad_glMatrixLoad3x2fNV;
-PFNGLMATRIXLOAD3X3FNVPROC glad_glMatrixLoad3x3fNV;
-PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC glad_glMatrixLoadTranspose3x3fNV;
-PFNGLMATRIXMULT3X2FNVPROC glad_glMatrixMult3x2fNV;
-PFNGLMATRIXMULT3X3FNVPROC glad_glMatrixMult3x3fNV;
-PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC glad_glMatrixMultTranspose3x3fNV;
-PFNGLSTENCILTHENCOVERFILLPATHNVPROC glad_glStencilThenCoverFillPathNV;
-PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC glad_glStencilThenCoverStrokePathNV;
-PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC glad_glStencilThenCoverFillPathInstancedNV;
-PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC glad_glStencilThenCoverStrokePathInstancedNV;
-PFNGLPATHGLYPHINDEXRANGENVPROC glad_glPathGlyphIndexRangeNV;
-PFNGLPATHGLYPHINDEXARRAYNVPROC glad_glPathGlyphIndexArrayNV;
-PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC glad_glPathMemoryGlyphIndexArrayNV;
-PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC glad_glProgramPathFragmentInputGenNV;
-PFNGLGETPROGRAMRESOURCEFVNVPROC glad_glGetProgramResourcefvNV;
-PFNGLPATHCOLORGENNVPROC glad_glPathColorGenNV;
-PFNGLPATHTEXGENNVPROC glad_glPathTexGenNV;
-PFNGLPATHFOGGENNVPROC glad_glPathFogGenNV;
-PFNGLGETPATHCOLORGENIVNVPROC glad_glGetPathColorGenivNV;
-PFNGLGETPATHCOLORGENFVNVPROC glad_glGetPathColorGenfvNV;
-PFNGLGETPATHTEXGENIVNVPROC glad_glGetPathTexGenivNV;
-PFNGLGETPATHTEXGENFVNVPROC glad_glGetPathTexGenfvNV;
-PFNGLPIXELDATARANGENVPROC glad_glPixelDataRangeNV;
-PFNGLFLUSHPIXELDATARANGENVPROC glad_glFlushPixelDataRangeNV;
-PFNGLPOINTPARAMETERINVPROC glad_glPointParameteriNV;
-PFNGLPOINTPARAMETERIVNVPROC glad_glPointParameterivNV;
-PFNGLPRESENTFRAMEKEYEDNVPROC glad_glPresentFrameKeyedNV;
-PFNGLPRESENTFRAMEDUALFILLNVPROC glad_glPresentFrameDualFillNV;
-PFNGLGETVIDEOIVNVPROC glad_glGetVideoivNV;
-PFNGLGETVIDEOUIVNVPROC glad_glGetVideouivNV;
-PFNGLGETVIDEOI64VNVPROC glad_glGetVideoi64vNV;
-PFNGLGETVIDEOUI64VNVPROC glad_glGetVideoui64vNV;
-PFNGLPRIMITIVERESTARTNVPROC glad_glPrimitiveRestartNV;
-PFNGLPRIMITIVERESTARTINDEXNVPROC glad_glPrimitiveRestartIndexNV;
-PFNGLQUERYRESOURCENVPROC glad_glQueryResourceNV;
-PFNGLGENQUERYRESOURCETAGNVPROC glad_glGenQueryResourceTagNV;
-PFNGLDELETEQUERYRESOURCETAGNVPROC glad_glDeleteQueryResourceTagNV;
-PFNGLQUERYRESOURCETAGNVPROC glad_glQueryResourceTagNV;
-PFNGLCOMBINERPARAMETERFVNVPROC glad_glCombinerParameterfvNV;
-PFNGLCOMBINERPARAMETERFNVPROC glad_glCombinerParameterfNV;
-PFNGLCOMBINERPARAMETERIVNVPROC glad_glCombinerParameterivNV;
-PFNGLCOMBINERPARAMETERINVPROC glad_glCombinerParameteriNV;
-PFNGLCOMBINERINPUTNVPROC glad_glCombinerInputNV;
-PFNGLCOMBINEROUTPUTNVPROC glad_glCombinerOutputNV;
-PFNGLFINALCOMBINERINPUTNVPROC glad_glFinalCombinerInputNV;
-PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC glad_glGetCombinerInputParameterfvNV;
-PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC glad_glGetCombinerInputParameterivNV;
-PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC glad_glGetCombinerOutputParameterfvNV;
-PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC glad_glGetCombinerOutputParameterivNV;
-PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC glad_glGetFinalCombinerInputParameterfvNV;
-PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC glad_glGetFinalCombinerInputParameterivNV;
-PFNGLCOMBINERSTAGEPARAMETERFVNVPROC glad_glCombinerStageParameterfvNV;
-PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC glad_glGetCombinerStageParameterfvNV;
-PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glFramebufferSampleLocationsfvNV;
-PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glNamedFramebufferSampleLocationsfvNV;
-PFNGLRESOLVEDEPTHVALUESNVPROC glad_glResolveDepthValuesNV;
-PFNGLMAKEBUFFERRESIDENTNVPROC glad_glMakeBufferResidentNV;
-PFNGLMAKEBUFFERNONRESIDENTNVPROC glad_glMakeBufferNonResidentNV;
-PFNGLISBUFFERRESIDENTNVPROC glad_glIsBufferResidentNV;
-PFNGLMAKENAMEDBUFFERRESIDENTNVPROC glad_glMakeNamedBufferResidentNV;
-PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC glad_glMakeNamedBufferNonResidentNV;
-PFNGLISNAMEDBUFFERRESIDENTNVPROC glad_glIsNamedBufferResidentNV;
-PFNGLGETBUFFERPARAMETERUI64VNVPROC glad_glGetBufferParameterui64vNV;
-PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC glad_glGetNamedBufferParameterui64vNV;
-PFNGLGETINTEGERUI64VNVPROC glad_glGetIntegerui64vNV;
-PFNGLUNIFORMUI64NVPROC glad_glUniformui64NV;
-PFNGLUNIFORMUI64VNVPROC glad_glUniformui64vNV;
-PFNGLPROGRAMUNIFORMUI64NVPROC glad_glProgramUniformui64NV;
-PFNGLPROGRAMUNIFORMUI64VNVPROC glad_glProgramUniformui64vNV;
-PFNGLTEXTUREBARRIERNVPROC glad_glTextureBarrierNV;
-PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC glad_glTexImage2DMultisampleCoverageNV;
-PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC glad_glTexImage3DMultisampleCoverageNV;
-PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC glad_glTextureImage2DMultisampleNV;
-PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC glad_glTextureImage3DMultisampleNV;
-PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC glad_glTextureImage2DMultisampleCoverageNV;
-PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC glad_glTextureImage3DMultisampleCoverageNV;
-PFNGLBEGINTRANSFORMFEEDBACKNVPROC glad_glBeginTransformFeedbackNV;
-PFNGLENDTRANSFORMFEEDBACKNVPROC glad_glEndTransformFeedbackNV;
-PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC glad_glTransformFeedbackAttribsNV;
-PFNGLBINDBUFFERRANGENVPROC glad_glBindBufferRangeNV;
-PFNGLBINDBUFFEROFFSETNVPROC glad_glBindBufferOffsetNV;
-PFNGLBINDBUFFERBASENVPROC glad_glBindBufferBaseNV;
-PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC glad_glTransformFeedbackVaryingsNV;
-PFNGLACTIVEVARYINGNVPROC glad_glActiveVaryingNV;
-PFNGLGETVARYINGLOCATIONNVPROC glad_glGetVaryingLocationNV;
-PFNGLGETACTIVEVARYINGNVPROC glad_glGetActiveVaryingNV;
-PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC glad_glGetTransformFeedbackVaryingNV;
-PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC glad_glTransformFeedbackStreamAttribsNV;
-PFNGLBINDTRANSFORMFEEDBACKNVPROC glad_glBindTransformFeedbackNV;
-PFNGLDELETETRANSFORMFEEDBACKSNVPROC glad_glDeleteTransformFeedbacksNV;
-PFNGLGENTRANSFORMFEEDBACKSNVPROC glad_glGenTransformFeedbacksNV;
-PFNGLISTRANSFORMFEEDBACKNVPROC glad_glIsTransformFeedbackNV;
-PFNGLPAUSETRANSFORMFEEDBACKNVPROC glad_glPauseTransformFeedbackNV;
-PFNGLRESUMETRANSFORMFEEDBACKNVPROC glad_glResumeTransformFeedbackNV;
-PFNGLDRAWTRANSFORMFEEDBACKNVPROC glad_glDrawTransformFeedbackNV;
-PFNGLVDPAUINITNVPROC glad_glVDPAUInitNV;
-PFNGLVDPAUFININVPROC glad_glVDPAUFiniNV;
-PFNGLVDPAUREGISTERVIDEOSURFACENVPROC glad_glVDPAURegisterVideoSurfaceNV;
-PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC glad_glVDPAURegisterOutputSurfaceNV;
-PFNGLVDPAUISSURFACENVPROC glad_glVDPAUIsSurfaceNV;
-PFNGLVDPAUUNREGISTERSURFACENVPROC glad_glVDPAUUnregisterSurfaceNV;
-PFNGLVDPAUGETSURFACEIVNVPROC glad_glVDPAUGetSurfaceivNV;
-PFNGLVDPAUSURFACEACCESSNVPROC glad_glVDPAUSurfaceAccessNV;
-PFNGLVDPAUMAPSURFACESNVPROC glad_glVDPAUMapSurfacesNV;
-PFNGLVDPAUUNMAPSURFACESNVPROC glad_glVDPAUUnmapSurfacesNV;
-PFNGLFLUSHVERTEXARRAYRANGENVPROC glad_glFlushVertexArrayRangeNV;
-PFNGLVERTEXARRAYRANGENVPROC glad_glVertexArrayRangeNV;
-PFNGLVERTEXATTRIBL1I64NVPROC glad_glVertexAttribL1i64NV;
-PFNGLVERTEXATTRIBL2I64NVPROC glad_glVertexAttribL2i64NV;
-PFNGLVERTEXATTRIBL3I64NVPROC glad_glVertexAttribL3i64NV;
-PFNGLVERTEXATTRIBL4I64NVPROC glad_glVertexAttribL4i64NV;
-PFNGLVERTEXATTRIBL1I64VNVPROC glad_glVertexAttribL1i64vNV;
-PFNGLVERTEXATTRIBL2I64VNVPROC glad_glVertexAttribL2i64vNV;
-PFNGLVERTEXATTRIBL3I64VNVPROC glad_glVertexAttribL3i64vNV;
-PFNGLVERTEXATTRIBL4I64VNVPROC glad_glVertexAttribL4i64vNV;
-PFNGLVERTEXATTRIBL1UI64NVPROC glad_glVertexAttribL1ui64NV;
-PFNGLVERTEXATTRIBL2UI64NVPROC glad_glVertexAttribL2ui64NV;
-PFNGLVERTEXATTRIBL3UI64NVPROC glad_glVertexAttribL3ui64NV;
-PFNGLVERTEXATTRIBL4UI64NVPROC glad_glVertexAttribL4ui64NV;
-PFNGLVERTEXATTRIBL1UI64VNVPROC glad_glVertexAttribL1ui64vNV;
-PFNGLVERTEXATTRIBL2UI64VNVPROC glad_glVertexAttribL2ui64vNV;
-PFNGLVERTEXATTRIBL3UI64VNVPROC glad_glVertexAttribL3ui64vNV;
-PFNGLVERTEXATTRIBL4UI64VNVPROC glad_glVertexAttribL4ui64vNV;
-PFNGLGETVERTEXATTRIBLI64VNVPROC glad_glGetVertexAttribLi64vNV;
-PFNGLGETVERTEXATTRIBLUI64VNVPROC glad_glGetVertexAttribLui64vNV;
-PFNGLVERTEXATTRIBLFORMATNVPROC glad_glVertexAttribLFormatNV;
-PFNGLBUFFERADDRESSRANGENVPROC glad_glBufferAddressRangeNV;
-PFNGLVERTEXFORMATNVPROC glad_glVertexFormatNV;
-PFNGLNORMALFORMATNVPROC glad_glNormalFormatNV;
-PFNGLCOLORFORMATNVPROC glad_glColorFormatNV;
-PFNGLINDEXFORMATNVPROC glad_glIndexFormatNV;
-PFNGLTEXCOORDFORMATNVPROC glad_glTexCoordFormatNV;
-PFNGLEDGEFLAGFORMATNVPROC glad_glEdgeFlagFormatNV;
-PFNGLSECONDARYCOLORFORMATNVPROC glad_glSecondaryColorFormatNV;
-PFNGLFOGCOORDFORMATNVPROC glad_glFogCoordFormatNV;
-PFNGLVERTEXATTRIBFORMATNVPROC glad_glVertexAttribFormatNV;
-PFNGLVERTEXATTRIBIFORMATNVPROC glad_glVertexAttribIFormatNV;
-PFNGLGETINTEGERUI64I_VNVPROC glad_glGetIntegerui64i_vNV;
-PFNGLAREPROGRAMSRESIDENTNVPROC glad_glAreProgramsResidentNV;
-PFNGLBINDPROGRAMNVPROC glad_glBindProgramNV;
-PFNGLDELETEPROGRAMSNVPROC glad_glDeleteProgramsNV;
-PFNGLEXECUTEPROGRAMNVPROC glad_glExecuteProgramNV;
-PFNGLGENPROGRAMSNVPROC glad_glGenProgramsNV;
-PFNGLGETPROGRAMPARAMETERDVNVPROC glad_glGetProgramParameterdvNV;
-PFNGLGETPROGRAMPARAMETERFVNVPROC glad_glGetProgramParameterfvNV;
-PFNGLGETPROGRAMIVNVPROC glad_glGetProgramivNV;
-PFNGLGETPROGRAMSTRINGNVPROC glad_glGetProgramStringNV;
-PFNGLGETTRACKMATRIXIVNVPROC glad_glGetTrackMatrixivNV;
-PFNGLGETVERTEXATTRIBDVNVPROC glad_glGetVertexAttribdvNV;
-PFNGLGETVERTEXATTRIBFVNVPROC glad_glGetVertexAttribfvNV;
-PFNGLGETVERTEXATTRIBIVNVPROC glad_glGetVertexAttribivNV;
-PFNGLGETVERTEXATTRIBPOINTERVNVPROC glad_glGetVertexAttribPointervNV;
-PFNGLISPROGRAMNVPROC glad_glIsProgramNV;
-PFNGLLOADPROGRAMNVPROC glad_glLoadProgramNV;
-PFNGLPROGRAMPARAMETER4DNVPROC glad_glProgramParameter4dNV;
-PFNGLPROGRAMPARAMETER4DVNVPROC glad_glProgramParameter4dvNV;
-PFNGLPROGRAMPARAMETER4FNVPROC glad_glProgramParameter4fNV;
-PFNGLPROGRAMPARAMETER4FVNVPROC glad_glProgramParameter4fvNV;
-PFNGLPROGRAMPARAMETERS4DVNVPROC glad_glProgramParameters4dvNV;
-PFNGLPROGRAMPARAMETERS4FVNVPROC glad_glProgramParameters4fvNV;
-PFNGLREQUESTRESIDENTPROGRAMSNVPROC glad_glRequestResidentProgramsNV;
-PFNGLTRACKMATRIXNVPROC glad_glTrackMatrixNV;
-PFNGLVERTEXATTRIBPOINTERNVPROC glad_glVertexAttribPointerNV;
-PFNGLVERTEXATTRIB1DNVPROC glad_glVertexAttrib1dNV;
-PFNGLVERTEXATTRIB1DVNVPROC glad_glVertexAttrib1dvNV;
-PFNGLVERTEXATTRIB1FNVPROC glad_glVertexAttrib1fNV;
-PFNGLVERTEXATTRIB1FVNVPROC glad_glVertexAttrib1fvNV;
-PFNGLVERTEXATTRIB1SNVPROC glad_glVertexAttrib1sNV;
-PFNGLVERTEXATTRIB1SVNVPROC glad_glVertexAttrib1svNV;
-PFNGLVERTEXATTRIB2DNVPROC glad_glVertexAttrib2dNV;
-PFNGLVERTEXATTRIB2DVNVPROC glad_glVertexAttrib2dvNV;
-PFNGLVERTEXATTRIB2FNVPROC glad_glVertexAttrib2fNV;
-PFNGLVERTEXATTRIB2FVNVPROC glad_glVertexAttrib2fvNV;
-PFNGLVERTEXATTRIB2SNVPROC glad_glVertexAttrib2sNV;
-PFNGLVERTEXATTRIB2SVNVPROC glad_glVertexAttrib2svNV;
-PFNGLVERTEXATTRIB3DNVPROC glad_glVertexAttrib3dNV;
-PFNGLVERTEXATTRIB3DVNVPROC glad_glVertexAttrib3dvNV;
-PFNGLVERTEXATTRIB3FNVPROC glad_glVertexAttrib3fNV;
-PFNGLVERTEXATTRIB3FVNVPROC glad_glVertexAttrib3fvNV;
-PFNGLVERTEXATTRIB3SNVPROC glad_glVertexAttrib3sNV;
-PFNGLVERTEXATTRIB3SVNVPROC glad_glVertexAttrib3svNV;
-PFNGLVERTEXATTRIB4DNVPROC glad_glVertexAttrib4dNV;
-PFNGLVERTEXATTRIB4DVNVPROC glad_glVertexAttrib4dvNV;
-PFNGLVERTEXATTRIB4FNVPROC glad_glVertexAttrib4fNV;
-PFNGLVERTEXATTRIB4FVNVPROC glad_glVertexAttrib4fvNV;
-PFNGLVERTEXATTRIB4SNVPROC glad_glVertexAttrib4sNV;
-PFNGLVERTEXATTRIB4SVNVPROC glad_glVertexAttrib4svNV;
-PFNGLVERTEXATTRIB4UBNVPROC glad_glVertexAttrib4ubNV;
-PFNGLVERTEXATTRIB4UBVNVPROC glad_glVertexAttrib4ubvNV;
-PFNGLVERTEXATTRIBS1DVNVPROC glad_glVertexAttribs1dvNV;
-PFNGLVERTEXATTRIBS1FVNVPROC glad_glVertexAttribs1fvNV;
-PFNGLVERTEXATTRIBS1SVNVPROC glad_glVertexAttribs1svNV;
-PFNGLVERTEXATTRIBS2DVNVPROC glad_glVertexAttribs2dvNV;
-PFNGLVERTEXATTRIBS2FVNVPROC glad_glVertexAttribs2fvNV;
-PFNGLVERTEXATTRIBS2SVNVPROC glad_glVertexAttribs2svNV;
-PFNGLVERTEXATTRIBS3DVNVPROC glad_glVertexAttribs3dvNV;
-PFNGLVERTEXATTRIBS3FVNVPROC glad_glVertexAttribs3fvNV;
-PFNGLVERTEXATTRIBS3SVNVPROC glad_glVertexAttribs3svNV;
-PFNGLVERTEXATTRIBS4DVNVPROC glad_glVertexAttribs4dvNV;
-PFNGLVERTEXATTRIBS4FVNVPROC glad_glVertexAttribs4fvNV;
-PFNGLVERTEXATTRIBS4SVNVPROC glad_glVertexAttribs4svNV;
-PFNGLVERTEXATTRIBS4UBVNVPROC glad_glVertexAttribs4ubvNV;
-PFNGLVERTEXATTRIBI1IEXTPROC glad_glVertexAttribI1iEXT;
-PFNGLVERTEXATTRIBI2IEXTPROC glad_glVertexAttribI2iEXT;
-PFNGLVERTEXATTRIBI3IEXTPROC glad_glVertexAttribI3iEXT;
-PFNGLVERTEXATTRIBI4IEXTPROC glad_glVertexAttribI4iEXT;
-PFNGLVERTEXATTRIBI1UIEXTPROC glad_glVertexAttribI1uiEXT;
-PFNGLVERTEXATTRIBI2UIEXTPROC glad_glVertexAttribI2uiEXT;
-PFNGLVERTEXATTRIBI3UIEXTPROC glad_glVertexAttribI3uiEXT;
-PFNGLVERTEXATTRIBI4UIEXTPROC glad_glVertexAttribI4uiEXT;
-PFNGLVERTEXATTRIBI1IVEXTPROC glad_glVertexAttribI1ivEXT;
-PFNGLVERTEXATTRIBI2IVEXTPROC glad_glVertexAttribI2ivEXT;
-PFNGLVERTEXATTRIBI3IVEXTPROC glad_glVertexAttribI3ivEXT;
-PFNGLVERTEXATTRIBI4IVEXTPROC glad_glVertexAttribI4ivEXT;
-PFNGLVERTEXATTRIBI1UIVEXTPROC glad_glVertexAttribI1uivEXT;
-PFNGLVERTEXATTRIBI2UIVEXTPROC glad_glVertexAttribI2uivEXT;
-PFNGLVERTEXATTRIBI3UIVEXTPROC glad_glVertexAttribI3uivEXT;
-PFNGLVERTEXATTRIBI4UIVEXTPROC glad_glVertexAttribI4uivEXT;
-PFNGLVERTEXATTRIBI4BVEXTPROC glad_glVertexAttribI4bvEXT;
-PFNGLVERTEXATTRIBI4SVEXTPROC glad_glVertexAttribI4svEXT;
-PFNGLVERTEXATTRIBI4UBVEXTPROC glad_glVertexAttribI4ubvEXT;
-PFNGLVERTEXATTRIBI4USVEXTPROC glad_glVertexAttribI4usvEXT;
-PFNGLVERTEXATTRIBIPOINTEREXTPROC glad_glVertexAttribIPointerEXT;
-PFNGLGETVERTEXATTRIBIIVEXTPROC glad_glGetVertexAttribIivEXT;
-PFNGLGETVERTEXATTRIBIUIVEXTPROC glad_glGetVertexAttribIuivEXT;
-PFNGLBEGINVIDEOCAPTURENVPROC glad_glBeginVideoCaptureNV;
-PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC glad_glBindVideoCaptureStreamBufferNV;
-PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC glad_glBindVideoCaptureStreamTextureNV;
-PFNGLENDVIDEOCAPTURENVPROC glad_glEndVideoCaptureNV;
-PFNGLGETVIDEOCAPTUREIVNVPROC glad_glGetVideoCaptureivNV;
-PFNGLGETVIDEOCAPTURESTREAMIVNVPROC glad_glGetVideoCaptureStreamivNV;
-PFNGLGETVIDEOCAPTURESTREAMFVNVPROC glad_glGetVideoCaptureStreamfvNV;
-PFNGLGETVIDEOCAPTURESTREAMDVNVPROC glad_glGetVideoCaptureStreamdvNV;
-PFNGLVIDEOCAPTURENVPROC glad_glVideoCaptureNV;
-PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC glad_glVideoCaptureStreamParameterivNV;
-PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC glad_glVideoCaptureStreamParameterfvNV;
-PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC glad_glVideoCaptureStreamParameterdvNV;
-PFNGLVIEWPORTSWIZZLENVPROC glad_glViewportSwizzleNV;
-PFNGLMULTITEXCOORD1BOESPROC glad_glMultiTexCoord1bOES;
-PFNGLMULTITEXCOORD1BVOESPROC glad_glMultiTexCoord1bvOES;
-PFNGLMULTITEXCOORD2BOESPROC glad_glMultiTexCoord2bOES;
-PFNGLMULTITEXCOORD2BVOESPROC glad_glMultiTexCoord2bvOES;
-PFNGLMULTITEXCOORD3BOESPROC glad_glMultiTexCoord3bOES;
-PFNGLMULTITEXCOORD3BVOESPROC glad_glMultiTexCoord3bvOES;
-PFNGLMULTITEXCOORD4BOESPROC glad_glMultiTexCoord4bOES;
-PFNGLMULTITEXCOORD4BVOESPROC glad_glMultiTexCoord4bvOES;
-PFNGLTEXCOORD1BOESPROC glad_glTexCoord1bOES;
-PFNGLTEXCOORD1BVOESPROC glad_glTexCoord1bvOES;
-PFNGLTEXCOORD2BOESPROC glad_glTexCoord2bOES;
-PFNGLTEXCOORD2BVOESPROC glad_glTexCoord2bvOES;
-PFNGLTEXCOORD3BOESPROC glad_glTexCoord3bOES;
-PFNGLTEXCOORD3BVOESPROC glad_glTexCoord3bvOES;
-PFNGLTEXCOORD4BOESPROC glad_glTexCoord4bOES;
-PFNGLTEXCOORD4BVOESPROC glad_glTexCoord4bvOES;
-PFNGLVERTEX2BOESPROC glad_glVertex2bOES;
-PFNGLVERTEX2BVOESPROC glad_glVertex2bvOES;
-PFNGLVERTEX3BOESPROC glad_glVertex3bOES;
-PFNGLVERTEX3BVOESPROC glad_glVertex3bvOES;
-PFNGLVERTEX4BOESPROC glad_glVertex4bOES;
-PFNGLVERTEX4BVOESPROC glad_glVertex4bvOES;
-PFNGLALPHAFUNCXOESPROC glad_glAlphaFuncxOES;
-PFNGLCLEARCOLORXOESPROC glad_glClearColorxOES;
-PFNGLCLEARDEPTHXOESPROC glad_glClearDepthxOES;
-PFNGLCLIPPLANEXOESPROC glad_glClipPlanexOES;
-PFNGLCOLOR4XOESPROC glad_glColor4xOES;
-PFNGLDEPTHRANGEXOESPROC glad_glDepthRangexOES;
-PFNGLFOGXOESPROC glad_glFogxOES;
-PFNGLFOGXVOESPROC glad_glFogxvOES;
-PFNGLFRUSTUMXOESPROC glad_glFrustumxOES;
-PFNGLGETCLIPPLANEXOESPROC glad_glGetClipPlanexOES;
-PFNGLGETFIXEDVOESPROC glad_glGetFixedvOES;
-PFNGLGETTEXENVXVOESPROC glad_glGetTexEnvxvOES;
-PFNGLGETTEXPARAMETERXVOESPROC glad_glGetTexParameterxvOES;
-PFNGLLIGHTMODELXOESPROC glad_glLightModelxOES;
-PFNGLLIGHTMODELXVOESPROC glad_glLightModelxvOES;
-PFNGLLIGHTXOESPROC glad_glLightxOES;
-PFNGLLIGHTXVOESPROC glad_glLightxvOES;
-PFNGLLINEWIDTHXOESPROC glad_glLineWidthxOES;
-PFNGLLOADMATRIXXOESPROC glad_glLoadMatrixxOES;
-PFNGLMATERIALXOESPROC glad_glMaterialxOES;
-PFNGLMATERIALXVOESPROC glad_glMaterialxvOES;
-PFNGLMULTMATRIXXOESPROC glad_glMultMatrixxOES;
-PFNGLMULTITEXCOORD4XOESPROC glad_glMultiTexCoord4xOES;
-PFNGLNORMAL3XOESPROC glad_glNormal3xOES;
-PFNGLORTHOXOESPROC glad_glOrthoxOES;
-PFNGLPOINTPARAMETERXVOESPROC glad_glPointParameterxvOES;
-PFNGLPOINTSIZEXOESPROC glad_glPointSizexOES;
-PFNGLPOLYGONOFFSETXOESPROC glad_glPolygonOffsetxOES;
-PFNGLROTATEXOESPROC glad_glRotatexOES;
-PFNGLSCALEXOESPROC glad_glScalexOES;
-PFNGLTEXENVXOESPROC glad_glTexEnvxOES;
-PFNGLTEXENVXVOESPROC glad_glTexEnvxvOES;
-PFNGLTEXPARAMETERXOESPROC glad_glTexParameterxOES;
-PFNGLTEXPARAMETERXVOESPROC glad_glTexParameterxvOES;
-PFNGLTRANSLATEXOESPROC glad_glTranslatexOES;
-PFNGLGETLIGHTXVOESPROC glad_glGetLightxvOES;
-PFNGLGETMATERIALXVOESPROC glad_glGetMaterialxvOES;
-PFNGLPOINTPARAMETERXOESPROC glad_glPointParameterxOES;
-PFNGLSAMPLECOVERAGEXOESPROC glad_glSampleCoveragexOES;
-PFNGLACCUMXOESPROC glad_glAccumxOES;
-PFNGLBITMAPXOESPROC glad_glBitmapxOES;
-PFNGLBLENDCOLORXOESPROC glad_glBlendColorxOES;
-PFNGLCLEARACCUMXOESPROC glad_glClearAccumxOES;
-PFNGLCOLOR3XOESPROC glad_glColor3xOES;
-PFNGLCOLOR3XVOESPROC glad_glColor3xvOES;
-PFNGLCOLOR4XVOESPROC glad_glColor4xvOES;
-PFNGLCONVOLUTIONPARAMETERXOESPROC glad_glConvolutionParameterxOES;
-PFNGLCONVOLUTIONPARAMETERXVOESPROC glad_glConvolutionParameterxvOES;
-PFNGLEVALCOORD1XOESPROC glad_glEvalCoord1xOES;
-PFNGLEVALCOORD1XVOESPROC glad_glEvalCoord1xvOES;
-PFNGLEVALCOORD2XOESPROC glad_glEvalCoord2xOES;
-PFNGLEVALCOORD2XVOESPROC glad_glEvalCoord2xvOES;
-PFNGLFEEDBACKBUFFERXOESPROC glad_glFeedbackBufferxOES;
-PFNGLGETCONVOLUTIONPARAMETERXVOESPROC glad_glGetConvolutionParameterxvOES;
-PFNGLGETHISTOGRAMPARAMETERXVOESPROC glad_glGetHistogramParameterxvOES;
-PFNGLGETLIGHTXOESPROC glad_glGetLightxOES;
-PFNGLGETMAPXVOESPROC glad_glGetMapxvOES;
-PFNGLGETMATERIALXOESPROC glad_glGetMaterialxOES;
-PFNGLGETPIXELMAPXVPROC glad_glGetPixelMapxv;
-PFNGLGETTEXGENXVOESPROC glad_glGetTexGenxvOES;
-PFNGLGETTEXLEVELPARAMETERXVOESPROC glad_glGetTexLevelParameterxvOES;
-PFNGLINDEXXOESPROC glad_glIndexxOES;
-PFNGLINDEXXVOESPROC glad_glIndexxvOES;
-PFNGLLOADTRANSPOSEMATRIXXOESPROC glad_glLoadTransposeMatrixxOES;
-PFNGLMAP1XOESPROC glad_glMap1xOES;
-PFNGLMAP2XOESPROC glad_glMap2xOES;
-PFNGLMAPGRID1XOESPROC glad_glMapGrid1xOES;
-PFNGLMAPGRID2XOESPROC glad_glMapGrid2xOES;
-PFNGLMULTTRANSPOSEMATRIXXOESPROC glad_glMultTransposeMatrixxOES;
-PFNGLMULTITEXCOORD1XOESPROC glad_glMultiTexCoord1xOES;
-PFNGLMULTITEXCOORD1XVOESPROC glad_glMultiTexCoord1xvOES;
-PFNGLMULTITEXCOORD2XOESPROC glad_glMultiTexCoord2xOES;
-PFNGLMULTITEXCOORD2XVOESPROC glad_glMultiTexCoord2xvOES;
-PFNGLMULTITEXCOORD3XOESPROC glad_glMultiTexCoord3xOES;
-PFNGLMULTITEXCOORD3XVOESPROC glad_glMultiTexCoord3xvOES;
-PFNGLMULTITEXCOORD4XVOESPROC glad_glMultiTexCoord4xvOES;
-PFNGLNORMAL3XVOESPROC glad_glNormal3xvOES;
-PFNGLPASSTHROUGHXOESPROC glad_glPassThroughxOES;
-PFNGLPIXELMAPXPROC glad_glPixelMapx;
-PFNGLPIXELSTOREXPROC glad_glPixelStorex;
-PFNGLPIXELTRANSFERXOESPROC glad_glPixelTransferxOES;
-PFNGLPIXELZOOMXOESPROC glad_glPixelZoomxOES;
-PFNGLPRIORITIZETEXTURESXOESPROC glad_glPrioritizeTexturesxOES;
-PFNGLRASTERPOS2XOESPROC glad_glRasterPos2xOES;
-PFNGLRASTERPOS2XVOESPROC glad_glRasterPos2xvOES;
-PFNGLRASTERPOS3XOESPROC glad_glRasterPos3xOES;
-PFNGLRASTERPOS3XVOESPROC glad_glRasterPos3xvOES;
-PFNGLRASTERPOS4XOESPROC glad_glRasterPos4xOES;
-PFNGLRASTERPOS4XVOESPROC glad_glRasterPos4xvOES;
-PFNGLRECTXOESPROC glad_glRectxOES;
-PFNGLRECTXVOESPROC glad_glRectxvOES;
-PFNGLTEXCOORD1XOESPROC glad_glTexCoord1xOES;
-PFNGLTEXCOORD1XVOESPROC glad_glTexCoord1xvOES;
-PFNGLTEXCOORD2XOESPROC glad_glTexCoord2xOES;
-PFNGLTEXCOORD2XVOESPROC glad_glTexCoord2xvOES;
-PFNGLTEXCOORD3XOESPROC glad_glTexCoord3xOES;
-PFNGLTEXCOORD3XVOESPROC glad_glTexCoord3xvOES;
-PFNGLTEXCOORD4XOESPROC glad_glTexCoord4xOES;
-PFNGLTEXCOORD4XVOESPROC glad_glTexCoord4xvOES;
-PFNGLTEXGENXOESPROC glad_glTexGenxOES;
-PFNGLTEXGENXVOESPROC glad_glTexGenxvOES;
-PFNGLVERTEX2XOESPROC glad_glVertex2xOES;
-PFNGLVERTEX2XVOESPROC glad_glVertex2xvOES;
-PFNGLVERTEX3XOESPROC glad_glVertex3xOES;
-PFNGLVERTEX3XVOESPROC glad_glVertex3xvOES;
-PFNGLVERTEX4XOESPROC glad_glVertex4xOES;
-PFNGLVERTEX4XVOESPROC glad_glVertex4xvOES;
-PFNGLQUERYMATRIXXOESPROC glad_glQueryMatrixxOES;
-PFNGLCLEARDEPTHFOESPROC glad_glClearDepthfOES;
-PFNGLCLIPPLANEFOESPROC glad_glClipPlanefOES;
-PFNGLDEPTHRANGEFOESPROC glad_glDepthRangefOES;
-PFNGLFRUSTUMFOESPROC glad_glFrustumfOES;
-PFNGLGETCLIPPLANEFOESPROC glad_glGetClipPlanefOES;
-PFNGLORTHOFOESPROC glad_glOrthofOES;
-PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR;
-PFNGLHINTPGIPROC glad_glHintPGI;
-PFNGLDETAILTEXFUNCSGISPROC glad_glDetailTexFuncSGIS;
-PFNGLGETDETAILTEXFUNCSGISPROC glad_glGetDetailTexFuncSGIS;
-PFNGLFOGFUNCSGISPROC glad_glFogFuncSGIS;
-PFNGLGETFOGFUNCSGISPROC glad_glGetFogFuncSGIS;
-PFNGLSAMPLEMASKSGISPROC glad_glSampleMaskSGIS;
-PFNGLSAMPLEPATTERNSGISPROC glad_glSamplePatternSGIS;
-PFNGLPIXELTEXGENPARAMETERISGISPROC glad_glPixelTexGenParameteriSGIS;
-PFNGLPIXELTEXGENPARAMETERIVSGISPROC glad_glPixelTexGenParameterivSGIS;
-PFNGLPIXELTEXGENPARAMETERFSGISPROC glad_glPixelTexGenParameterfSGIS;
-PFNGLPIXELTEXGENPARAMETERFVSGISPROC glad_glPixelTexGenParameterfvSGIS;
-PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC glad_glGetPixelTexGenParameterivSGIS;
-PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC glad_glGetPixelTexGenParameterfvSGIS;
-PFNGLPOINTPARAMETERFSGISPROC glad_glPointParameterfSGIS;
-PFNGLPOINTPARAMETERFVSGISPROC glad_glPointParameterfvSGIS;
-PFNGLSHARPENTEXFUNCSGISPROC glad_glSharpenTexFuncSGIS;
-PFNGLGETSHARPENTEXFUNCSGISPROC glad_glGetSharpenTexFuncSGIS;
-PFNGLTEXIMAGE4DSGISPROC glad_glTexImage4DSGIS;
-PFNGLTEXSUBIMAGE4DSGISPROC glad_glTexSubImage4DSGIS;
-PFNGLTEXTURECOLORMASKSGISPROC glad_glTextureColorMaskSGIS;
-PFNGLGETTEXFILTERFUNCSGISPROC glad_glGetTexFilterFuncSGIS;
-PFNGLTEXFILTERFUNCSGISPROC glad_glTexFilterFuncSGIS;
-PFNGLASYNCMARKERSGIXPROC glad_glAsyncMarkerSGIX;
-PFNGLFINISHASYNCSGIXPROC glad_glFinishAsyncSGIX;
-PFNGLPOLLASYNCSGIXPROC glad_glPollAsyncSGIX;
-PFNGLGENASYNCMARKERSSGIXPROC glad_glGenAsyncMarkersSGIX;
-PFNGLDELETEASYNCMARKERSSGIXPROC glad_glDeleteAsyncMarkersSGIX;
-PFNGLISASYNCMARKERSGIXPROC glad_glIsAsyncMarkerSGIX;
-PFNGLFLUSHRASTERSGIXPROC glad_glFlushRasterSGIX;
-PFNGLFRAGMENTCOLORMATERIALSGIXPROC glad_glFragmentColorMaterialSGIX;
-PFNGLFRAGMENTLIGHTFSGIXPROC glad_glFragmentLightfSGIX;
-PFNGLFRAGMENTLIGHTFVSGIXPROC glad_glFragmentLightfvSGIX;
-PFNGLFRAGMENTLIGHTISGIXPROC glad_glFragmentLightiSGIX;
-PFNGLFRAGMENTLIGHTIVSGIXPROC glad_glFragmentLightivSGIX;
-PFNGLFRAGMENTLIGHTMODELFSGIXPROC glad_glFragmentLightModelfSGIX;
-PFNGLFRAGMENTLIGHTMODELFVSGIXPROC glad_glFragmentLightModelfvSGIX;
-PFNGLFRAGMENTLIGHTMODELISGIXPROC glad_glFragmentLightModeliSGIX;
-PFNGLFRAGMENTLIGHTMODELIVSGIXPROC glad_glFragmentLightModelivSGIX;
-PFNGLFRAGMENTMATERIALFSGIXPROC glad_glFragmentMaterialfSGIX;
-PFNGLFRAGMENTMATERIALFVSGIXPROC glad_glFragmentMaterialfvSGIX;
-PFNGLFRAGMENTMATERIALISGIXPROC glad_glFragmentMaterialiSGIX;
-PFNGLFRAGMENTMATERIALIVSGIXPROC glad_glFragmentMaterialivSGIX;
-PFNGLGETFRAGMENTLIGHTFVSGIXPROC glad_glGetFragmentLightfvSGIX;
-PFNGLGETFRAGMENTLIGHTIVSGIXPROC glad_glGetFragmentLightivSGIX;
-PFNGLGETFRAGMENTMATERIALFVSGIXPROC glad_glGetFragmentMaterialfvSGIX;
-PFNGLGETFRAGMENTMATERIALIVSGIXPROC glad_glGetFragmentMaterialivSGIX;
-PFNGLLIGHTENVISGIXPROC glad_glLightEnviSGIX;
-PFNGLFRAMEZOOMSGIXPROC glad_glFrameZoomSGIX;
-PFNGLIGLOOINTERFACESGIXPROC glad_glIglooInterfaceSGIX;
-PFNGLGETINSTRUMENTSSGIXPROC glad_glGetInstrumentsSGIX;
-PFNGLINSTRUMENTSBUFFERSGIXPROC glad_glInstrumentsBufferSGIX;
-PFNGLPOLLINSTRUMENTSSGIXPROC glad_glPollInstrumentsSGIX;
-PFNGLREADINSTRUMENTSSGIXPROC glad_glReadInstrumentsSGIX;
-PFNGLSTARTINSTRUMENTSSGIXPROC glad_glStartInstrumentsSGIX;
-PFNGLSTOPINSTRUMENTSSGIXPROC glad_glStopInstrumentsSGIX;
-PFNGLGETLISTPARAMETERFVSGIXPROC glad_glGetListParameterfvSGIX;
-PFNGLGETLISTPARAMETERIVSGIXPROC glad_glGetListParameterivSGIX;
-PFNGLLISTPARAMETERFSGIXPROC glad_glListParameterfSGIX;
-PFNGLLISTPARAMETERFVSGIXPROC glad_glListParameterfvSGIX;
-PFNGLLISTPARAMETERISGIXPROC glad_glListParameteriSGIX;
-PFNGLLISTPARAMETERIVSGIXPROC glad_glListParameterivSGIX;
-PFNGLPIXELTEXGENSGIXPROC glad_glPixelTexGenSGIX;
-PFNGLDEFORMATIONMAP3DSGIXPROC glad_glDeformationMap3dSGIX;
-PFNGLDEFORMATIONMAP3FSGIXPROC glad_glDeformationMap3fSGIX;
-PFNGLDEFORMSGIXPROC glad_glDeformSGIX;
-PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC glad_glLoadIdentityDeformationMapSGIX;
-PFNGLREFERENCEPLANESGIXPROC glad_glReferencePlaneSGIX;
-PFNGLSPRITEPARAMETERFSGIXPROC glad_glSpriteParameterfSGIX;
-PFNGLSPRITEPARAMETERFVSGIXPROC glad_glSpriteParameterfvSGIX;
-PFNGLSPRITEPARAMETERISGIXPROC glad_glSpriteParameteriSGIX;
-PFNGLSPRITEPARAMETERIVSGIXPROC glad_glSpriteParameterivSGIX;
-PFNGLTAGSAMPLEBUFFERSGIXPROC glad_glTagSampleBufferSGIX;
-PFNGLCOLORTABLESGIPROC glad_glColorTableSGI;
-PFNGLCOLORTABLEPARAMETERFVSGIPROC glad_glColorTableParameterfvSGI;
-PFNGLCOLORTABLEPARAMETERIVSGIPROC glad_glColorTableParameterivSGI;
-PFNGLCOPYCOLORTABLESGIPROC glad_glCopyColorTableSGI;
-PFNGLGETCOLORTABLESGIPROC glad_glGetColorTableSGI;
-PFNGLGETCOLORTABLEPARAMETERFVSGIPROC glad_glGetColorTableParameterfvSGI;
-PFNGLGETCOLORTABLEPARAMETERIVSGIPROC glad_glGetColorTableParameterivSGI;
-PFNGLFINISHTEXTURESUNXPROC glad_glFinishTextureSUNX;
-PFNGLGLOBALALPHAFACTORBSUNPROC glad_glGlobalAlphaFactorbSUN;
-PFNGLGLOBALALPHAFACTORSSUNPROC glad_glGlobalAlphaFactorsSUN;
-PFNGLGLOBALALPHAFACTORISUNPROC glad_glGlobalAlphaFactoriSUN;
-PFNGLGLOBALALPHAFACTORFSUNPROC glad_glGlobalAlphaFactorfSUN;
-PFNGLGLOBALALPHAFACTORDSUNPROC glad_glGlobalAlphaFactordSUN;
-PFNGLGLOBALALPHAFACTORUBSUNPROC glad_glGlobalAlphaFactorubSUN;
-PFNGLGLOBALALPHAFACTORUSSUNPROC glad_glGlobalAlphaFactorusSUN;
-PFNGLGLOBALALPHAFACTORUISUNPROC glad_glGlobalAlphaFactoruiSUN;
-PFNGLDRAWMESHARRAYSSUNPROC glad_glDrawMeshArraysSUN;
-PFNGLREPLACEMENTCODEUISUNPROC glad_glReplacementCodeuiSUN;
-PFNGLREPLACEMENTCODEUSSUNPROC glad_glReplacementCodeusSUN;
-PFNGLREPLACEMENTCODEUBSUNPROC glad_glReplacementCodeubSUN;
-PFNGLREPLACEMENTCODEUIVSUNPROC glad_glReplacementCodeuivSUN;
-PFNGLREPLACEMENTCODEUSVSUNPROC glad_glReplacementCodeusvSUN;
-PFNGLREPLACEMENTCODEUBVSUNPROC glad_glReplacementCodeubvSUN;
-PFNGLREPLACEMENTCODEPOINTERSUNPROC glad_glReplacementCodePointerSUN;
-PFNGLCOLOR4UBVERTEX2FSUNPROC glad_glColor4ubVertex2fSUN;
-PFNGLCOLOR4UBVERTEX2FVSUNPROC glad_glColor4ubVertex2fvSUN;
-PFNGLCOLOR4UBVERTEX3FSUNPROC glad_glColor4ubVertex3fSUN;
-PFNGLCOLOR4UBVERTEX3FVSUNPROC glad_glColor4ubVertex3fvSUN;
-PFNGLCOLOR3FVERTEX3FSUNPROC glad_glColor3fVertex3fSUN;
-PFNGLCOLOR3FVERTEX3FVSUNPROC glad_glColor3fVertex3fvSUN;
-PFNGLNORMAL3FVERTEX3FSUNPROC glad_glNormal3fVertex3fSUN;
-PFNGLNORMAL3FVERTEX3FVSUNPROC glad_glNormal3fVertex3fvSUN;
-PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC glad_glColor4fNormal3fVertex3fSUN;
-PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC glad_glColor4fNormal3fVertex3fvSUN;
-PFNGLTEXCOORD2FVERTEX3FSUNPROC glad_glTexCoord2fVertex3fSUN;
-PFNGLTEXCOORD2FVERTEX3FVSUNPROC glad_glTexCoord2fVertex3fvSUN;
-PFNGLTEXCOORD4FVERTEX4FSUNPROC glad_glTexCoord4fVertex4fSUN;
-PFNGLTEXCOORD4FVERTEX4FVSUNPROC glad_glTexCoord4fVertex4fvSUN;
-PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC glad_glTexCoord2fColor4ubVertex3fSUN;
-PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC glad_glTexCoord2fColor4ubVertex3fvSUN;
-PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC glad_glTexCoord2fColor3fVertex3fSUN;
-PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC glad_glTexCoord2fColor3fVertex3fvSUN;
-PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC glad_glTexCoord2fNormal3fVertex3fSUN;
-PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC glad_glTexCoord2fNormal3fVertex3fvSUN;
-PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC glad_glTexCoord2fColor4fNormal3fVertex3fSUN;
-PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC glad_glTexCoord2fColor4fNormal3fVertex3fvSUN;
-PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC glad_glTexCoord4fColor4fNormal3fVertex4fSUN;
-PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC glad_glTexCoord4fColor4fNormal3fVertex4fvSUN;
-PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC glad_glReplacementCodeuiVertex3fSUN;
-PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC glad_glReplacementCodeuiVertex3fvSUN;
-PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC glad_glReplacementCodeuiColor4ubVertex3fSUN;
-PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC glad_glReplacementCodeuiColor4ubVertex3fvSUN;
-PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC glad_glReplacementCodeuiColor3fVertex3fSUN;
-PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC glad_glReplacementCodeuiColor3fVertex3fvSUN;
-PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC glad_glReplacementCodeuiNormal3fVertex3fSUN;
-PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC glad_glReplacementCodeuiNormal3fVertex3fvSUN;
-PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC glad_glReplacementCodeuiColor4fNormal3fVertex3fSUN;
-PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC glad_glReplacementCodeuiColor4fNormal3fVertex3fvSUN;
-PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC glad_glReplacementCodeuiTexCoord2fVertex3fSUN;
-PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC glad_glReplacementCodeuiTexCoord2fVertex3fvSUN;
-PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC glad_glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN;
-PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC glad_glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN;
-PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC glad_glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN;
-PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC glad_glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN;
+int GLAD_GL_VERSION_1_0 = 0;
+int GLAD_GL_VERSION_1_1 = 0;
+int GLAD_GL_VERSION_1_2 = 0;
+int GLAD_GL_VERSION_1_3 = 0;
+int GLAD_GL_VERSION_1_4 = 0;
+int GLAD_GL_VERSION_1_5 = 0;
+int GLAD_GL_VERSION_2_0 = 0;
+int GLAD_GL_VERSION_2_1 = 0;
+int GLAD_GL_VERSION_3_0 = 0;
+int GLAD_GL_VERSION_3_1 = 0;
+int GLAD_GL_VERSION_3_2 = 0;
+int GLAD_GL_VERSION_3_3 = 0;
+PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;
+PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;
+PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
+PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
+PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL;
+PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;
+PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
+PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
+PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL;
+PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;
+PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
+PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
+PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;
+PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL;
+PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL;
+PFNGLENABLEIPROC glad_glEnablei = NULL;
+PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;
+PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
+PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
+PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
+PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
+PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
+PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
+PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
+PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
+PFNGLHINTPROC glad_glHint = NULL;
+PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;
+PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;
+PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL;
+PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;
+PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
+PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;
+PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
+PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;
+PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
+PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
+PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
+PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
+PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;
+PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
+PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;
+PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
+PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL;
+PFNGLCOLORMASKIPROC glad_glColorMaski = NULL;
+PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;
+PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
+PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL;
+PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;
+PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;
+PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;
+PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;
+PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL;
+PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
+PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
+PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;
+PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;
+PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL;
+PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;
+PFNGLCLEARPROC glad_glClear = NULL;
+PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;
+PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
+PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
+PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
+PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;
+PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;
+PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;
+PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
+PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;
+PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
+PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
+PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
+PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
+PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;
+PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
+PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
+PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;
+PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
+PFNGLISSHADERPROC glad_glIsShader = NULL;
+PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;
+PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;
+PFNGLENABLEPROC glad_glEnable = NULL;
+PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
+PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
+PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;
+PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL;
+PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;
+PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
+PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
+PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
+PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;
+PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
+PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
+PFNGLFLUSHPROC glad_glFlush = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
+PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
+PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
+PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL;
+PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;
+PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;
+PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;
+PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL;
+PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
+PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;
+PFNGLCLAMPCOLORPROC glad_glClampColor = NULL;
+PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
+PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
+PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL;
+PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
+PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
+PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;
+PFNGLISSYNCPROC glad_glIsSync = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
+PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
+PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
+PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL;
+PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
+PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
+PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
+PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
+PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
+PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;
+PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
+PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
+PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
+PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
+PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
+PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;
+PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL;
+PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;
+PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
+PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
+PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;
+PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;
+PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
+PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;
+PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
+PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;
+PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;
+PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
+PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL;
+PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
+PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
+PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;
+PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
+PFNGLDELETESYNCPROC glad_glDeleteSync = NULL;
+PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
+PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
+PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;
+PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
+PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
+PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
+PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
+PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
+PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
+PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
+PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
+PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;
+PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;
+PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;
+PFNGLFINISHPROC glad_glFinish = NULL;
+PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
+PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;
+PFNGLVIEWPORTPROC glad_glViewport = NULL;
+PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
+PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
+PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;
+PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
+PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;
+PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
+PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
+PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
+PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;
+PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
+PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
+PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;
+PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;
+PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL;
+PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;
+PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
+PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
+PFNGLGETSTRINGPROC glad_glGetString = NULL;
+PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;
+PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
+PFNGLENDQUERYPROC glad_glEndQuery = NULL;
+PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL;
+PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;
+PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
+PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
+PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
+PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL;
+PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
+PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;
+PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
+PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;
+PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;
+PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
+PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;
+PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;
+PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
+PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
+PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
+PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
+PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
+PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
+PFNGLDISABLEPROC glad_glDisable = NULL;
+PFNGLLOGICOPPROC glad_glLogicOp = NULL;
+PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
+PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
+PFNGLCULLFACEPROC glad_glCullFace = NULL;
+PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
+PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
+PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;
+PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;
+PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
+PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;
+PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
+PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
+PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
+PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;
+PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;
+PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
+PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;
+PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
+PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;
+PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;
+PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
+PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;
+PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
+PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;
+PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;
+PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
+PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;
+PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
+PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;
+PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
+PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
+PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
+PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
+PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
+PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;
+PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
+PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
+PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;
+PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
+PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;
+PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL;
+PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;
+PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
+PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;
+PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;
+PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
+PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;
+PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
+PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;
+PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
+PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
+PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;
+PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
+PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;
+PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;
+PFNGLSCISSORPROC glad_glScissor = NULL;
+PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL;
+PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
+PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL;
+PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
+PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
+PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;
+PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;
+PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;
+PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL;
+PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;
+PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
+PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
+PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
+PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
+PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;
+PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
+PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
+PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
+PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;
+PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
+PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;
+PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
+PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL;
+PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
+PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;
+PFNGLCOLORMASKPROC glad_glColorMask = NULL;
+PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;
+PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
+PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
+PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
+PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;
+PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
+PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
+PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;
+PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
+PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL;
+PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;
+PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;
+PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;
+PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;
+PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
+PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;
+PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL;
+PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
+PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
+PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
+PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
+PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
+PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
+PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
+PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;
+PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
+PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
+PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
+PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
+PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;
+PFNGLDISABLEIPROC glad_glDisablei = NULL;
+PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
+PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
+PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;
+PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;
+PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL;
+PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;
+PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
+PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
+PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
+PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;
+PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
+PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;
+PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL;
+PFNGLGETERRORPROC glad_glGetError = NULL;
+PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;
+PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
+PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;
+PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
+PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;
+PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;
+PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;
+PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL;
+PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
+PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
+PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;
+PFNGLISQUERYPROC glad_glIsQuery = NULL;
+PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;
+PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
+PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
+PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;
+PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
+PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
+PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;
+PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
+PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;
+PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
+PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;
+PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;
+PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
+PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;
+PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;
+PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
+PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;
+PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;
+PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
+PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;
+PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
+PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
+int GLAD_GL_SGIX_pixel_tiles = 0;
+int GLAD_GL_EXT_post_depth_coverage = 0;
+int GLAD_GL_APPLE_element_array = 0;
+int GLAD_GL_AMD_multi_draw_indirect = 0;
+int GLAD_GL_EXT_blend_subtract = 0;
+int GLAD_GL_SGIX_tag_sample_buffer = 0;
+int GLAD_GL_NV_point_sprite = 0;
+int GLAD_GL_IBM_texture_mirrored_repeat = 0;
+int GLAD_GL_APPLE_transform_hint = 0;
+int GLAD_GL_ATI_separate_stencil = 0;
+int GLAD_GL_NV_shader_atomic_int64 = 0;
+int GLAD_GL_EXT_semaphore_win32 = 0;
+int GLAD_GL_NV_vertex_program2_option = 0;
+int GLAD_GL_EXT_texture_buffer_object = 0;
+int GLAD_GL_ARB_vertex_blend = 0;
+int GLAD_GL_OVR_multiview = 0;
+int GLAD_GL_AMD_shader_gpu_shader_half_float_fetch = 0;
+int GLAD_GL_NV_vertex_program2 = 0;
+int GLAD_GL_ARB_program_interface_query = 0;
+int GLAD_GL_EXT_misc_attribute = 0;
+int GLAD_GL_NV_multisample_coverage = 0;
+int GLAD_GL_ARB_shading_language_packing = 0;
+int GLAD_GL_EXT_texture_cube_map = 0;
+int GLAD_GL_NV_viewport_array2 = 0;
+int GLAD_GL_ARB_texture_stencil8 = 0;
+int GLAD_GL_EXT_index_func = 0;
+int GLAD_GL_EXT_memory_object_fd = 0;
+int GLAD_GL_OES_compressed_paletted_texture = 0;
+int GLAD_GL_MESA_shader_integer_functions = 0;
+int GLAD_GL_NV_shader_buffer_load = 0;
+int GLAD_GL_EXT_color_subtable = 0;
+int GLAD_GL_SUNX_constant_data = 0;
+int GLAD_GL_EXT_texture_compression_s3tc = 0;
+int GLAD_GL_EXT_multi_draw_arrays = 0;
+int GLAD_GL_ARB_shader_atomic_counters = 0;
+int GLAD_GL_ARB_arrays_of_arrays = 0;
+int GLAD_GL_NV_conditional_render = 0;
+int GLAD_GL_EXT_texture_env_combine = 0;
+int GLAD_GL_NV_fog_distance = 0;
+int GLAD_GL_SGIX_async_histogram = 0;
+int GLAD_GL_MESA_resize_buffers = 0;
+int GLAD_GL_NV_light_max_exponent = 0;
+int GLAD_GL_NV_texture_env_combine4 = 0;
+int GLAD_GL_ARB_spirv_extensions = 0;
+int GLAD_GL_ARB_texture_view = 0;
+int GLAD_GL_ARB_texture_env_combine = 0;
+int GLAD_GL_ARB_map_buffer_range = 0;
+int GLAD_GL_EXT_convolution = 0;
+int GLAD_GL_NV_compute_program5 = 0;
+int GLAD_GL_NV_vertex_attrib_integer_64bit = 0;
+int GLAD_GL_EXT_paletted_texture = 0;
+int GLAD_GL_ARB_texture_buffer_object = 0;
+int GLAD_GL_ATI_pn_triangles = 0;
+int GLAD_GL_SGIX_resample = 0;
+int GLAD_GL_SGIX_flush_raster = 0;
+int GLAD_GL_EXT_light_texture = 0;
+int GLAD_GL_ARB_point_sprite = 0;
+int GLAD_GL_SUN_convolution_border_modes = 0;
+int GLAD_GL_EXT_semaphore_fd = 0;
+int GLAD_GL_NV_parameter_buffer_object2 = 0;
+int GLAD_GL_ARB_half_float_pixel = 0;
+int GLAD_GL_NV_tessellation_program5 = 0;
+int GLAD_GL_REND_screen_coordinates = 0;
+int GLAD_GL_EXT_shared_texture_palette = 0;
+int GLAD_GL_EXT_packed_float = 0;
+int GLAD_GL_OML_subsample = 0;
+int GLAD_GL_SGIX_vertex_preclip = 0;
+int GLAD_GL_SGIX_texture_scale_bias = 0;
+int GLAD_GL_AMD_draw_buffers_blend = 0;
+int GLAD_GL_APPLE_texture_range = 0;
+int GLAD_GL_EXT_texture_array = 0;
+int GLAD_GL_NV_texture_barrier = 0;
+int GLAD_GL_ARB_texture_query_levels = 0;
+int GLAD_GL_NV_texgen_emboss = 0;
+int GLAD_GL_EXT_texture_swizzle = 0;
+int GLAD_GL_ARB_texture_rg = 0;
+int GLAD_GL_ARB_vertex_type_2_10_10_10_rev = 0;
+int GLAD_GL_ARB_fragment_shader = 0;
+int GLAD_GL_3DFX_tbuffer = 0;
+int GLAD_GL_GREMEDY_frame_terminator = 0;
+int GLAD_GL_IBM_cull_vertex = 0;
+int GLAD_GL_EXT_separate_shader_objects = 0;
+int GLAD_GL_NV_texture_multisample = 0;
+int GLAD_GL_ARB_shader_objects = 0;
+int GLAD_GL_ARB_framebuffer_object = 0;
+int GLAD_GL_EXT_external_buffer = 0;
+int GLAD_GL_ATI_envmap_bumpmap = 0;
+int GLAD_GL_AMD_shader_explicit_vertex_parameter = 0;
+int GLAD_GL_ARB_robust_buffer_access_behavior = 0;
+int GLAD_GL_ARB_shader_stencil_export = 0;
+int GLAD_GL_NV_texture_rectangle = 0;
+int GLAD_GL_ARB_enhanced_layouts = 0;
+int GLAD_GL_ARB_texture_rectangle = 0;
+int GLAD_GL_SGI_texture_color_table = 0;
+int GLAD_GL_NV_viewport_swizzle = 0;
+int GLAD_GL_ATI_map_object_buffer = 0;
+int GLAD_GL_ARB_robustness = 0;
+int GLAD_GL_NV_pixel_data_range = 0;
+int GLAD_GL_EXT_framebuffer_blit = 0;
+int GLAD_GL_ARB_gpu_shader_fp64 = 0;
+int GLAD_GL_NV_command_list = 0;
+int GLAD_GL_SGIX_depth_texture = 0;
+int GLAD_GL_AMD_framebuffer_sample_positions = 0;
+int GLAD_GL_GREMEDY_string_marker = 0;
+int GLAD_GL_ARB_texture_compression_bptc = 0;
+int GLAD_GL_EXT_subtexture = 0;
+int GLAD_GL_EXT_pixel_transform_color_table = 0;
+int GLAD_GL_EXT_texture_compression_rgtc = 0;
+int GLAD_GL_ARB_shader_atomic_counter_ops = 0;
+int GLAD_GL_SGIX_depth_pass_instrument = 0;
+int GLAD_GL_EXT_gpu_program_parameters = 0;
+int GLAD_GL_NV_evaluators = 0;
+int GLAD_GL_EXT_shader_framebuffer_fetch_non_coherent = 0;
+int GLAD_GL_SGIS_texture_filter4 = 0;
+int GLAD_GL_AMD_performance_monitor = 0;
+int GLAD_GL_NV_geometry_shader4 = 0;
+int GLAD_GL_EXT_stencil_clear_tag = 0;
+int GLAD_GL_NV_vertex_program1_1 = 0;
+int GLAD_GL_NV_present_video = 0;
+int GLAD_GL_ARB_texture_compression_rgtc = 0;
+int GLAD_GL_HP_convolution_border_modes = 0;
+int GLAD_GL_EXT_shader_integer_mix = 0;
+int GLAD_GL_SGIX_framezoom = 0;
+int GLAD_GL_ARB_stencil_texturing = 0;
+int GLAD_GL_ARB_shader_clock = 0;
+int GLAD_GL_NV_shader_atomic_fp16_vector = 0;
+int GLAD_GL_SGIX_fog_offset = 0;
+int GLAD_GL_ARB_draw_elements_base_vertex = 0;
+int GLAD_GL_INGR_interlace_read = 0;
+int GLAD_GL_NV_transform_feedback = 0;
+int GLAD_GL_NV_fragment_program = 0;
+int GLAD_GL_AMD_stencil_operation_extended = 0;
+int GLAD_GL_ARB_seamless_cubemap_per_texture = 0;
+int GLAD_GL_ARB_instanced_arrays = 0;
+int GLAD_GL_ARB_get_texture_sub_image = 0;
+int GLAD_GL_NV_vertex_array_range2 = 0;
+int GLAD_GL_KHR_robustness = 0;
+int GLAD_GL_AMD_sparse_texture = 0;
+int GLAD_GL_ARB_clip_control = 0;
+int GLAD_GL_NV_fragment_coverage_to_color = 0;
+int GLAD_GL_NV_fence = 0;
+int GLAD_GL_ARB_texture_buffer_range = 0;
+int GLAD_GL_SUN_mesh_array = 0;
+int GLAD_GL_ARB_vertex_attrib_binding = 0;
+int GLAD_GL_ARB_framebuffer_no_attachments = 0;
+int GLAD_GL_ARB_cl_event = 0;
+int GLAD_GL_EXT_vertex_weighting = 0;
+int GLAD_GL_ARB_derivative_control = 0;
+int GLAD_GL_NV_packed_depth_stencil = 0;
+int GLAD_GL_OES_single_precision = 0;
+int GLAD_GL_NV_primitive_restart = 0;
+int GLAD_GL_SUN_global_alpha = 0;
+int GLAD_GL_ARB_fragment_shader_interlock = 0;
+int GLAD_GL_EXT_texture_object = 0;
+int GLAD_GL_AMD_name_gen_delete = 0;
+int GLAD_GL_NV_texture_compression_vtc = 0;
+int GLAD_GL_NV_sample_mask_override_coverage = 0;
+int GLAD_GL_NV_texture_shader3 = 0;
+int GLAD_GL_MESA_tile_raster_order = 0;
+int GLAD_GL_ARB_texture_filter_anisotropic = 0;
+int GLAD_GL_EXT_texture = 0;
+int GLAD_GL_ARB_buffer_storage = 0;
+int GLAD_GL_AMD_shader_atomic_counter_ops = 0;
+int GLAD_GL_APPLE_vertex_program_evaluators = 0;
+int GLAD_GL_AMD_texture_gather_bias_lod = 0;
+int GLAD_GL_NV_texgen_reflection = 0;
+int GLAD_GL_ARB_explicit_uniform_location = 0;
+int GLAD_GL_ARB_depth_buffer_float = 0;
+int GLAD_GL_NV_path_rendering_shared_edge = 0;
+int GLAD_GL_SGIX_shadow_ambient = 0;
+int GLAD_GL_ARB_texture_cube_map = 0;
+int GLAD_GL_AMD_vertex_shader_viewport_index = 0;
+int GLAD_GL_SGIX_list_priority = 0;
+int GLAD_GL_NV_vertex_buffer_unified_memory = 0;
+int GLAD_GL_NV_uniform_buffer_unified_memory = 0;
+int GLAD_GL_ARB_clear_texture = 0;
+int GLAD_GL_ATI_texture_env_combine3 = 0;
+int GLAD_GL_NV_depth_clamp = 0;
+int GLAD_GL_ARB_map_buffer_alignment = 0;
+int GLAD_GL_EXT_memory_object = 0;
+int GLAD_GL_NV_blend_equation_advanced = 0;
+int GLAD_GL_SGIS_sharpen_texture = 0;
+int GLAD_GL_KHR_robust_buffer_access_behavior = 0;
+int GLAD_GL_ARB_pipeline_statistics_query = 0;
+int GLAD_GL_ARB_vertex_program = 0;
+int GLAD_GL_ARB_texture_rgb10_a2ui = 0;
+int GLAD_GL_OML_interlace = 0;
+int GLAD_GL_ATI_pixel_format_float = 0;
+int GLAD_GL_NV_clip_space_w_scaling = 0;
+int GLAD_GL_ARB_vertex_buffer_object = 0;
+int GLAD_GL_EXT_shadow_funcs = 0;
+int GLAD_GL_ATI_text_fragment_shader = 0;
+int GLAD_GL_NV_vertex_array_range = 0;
+int GLAD_GL_SGIX_fragment_lighting = 0;
+int GLAD_GL_AMD_shader_ballot = 0;
+int GLAD_GL_NV_texture_expand_normal = 0;
+int GLAD_GL_NV_framebuffer_multisample_coverage = 0;
+int GLAD_GL_EXT_timer_query = 0;
+int GLAD_GL_EXT_vertex_array_bgra = 0;
+int GLAD_GL_NV_bindless_texture = 0;
+int GLAD_GL_KHR_debug = 0;
+int GLAD_GL_SGIS_texture_border_clamp = 0;
+int GLAD_GL_ATI_vertex_attrib_array_object = 0;
+int GLAD_GL_SGIX_clipmap = 0;
+int GLAD_GL_EXT_geometry_shader4 = 0;
+int GLAD_GL_ARB_shader_texture_image_samples = 0;
+int GLAD_GL_MESA_ycbcr_texture = 0;
+int GLAD_GL_MESAX_texture_stack = 0;
+int GLAD_GL_AMD_seamless_cubemap_per_texture = 0;
+int GLAD_GL_EXT_bindable_uniform = 0;
+int GLAD_GL_KHR_texture_compression_astc_hdr = 0;
+int GLAD_GL_ARB_shader_ballot = 0;
+int GLAD_GL_KHR_blend_equation_advanced = 0;
+int GLAD_GL_ARB_fragment_program_shadow = 0;
+int GLAD_GL_ATI_element_array = 0;
+int GLAD_GL_AMD_texture_texture4 = 0;
+int GLAD_GL_SGIX_reference_plane = 0;
+int GLAD_GL_EXT_stencil_two_side = 0;
+int GLAD_GL_ARB_transform_feedback_overflow_query = 0;
+int GLAD_GL_SGIX_texture_lod_bias = 0;
+int GLAD_GL_KHR_no_error = 0;
+int GLAD_GL_NV_explicit_multisample = 0;
+int GLAD_GL_NV_stereo_view_rendering = 0;
+int GLAD_GL_IBM_static_data = 0;
+int GLAD_GL_EXT_clip_volume_hint = 0;
+int GLAD_GL_EXT_texture_perturb_normal = 0;
+int GLAD_GL_NV_fragment_program2 = 0;
+int GLAD_GL_NV_fragment_program4 = 0;
+int GLAD_GL_EXT_point_parameters = 0;
+int GLAD_GL_PGI_misc_hints = 0;
+int GLAD_GL_EXT_EGL_image_storage = 0;
+int GLAD_GL_SGIX_subsample = 0;
+int GLAD_GL_AMD_shader_stencil_export = 0;
+int GLAD_GL_ARB_shader_texture_lod = 0;
+int GLAD_GL_ARB_vertex_shader = 0;
+int GLAD_GL_ARB_depth_clamp = 0;
+int GLAD_GL_SGIS_texture_select = 0;
+int GLAD_GL_NV_texture_shader = 0;
+int GLAD_GL_ARB_tessellation_shader = 0;
+int GLAD_GL_EXT_draw_buffers2 = 0;
+int GLAD_GL_ARB_vertex_attrib_64bit = 0;
+int GLAD_GL_EXT_texture_filter_minmax = 0;
+int GLAD_GL_NV_query_resource = 0;
+int GLAD_GL_AMD_interleaved_elements = 0;
+int GLAD_GL_ARB_fragment_program = 0;
+int GLAD_GL_OML_resample = 0;
+int GLAD_GL_APPLE_ycbcr_422 = 0;
+int GLAD_GL_SGIX_texture_add_env = 0;
+int GLAD_GL_ARB_shadow_ambient = 0;
+int GLAD_GL_ARB_texture_storage = 0;
+int GLAD_GL_EXT_pixel_buffer_object = 0;
+int GLAD_GL_ARB_copy_image = 0;
+int GLAD_GL_SGIS_pixel_texture = 0;
+int GLAD_GL_SGIS_generate_mipmap = 0;
+int GLAD_GL_SGIX_instruments = 0;
+int GLAD_GL_ARB_fragment_layer_viewport = 0;
+int GLAD_GL_ARB_shader_storage_buffer_object = 0;
+int GLAD_GL_EXT_sparse_texture2 = 0;
+int GLAD_GL_EXT_blend_minmax = 0;
+int GLAD_GL_MESA_pack_invert = 0;
+int GLAD_GL_ARB_base_instance = 0;
+int GLAD_GL_SGIX_convolution_accuracy = 0;
+int GLAD_GL_PGI_vertex_hints = 0;
+int GLAD_GL_AMD_transform_feedback4 = 0;
+int GLAD_GL_ARB_ES3_1_compatibility = 0;
+int GLAD_GL_EXT_memory_object_win32 = 0;
+int GLAD_GL_EXT_texture_integer = 0;
+int GLAD_GL_ARB_texture_multisample = 0;
+int GLAD_GL_ATI_vertex_streams = 0;
+int GLAD_GL_AMD_gpu_shader_int64 = 0;
+int GLAD_GL_S3_s3tc = 0;
+int GLAD_GL_ARB_query_buffer_object = 0;
+int GLAD_GL_AMD_vertex_shader_tessellator = 0;
+int GLAD_GL_ARB_invalidate_subdata = 0;
+int GLAD_GL_NV_draw_vulkan_image = 0;
+int GLAD_GL_EXT_index_material = 0;
+int GLAD_GL_NVX_linked_gpu_multicast = 0;
+int GLAD_GL_NV_blend_equation_advanced_coherent = 0;
+int GLAD_GL_KHR_texture_compression_astc_sliced_3d = 0;
+int GLAD_GL_INTEL_parallel_arrays = 0;
+int GLAD_GL_ATI_draw_buffers = 0;
+int GLAD_GL_WIN_specular_fog = 0;
+int GLAD_GL_EXT_cmyka = 0;
+int GLAD_GL_SGIX_pixel_texture = 0;
+int GLAD_GL_APPLE_specular_vector = 0;
+int GLAD_GL_ARB_compatibility = 0;
+int GLAD_GL_ARB_timer_query = 0;
+int GLAD_GL_SGIX_interlace = 0;
+int GLAD_GL_NV_parameter_buffer_object = 0;
+int GLAD_GL_AMD_shader_trinary_minmax = 0;
+int GLAD_GL_ARB_direct_state_access = 0;
+int GLAD_GL_EXT_rescale_normal = 0;
+int GLAD_GL_ARB_pixel_buffer_object = 0;
+int GLAD_GL_ARB_uniform_buffer_object = 0;
+int GLAD_GL_ARB_vertex_type_10f_11f_11f_rev = 0;
+int GLAD_GL_ARB_texture_swizzle = 0;
+int GLAD_GL_NV_transform_feedback2 = 0;
+int GLAD_GL_SGIX_async_pixel = 0;
+int GLAD_GL_NV_fragment_program_option = 0;
+int GLAD_GL_ARB_explicit_attrib_location = 0;
+int GLAD_GL_EXT_blend_color = 0;
+int GLAD_GL_NV_shader_thread_group = 0;
+int GLAD_GL_EXT_stencil_wrap = 0;
+int GLAD_GL_EXT_index_array_formats = 0;
+int GLAD_GL_OVR_multiview2 = 0;
+int GLAD_GL_EXT_histogram = 0;
+int GLAD_GL_EXT_polygon_offset = 0;
+int GLAD_GL_SGIS_point_parameters = 0;
+int GLAD_GL_SGIX_ycrcb = 0;
+int GLAD_GL_EXT_direct_state_access = 0;
+int GLAD_GL_ARB_cull_distance = 0;
+int GLAD_GL_AMD_sample_positions = 0;
+int GLAD_GL_NV_vertex_program = 0;
+int GLAD_GL_NV_shader_thread_shuffle = 0;
+int GLAD_GL_ARB_shader_precision = 0;
+int GLAD_GL_EXT_vertex_shader = 0;
+int GLAD_GL_EXT_blend_func_separate = 0;
+int GLAD_GL_APPLE_fence = 0;
+int GLAD_GL_NV_query_resource_tag = 0;
+int GLAD_GL_OES_byte_coordinates = 0;
+int GLAD_GL_ARB_transpose_matrix = 0;
+int GLAD_GL_ARB_provoking_vertex = 0;
+int GLAD_GL_EXT_fog_coord = 0;
+int GLAD_GL_EXT_vertex_array = 0;
+int GLAD_GL_ARB_half_float_vertex = 0;
+int GLAD_GL_EXT_blend_equation_separate = 0;
+int GLAD_GL_NV_framebuffer_mixed_samples = 0;
+int GLAD_GL_NVX_conditional_render = 0;
+int GLAD_GL_ARB_multi_draw_indirect = 0;
+int GLAD_GL_EXT_raster_multisample = 0;
+int GLAD_GL_NV_copy_image = 0;
+int GLAD_GL_HP_texture_lighting = 0;
+int GLAD_GL_INTEL_framebuffer_CMAA = 0;
+int GLAD_GL_ARB_transform_feedback2 = 0;
+int GLAD_GL_ARB_transform_feedback3 = 0;
+int GLAD_GL_SGIX_ycrcba = 0;
+int GLAD_GL_EXT_debug_marker = 0;
+int GLAD_GL_EXT_bgra = 0;
+int GLAD_GL_ARB_sparse_texture_clamp = 0;
+int GLAD_GL_EXT_pixel_transform = 0;
+int GLAD_GL_ARB_conservative_depth = 0;
+int GLAD_GL_ATI_fragment_shader = 0;
+int GLAD_GL_ARB_vertex_array_object = 0;
+int GLAD_GL_SUN_triangle_list = 0;
+int GLAD_GL_EXT_texture_env_add = 0;
+int GLAD_GL_EXT_packed_depth_stencil = 0;
+int GLAD_GL_EXT_texture_mirror_clamp = 0;
+int GLAD_GL_NV_multisample_filter_hint = 0;
+int GLAD_GL_APPLE_float_pixels = 0;
+int GLAD_GL_ARB_transform_feedback_instanced = 0;
+int GLAD_GL_SGIX_async = 0;
+int GLAD_GL_EXT_texture_compression_latc = 0;
+int GLAD_GL_NV_robustness_video_memory_purge = 0;
+int GLAD_GL_ARB_shading_language_100 = 0;
+int GLAD_GL_INTEL_performance_query = 0;
+int GLAD_GL_ARB_texture_mirror_clamp_to_edge = 0;
+int GLAD_GL_NV_gpu_shader5 = 0;
+int GLAD_GL_NV_bindless_multi_draw_indirect_count = 0;
+int GLAD_GL_ARB_ES2_compatibility = 0;
+int GLAD_GL_ARB_indirect_parameters = 0;
+int GLAD_GL_EXT_window_rectangles = 0;
+int GLAD_GL_NV_half_float = 0;
+int GLAD_GL_ARB_ES3_2_compatibility = 0;
+int GLAD_GL_ATI_texture_mirror_once = 0;
+int GLAD_GL_IBM_rasterpos_clip = 0;
+int GLAD_GL_EXT_semaphore = 0;
+int GLAD_GL_SGIX_shadow = 0;
+int GLAD_GL_EXT_polygon_offset_clamp = 0;
+int GLAD_GL_NV_deep_texture3D = 0;
+int GLAD_GL_ARB_shader_draw_parameters = 0;
+int GLAD_GL_SGIX_calligraphic_fragment = 0;
+int GLAD_GL_ARB_shader_bit_encoding = 0;
+int GLAD_GL_EXT_compiled_vertex_array = 0;
+int GLAD_GL_NV_depth_buffer_float = 0;
+int GLAD_GL_NV_occlusion_query = 0;
+int GLAD_GL_APPLE_flush_buffer_range = 0;
+int GLAD_GL_ARB_imaging = 0;
+int GLAD_GL_NV_shader_atomic_float = 0;
+int GLAD_GL_ARB_draw_buffers_blend = 0;
+int GLAD_GL_AMD_gcn_shader = 0;
+int GLAD_GL_AMD_blend_minmax_factor = 0;
+int GLAD_GL_EXT_texture_sRGB_decode = 0;
+int GLAD_GL_ARB_shading_language_420pack = 0;
+int GLAD_GL_ARB_shader_viewport_layer_array = 0;
+int GLAD_GL_ATI_meminfo = 0;
+int GLAD_GL_EXT_abgr = 0;
+int GLAD_GL_AMD_pinned_memory = 0;
+int GLAD_GL_EXT_texture_snorm = 0;
+int GLAD_GL_SGIX_texture_coordinate_clamp = 0;
+int GLAD_GL_ARB_clear_buffer_object = 0;
+int GLAD_GL_ARB_multisample = 0;
+int GLAD_GL_EXT_debug_label = 0;
+int GLAD_GL_ARB_sample_shading = 0;
+int GLAD_GL_NV_internalformat_sample_query = 0;
+int GLAD_GL_INTEL_map_texture = 0;
+int GLAD_GL_ARB_texture_env_crossbar = 0;
+int GLAD_GL_EXT_422_pixels = 0;
+int GLAD_GL_NV_blend_minmax_factor = 0;
+int GLAD_GL_NV_conservative_raster_pre_snap_triangles = 0;
+int GLAD_GL_ARB_compute_shader = 0;
+int GLAD_GL_EXT_blend_logic_op = 0;
+int GLAD_GL_ARB_blend_func_extended = 0;
+int GLAD_GL_IBM_vertex_array_lists = 0;
+int GLAD_GL_ARB_color_buffer_float = 0;
+int GLAD_GL_ARB_bindless_texture = 0;
+int GLAD_GL_ARB_window_pos = 0;
+int GLAD_GL_ARB_internalformat_query = 0;
+int GLAD_GL_ARB_shadow = 0;
+int GLAD_GL_ARB_texture_mirrored_repeat = 0;
+int GLAD_GL_EXT_shader_image_load_store = 0;
+int GLAD_GL_EXT_copy_texture = 0;
+int GLAD_GL_NV_register_combiners2 = 0;
+int GLAD_GL_SGIX_ycrcb_subsample = 0;
+int GLAD_GL_NV_alpha_to_coverage_dither_control = 0;
+int GLAD_GL_SGIX_ir_instrument1 = 0;
+int GLAD_GL_NV_draw_texture = 0;
+int GLAD_GL_EXT_texture_shared_exponent = 0;
+int GLAD_GL_NV_texture_shader2 = 0;
+int GLAD_GL_EXT_draw_instanced = 0;
+int GLAD_GL_NV_copy_depth_to_color = 0;
+int GLAD_GL_ARB_viewport_array = 0;
+int GLAD_GL_ARB_separate_shader_objects = 0;
+int GLAD_GL_NV_conservative_raster_pre_snap = 0;
+int GLAD_GL_EXT_depth_bounds_test = 0;
+int GLAD_GL_HP_image_transform = 0;
+int GLAD_GL_ARB_texture_env_add = 0;
+int GLAD_GL_NV_video_capture = 0;
+int GLAD_GL_ARB_sampler_objects = 0;
+int GLAD_GL_ARB_matrix_palette = 0;
+int GLAD_GL_SGIS_texture_color_mask = 0;
+int GLAD_GL_EXT_packed_pixels = 0;
+int GLAD_GL_EXT_coordinate_frame = 0;
+int GLAD_GL_ARB_texture_compression = 0;
+int GLAD_GL_ARB_multi_bind = 0;
+int GLAD_GL_APPLE_aux_depth_stencil = 0;
+int GLAD_GL_ARB_shader_subroutine = 0;
+int GLAD_GL_EXT_framebuffer_sRGB = 0;
+int GLAD_GL_ARB_texture_storage_multisample = 0;
+int GLAD_GL_KHR_blend_equation_advanced_coherent = 0;
+int GLAD_GL_EXT_vertex_attrib_64bit = 0;
+int GLAD_GL_NV_shader_atomic_float64 = 0;
+int GLAD_GL_ARB_depth_texture = 0;
+int GLAD_GL_NV_shader_buffer_store = 0;
+int GLAD_GL_OES_query_matrix = 0;
+int GLAD_GL_MESA_window_pos = 0;
+int GLAD_GL_NV_fill_rectangle = 0;
+int GLAD_GL_NV_shader_storage_buffer_object = 0;
+int GLAD_GL_ARB_texture_query_lod = 0;
+int GLAD_GL_ARB_copy_buffer = 0;
+int GLAD_GL_ARB_shader_image_size = 0;
+int GLAD_GL_NV_shader_atomic_counters = 0;
+int GLAD_GL_APPLE_object_purgeable = 0;
+int GLAD_GL_ARB_occlusion_query = 0;
+int GLAD_GL_INGR_color_clamp = 0;
+int GLAD_GL_SGI_color_table = 0;
+int GLAD_GL_NV_gpu_program5_mem_extended = 0;
+int GLAD_GL_ARB_texture_cube_map_array = 0;
+int GLAD_GL_SGIX_scalebias_hint = 0;
+int GLAD_GL_EXT_gpu_shader4 = 0;
+int GLAD_GL_NV_geometry_program4 = 0;
+int GLAD_GL_EXT_framebuffer_multisample_blit_scaled = 0;
+int GLAD_GL_AMD_debug_output = 0;
+int GLAD_GL_ARB_texture_border_clamp = 0;
+int GLAD_GL_EXT_win32_keyed_mutex = 0;
+int GLAD_GL_ARB_fragment_coord_conventions = 0;
+int GLAD_GL_ARB_multitexture = 0;
+int GLAD_GL_SGIX_polynomial_ffd = 0;
+int GLAD_GL_EXT_texture_env_dot3 = 0;
+int GLAD_GL_EXT_provoking_vertex = 0;
+int GLAD_GL_ARB_point_parameters = 0;
+int GLAD_GL_ARB_shader_image_load_store = 0;
+int GLAD_GL_ARB_conditional_render_inverted = 0;
+int GLAD_GL_HP_occlusion_test = 0;
+int GLAD_GL_ARB_ES3_compatibility = 0;
+int GLAD_GL_ARB_texture_barrier = 0;
+int GLAD_GL_ARB_texture_buffer_object_rgb32 = 0;
+int GLAD_GL_NV_bindless_multi_draw_indirect = 0;
+int GLAD_GL_SGIX_texture_multi_buffer = 0;
+int GLAD_GL_INTEL_blackhole_render = 0;
+int GLAD_GL_AMD_shader_image_load_store_lod = 0;
+int GLAD_GL_KHR_texture_compression_astc_ldr = 0;
+int GLAD_GL_3DFX_multisample = 0;
+int GLAD_GL_INTEL_fragment_shader_ordering = 0;
+int GLAD_GL_ARB_texture_env_dot3 = 0;
+int GLAD_GL_NV_gpu_program4 = 0;
+int GLAD_GL_NV_gpu_program5 = 0;
+int GLAD_GL_NV_float_buffer = 0;
+int GLAD_GL_SGIS_texture_edge_clamp = 0;
+int GLAD_GL_ARB_framebuffer_sRGB = 0;
+int GLAD_GL_SUN_slice_accum = 0;
+int GLAD_GL_EXT_index_texture = 0;
+int GLAD_GL_EXT_shader_image_load_formatted = 0;
+int GLAD_GL_ARB_geometry_shader4 = 0;
+int GLAD_GL_EXT_separate_specular_color = 0;
+int GLAD_GL_AMD_depth_clamp_separate = 0;
+int GLAD_GL_NV_conservative_raster = 0;
+int GLAD_GL_ARB_sparse_texture2 = 0;
+int GLAD_GL_SGIX_sprite = 0;
+int GLAD_GL_ARB_get_program_binary = 0;
+int GLAD_GL_AMD_occlusion_query_event = 0;
+int GLAD_GL_SGIS_multisample = 0;
+int GLAD_GL_EXT_framebuffer_object = 0;
+int GLAD_GL_ARB_robustness_isolation = 0;
+int GLAD_GL_ARB_vertex_array_bgra = 0;
+int GLAD_GL_APPLE_vertex_array_range = 0;
+int GLAD_GL_AMD_query_buffer_object = 0;
+int GLAD_GL_NV_register_combiners = 0;
+int GLAD_GL_ARB_draw_buffers = 0;
+int GLAD_GL_NVX_blend_equation_advanced_multi_draw_buffers = 0;
+int GLAD_GL_AMD_gpu_shader_int16 = 0;
+int GLAD_GL_ARB_debug_output = 0;
+int GLAD_GL_EXT_shader_framebuffer_fetch = 0;
+int GLAD_GL_SGI_color_matrix = 0;
+int GLAD_GL_EXT_cull_vertex = 0;
+int GLAD_GL_AMD_framebuffer_multisample_advanced = 0;
+int GLAD_GL_EXT_texture_sRGB = 0;
+int GLAD_GL_APPLE_row_bytes = 0;
+int GLAD_GL_NV_conservative_raster_underestimation = 0;
+int GLAD_GL_IBM_multimode_draw_arrays = 0;
+int GLAD_GL_KHR_parallel_shader_compile = 0;
+int GLAD_GL_APPLE_vertex_array_object = 0;
+int GLAD_GL_3DFX_texture_compression_FXT1 = 0;
+int GLAD_GL_NV_fragment_shader_interlock = 0;
+int GLAD_GL_AMD_conservative_depth = 0;
+int GLAD_GL_ARB_texture_float = 0;
+int GLAD_GL_ARB_compressed_texture_pixel_storage = 0;
+int GLAD_GL_SGIS_detail_texture = 0;
+int GLAD_GL_NV_geometry_shader_passthrough = 0;
+int GLAD_GL_ARB_draw_instanced = 0;
+int GLAD_GL_OES_read_format = 0;
+int GLAD_GL_ATI_texture_float = 0;
+int GLAD_GL_ARB_texture_gather = 0;
+int GLAD_GL_AMD_vertex_shader_layer = 0;
+int GLAD_GL_ARB_shading_language_include = 0;
+int GLAD_GL_APPLE_client_storage = 0;
+int GLAD_GL_WIN_phong_shading = 0;
+int GLAD_GL_INGR_blend_func_separate = 0;
+int GLAD_GL_NV_path_rendering = 0;
+int GLAD_GL_NV_conservative_raster_dilate = 0;
+int GLAD_GL_AMD_gpu_shader_half_float = 0;
+int GLAD_GL_ARB_post_depth_coverage = 0;
+int GLAD_GL_ARB_texture_non_power_of_two = 0;
+int GLAD_GL_APPLE_rgb_422 = 0;
+int GLAD_GL_EXT_texture_lod_bias = 0;
+int GLAD_GL_ARB_gpu_shader_int64 = 0;
+int GLAD_GL_ARB_seamless_cube_map = 0;
+int GLAD_GL_ARB_shader_group_vote = 0;
+int GLAD_GL_NV_vdpau_interop = 0;
+int GLAD_GL_ARB_occlusion_query2 = 0;
+int GLAD_GL_ARB_internalformat_query2 = 0;
+int GLAD_GL_EXT_texture_filter_anisotropic = 0;
+int GLAD_GL_SUN_vertex = 0;
+int GLAD_GL_EXT_transform_feedback = 0;
+int GLAD_GL_SGIX_igloo_interface = 0;
+int GLAD_GL_SGIS_texture_lod = 0;
+int GLAD_GL_NV_vertex_program3 = 0;
+int GLAD_GL_ARB_draw_indirect = 0;
+int GLAD_GL_NV_vertex_program4 = 0;
+int GLAD_GL_AMD_transform_feedback3_lines_triangles = 0;
+int GLAD_GL_SGIS_fog_function = 0;
+int GLAD_GL_EXT_x11_sync_object = 0;
+int GLAD_GL_ARB_sync = 0;
+int GLAD_GL_NV_texture_rectangle_compressed = 0;
+int GLAD_GL_NV_sample_locations = 0;
+int GLAD_GL_NV_gpu_multicast = 0;
+int GLAD_GL_ARB_gl_spirv = 0;
+int GLAD_GL_ARB_compute_variable_group_size = 0;
+int GLAD_GL_OES_fixed_point = 0;
+int GLAD_GL_MESA_program_binary_formats = 0;
+int GLAD_GL_NV_blend_square = 0;
+int GLAD_GL_EXT_framebuffer_multisample = 0;
+int GLAD_GL_ARB_gpu_shader5 = 0;
+int GLAD_GL_SGIS_texture4D = 0;
+int GLAD_GL_EXT_texture3D = 0;
+int GLAD_GL_EXT_multisample = 0;
+int GLAD_GL_EXT_secondary_color = 0;
+int GLAD_GL_INTEL_conservative_rasterization = 0;
+int GLAD_GL_ARB_texture_filter_minmax = 0;
+int GLAD_GL_ATI_vertex_array_object = 0;
+int GLAD_GL_ARB_parallel_shader_compile = 0;
+int GLAD_GL_NVX_gpu_memory_info = 0;
+int GLAD_GL_ARB_sparse_texture = 0;
+int GLAD_GL_SGIS_point_line_texgen = 0;
+int GLAD_GL_ARB_sample_locations = 0;
+int GLAD_GL_ARB_sparse_buffer = 0;
+int GLAD_GL_ARB_polygon_offset_clamp = 0;
+int GLAD_GL_EXT_draw_range_elements = 0;
+int GLAD_GL_SGIX_blend_alpha_minmax = 0;
+int GLAD_GL_KHR_context_flush_control = 0;
+PFNGLTBUFFERMASK3DFXPROC glad_glTbufferMask3DFX = NULL;
+PFNGLDEBUGMESSAGEENABLEAMDPROC glad_glDebugMessageEnableAMD = NULL;
+PFNGLDEBUGMESSAGEINSERTAMDPROC glad_glDebugMessageInsertAMD = NULL;
+PFNGLDEBUGMESSAGECALLBACKAMDPROC glad_glDebugMessageCallbackAMD = NULL;
+PFNGLGETDEBUGMESSAGELOGAMDPROC glad_glGetDebugMessageLogAMD = NULL;
+PFNGLBLENDFUNCINDEXEDAMDPROC glad_glBlendFuncIndexedAMD = NULL;
+PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC glad_glBlendFuncSeparateIndexedAMD = NULL;
+PFNGLBLENDEQUATIONINDEXEDAMDPROC glad_glBlendEquationIndexedAMD = NULL;
+PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC glad_glBlendEquationSeparateIndexedAMD = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC glad_glRenderbufferStorageMultisampleAdvancedAMD = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC glad_glNamedRenderbufferStorageMultisampleAdvancedAMD = NULL;
+PFNGLFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC glad_glFramebufferSamplePositionsfvAMD = NULL;
+PFNGLNAMEDFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC glad_glNamedFramebufferSamplePositionsfvAMD = NULL;
+PFNGLGETFRAMEBUFFERPARAMETERFVAMDPROC glad_glGetFramebufferParameterfvAMD = NULL;
+PFNGLGETNAMEDFRAMEBUFFERPARAMETERFVAMDPROC glad_glGetNamedFramebufferParameterfvAMD = NULL;
+PFNGLUNIFORM1I64NVPROC glad_glUniform1i64NV = NULL;
+PFNGLUNIFORM2I64NVPROC glad_glUniform2i64NV = NULL;
+PFNGLUNIFORM3I64NVPROC glad_glUniform3i64NV = NULL;
+PFNGLUNIFORM4I64NVPROC glad_glUniform4i64NV = NULL;
+PFNGLUNIFORM1I64VNVPROC glad_glUniform1i64vNV = NULL;
+PFNGLUNIFORM2I64VNVPROC glad_glUniform2i64vNV = NULL;
+PFNGLUNIFORM3I64VNVPROC glad_glUniform3i64vNV = NULL;
+PFNGLUNIFORM4I64VNVPROC glad_glUniform4i64vNV = NULL;
+PFNGLUNIFORM1UI64NVPROC glad_glUniform1ui64NV = NULL;
+PFNGLUNIFORM2UI64NVPROC glad_glUniform2ui64NV = NULL;
+PFNGLUNIFORM3UI64NVPROC glad_glUniform3ui64NV = NULL;
+PFNGLUNIFORM4UI64NVPROC glad_glUniform4ui64NV = NULL;
+PFNGLUNIFORM1UI64VNVPROC glad_glUniform1ui64vNV = NULL;
+PFNGLUNIFORM2UI64VNVPROC glad_glUniform2ui64vNV = NULL;
+PFNGLUNIFORM3UI64VNVPROC glad_glUniform3ui64vNV = NULL;
+PFNGLUNIFORM4UI64VNVPROC glad_glUniform4ui64vNV = NULL;
+PFNGLGETUNIFORMI64VNVPROC glad_glGetUniformi64vNV = NULL;
+PFNGLGETUNIFORMUI64VNVPROC glad_glGetUniformui64vNV = NULL;
+PFNGLPROGRAMUNIFORM1I64NVPROC glad_glProgramUniform1i64NV = NULL;
+PFNGLPROGRAMUNIFORM2I64NVPROC glad_glProgramUniform2i64NV = NULL;
+PFNGLPROGRAMUNIFORM3I64NVPROC glad_glProgramUniform3i64NV = NULL;
+PFNGLPROGRAMUNIFORM4I64NVPROC glad_glProgramUniform4i64NV = NULL;
+PFNGLPROGRAMUNIFORM1I64VNVPROC glad_glProgramUniform1i64vNV = NULL;
+PFNGLPROGRAMUNIFORM2I64VNVPROC glad_glProgramUniform2i64vNV = NULL;
+PFNGLPROGRAMUNIFORM3I64VNVPROC glad_glProgramUniform3i64vNV = NULL;
+PFNGLPROGRAMUNIFORM4I64VNVPROC glad_glProgramUniform4i64vNV = NULL;
+PFNGLPROGRAMUNIFORM1UI64NVPROC glad_glProgramUniform1ui64NV = NULL;
+PFNGLPROGRAMUNIFORM2UI64NVPROC glad_glProgramUniform2ui64NV = NULL;
+PFNGLPROGRAMUNIFORM3UI64NVPROC glad_glProgramUniform3ui64NV = NULL;
+PFNGLPROGRAMUNIFORM4UI64NVPROC glad_glProgramUniform4ui64NV = NULL;
+PFNGLPROGRAMUNIFORM1UI64VNVPROC glad_glProgramUniform1ui64vNV = NULL;
+PFNGLPROGRAMUNIFORM2UI64VNVPROC glad_glProgramUniform2ui64vNV = NULL;
+PFNGLPROGRAMUNIFORM3UI64VNVPROC glad_glProgramUniform3ui64vNV = NULL;
+PFNGLPROGRAMUNIFORM4UI64VNVPROC glad_glProgramUniform4ui64vNV = NULL;
+PFNGLVERTEXATTRIBPARAMETERIAMDPROC glad_glVertexAttribParameteriAMD = NULL;
+PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC glad_glMultiDrawArraysIndirectAMD = NULL;
+PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC glad_glMultiDrawElementsIndirectAMD = NULL;
+PFNGLGENNAMESAMDPROC glad_glGenNamesAMD = NULL;
+PFNGLDELETENAMESAMDPROC glad_glDeleteNamesAMD = NULL;
+PFNGLISNAMEAMDPROC glad_glIsNameAMD = NULL;
+PFNGLQUERYOBJECTPARAMETERUIAMDPROC glad_glQueryObjectParameteruiAMD = NULL;
+PFNGLGETPERFMONITORGROUPSAMDPROC glad_glGetPerfMonitorGroupsAMD = NULL;
+PFNGLGETPERFMONITORCOUNTERSAMDPROC glad_glGetPerfMonitorCountersAMD = NULL;
+PFNGLGETPERFMONITORGROUPSTRINGAMDPROC glad_glGetPerfMonitorGroupStringAMD = NULL;
+PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC glad_glGetPerfMonitorCounterStringAMD = NULL;
+PFNGLGETPERFMONITORCOUNTERINFOAMDPROC glad_glGetPerfMonitorCounterInfoAMD = NULL;
+PFNGLGENPERFMONITORSAMDPROC glad_glGenPerfMonitorsAMD = NULL;
+PFNGLDELETEPERFMONITORSAMDPROC glad_glDeletePerfMonitorsAMD = NULL;
+PFNGLSELECTPERFMONITORCOUNTERSAMDPROC glad_glSelectPerfMonitorCountersAMD = NULL;
+PFNGLBEGINPERFMONITORAMDPROC glad_glBeginPerfMonitorAMD = NULL;
+PFNGLENDPERFMONITORAMDPROC glad_glEndPerfMonitorAMD = NULL;
+PFNGLGETPERFMONITORCOUNTERDATAAMDPROC glad_glGetPerfMonitorCounterDataAMD = NULL;
+PFNGLSETMULTISAMPLEFVAMDPROC glad_glSetMultisamplefvAMD = NULL;
+PFNGLTEXSTORAGESPARSEAMDPROC glad_glTexStorageSparseAMD = NULL;
+PFNGLTEXTURESTORAGESPARSEAMDPROC glad_glTextureStorageSparseAMD = NULL;
+PFNGLSTENCILOPVALUEAMDPROC glad_glStencilOpValueAMD = NULL;
+PFNGLTESSELLATIONFACTORAMDPROC glad_glTessellationFactorAMD = NULL;
+PFNGLTESSELLATIONMODEAMDPROC glad_glTessellationModeAMD = NULL;
+PFNGLELEMENTPOINTERAPPLEPROC glad_glElementPointerAPPLE = NULL;
+PFNGLDRAWELEMENTARRAYAPPLEPROC glad_glDrawElementArrayAPPLE = NULL;
+PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC glad_glDrawRangeElementArrayAPPLE = NULL;
+PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC glad_glMultiDrawElementArrayAPPLE = NULL;
+PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC glad_glMultiDrawRangeElementArrayAPPLE = NULL;
+PFNGLGENFENCESAPPLEPROC glad_glGenFencesAPPLE = NULL;
+PFNGLDELETEFENCESAPPLEPROC glad_glDeleteFencesAPPLE = NULL;
+PFNGLSETFENCEAPPLEPROC glad_glSetFenceAPPLE = NULL;
+PFNGLISFENCEAPPLEPROC glad_glIsFenceAPPLE = NULL;
+PFNGLTESTFENCEAPPLEPROC glad_glTestFenceAPPLE = NULL;
+PFNGLFINISHFENCEAPPLEPROC glad_glFinishFenceAPPLE = NULL;
+PFNGLTESTOBJECTAPPLEPROC glad_glTestObjectAPPLE = NULL;
+PFNGLFINISHOBJECTAPPLEPROC glad_glFinishObjectAPPLE = NULL;
+PFNGLBUFFERPARAMETERIAPPLEPROC glad_glBufferParameteriAPPLE = NULL;
+PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glad_glFlushMappedBufferRangeAPPLE = NULL;
+PFNGLOBJECTPURGEABLEAPPLEPROC glad_glObjectPurgeableAPPLE = NULL;
+PFNGLOBJECTUNPURGEABLEAPPLEPROC glad_glObjectUnpurgeableAPPLE = NULL;
+PFNGLGETOBJECTPARAMETERIVAPPLEPROC glad_glGetObjectParameterivAPPLE = NULL;
+PFNGLTEXTURERANGEAPPLEPROC glad_glTextureRangeAPPLE = NULL;
+PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC glad_glGetTexParameterPointervAPPLE = NULL;
+PFNGLBINDVERTEXARRAYAPPLEPROC glad_glBindVertexArrayAPPLE = NULL;
+PFNGLDELETEVERTEXARRAYSAPPLEPROC glad_glDeleteVertexArraysAPPLE = NULL;
+PFNGLGENVERTEXARRAYSAPPLEPROC glad_glGenVertexArraysAPPLE = NULL;
+PFNGLISVERTEXARRAYAPPLEPROC glad_glIsVertexArrayAPPLE = NULL;
+PFNGLVERTEXARRAYRANGEAPPLEPROC glad_glVertexArrayRangeAPPLE = NULL;
+PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC glad_glFlushVertexArrayRangeAPPLE = NULL;
+PFNGLVERTEXARRAYPARAMETERIAPPLEPROC glad_glVertexArrayParameteriAPPLE = NULL;
+PFNGLENABLEVERTEXATTRIBAPPLEPROC glad_glEnableVertexAttribAPPLE = NULL;
+PFNGLDISABLEVERTEXATTRIBAPPLEPROC glad_glDisableVertexAttribAPPLE = NULL;
+PFNGLISVERTEXATTRIBENABLEDAPPLEPROC glad_glIsVertexAttribEnabledAPPLE = NULL;
+PFNGLMAPVERTEXATTRIB1DAPPLEPROC glad_glMapVertexAttrib1dAPPLE = NULL;
+PFNGLMAPVERTEXATTRIB1FAPPLEPROC glad_glMapVertexAttrib1fAPPLE = NULL;
+PFNGLMAPVERTEXATTRIB2DAPPLEPROC glad_glMapVertexAttrib2dAPPLE = NULL;
+PFNGLMAPVERTEXATTRIB2FAPPLEPROC glad_glMapVertexAttrib2fAPPLE = NULL;
+PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;
+PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;
+PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;
+PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
+PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
+PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion = NULL;
+PFNGLPRIMITIVEBOUNDINGBOXARBPROC glad_glPrimitiveBoundingBoxARB = NULL;
+PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance = NULL;
+PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance = NULL;
+PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance = NULL;
+PFNGLGETTEXTUREHANDLEARBPROC glad_glGetTextureHandleARB = NULL;
+PFNGLGETTEXTURESAMPLERHANDLEARBPROC glad_glGetTextureSamplerHandleARB = NULL;
+PFNGLMAKETEXTUREHANDLERESIDENTARBPROC glad_glMakeTextureHandleResidentARB = NULL;
+PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC glad_glMakeTextureHandleNonResidentARB = NULL;
+PFNGLGETIMAGEHANDLEARBPROC glad_glGetImageHandleARB = NULL;
+PFNGLMAKEIMAGEHANDLERESIDENTARBPROC glad_glMakeImageHandleResidentARB = NULL;
+PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC glad_glMakeImageHandleNonResidentARB = NULL;
+PFNGLUNIFORMHANDLEUI64ARBPROC glad_glUniformHandleui64ARB = NULL;
+PFNGLUNIFORMHANDLEUI64VARBPROC glad_glUniformHandleui64vARB = NULL;
+PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC glad_glProgramUniformHandleui64ARB = NULL;
+PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC glad_glProgramUniformHandleui64vARB = NULL;
+PFNGLISTEXTUREHANDLERESIDENTARBPROC glad_glIsTextureHandleResidentARB = NULL;
+PFNGLISIMAGEHANDLERESIDENTARBPROC glad_glIsImageHandleResidentARB = NULL;
+PFNGLVERTEXATTRIBL1UI64ARBPROC glad_glVertexAttribL1ui64ARB = NULL;
+PFNGLVERTEXATTRIBL1UI64VARBPROC glad_glVertexAttribL1ui64vARB = NULL;
+PFNGLGETVERTEXATTRIBLUI64VARBPROC glad_glGetVertexAttribLui64vARB = NULL;
+PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL;
+PFNGLCREATESYNCFROMCLEVENTARBPROC glad_glCreateSyncFromCLeventARB = NULL;
+PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData = NULL;
+PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData = NULL;
+PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL;
+PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL;
+PFNGLCLIPCONTROLPROC glad_glClipControl = NULL;
+PFNGLCLAMPCOLORARBPROC glad_glClampColorARB = NULL;
+PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL;
+PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect = NULL;
+PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC glad_glDispatchComputeGroupSizeARB = NULL;
+PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL;
+PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL;
+PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL;
+PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL;
+PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB = NULL;
+PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks = NULL;
+PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase = NULL;
+PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange = NULL;
+PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv = NULL;
+PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v = NULL;
+PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v = NULL;
+PFNGLCREATEBUFFERSPROC glad_glCreateBuffers = NULL;
+PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage = NULL;
+PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData = NULL;
+PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData = NULL;
+PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData = NULL;
+PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData = NULL;
+PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData = NULL;
+PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer = NULL;
+PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange = NULL;
+PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer = NULL;
+PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange = NULL;
+PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv = NULL;
+PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v = NULL;
+PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv = NULL;
+PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData = NULL;
+PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers = NULL;
+PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer = NULL;
+PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer = NULL;
+PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer = NULL;
+PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers = NULL;
+PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer = NULL;
+PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData = NULL;
+PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi = NULL;
+PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer = NULL;
+PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus = NULL;
+PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv = NULL;
+PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv = NULL;
+PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample = NULL;
+PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv = NULL;
+PFNGLCREATETEXTURESPROC glad_glCreateTextures = NULL;
+PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer = NULL;
+PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange = NULL;
+PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D = NULL;
+PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D = NULL;
+PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D = NULL;
+PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample = NULL;
+PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample = NULL;
+PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D = NULL;
+PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D = NULL;
+PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D = NULL;
+PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D = NULL;
+PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D = NULL;
+PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D = NULL;
+PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf = NULL;
+PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv = NULL;
+PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri = NULL;
+PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv = NULL;
+PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv = NULL;
+PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv = NULL;
+PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap = NULL;
+PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit = NULL;
+PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage = NULL;
+PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage = NULL;
+PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv = NULL;
+PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv = NULL;
+PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv = NULL;
+PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv = NULL;
+PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv = NULL;
+PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv = NULL;
+PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays = NULL;
+PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib = NULL;
+PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib = NULL;
+PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer = NULL;
+PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer = NULL;
+PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers = NULL;
+PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding = NULL;
+PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat = NULL;
+PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat = NULL;
+PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat = NULL;
+PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor = NULL;
+PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv = NULL;
+PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv = NULL;
+PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv = NULL;
+PFNGLCREATESAMPLERSPROC glad_glCreateSamplers = NULL;
+PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines = NULL;
+PFNGLCREATEQUERIESPROC glad_glCreateQueries = NULL;
+PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v = NULL;
+PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv = NULL;
+PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v = NULL;
+PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv = NULL;
+PFNGLDRAWBUFFERSARBPROC glad_glDrawBuffersARB = NULL;
+PFNGLBLENDEQUATIONIARBPROC glad_glBlendEquationiARB = NULL;
+PFNGLBLENDEQUATIONSEPARATEIARBPROC glad_glBlendEquationSeparateiARB = NULL;
+PFNGLBLENDFUNCIARBPROC glad_glBlendFunciARB = NULL;
+PFNGLBLENDFUNCSEPARATEIARBPROC glad_glBlendFuncSeparateiARB = NULL;
+PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL;
+PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL;
+PFNGLDRAWARRAYSINSTANCEDARBPROC glad_glDrawArraysInstancedARB = NULL;
+PFNGLDRAWELEMENTSINSTANCEDARBPROC glad_glDrawElementsInstancedARB = NULL;
+PFNGLPROGRAMSTRINGARBPROC glad_glProgramStringARB = NULL;
+PFNGLBINDPROGRAMARBPROC glad_glBindProgramARB = NULL;
+PFNGLDELETEPROGRAMSARBPROC glad_glDeleteProgramsARB = NULL;
+PFNGLGENPROGRAMSARBPROC glad_glGenProgramsARB = NULL;
+PFNGLPROGRAMENVPARAMETER4DARBPROC glad_glProgramEnvParameter4dARB = NULL;
+PFNGLPROGRAMENVPARAMETER4DVARBPROC glad_glProgramEnvParameter4dvARB = NULL;
+PFNGLPROGRAMENVPARAMETER4FARBPROC glad_glProgramEnvParameter4fARB = NULL;
+PFNGLPROGRAMENVPARAMETER4FVARBPROC glad_glProgramEnvParameter4fvARB = NULL;
+PFNGLPROGRAMLOCALPARAMETER4DARBPROC glad_glProgramLocalParameter4dARB = NULL;
+PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glad_glProgramLocalParameter4dvARB = NULL;
+PFNGLPROGRAMLOCALPARAMETER4FARBPROC glad_glProgramLocalParameter4fARB = NULL;
+PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glad_glProgramLocalParameter4fvARB = NULL;
+PFNGLGETPROGRAMENVPARAMETERDVARBPROC glad_glGetProgramEnvParameterdvARB = NULL;
+PFNGLGETPROGRAMENVPARAMETERFVARBPROC glad_glGetProgramEnvParameterfvARB = NULL;
+PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glad_glGetProgramLocalParameterdvARB = NULL;
+PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glad_glGetProgramLocalParameterfvARB = NULL;
+PFNGLGETPROGRAMIVARBPROC glad_glGetProgramivARB = NULL;
+PFNGLGETPROGRAMSTRINGARBPROC glad_glGetProgramStringARB = NULL;
+PFNGLISPROGRAMARBPROC glad_glIsProgramARB = NULL;
+PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = NULL;
+PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv = NULL;
+PFNGLPROGRAMPARAMETERIARBPROC glad_glProgramParameteriARB = NULL;
+PFNGLFRAMEBUFFERTEXTUREARBPROC glad_glFramebufferTextureARB = NULL;
+PFNGLFRAMEBUFFERTEXTURELAYERARBPROC glad_glFramebufferTextureLayerARB = NULL;
+PFNGLFRAMEBUFFERTEXTUREFACEARBPROC glad_glFramebufferTextureFaceARB = NULL;
+PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL;
+PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL;
+PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL;
+PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage = NULL;
+PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage = NULL;
+PFNGLSPECIALIZESHADERARBPROC glad_glSpecializeShaderARB = NULL;
+PFNGLUNIFORM1DPROC glad_glUniform1d = NULL;
+PFNGLUNIFORM2DPROC glad_glUniform2d = NULL;
+PFNGLUNIFORM3DPROC glad_glUniform3d = NULL;
+PFNGLUNIFORM4DPROC glad_glUniform4d = NULL;
+PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL;
+PFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL;
+PFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL;
+PFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL;
+PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL;
+PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL;
+PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL;
+PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL;
+PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL;
+PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL;
+PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL;
+PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL;
+PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL;
+PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL;
+PFNGLUNIFORM1I64ARBPROC glad_glUniform1i64ARB = NULL;
+PFNGLUNIFORM2I64ARBPROC glad_glUniform2i64ARB = NULL;
+PFNGLUNIFORM3I64ARBPROC glad_glUniform3i64ARB = NULL;
+PFNGLUNIFORM4I64ARBPROC glad_glUniform4i64ARB = NULL;
+PFNGLUNIFORM1I64VARBPROC glad_glUniform1i64vARB = NULL;
+PFNGLUNIFORM2I64VARBPROC glad_glUniform2i64vARB = NULL;
+PFNGLUNIFORM3I64VARBPROC glad_glUniform3i64vARB = NULL;
+PFNGLUNIFORM4I64VARBPROC glad_glUniform4i64vARB = NULL;
+PFNGLUNIFORM1UI64ARBPROC glad_glUniform1ui64ARB = NULL;
+PFNGLUNIFORM2UI64ARBPROC glad_glUniform2ui64ARB = NULL;
+PFNGLUNIFORM3UI64ARBPROC glad_glUniform3ui64ARB = NULL;
+PFNGLUNIFORM4UI64ARBPROC glad_glUniform4ui64ARB = NULL;
+PFNGLUNIFORM1UI64VARBPROC glad_glUniform1ui64vARB = NULL;
+PFNGLUNIFORM2UI64VARBPROC glad_glUniform2ui64vARB = NULL;
+PFNGLUNIFORM3UI64VARBPROC glad_glUniform3ui64vARB = NULL;
+PFNGLUNIFORM4UI64VARBPROC glad_glUniform4ui64vARB = NULL;
+PFNGLGETUNIFORMI64VARBPROC glad_glGetUniformi64vARB = NULL;
+PFNGLGETUNIFORMUI64VARBPROC glad_glGetUniformui64vARB = NULL;
+PFNGLGETNUNIFORMI64VARBPROC glad_glGetnUniformi64vARB = NULL;
+PFNGLGETNUNIFORMUI64VARBPROC glad_glGetnUniformui64vARB = NULL;
+PFNGLPROGRAMUNIFORM1I64ARBPROC glad_glProgramUniform1i64ARB = NULL;
+PFNGLPROGRAMUNIFORM2I64ARBPROC glad_glProgramUniform2i64ARB = NULL;
+PFNGLPROGRAMUNIFORM3I64ARBPROC glad_glProgramUniform3i64ARB = NULL;
+PFNGLPROGRAMUNIFORM4I64ARBPROC glad_glProgramUniform4i64ARB = NULL;
+PFNGLPROGRAMUNIFORM1I64VARBPROC glad_glProgramUniform1i64vARB = NULL;
+PFNGLPROGRAMUNIFORM2I64VARBPROC glad_glProgramUniform2i64vARB = NULL;
+PFNGLPROGRAMUNIFORM3I64VARBPROC glad_glProgramUniform3i64vARB = NULL;
+PFNGLPROGRAMUNIFORM4I64VARBPROC glad_glProgramUniform4i64vARB = NULL;
+PFNGLPROGRAMUNIFORM1UI64ARBPROC glad_glProgramUniform1ui64ARB = NULL;
+PFNGLPROGRAMUNIFORM2UI64ARBPROC glad_glProgramUniform2ui64ARB = NULL;
+PFNGLPROGRAMUNIFORM3UI64ARBPROC glad_glProgramUniform3ui64ARB = NULL;
+PFNGLPROGRAMUNIFORM4UI64ARBPROC glad_glProgramUniform4ui64ARB = NULL;
+PFNGLPROGRAMUNIFORM1UI64VARBPROC glad_glProgramUniform1ui64vARB = NULL;
+PFNGLPROGRAMUNIFORM2UI64VARBPROC glad_glProgramUniform2ui64vARB = NULL;
+PFNGLPROGRAMUNIFORM3UI64VARBPROC glad_glProgramUniform3ui64vARB = NULL;
+PFNGLPROGRAMUNIFORM4UI64VARBPROC glad_glProgramUniform4ui64vARB = NULL;
+PFNGLCOLORTABLEPROC glad_glColorTable = NULL;
+PFNGLCOLORTABLEPARAMETERFVPROC glad_glColorTableParameterfv = NULL;
+PFNGLCOLORTABLEPARAMETERIVPROC glad_glColorTableParameteriv = NULL;
+PFNGLCOPYCOLORTABLEPROC glad_glCopyColorTable = NULL;
+PFNGLGETCOLORTABLEPROC glad_glGetColorTable = NULL;
+PFNGLGETCOLORTABLEPARAMETERFVPROC glad_glGetColorTableParameterfv = NULL;
+PFNGLGETCOLORTABLEPARAMETERIVPROC glad_glGetColorTableParameteriv = NULL;
+PFNGLCOLORSUBTABLEPROC glad_glColorSubTable = NULL;
+PFNGLCOPYCOLORSUBTABLEPROC glad_glCopyColorSubTable = NULL;
+PFNGLCONVOLUTIONFILTER1DPROC glad_glConvolutionFilter1D = NULL;
+PFNGLCONVOLUTIONFILTER2DPROC glad_glConvolutionFilter2D = NULL;
+PFNGLCONVOLUTIONPARAMETERFPROC glad_glConvolutionParameterf = NULL;
+PFNGLCONVOLUTIONPARAMETERFVPROC glad_glConvolutionParameterfv = NULL;
+PFNGLCONVOLUTIONPARAMETERIPROC glad_glConvolutionParameteri = NULL;
+PFNGLCONVOLUTIONPARAMETERIVPROC glad_glConvolutionParameteriv = NULL;
+PFNGLCOPYCONVOLUTIONFILTER1DPROC glad_glCopyConvolutionFilter1D = NULL;
+PFNGLCOPYCONVOLUTIONFILTER2DPROC glad_glCopyConvolutionFilter2D = NULL;
+PFNGLGETCONVOLUTIONFILTERPROC glad_glGetConvolutionFilter = NULL;
+PFNGLGETCONVOLUTIONPARAMETERFVPROC glad_glGetConvolutionParameterfv = NULL;
+PFNGLGETCONVOLUTIONPARAMETERIVPROC glad_glGetConvolutionParameteriv = NULL;
+PFNGLGETSEPARABLEFILTERPROC glad_glGetSeparableFilter = NULL;
+PFNGLSEPARABLEFILTER2DPROC glad_glSeparableFilter2D = NULL;
+PFNGLGETHISTOGRAMPROC glad_glGetHistogram = NULL;
+PFNGLGETHISTOGRAMPARAMETERFVPROC glad_glGetHistogramParameterfv = NULL;
+PFNGLGETHISTOGRAMPARAMETERIVPROC glad_glGetHistogramParameteriv = NULL;
+PFNGLGETMINMAXPROC glad_glGetMinmax = NULL;
+PFNGLGETMINMAXPARAMETERFVPROC glad_glGetMinmaxParameterfv = NULL;
+PFNGLGETMINMAXPARAMETERIVPROC glad_glGetMinmaxParameteriv = NULL;
+PFNGLHISTOGRAMPROC glad_glHistogram = NULL;
+PFNGLMINMAXPROC glad_glMinmax = NULL;
+PFNGLRESETHISTOGRAMPROC glad_glResetHistogram = NULL;
+PFNGLRESETMINMAXPROC glad_glResetMinmax = NULL;
+PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC glad_glMultiDrawArraysIndirectCountARB = NULL;
+PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC glad_glMultiDrawElementsIndirectCountARB = NULL;
+PFNGLVERTEXATTRIBDIVISORARBPROC glad_glVertexAttribDivisorARB = NULL;
+PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL;
+PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v = NULL;
+PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage = NULL;
+PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage = NULL;
+PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData = NULL;
+PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData = NULL;
+PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL;
+PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL;
+PFNGLCURRENTPALETTEMATRIXARBPROC glad_glCurrentPaletteMatrixARB = NULL;
+PFNGLMATRIXINDEXUBVARBPROC glad_glMatrixIndexubvARB = NULL;
+PFNGLMATRIXINDEXUSVARBPROC glad_glMatrixIndexusvARB = NULL;
+PFNGLMATRIXINDEXUIVARBPROC glad_glMatrixIndexuivARB = NULL;
+PFNGLMATRIXINDEXPOINTERARBPROC glad_glMatrixIndexPointerARB = NULL;
+PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase = NULL;
+PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange = NULL;
+PFNGLBINDTEXTURESPROC glad_glBindTextures = NULL;
+PFNGLBINDSAMPLERSPROC glad_glBindSamplers = NULL;
+PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures = NULL;
+PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers = NULL;
+PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect = NULL;
+PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect = NULL;
+PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB = NULL;
+PFNGLACTIVETEXTUREARBPROC glad_glActiveTextureARB = NULL;
+PFNGLCLIENTACTIVETEXTUREARBPROC glad_glClientActiveTextureARB = NULL;
+PFNGLMULTITEXCOORD1DARBPROC glad_glMultiTexCoord1dARB = NULL;
+PFNGLMULTITEXCOORD1DVARBPROC glad_glMultiTexCoord1dvARB = NULL;
+PFNGLMULTITEXCOORD1FARBPROC glad_glMultiTexCoord1fARB = NULL;
+PFNGLMULTITEXCOORD1FVARBPROC glad_glMultiTexCoord1fvARB = NULL;
+PFNGLMULTITEXCOORD1IARBPROC glad_glMultiTexCoord1iARB = NULL;
+PFNGLMULTITEXCOORD1IVARBPROC glad_glMultiTexCoord1ivARB = NULL;
+PFNGLMULTITEXCOORD1SARBPROC glad_glMultiTexCoord1sARB = NULL;
+PFNGLMULTITEXCOORD1SVARBPROC glad_glMultiTexCoord1svARB = NULL;
+PFNGLMULTITEXCOORD2DARBPROC glad_glMultiTexCoord2dARB = NULL;
+PFNGLMULTITEXCOORD2DVARBPROC glad_glMultiTexCoord2dvARB = NULL;
+PFNGLMULTITEXCOORD2FARBPROC glad_glMultiTexCoord2fARB = NULL;
+PFNGLMULTITEXCOORD2FVARBPROC glad_glMultiTexCoord2fvARB = NULL;
+PFNGLMULTITEXCOORD2IARBPROC glad_glMultiTexCoord2iARB = NULL;
+PFNGLMULTITEXCOORD2IVARBPROC glad_glMultiTexCoord2ivARB = NULL;
+PFNGLMULTITEXCOORD2SARBPROC glad_glMultiTexCoord2sARB = NULL;
+PFNGLMULTITEXCOORD2SVARBPROC glad_glMultiTexCoord2svARB = NULL;
+PFNGLMULTITEXCOORD3DARBPROC glad_glMultiTexCoord3dARB = NULL;
+PFNGLMULTITEXCOORD3DVARBPROC glad_glMultiTexCoord3dvARB = NULL;
+PFNGLMULTITEXCOORD3FARBPROC glad_glMultiTexCoord3fARB = NULL;
+PFNGLMULTITEXCOORD3FVARBPROC glad_glMultiTexCoord3fvARB = NULL;
+PFNGLMULTITEXCOORD3IARBPROC glad_glMultiTexCoord3iARB = NULL;
+PFNGLMULTITEXCOORD3IVARBPROC glad_glMultiTexCoord3ivARB = NULL;
+PFNGLMULTITEXCOORD3SARBPROC glad_glMultiTexCoord3sARB = NULL;
+PFNGLMULTITEXCOORD3SVARBPROC glad_glMultiTexCoord3svARB = NULL;
+PFNGLMULTITEXCOORD4DARBPROC glad_glMultiTexCoord4dARB = NULL;
+PFNGLMULTITEXCOORD4DVARBPROC glad_glMultiTexCoord4dvARB = NULL;
+PFNGLMULTITEXCOORD4FARBPROC glad_glMultiTexCoord4fARB = NULL;
+PFNGLMULTITEXCOORD4FVARBPROC glad_glMultiTexCoord4fvARB = NULL;
+PFNGLMULTITEXCOORD4IARBPROC glad_glMultiTexCoord4iARB = NULL;
+PFNGLMULTITEXCOORD4IVARBPROC glad_glMultiTexCoord4ivARB = NULL;
+PFNGLMULTITEXCOORD4SARBPROC glad_glMultiTexCoord4sARB = NULL;
+PFNGLMULTITEXCOORD4SVARBPROC glad_glMultiTexCoord4svARB = NULL;
+PFNGLGENQUERIESARBPROC glad_glGenQueriesARB = NULL;
+PFNGLDELETEQUERIESARBPROC glad_glDeleteQueriesARB = NULL;
+PFNGLISQUERYARBPROC glad_glIsQueryARB = NULL;
+PFNGLBEGINQUERYARBPROC glad_glBeginQueryARB = NULL;
+PFNGLENDQUERYARBPROC glad_glEndQueryARB = NULL;
+PFNGLGETQUERYIVARBPROC glad_glGetQueryivARB = NULL;
+PFNGLGETQUERYOBJECTIVARBPROC glad_glGetQueryObjectivARB = NULL;
+PFNGLGETQUERYOBJECTUIVARBPROC glad_glGetQueryObjectuivARB = NULL;
+PFNGLMAXSHADERCOMPILERTHREADSARBPROC glad_glMaxShaderCompilerThreadsARB = NULL;
+PFNGLPOINTPARAMETERFARBPROC glad_glPointParameterfARB = NULL;
+PFNGLPOINTPARAMETERFVARBPROC glad_glPointParameterfvARB = NULL;
+PFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp = NULL;
+PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv = NULL;
+PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex = NULL;
+PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL;
+PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL;
+PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation = NULL;
+PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex = NULL;
+PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB = NULL;
+PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB = NULL;
+PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB = NULL;
+PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB = NULL;
+PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB = NULL;
+PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB = NULL;
+PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB = NULL;
+PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB = NULL;
+PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB = NULL;
+PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB = NULL;
+PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB = NULL;
+PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB = NULL;
+PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB = NULL;
+PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB = NULL;
+PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB = NULL;
+PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB = NULL;
+PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB = NULL;
+PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB = NULL;
+PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB = NULL;
+PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB = NULL;
+PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glFramebufferSampleLocationsfvARB = NULL;
+PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC glad_glNamedFramebufferSampleLocationsfvARB = NULL;
+PFNGLEVALUATEDEPTHVALUESARBPROC glad_glEvaluateDepthValuesARB = NULL;
+PFNGLMINSAMPLESHADINGARBPROC glad_glMinSampleShadingARB = NULL;
+PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL;
+PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL;
+PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL;
+PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL;
+PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL;
+PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL;
+PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL;
+PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL;
+PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL;
+PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL;
+PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL;
+PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL;
+PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL;
+PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL;
+PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL;
+PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL;
+PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL;
+PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL;
+PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL;
+PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL;
+PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL;
+PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL;
+PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL;
+PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL;
+PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL;
+PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL;
+PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL;
+PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL;
+PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL;
+PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL;
+PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL;
+PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL;
+PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL;
+PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL;
+PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL;
+PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL;
+PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL;
+PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL;
+PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL;
+PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL;
+PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL;
+PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL;
+PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv = NULL;
+PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture = NULL;
+PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL;
+PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB = NULL;
+PFNGLGETHANDLEARBPROC glad_glGetHandleARB = NULL;
+PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB = NULL;
+PFNGLCREATESHADEROBJECTARBPROC glad_glCreateShaderObjectARB = NULL;
+PFNGLSHADERSOURCEARBPROC glad_glShaderSourceARB = NULL;
+PFNGLCOMPILESHADERARBPROC glad_glCompileShaderARB = NULL;
+PFNGLCREATEPROGRAMOBJECTARBPROC glad_glCreateProgramObjectARB = NULL;
+PFNGLATTACHOBJECTARBPROC glad_glAttachObjectARB = NULL;
+PFNGLLINKPROGRAMARBPROC glad_glLinkProgramARB = NULL;
+PFNGLUSEPROGRAMOBJECTARBPROC glad_glUseProgramObjectARB = NULL;
+PFNGLVALIDATEPROGRAMARBPROC glad_glValidateProgramARB = NULL;
+PFNGLUNIFORM1FARBPROC glad_glUniform1fARB = NULL;
+PFNGLUNIFORM2FARBPROC glad_glUniform2fARB = NULL;
+PFNGLUNIFORM3FARBPROC glad_glUniform3fARB = NULL;
+PFNGLUNIFORM4FARBPROC glad_glUniform4fARB = NULL;
+PFNGLUNIFORM1IARBPROC glad_glUniform1iARB = NULL;
+PFNGLUNIFORM2IARBPROC glad_glUniform2iARB = NULL;
+PFNGLUNIFORM3IARBPROC glad_glUniform3iARB = NULL;
+PFNGLUNIFORM4IARBPROC glad_glUniform4iARB = NULL;
+PFNGLUNIFORM1FVARBPROC glad_glUniform1fvARB = NULL;
+PFNGLUNIFORM2FVARBPROC glad_glUniform2fvARB = NULL;
+PFNGLUNIFORM3FVARBPROC glad_glUniform3fvARB = NULL;
+PFNGLUNIFORM4FVARBPROC glad_glUniform4fvARB = NULL;
+PFNGLUNIFORM1IVARBPROC glad_glUniform1ivARB = NULL;
+PFNGLUNIFORM2IVARBPROC glad_glUniform2ivARB = NULL;
+PFNGLUNIFORM3IVARBPROC glad_glUniform3ivARB = NULL;
+PFNGLUNIFORM4IVARBPROC glad_glUniform4ivARB = NULL;
+PFNGLUNIFORMMATRIX2FVARBPROC glad_glUniformMatrix2fvARB = NULL;
+PFNGLUNIFORMMATRIX3FVARBPROC glad_glUniformMatrix3fvARB = NULL;
+PFNGLUNIFORMMATRIX4FVARBPROC glad_glUniformMatrix4fvARB = NULL;
+PFNGLGETOBJECTPARAMETERFVARBPROC glad_glGetObjectParameterfvARB = NULL;
+PFNGLGETOBJECTPARAMETERIVARBPROC glad_glGetObjectParameterivARB = NULL;
+PFNGLGETINFOLOGARBPROC glad_glGetInfoLogARB = NULL;
+PFNGLGETATTACHEDOBJECTSARBPROC glad_glGetAttachedObjectsARB = NULL;
+PFNGLGETUNIFORMLOCATIONARBPROC glad_glGetUniformLocationARB = NULL;
+PFNGLGETACTIVEUNIFORMARBPROC glad_glGetActiveUniformARB = NULL;
+PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB = NULL;
+PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB = NULL;
+PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB = NULL;
+PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding = NULL;
+PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL;
+PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL;
+PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL;
+PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL;
+PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL;
+PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL;
+PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL;
+PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL;
+PFNGLNAMEDSTRINGARBPROC glad_glNamedStringARB = NULL;
+PFNGLDELETENAMEDSTRINGARBPROC glad_glDeleteNamedStringARB = NULL;
+PFNGLCOMPILESHADERINCLUDEARBPROC glad_glCompileShaderIncludeARB = NULL;
+PFNGLISNAMEDSTRINGARBPROC glad_glIsNamedStringARB = NULL;
+PFNGLGETNAMEDSTRINGARBPROC glad_glGetNamedStringARB = NULL;
+PFNGLGETNAMEDSTRINGIVARBPROC glad_glGetNamedStringivARB = NULL;
+PFNGLBUFFERPAGECOMMITMENTARBPROC glad_glBufferPageCommitmentARB = NULL;
+PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC glad_glNamedBufferPageCommitmentEXT = NULL;
+PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC glad_glNamedBufferPageCommitmentARB = NULL;
+PFNGLTEXPAGECOMMITMENTARBPROC glad_glTexPageCommitmentARB = NULL;
+PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL;
+PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL;
+PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier = NULL;
+PFNGLTEXBUFFERARBPROC glad_glTexBufferARB = NULL;
+PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange = NULL;
+PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glad_glCompressedTexImage3DARB = NULL;
+PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glad_glCompressedTexImage2DARB = NULL;
+PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glad_glCompressedTexImage1DARB = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glad_glCompressedTexSubImage3DARB = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glad_glCompressedTexSubImage2DARB = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glad_glCompressedTexSubImage1DARB = NULL;
+PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glad_glGetCompressedTexImageARB = NULL;
+PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D = NULL;
+PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL;
+PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL;
+PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample = NULL;
+PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL;
+PFNGLTEXTUREVIEWPROC glad_glTextureView = NULL;
+PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;
+PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL;
+PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;
+PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL;
+PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL;
+PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;
+PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL;
+PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL;
+PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL;
+PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL;
+PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL;
+PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced = NULL;
+PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced = NULL;
+PFNGLLOADTRANSPOSEMATRIXFARBPROC glad_glLoadTransposeMatrixfARB = NULL;
+PFNGLLOADTRANSPOSEMATRIXDARBPROC glad_glLoadTransposeMatrixdARB = NULL;
+PFNGLMULTTRANSPOSEMATRIXFARBPROC glad_glMultTransposeMatrixfARB = NULL;
+PFNGLMULTTRANSPOSEMATRIXDARBPROC glad_glMultTransposeMatrixdARB = NULL;
+PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL;
+PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL;
+PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL;
+PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL;
+PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL;
+PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL;
+PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL;
+PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL;
+PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL;
+PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL;
+PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer = NULL;
+PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat = NULL;
+PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat = NULL;
+PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat = NULL;
+PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding = NULL;
+PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor = NULL;
+PFNGLWEIGHTBVARBPROC glad_glWeightbvARB = NULL;
+PFNGLWEIGHTSVARBPROC glad_glWeightsvARB = NULL;
+PFNGLWEIGHTIVARBPROC glad_glWeightivARB = NULL;
+PFNGLWEIGHTFVARBPROC glad_glWeightfvARB = NULL;
+PFNGLWEIGHTDVARBPROC glad_glWeightdvARB = NULL;
+PFNGLWEIGHTUBVARBPROC glad_glWeightubvARB = NULL;
+PFNGLWEIGHTUSVARBPROC glad_glWeightusvARB = NULL;
+PFNGLWEIGHTUIVARBPROC glad_glWeightuivARB = NULL;
+PFNGLWEIGHTPOINTERARBPROC glad_glWeightPointerARB = NULL;
+PFNGLVERTEXBLENDARBPROC glad_glVertexBlendARB = NULL;
+PFNGLBINDBUFFERARBPROC glad_glBindBufferARB = NULL;
+PFNGLDELETEBUFFERSARBPROC glad_glDeleteBuffersARB = NULL;
+PFNGLGENBUFFERSARBPROC glad_glGenBuffersARB = NULL;
+PFNGLISBUFFERARBPROC glad_glIsBufferARB = NULL;
+PFNGLBUFFERDATAARBPROC glad_glBufferDataARB = NULL;
+PFNGLBUFFERSUBDATAARBPROC glad_glBufferSubDataARB = NULL;
+PFNGLGETBUFFERSUBDATAARBPROC glad_glGetBufferSubDataARB = NULL;
+PFNGLMAPBUFFERARBPROC glad_glMapBufferARB = NULL;
+PFNGLUNMAPBUFFERARBPROC glad_glUnmapBufferARB = NULL;
+PFNGLGETBUFFERPARAMETERIVARBPROC glad_glGetBufferParameterivARB = NULL;
+PFNGLGETBUFFERPOINTERVARBPROC glad_glGetBufferPointervARB = NULL;
+PFNGLVERTEXATTRIB1DARBPROC glad_glVertexAttrib1dARB = NULL;
+PFNGLVERTEXATTRIB1DVARBPROC glad_glVertexAttrib1dvARB = NULL;
+PFNGLVERTEXATTRIB1FARBPROC glad_glVertexAttrib1fARB = NULL;
+PFNGLVERTEXATTRIB1FVARBPROC glad_glVertexAttrib1fvARB = NULL;
+PFNGLVERTEXATTRIB1SARBPROC glad_glVertexAttrib1sARB = NULL;
+PFNGLVERTEXATTRIB1SVARBPROC glad_glVertexAttrib1svARB = NULL;
+PFNGLVERTEXATTRIB2DARBPROC glad_glVertexAttrib2dARB = NULL;
+PFNGLVERTEXATTRIB2DVARBPROC glad_glVertexAttrib2dvARB = NULL;
+PFNGLVERTEXATTRIB2FARBPROC glad_glVertexAttrib2fARB = NULL;
+PFNGLVERTEXATTRIB2FVARBPROC glad_glVertexAttrib2fvARB = NULL;
+PFNGLVERTEXATTRIB2SARBPROC glad_glVertexAttrib2sARB = NULL;
+PFNGLVERTEXATTRIB2SVARBPROC glad_glVertexAttrib2svARB = NULL;
+PFNGLVERTEXATTRIB3DARBPROC glad_glVertexAttrib3dARB = NULL;
+PFNGLVERTEXATTRIB3DVARBPROC glad_glVertexAttrib3dvARB = NULL;
+PFNGLVERTEXATTRIB3FARBPROC glad_glVertexAttrib3fARB = NULL;
+PFNGLVERTEXATTRIB3FVARBPROC glad_glVertexAttrib3fvARB = NULL;
+PFNGLVERTEXATTRIB3SARBPROC glad_glVertexAttrib3sARB = NULL;
+PFNGLVERTEXATTRIB3SVARBPROC glad_glVertexAttrib3svARB = NULL;
+PFNGLVERTEXATTRIB4NBVARBPROC glad_glVertexAttrib4NbvARB = NULL;
+PFNGLVERTEXATTRIB4NIVARBPROC glad_glVertexAttrib4NivARB = NULL;
+PFNGLVERTEXATTRIB4NSVARBPROC glad_glVertexAttrib4NsvARB = NULL;
+PFNGLVERTEXATTRIB4NUBARBPROC glad_glVertexAttrib4NubARB = NULL;
+PFNGLVERTEXATTRIB4NUBVARBPROC glad_glVertexAttrib4NubvARB = NULL;
+PFNGLVERTEXATTRIB4NUIVARBPROC glad_glVertexAttrib4NuivARB = NULL;
+PFNGLVERTEXATTRIB4NUSVARBPROC glad_glVertexAttrib4NusvARB = NULL;
+PFNGLVERTEXATTRIB4BVARBPROC glad_glVertexAttrib4bvARB = NULL;
+PFNGLVERTEXATTRIB4DARBPROC glad_glVertexAttrib4dARB = NULL;
+PFNGLVERTEXATTRIB4DVARBPROC glad_glVertexAttrib4dvARB = NULL;
+PFNGLVERTEXATTRIB4FARBPROC glad_glVertexAttrib4fARB = NULL;
+PFNGLVERTEXATTRIB4FVARBPROC glad_glVertexAttrib4fvARB = NULL;
+PFNGLVERTEXATTRIB4IVARBPROC glad_glVertexAttrib4ivARB = NULL;
+PFNGLVERTEXATTRIB4SARBPROC glad_glVertexAttrib4sARB = NULL;
+PFNGLVERTEXATTRIB4SVARBPROC glad_glVertexAttrib4svARB = NULL;
+PFNGLVERTEXATTRIB4UBVARBPROC glad_glVertexAttrib4ubvARB = NULL;
+PFNGLVERTEXATTRIB4UIVARBPROC glad_glVertexAttrib4uivARB = NULL;
+PFNGLVERTEXATTRIB4USVARBPROC glad_glVertexAttrib4usvARB = NULL;
+PFNGLVERTEXATTRIBPOINTERARBPROC glad_glVertexAttribPointerARB = NULL;
+PFNGLENABLEVERTEXATTRIBARRAYARBPROC glad_glEnableVertexAttribArrayARB = NULL;
+PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glad_glDisableVertexAttribArrayARB = NULL;
+PFNGLGETVERTEXATTRIBDVARBPROC glad_glGetVertexAttribdvARB = NULL;
+PFNGLGETVERTEXATTRIBFVARBPROC glad_glGetVertexAttribfvARB = NULL;
+PFNGLGETVERTEXATTRIBIVARBPROC glad_glGetVertexAttribivARB = NULL;
+PFNGLGETVERTEXATTRIBPOINTERVARBPROC glad_glGetVertexAttribPointervARB = NULL;
+PFNGLBINDATTRIBLOCATIONARBPROC glad_glBindAttribLocationARB = NULL;
+PFNGLGETACTIVEATTRIBARBPROC glad_glGetActiveAttribARB = NULL;
+PFNGLGETATTRIBLOCATIONARBPROC glad_glGetAttribLocationARB = NULL;
+PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL;
+PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;
+PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
+PFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL;
+PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL;
+PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL;
+PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL;
+PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL;
+PFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL;
+PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL;
+PFNGLWINDOWPOS2DARBPROC glad_glWindowPos2dARB = NULL;
+PFNGLWINDOWPOS2DVARBPROC glad_glWindowPos2dvARB = NULL;
+PFNGLWINDOWPOS2FARBPROC glad_glWindowPos2fARB = NULL;
+PFNGLWINDOWPOS2FVARBPROC glad_glWindowPos2fvARB = NULL;
+PFNGLWINDOWPOS2IARBPROC glad_glWindowPos2iARB = NULL;
+PFNGLWINDOWPOS2IVARBPROC glad_glWindowPos2ivARB = NULL;
+PFNGLWINDOWPOS2SARBPROC glad_glWindowPos2sARB = NULL;
+PFNGLWINDOWPOS2SVARBPROC glad_glWindowPos2svARB = NULL;
+PFNGLWINDOWPOS3DARBPROC glad_glWindowPos3dARB = NULL;
+PFNGLWINDOWPOS3DVARBPROC glad_glWindowPos3dvARB = NULL;
+PFNGLWINDOWPOS3FARBPROC glad_glWindowPos3fARB = NULL;
+PFNGLWINDOWPOS3FVARBPROC glad_glWindowPos3fvARB = NULL;
+PFNGLWINDOWPOS3IARBPROC glad_glWindowPos3iARB = NULL;
+PFNGLWINDOWPOS3IVARBPROC glad_glWindowPos3ivARB = NULL;
+PFNGLWINDOWPOS3SARBPROC glad_glWindowPos3sARB = NULL;
+PFNGLWINDOWPOS3SVARBPROC glad_glWindowPos3svARB = NULL;
+PFNGLDRAWBUFFERSATIPROC glad_glDrawBuffersATI = NULL;
+PFNGLELEMENTPOINTERATIPROC glad_glElementPointerATI = NULL;
+PFNGLDRAWELEMENTARRAYATIPROC glad_glDrawElementArrayATI = NULL;
+PFNGLDRAWRANGEELEMENTARRAYATIPROC glad_glDrawRangeElementArrayATI = NULL;
+PFNGLTEXBUMPPARAMETERIVATIPROC glad_glTexBumpParameterivATI = NULL;
+PFNGLTEXBUMPPARAMETERFVATIPROC glad_glTexBumpParameterfvATI = NULL;
+PFNGLGETTEXBUMPPARAMETERIVATIPROC glad_glGetTexBumpParameterivATI = NULL;
+PFNGLGETTEXBUMPPARAMETERFVATIPROC glad_glGetTexBumpParameterfvATI = NULL;
+PFNGLGENFRAGMENTSHADERSATIPROC glad_glGenFragmentShadersATI = NULL;
+PFNGLBINDFRAGMENTSHADERATIPROC glad_glBindFragmentShaderATI = NULL;
+PFNGLDELETEFRAGMENTSHADERATIPROC glad_glDeleteFragmentShaderATI = NULL;
+PFNGLBEGINFRAGMENTSHADERATIPROC glad_glBeginFragmentShaderATI = NULL;
+PFNGLENDFRAGMENTSHADERATIPROC glad_glEndFragmentShaderATI = NULL;
+PFNGLPASSTEXCOORDATIPROC glad_glPassTexCoordATI = NULL;
+PFNGLSAMPLEMAPATIPROC glad_glSampleMapATI = NULL;
+PFNGLCOLORFRAGMENTOP1ATIPROC glad_glColorFragmentOp1ATI = NULL;
+PFNGLCOLORFRAGMENTOP2ATIPROC glad_glColorFragmentOp2ATI = NULL;
+PFNGLCOLORFRAGMENTOP3ATIPROC glad_glColorFragmentOp3ATI = NULL;
+PFNGLALPHAFRAGMENTOP1ATIPROC glad_glAlphaFragmentOp1ATI = NULL;
+PFNGLALPHAFRAGMENTOP2ATIPROC glad_glAlphaFragmentOp2ATI = NULL;
+PFNGLALPHAFRAGMENTOP3ATIPROC glad_glAlphaFragmentOp3ATI = NULL;
+PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glad_glSetFragmentShaderConstantATI = NULL;
+PFNGLMAPOBJECTBUFFERATIPROC glad_glMapObjectBufferATI = NULL;
+PFNGLUNMAPOBJECTBUFFERATIPROC glad_glUnmapObjectBufferATI = NULL;
+PFNGLPNTRIANGLESIATIPROC glad_glPNTrianglesiATI = NULL;
+PFNGLPNTRIANGLESFATIPROC glad_glPNTrianglesfATI = NULL;
+PFNGLSTENCILOPSEPARATEATIPROC glad_glStencilOpSeparateATI = NULL;
+PFNGLSTENCILFUNCSEPARATEATIPROC glad_glStencilFuncSeparateATI = NULL;
+PFNGLNEWOBJECTBUFFERATIPROC glad_glNewObjectBufferATI = NULL;
+PFNGLISOBJECTBUFFERATIPROC glad_glIsObjectBufferATI = NULL;
+PFNGLUPDATEOBJECTBUFFERATIPROC glad_glUpdateObjectBufferATI = NULL;
+PFNGLGETOBJECTBUFFERFVATIPROC glad_glGetObjectBufferfvATI = NULL;
+PFNGLGETOBJECTBUFFERIVATIPROC glad_glGetObjectBufferivATI = NULL;
+PFNGLFREEOBJECTBUFFERATIPROC glad_glFreeObjectBufferATI = NULL;
+PFNGLARRAYOBJECTATIPROC glad_glArrayObjectATI = NULL;
+PFNGLGETARRAYOBJECTFVATIPROC glad_glGetArrayObjectfvATI = NULL;
+PFNGLGETARRAYOBJECTIVATIPROC glad_glGetArrayObjectivATI = NULL;
+PFNGLVARIANTARRAYOBJECTATIPROC glad_glVariantArrayObjectATI = NULL;
+PFNGLGETVARIANTARRAYOBJECTFVATIPROC glad_glGetVariantArrayObjectfvATI = NULL;
+PFNGLGETVARIANTARRAYOBJECTIVATIPROC glad_glGetVariantArrayObjectivATI = NULL;
+PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glad_glVertexAttribArrayObjectATI = NULL;
+PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC glad_glGetVertexAttribArrayObjectfvATI = NULL;
+PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC glad_glGetVertexAttribArrayObjectivATI = NULL;
+PFNGLVERTEXSTREAM1SATIPROC glad_glVertexStream1sATI = NULL;
+PFNGLVERTEXSTREAM1SVATIPROC glad_glVertexStream1svATI = NULL;
+PFNGLVERTEXSTREAM1IATIPROC glad_glVertexStream1iATI = NULL;
+PFNGLVERTEXSTREAM1IVATIPROC glad_glVertexStream1ivATI = NULL;
+PFNGLVERTEXSTREAM1FATIPROC glad_glVertexStream1fATI = NULL;
+PFNGLVERTEXSTREAM1FVATIPROC glad_glVertexStream1fvATI = NULL;
+PFNGLVERTEXSTREAM1DATIPROC glad_glVertexStream1dATI = NULL;
+PFNGLVERTEXSTREAM1DVATIPROC glad_glVertexStream1dvATI = NULL;
+PFNGLVERTEXSTREAM2SATIPROC glad_glVertexStream2sATI = NULL;
+PFNGLVERTEXSTREAM2SVATIPROC glad_glVertexStream2svATI = NULL;
+PFNGLVERTEXSTREAM2IATIPROC glad_glVertexStream2iATI = NULL;
+PFNGLVERTEXSTREAM2IVATIPROC glad_glVertexStream2ivATI = NULL;
+PFNGLVERTEXSTREAM2FATIPROC glad_glVertexStream2fATI = NULL;
+PFNGLVERTEXSTREAM2FVATIPROC glad_glVertexStream2fvATI = NULL;
+PFNGLVERTEXSTREAM2DATIPROC glad_glVertexStream2dATI = NULL;
+PFNGLVERTEXSTREAM2DVATIPROC glad_glVertexStream2dvATI = NULL;
+PFNGLVERTEXSTREAM3SATIPROC glad_glVertexStream3sATI = NULL;
+PFNGLVERTEXSTREAM3SVATIPROC glad_glVertexStream3svATI = NULL;
+PFNGLVERTEXSTREAM3IATIPROC glad_glVertexStream3iATI = NULL;
+PFNGLVERTEXSTREAM3IVATIPROC glad_glVertexStream3ivATI = NULL;
+PFNGLVERTEXSTREAM3FATIPROC glad_glVertexStream3fATI = NULL;
+PFNGLVERTEXSTREAM3FVATIPROC glad_glVertexStream3fvATI = NULL;
+PFNGLVERTEXSTREAM3DATIPROC glad_glVertexStream3dATI = NULL;
+PFNGLVERTEXSTREAM3DVATIPROC glad_glVertexStream3dvATI = NULL;
+PFNGLVERTEXSTREAM4SATIPROC glad_glVertexStream4sATI = NULL;
+PFNGLVERTEXSTREAM4SVATIPROC glad_glVertexStream4svATI = NULL;
+PFNGLVERTEXSTREAM4IATIPROC glad_glVertexStream4iATI = NULL;
+PFNGLVERTEXSTREAM4IVATIPROC glad_glVertexStream4ivATI = NULL;
+PFNGLVERTEXSTREAM4FATIPROC glad_glVertexStream4fATI = NULL;
+PFNGLVERTEXSTREAM4FVATIPROC glad_glVertexStream4fvATI = NULL;
+PFNGLVERTEXSTREAM4DATIPROC glad_glVertexStream4dATI = NULL;
+PFNGLVERTEXSTREAM4DVATIPROC glad_glVertexStream4dvATI = NULL;
+PFNGLNORMALSTREAM3BATIPROC glad_glNormalStream3bATI = NULL;
+PFNGLNORMALSTREAM3BVATIPROC glad_glNormalStream3bvATI = NULL;
+PFNGLNORMALSTREAM3SATIPROC glad_glNormalStream3sATI = NULL;
+PFNGLNORMALSTREAM3SVATIPROC glad_glNormalStream3svATI = NULL;
+PFNGLNORMALSTREAM3IATIPROC glad_glNormalStream3iATI = NULL;
+PFNGLNORMALSTREAM3IVATIPROC glad_glNormalStream3ivATI = NULL;
+PFNGLNORMALSTREAM3FATIPROC glad_glNormalStream3fATI = NULL;
+PFNGLNORMALSTREAM3FVATIPROC glad_glNormalStream3fvATI = NULL;
+PFNGLNORMALSTREAM3DATIPROC glad_glNormalStream3dATI = NULL;
+PFNGLNORMALSTREAM3DVATIPROC glad_glNormalStream3dvATI = NULL;
+PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC glad_glClientActiveVertexStreamATI = NULL;
+PFNGLVERTEXBLENDENVIATIPROC glad_glVertexBlendEnviATI = NULL;
+PFNGLVERTEXBLENDENVFATIPROC glad_glVertexBlendEnvfATI = NULL;
+PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC glad_glEGLImageTargetTexStorageEXT = NULL;
+PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC glad_glEGLImageTargetTextureStorageEXT = NULL;
+PFNGLUNIFORMBUFFEREXTPROC glad_glUniformBufferEXT = NULL;
+PFNGLGETUNIFORMBUFFERSIZEEXTPROC glad_glGetUniformBufferSizeEXT = NULL;
+PFNGLGETUNIFORMOFFSETEXTPROC glad_glGetUniformOffsetEXT = NULL;
+PFNGLBLENDCOLOREXTPROC glad_glBlendColorEXT = NULL;
+PFNGLBLENDEQUATIONSEPARATEEXTPROC glad_glBlendEquationSeparateEXT = NULL;
+PFNGLBLENDFUNCSEPARATEEXTPROC glad_glBlendFuncSeparateEXT = NULL;
+PFNGLBLENDEQUATIONEXTPROC glad_glBlendEquationEXT = NULL;
+PFNGLCOLORSUBTABLEEXTPROC glad_glColorSubTableEXT = NULL;
+PFNGLCOPYCOLORSUBTABLEEXTPROC glad_glCopyColorSubTableEXT = NULL;
+PFNGLLOCKARRAYSEXTPROC glad_glLockArraysEXT = NULL;
+PFNGLUNLOCKARRAYSEXTPROC glad_glUnlockArraysEXT = NULL;
+PFNGLCONVOLUTIONFILTER1DEXTPROC glad_glConvolutionFilter1DEXT = NULL;
+PFNGLCONVOLUTIONFILTER2DEXTPROC glad_glConvolutionFilter2DEXT = NULL;
+PFNGLCONVOLUTIONPARAMETERFEXTPROC glad_glConvolutionParameterfEXT = NULL;
+PFNGLCONVOLUTIONPARAMETERFVEXTPROC glad_glConvolutionParameterfvEXT = NULL;
+PFNGLCONVOLUTIONPARAMETERIEXTPROC glad_glConvolutionParameteriEXT = NULL;
+PFNGLCONVOLUTIONPARAMETERIVEXTPROC glad_glConvolutionParameterivEXT = NULL;
+PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC glad_glCopyConvolutionFilter1DEXT = NULL;
+PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC glad_glCopyConvolutionFilter2DEXT = NULL;
+PFNGLGETCONVOLUTIONFILTEREXTPROC glad_glGetConvolutionFilterEXT = NULL;
+PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC glad_glGetConvolutionParameterfvEXT = NULL;
+PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC glad_glGetConvolutionParameterivEXT = NULL;
+PFNGLGETSEPARABLEFILTEREXTPROC glad_glGetSeparableFilterEXT = NULL;
+PFNGLSEPARABLEFILTER2DEXTPROC glad_glSeparableFilter2DEXT = NULL;
+PFNGLTANGENT3BEXTPROC glad_glTangent3bEXT = NULL;
+PFNGLTANGENT3BVEXTPROC glad_glTangent3bvEXT = NULL;
+PFNGLTANGENT3DEXTPROC glad_glTangent3dEXT = NULL;
+PFNGLTANGENT3DVEXTPROC glad_glTangent3dvEXT = NULL;
+PFNGLTANGENT3FEXTPROC glad_glTangent3fEXT = NULL;
+PFNGLTANGENT3FVEXTPROC glad_glTangent3fvEXT = NULL;
+PFNGLTANGENT3IEXTPROC glad_glTangent3iEXT = NULL;
+PFNGLTANGENT3IVEXTPROC glad_glTangent3ivEXT = NULL;
+PFNGLTANGENT3SEXTPROC glad_glTangent3sEXT = NULL;
+PFNGLTANGENT3SVEXTPROC glad_glTangent3svEXT = NULL;
+PFNGLBINORMAL3BEXTPROC glad_glBinormal3bEXT = NULL;
+PFNGLBINORMAL3BVEXTPROC glad_glBinormal3bvEXT = NULL;
+PFNGLBINORMAL3DEXTPROC glad_glBinormal3dEXT = NULL;
+PFNGLBINORMAL3DVEXTPROC glad_glBinormal3dvEXT = NULL;
+PFNGLBINORMAL3FEXTPROC glad_glBinormal3fEXT = NULL;
+PFNGLBINORMAL3FVEXTPROC glad_glBinormal3fvEXT = NULL;
+PFNGLBINORMAL3IEXTPROC glad_glBinormal3iEXT = NULL;
+PFNGLBINORMAL3IVEXTPROC glad_glBinormal3ivEXT = NULL;
+PFNGLBINORMAL3SEXTPROC glad_glBinormal3sEXT = NULL;
+PFNGLBINORMAL3SVEXTPROC glad_glBinormal3svEXT = NULL;
+PFNGLTANGENTPOINTEREXTPROC glad_glTangentPointerEXT = NULL;
+PFNGLBINORMALPOINTEREXTPROC glad_glBinormalPointerEXT = NULL;
+PFNGLCOPYTEXIMAGE1DEXTPROC glad_glCopyTexImage1DEXT = NULL;
+PFNGLCOPYTEXIMAGE2DEXTPROC glad_glCopyTexImage2DEXT = NULL;
+PFNGLCOPYTEXSUBIMAGE1DEXTPROC glad_glCopyTexSubImage1DEXT = NULL;
+PFNGLCOPYTEXSUBIMAGE2DEXTPROC glad_glCopyTexSubImage2DEXT = NULL;
+PFNGLCOPYTEXSUBIMAGE3DEXTPROC glad_glCopyTexSubImage3DEXT = NULL;
+PFNGLCULLPARAMETERDVEXTPROC glad_glCullParameterdvEXT = NULL;
+PFNGLCULLPARAMETERFVEXTPROC glad_glCullParameterfvEXT = NULL;
+PFNGLLABELOBJECTEXTPROC glad_glLabelObjectEXT = NULL;
+PFNGLGETOBJECTLABELEXTPROC glad_glGetObjectLabelEXT = NULL;
+PFNGLINSERTEVENTMARKEREXTPROC glad_glInsertEventMarkerEXT = NULL;
+PFNGLPUSHGROUPMARKEREXTPROC glad_glPushGroupMarkerEXT = NULL;
+PFNGLPOPGROUPMARKEREXTPROC glad_glPopGroupMarkerEXT = NULL;
+PFNGLDEPTHBOUNDSEXTPROC glad_glDepthBoundsEXT = NULL;
+PFNGLMATRIXLOADFEXTPROC glad_glMatrixLoadfEXT = NULL;
+PFNGLMATRIXLOADDEXTPROC glad_glMatrixLoaddEXT = NULL;
+PFNGLMATRIXMULTFEXTPROC glad_glMatrixMultfEXT = NULL;
+PFNGLMATRIXMULTDEXTPROC glad_glMatrixMultdEXT = NULL;
+PFNGLMATRIXLOADIDENTITYEXTPROC glad_glMatrixLoadIdentityEXT = NULL;
+PFNGLMATRIXROTATEFEXTPROC glad_glMatrixRotatefEXT = NULL;
+PFNGLMATRIXROTATEDEXTPROC glad_glMatrixRotatedEXT = NULL;
+PFNGLMATRIXSCALEFEXTPROC glad_glMatrixScalefEXT = NULL;
+PFNGLMATRIXSCALEDEXTPROC glad_glMatrixScaledEXT = NULL;
+PFNGLMATRIXTRANSLATEFEXTPROC glad_glMatrixTranslatefEXT = NULL;
+PFNGLMATRIXTRANSLATEDEXTPROC glad_glMatrixTranslatedEXT = NULL;
+PFNGLMATRIXFRUSTUMEXTPROC glad_glMatrixFrustumEXT = NULL;
+PFNGLMATRIXORTHOEXTPROC glad_glMatrixOrthoEXT = NULL;
+PFNGLMATRIXPOPEXTPROC glad_glMatrixPopEXT = NULL;
+PFNGLMATRIXPUSHEXTPROC glad_glMatrixPushEXT = NULL;
+PFNGLCLIENTATTRIBDEFAULTEXTPROC glad_glClientAttribDefaultEXT = NULL;
+PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC glad_glPushClientAttribDefaultEXT = NULL;
+PFNGLTEXTUREPARAMETERFEXTPROC glad_glTextureParameterfEXT = NULL;
+PFNGLTEXTUREPARAMETERFVEXTPROC glad_glTextureParameterfvEXT = NULL;
+PFNGLTEXTUREPARAMETERIEXTPROC glad_glTextureParameteriEXT = NULL;
+PFNGLTEXTUREPARAMETERIVEXTPROC glad_glTextureParameterivEXT = NULL;
+PFNGLTEXTUREIMAGE1DEXTPROC glad_glTextureImage1DEXT = NULL;
+PFNGLTEXTUREIMAGE2DEXTPROC glad_glTextureImage2DEXT = NULL;
+PFNGLTEXTURESUBIMAGE1DEXTPROC glad_glTextureSubImage1DEXT = NULL;
+PFNGLTEXTURESUBIMAGE2DEXTPROC glad_glTextureSubImage2DEXT = NULL;
+PFNGLCOPYTEXTUREIMAGE1DEXTPROC glad_glCopyTextureImage1DEXT = NULL;
+PFNGLCOPYTEXTUREIMAGE2DEXTPROC glad_glCopyTextureImage2DEXT = NULL;
+PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC glad_glCopyTextureSubImage1DEXT = NULL;
+PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC glad_glCopyTextureSubImage2DEXT = NULL;
+PFNGLGETTEXTUREIMAGEEXTPROC glad_glGetTextureImageEXT = NULL;
+PFNGLGETTEXTUREPARAMETERFVEXTPROC glad_glGetTextureParameterfvEXT = NULL;
+PFNGLGETTEXTUREPARAMETERIVEXTPROC glad_glGetTextureParameterivEXT = NULL;
+PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC glad_glGetTextureLevelParameterfvEXT = NULL;
+PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC glad_glGetTextureLevelParameterivEXT = NULL;
+PFNGLTEXTUREIMAGE3DEXTPROC glad_glTextureImage3DEXT = NULL;
+PFNGLTEXTURESUBIMAGE3DEXTPROC glad_glTextureSubImage3DEXT = NULL;
+PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC glad_glCopyTextureSubImage3DEXT = NULL;
+PFNGLBINDMULTITEXTUREEXTPROC glad_glBindMultiTextureEXT = NULL;
+PFNGLMULTITEXCOORDPOINTEREXTPROC glad_glMultiTexCoordPointerEXT = NULL;
+PFNGLMULTITEXENVFEXTPROC glad_glMultiTexEnvfEXT = NULL;
+PFNGLMULTITEXENVFVEXTPROC glad_glMultiTexEnvfvEXT = NULL;
+PFNGLMULTITEXENVIEXTPROC glad_glMultiTexEnviEXT = NULL;
+PFNGLMULTITEXENVIVEXTPROC glad_glMultiTexEnvivEXT = NULL;
+PFNGLMULTITEXGENDEXTPROC glad_glMultiTexGendEXT = NULL;
+PFNGLMULTITEXGENDVEXTPROC glad_glMultiTexGendvEXT = NULL;
+PFNGLMULTITEXGENFEXTPROC glad_glMultiTexGenfEXT = NULL;
+PFNGLMULTITEXGENFVEXTPROC glad_glMultiTexGenfvEXT = NULL;
+PFNGLMULTITEXGENIEXTPROC glad_glMultiTexGeniEXT = NULL;
+PFNGLMULTITEXGENIVEXTPROC glad_glMultiTexGenivEXT = NULL;
+PFNGLGETMULTITEXENVFVEXTPROC glad_glGetMultiTexEnvfvEXT = NULL;
+PFNGLGETMULTITEXENVIVEXTPROC glad_glGetMultiTexEnvivEXT = NULL;
+PFNGLGETMULTITEXGENDVEXTPROC glad_glGetMultiTexGendvEXT = NULL;
+PFNGLGETMULTITEXGENFVEXTPROC glad_glGetMultiTexGenfvEXT = NULL;
+PFNGLGETMULTITEXGENIVEXTPROC glad_glGetMultiTexGenivEXT = NULL;
+PFNGLMULTITEXPARAMETERIEXTPROC glad_glMultiTexParameteriEXT = NULL;
+PFNGLMULTITEXPARAMETERIVEXTPROC glad_glMultiTexParameterivEXT = NULL;
+PFNGLMULTITEXPARAMETERFEXTPROC glad_glMultiTexParameterfEXT = NULL;
+PFNGLMULTITEXPARAMETERFVEXTPROC glad_glMultiTexParameterfvEXT = NULL;
+PFNGLMULTITEXIMAGE1DEXTPROC glad_glMultiTexImage1DEXT = NULL;
+PFNGLMULTITEXIMAGE2DEXTPROC glad_glMultiTexImage2DEXT = NULL;
+PFNGLMULTITEXSUBIMAGE1DEXTPROC glad_glMultiTexSubImage1DEXT = NULL;
+PFNGLMULTITEXSUBIMAGE2DEXTPROC glad_glMultiTexSubImage2DEXT = NULL;
+PFNGLCOPYMULTITEXIMAGE1DEXTPROC glad_glCopyMultiTexImage1DEXT = NULL;
+PFNGLCOPYMULTITEXIMAGE2DEXTPROC glad_glCopyMultiTexImage2DEXT = NULL;
+PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC glad_glCopyMultiTexSubImage1DEXT = NULL;
+PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC glad_glCopyMultiTexSubImage2DEXT = NULL;
+PFNGLGETMULTITEXIMAGEEXTPROC glad_glGetMultiTexImageEXT = NULL;
+PFNGLGETMULTITEXPARAMETERFVEXTPROC glad_glGetMultiTexParameterfvEXT = NULL;
+PFNGLGETMULTITEXPARAMETERIVEXTPROC glad_glGetMultiTexParameterivEXT = NULL;
+PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC glad_glGetMultiTexLevelParameterfvEXT = NULL;
+PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC glad_glGetMultiTexLevelParameterivEXT = NULL;
+PFNGLMULTITEXIMAGE3DEXTPROC glad_glMultiTexImage3DEXT = NULL;
+PFNGLMULTITEXSUBIMAGE3DEXTPROC glad_glMultiTexSubImage3DEXT = NULL;
+PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC glad_glCopyMultiTexSubImage3DEXT = NULL;
+PFNGLENABLECLIENTSTATEINDEXEDEXTPROC glad_glEnableClientStateIndexedEXT = NULL;
+PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC glad_glDisableClientStateIndexedEXT = NULL;
+PFNGLGETFLOATINDEXEDVEXTPROC glad_glGetFloatIndexedvEXT = NULL;
+PFNGLGETDOUBLEINDEXEDVEXTPROC glad_glGetDoubleIndexedvEXT = NULL;
+PFNGLGETPOINTERINDEXEDVEXTPROC glad_glGetPointerIndexedvEXT = NULL;
+PFNGLENABLEINDEXEDEXTPROC glad_glEnableIndexedEXT = NULL;
+PFNGLDISABLEINDEXEDEXTPROC glad_glDisableIndexedEXT = NULL;
+PFNGLISENABLEDINDEXEDEXTPROC glad_glIsEnabledIndexedEXT = NULL;
+PFNGLGETINTEGERINDEXEDVEXTPROC glad_glGetIntegerIndexedvEXT = NULL;
+PFNGLGETBOOLEANINDEXEDVEXTPROC glad_glGetBooleanIndexedvEXT = NULL;
+PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC glad_glCompressedTextureImage3DEXT = NULL;
+PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC glad_glCompressedTextureImage2DEXT = NULL;
+PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC glad_glCompressedTextureImage1DEXT = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC glad_glCompressedTextureSubImage3DEXT = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC glad_glCompressedTextureSubImage2DEXT = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC glad_glCompressedTextureSubImage1DEXT = NULL;
+PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC glad_glGetCompressedTextureImageEXT = NULL;
+PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC glad_glCompressedMultiTexImage3DEXT = NULL;
+PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC glad_glCompressedMultiTexImage2DEXT = NULL;
+PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC glad_glCompressedMultiTexImage1DEXT = NULL;
+PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC glad_glCompressedMultiTexSubImage3DEXT = NULL;
+PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC glad_glCompressedMultiTexSubImage2DEXT = NULL;
+PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC glad_glCompressedMultiTexSubImage1DEXT = NULL;
+PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC glad_glGetCompressedMultiTexImageEXT = NULL;
+PFNGLMATRIXLOADTRANSPOSEFEXTPROC glad_glMatrixLoadTransposefEXT = NULL;
+PFNGLMATRIXLOADTRANSPOSEDEXTPROC glad_glMatrixLoadTransposedEXT = NULL;
+PFNGLMATRIXMULTTRANSPOSEFEXTPROC glad_glMatrixMultTransposefEXT = NULL;
+PFNGLMATRIXMULTTRANSPOSEDEXTPROC glad_glMatrixMultTransposedEXT = NULL;
+PFNGLNAMEDBUFFERDATAEXTPROC glad_glNamedBufferDataEXT = NULL;
+PFNGLNAMEDBUFFERSUBDATAEXTPROC glad_glNamedBufferSubDataEXT = NULL;
+PFNGLMAPNAMEDBUFFEREXTPROC glad_glMapNamedBufferEXT = NULL;
+PFNGLUNMAPNAMEDBUFFEREXTPROC glad_glUnmapNamedBufferEXT = NULL;
+PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC glad_glGetNamedBufferParameterivEXT = NULL;
+PFNGLGETNAMEDBUFFERPOINTERVEXTPROC glad_glGetNamedBufferPointervEXT = NULL;
+PFNGLGETNAMEDBUFFERSUBDATAEXTPROC glad_glGetNamedBufferSubDataEXT = NULL;
+PFNGLPROGRAMUNIFORM1FEXTPROC glad_glProgramUniform1fEXT = NULL;
+PFNGLPROGRAMUNIFORM2FEXTPROC glad_glProgramUniform2fEXT = NULL;
+PFNGLPROGRAMUNIFORM3FEXTPROC glad_glProgramUniform3fEXT = NULL;
+PFNGLPROGRAMUNIFORM4FEXTPROC glad_glProgramUniform4fEXT = NULL;
+PFNGLPROGRAMUNIFORM1IEXTPROC glad_glProgramUniform1iEXT = NULL;
+PFNGLPROGRAMUNIFORM2IEXTPROC glad_glProgramUniform2iEXT = NULL;
+PFNGLPROGRAMUNIFORM3IEXTPROC glad_glProgramUniform3iEXT = NULL;
+PFNGLPROGRAMUNIFORM4IEXTPROC glad_glProgramUniform4iEXT = NULL;
+PFNGLPROGRAMUNIFORM1FVEXTPROC glad_glProgramUniform1fvEXT = NULL;
+PFNGLPROGRAMUNIFORM2FVEXTPROC glad_glProgramUniform2fvEXT = NULL;
+PFNGLPROGRAMUNIFORM3FVEXTPROC glad_glProgramUniform3fvEXT = NULL;
+PFNGLPROGRAMUNIFORM4FVEXTPROC glad_glProgramUniform4fvEXT = NULL;
+PFNGLPROGRAMUNIFORM1IVEXTPROC glad_glProgramUniform1ivEXT = NULL;
+PFNGLPROGRAMUNIFORM2IVEXTPROC glad_glProgramUniform2ivEXT = NULL;
+PFNGLPROGRAMUNIFORM3IVEXTPROC glad_glProgramUniform3ivEXT = NULL;
+PFNGLPROGRAMUNIFORM4IVEXTPROC glad_glProgramUniform4ivEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC glad_glProgramUniformMatrix2fvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC glad_glProgramUniformMatrix3fvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC glad_glProgramUniformMatrix4fvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC glad_glProgramUniformMatrix2x3fvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC glad_glProgramUniformMatrix3x2fvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC glad_glProgramUniformMatrix2x4fvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC glad_glProgramUniformMatrix4x2fvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC glad_glProgramUniformMatrix3x4fvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC glad_glProgramUniformMatrix4x3fvEXT = NULL;
+PFNGLTEXTUREBUFFEREXTPROC glad_glTextureBufferEXT = NULL;
+PFNGLMULTITEXBUFFEREXTPROC glad_glMultiTexBufferEXT = NULL;
+PFNGLTEXTUREPARAMETERIIVEXTPROC glad_glTextureParameterIivEXT = NULL;
+PFNGLTEXTUREPARAMETERIUIVEXTPROC glad_glTextureParameterIuivEXT = NULL;
+PFNGLGETTEXTUREPARAMETERIIVEXTPROC glad_glGetTextureParameterIivEXT = NULL;
+PFNGLGETTEXTUREPARAMETERIUIVEXTPROC glad_glGetTextureParameterIuivEXT = NULL;
+PFNGLMULTITEXPARAMETERIIVEXTPROC glad_glMultiTexParameterIivEXT = NULL;
+PFNGLMULTITEXPARAMETERIUIVEXTPROC glad_glMultiTexParameterIuivEXT = NULL;
+PFNGLGETMULTITEXPARAMETERIIVEXTPROC glad_glGetMultiTexParameterIivEXT = NULL;
+PFNGLGETMULTITEXPARAMETERIUIVEXTPROC glad_glGetMultiTexParameterIuivEXT = NULL;
+PFNGLPROGRAMUNIFORM1UIEXTPROC glad_glProgramUniform1uiEXT = NULL;
+PFNGLPROGRAMUNIFORM2UIEXTPROC glad_glProgramUniform2uiEXT = NULL;
+PFNGLPROGRAMUNIFORM3UIEXTPROC glad_glProgramUniform3uiEXT = NULL;
+PFNGLPROGRAMUNIFORM4UIEXTPROC glad_glProgramUniform4uiEXT = NULL;
+PFNGLPROGRAMUNIFORM1UIVEXTPROC glad_glProgramUniform1uivEXT = NULL;
+PFNGLPROGRAMUNIFORM2UIVEXTPROC glad_glProgramUniform2uivEXT = NULL;
+PFNGLPROGRAMUNIFORM3UIVEXTPROC glad_glProgramUniform3uivEXT = NULL;
+PFNGLPROGRAMUNIFORM4UIVEXTPROC glad_glProgramUniform4uivEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC glad_glNamedProgramLocalParameters4fvEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC glad_glNamedProgramLocalParameterI4iEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC glad_glNamedProgramLocalParameterI4ivEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC glad_glNamedProgramLocalParametersI4ivEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC glad_glNamedProgramLocalParameterI4uiEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC glad_glNamedProgramLocalParameterI4uivEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC glad_glNamedProgramLocalParametersI4uivEXT = NULL;
+PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC glad_glGetNamedProgramLocalParameterIivEXT = NULL;
+PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC glad_glGetNamedProgramLocalParameterIuivEXT = NULL;
+PFNGLENABLECLIENTSTATEIEXTPROC glad_glEnableClientStateiEXT = NULL;
+PFNGLDISABLECLIENTSTATEIEXTPROC glad_glDisableClientStateiEXT = NULL;
+PFNGLGETFLOATI_VEXTPROC glad_glGetFloati_vEXT = NULL;
+PFNGLGETDOUBLEI_VEXTPROC glad_glGetDoublei_vEXT = NULL;
+PFNGLGETPOINTERI_VEXTPROC glad_glGetPointeri_vEXT = NULL;
+PFNGLNAMEDPROGRAMSTRINGEXTPROC glad_glNamedProgramStringEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC glad_glNamedProgramLocalParameter4dEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC glad_glNamedProgramLocalParameter4dvEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC glad_glNamedProgramLocalParameter4fEXT = NULL;
+PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC glad_glNamedProgramLocalParameter4fvEXT = NULL;
+PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC glad_glGetNamedProgramLocalParameterdvEXT = NULL;
+PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC glad_glGetNamedProgramLocalParameterfvEXT = NULL;
+PFNGLGETNAMEDPROGRAMIVEXTPROC glad_glGetNamedProgramivEXT = NULL;
+PFNGLGETNAMEDPROGRAMSTRINGEXTPROC glad_glGetNamedProgramStringEXT = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC glad_glNamedRenderbufferStorageEXT = NULL;
+PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC glad_glGetNamedRenderbufferParameterivEXT = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glNamedRenderbufferStorageMultisampleEXT = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC glad_glNamedRenderbufferStorageMultisampleCoverageEXT = NULL;
+PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC glad_glCheckNamedFramebufferStatusEXT = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC glad_glNamedFramebufferTexture1DEXT = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC glad_glNamedFramebufferTexture2DEXT = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC glad_glNamedFramebufferTexture3DEXT = NULL;
+PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC glad_glNamedFramebufferRenderbufferEXT = NULL;
+PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetNamedFramebufferAttachmentParameterivEXT = NULL;
+PFNGLGENERATETEXTUREMIPMAPEXTPROC glad_glGenerateTextureMipmapEXT = NULL;
+PFNGLGENERATEMULTITEXMIPMAPEXTPROC glad_glGenerateMultiTexMipmapEXT = NULL;
+PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC glad_glFramebufferDrawBufferEXT = NULL;
+PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC glad_glFramebufferDrawBuffersEXT = NULL;
+PFNGLFRAMEBUFFERREADBUFFEREXTPROC glad_glFramebufferReadBufferEXT = NULL;
+PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC glad_glGetFramebufferParameterivEXT = NULL;
+PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC glad_glNamedCopyBufferSubDataEXT = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC glad_glNamedFramebufferTextureEXT = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC glad_glNamedFramebufferTextureLayerEXT = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC glad_glNamedFramebufferTextureFaceEXT = NULL;
+PFNGLTEXTURERENDERBUFFEREXTPROC glad_glTextureRenderbufferEXT = NULL;
+PFNGLMULTITEXRENDERBUFFEREXTPROC glad_glMultiTexRenderbufferEXT = NULL;
+PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC glad_glVertexArrayVertexOffsetEXT = NULL;
+PFNGLVERTEXARRAYCOLOROFFSETEXTPROC glad_glVertexArrayColorOffsetEXT = NULL;
+PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC glad_glVertexArrayEdgeFlagOffsetEXT = NULL;
+PFNGLVERTEXARRAYINDEXOFFSETEXTPROC glad_glVertexArrayIndexOffsetEXT = NULL;
+PFNGLVERTEXARRAYNORMALOFFSETEXTPROC glad_glVertexArrayNormalOffsetEXT = NULL;
+PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC glad_glVertexArrayTexCoordOffsetEXT = NULL;
+PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC glad_glVertexArrayMultiTexCoordOffsetEXT = NULL;
+PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC glad_glVertexArrayFogCoordOffsetEXT = NULL;
+PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC glad_glVertexArraySecondaryColorOffsetEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC glad_glVertexArrayVertexAttribOffsetEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC glad_glVertexArrayVertexAttribIOffsetEXT = NULL;
+PFNGLENABLEVERTEXARRAYEXTPROC glad_glEnableVertexArrayEXT = NULL;
+PFNGLDISABLEVERTEXARRAYEXTPROC glad_glDisableVertexArrayEXT = NULL;
+PFNGLENABLEVERTEXARRAYATTRIBEXTPROC glad_glEnableVertexArrayAttribEXT = NULL;
+PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC glad_glDisableVertexArrayAttribEXT = NULL;
+PFNGLGETVERTEXARRAYINTEGERVEXTPROC glad_glGetVertexArrayIntegervEXT = NULL;
+PFNGLGETVERTEXARRAYPOINTERVEXTPROC glad_glGetVertexArrayPointervEXT = NULL;
+PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC glad_glGetVertexArrayIntegeri_vEXT = NULL;
+PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC glad_glGetVertexArrayPointeri_vEXT = NULL;
+PFNGLMAPNAMEDBUFFERRANGEEXTPROC glad_glMapNamedBufferRangeEXT = NULL;
+PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC glad_glFlushMappedNamedBufferRangeEXT = NULL;
+PFNGLNAMEDBUFFERSTORAGEEXTPROC glad_glNamedBufferStorageEXT = NULL;
+PFNGLCLEARNAMEDBUFFERDATAEXTPROC glad_glClearNamedBufferDataEXT = NULL;
+PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC glad_glClearNamedBufferSubDataEXT = NULL;
+PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC glad_glNamedFramebufferParameteriEXT = NULL;
+PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC glad_glGetNamedFramebufferParameterivEXT = NULL;
+PFNGLPROGRAMUNIFORM1DEXTPROC glad_glProgramUniform1dEXT = NULL;
+PFNGLPROGRAMUNIFORM2DEXTPROC glad_glProgramUniform2dEXT = NULL;
+PFNGLPROGRAMUNIFORM3DEXTPROC glad_glProgramUniform3dEXT = NULL;
+PFNGLPROGRAMUNIFORM4DEXTPROC glad_glProgramUniform4dEXT = NULL;
+PFNGLPROGRAMUNIFORM1DVEXTPROC glad_glProgramUniform1dvEXT = NULL;
+PFNGLPROGRAMUNIFORM2DVEXTPROC glad_glProgramUniform2dvEXT = NULL;
+PFNGLPROGRAMUNIFORM3DVEXTPROC glad_glProgramUniform3dvEXT = NULL;
+PFNGLPROGRAMUNIFORM4DVEXTPROC glad_glProgramUniform4dvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC glad_glProgramUniformMatrix2dvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC glad_glProgramUniformMatrix3dvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC glad_glProgramUniformMatrix4dvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC glad_glProgramUniformMatrix2x3dvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC glad_glProgramUniformMatrix2x4dvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC glad_glProgramUniformMatrix3x2dvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC glad_glProgramUniformMatrix3x4dvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC glad_glProgramUniformMatrix4x2dvEXT = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC glad_glProgramUniformMatrix4x3dvEXT = NULL;
+PFNGLTEXTUREBUFFERRANGEEXTPROC glad_glTextureBufferRangeEXT = NULL;
+PFNGLTEXTURESTORAGE1DEXTPROC glad_glTextureStorage1DEXT = NULL;
+PFNGLTEXTURESTORAGE2DEXTPROC glad_glTextureStorage2DEXT = NULL;
+PFNGLTEXTURESTORAGE3DEXTPROC glad_glTextureStorage3DEXT = NULL;
+PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC glad_glTextureStorage2DMultisampleEXT = NULL;
+PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC glad_glTextureStorage3DMultisampleEXT = NULL;
+PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC glad_glVertexArrayBindVertexBufferEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC glad_glVertexArrayVertexAttribFormatEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC glad_glVertexArrayVertexAttribIFormatEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC glad_glVertexArrayVertexAttribLFormatEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC glad_glVertexArrayVertexAttribBindingEXT = NULL;
+PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC glad_glVertexArrayVertexBindingDivisorEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC glad_glVertexArrayVertexAttribLOffsetEXT = NULL;
+PFNGLTEXTUREPAGECOMMITMENTEXTPROC glad_glTexturePageCommitmentEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC glad_glVertexArrayVertexAttribDivisorEXT = NULL;
+PFNGLCOLORMASKINDEXEDEXTPROC glad_glColorMaskIndexedEXT = NULL;
+PFNGLDRAWARRAYSINSTANCEDEXTPROC glad_glDrawArraysInstancedEXT = NULL;
+PFNGLDRAWELEMENTSINSTANCEDEXTPROC glad_glDrawElementsInstancedEXT = NULL;
+PFNGLDRAWRANGEELEMENTSEXTPROC glad_glDrawRangeElementsEXT = NULL;
+PFNGLBUFFERSTORAGEEXTERNALEXTPROC glad_glBufferStorageExternalEXT = NULL;
+PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC glad_glNamedBufferStorageExternalEXT = NULL;
+PFNGLFOGCOORDFEXTPROC glad_glFogCoordfEXT = NULL;
+PFNGLFOGCOORDFVEXTPROC glad_glFogCoordfvEXT = NULL;
+PFNGLFOGCOORDDEXTPROC glad_glFogCoorddEXT = NULL;
+PFNGLFOGCOORDDVEXTPROC glad_glFogCoorddvEXT = NULL;
+PFNGLFOGCOORDPOINTEREXTPROC glad_glFogCoordPointerEXT = NULL;
+PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT = NULL;
+PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT = NULL;
+PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT = NULL;
+PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT = NULL;
+PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT = NULL;
+PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT = NULL;
+PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT = NULL;
+PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT = NULL;
+PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT = NULL;
+PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT = NULL;
+PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT = NULL;
+PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL;
+PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL;
+PFNGLPROGRAMPARAMETERIEXTPROC glad_glProgramParameteriEXT = NULL;
+PFNGLPROGRAMENVPARAMETERS4FVEXTPROC glad_glProgramEnvParameters4fvEXT = NULL;
+PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC glad_glProgramLocalParameters4fvEXT = NULL;
+PFNGLGETUNIFORMUIVEXTPROC glad_glGetUniformuivEXT = NULL;
+PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT = NULL;
+PFNGLGETFRAGDATALOCATIONEXTPROC glad_glGetFragDataLocationEXT = NULL;
+PFNGLUNIFORM1UIEXTPROC glad_glUniform1uiEXT = NULL;
+PFNGLUNIFORM2UIEXTPROC glad_glUniform2uiEXT = NULL;
+PFNGLUNIFORM3UIEXTPROC glad_glUniform3uiEXT = NULL;
+PFNGLUNIFORM4UIEXTPROC glad_glUniform4uiEXT = NULL;
+PFNGLUNIFORM1UIVEXTPROC glad_glUniform1uivEXT = NULL;
+PFNGLUNIFORM2UIVEXTPROC glad_glUniform2uivEXT = NULL;
+PFNGLUNIFORM3UIVEXTPROC glad_glUniform3uivEXT = NULL;
+PFNGLUNIFORM4UIVEXTPROC glad_glUniform4uivEXT = NULL;
+PFNGLGETHISTOGRAMEXTPROC glad_glGetHistogramEXT = NULL;
+PFNGLGETHISTOGRAMPARAMETERFVEXTPROC glad_glGetHistogramParameterfvEXT = NULL;
+PFNGLGETHISTOGRAMPARAMETERIVEXTPROC glad_glGetHistogramParameterivEXT = NULL;
+PFNGLGETMINMAXEXTPROC glad_glGetMinmaxEXT = NULL;
+PFNGLGETMINMAXPARAMETERFVEXTPROC glad_glGetMinmaxParameterfvEXT = NULL;
+PFNGLGETMINMAXPARAMETERIVEXTPROC glad_glGetMinmaxParameterivEXT = NULL;
+PFNGLHISTOGRAMEXTPROC glad_glHistogramEXT = NULL;
+PFNGLMINMAXEXTPROC glad_glMinmaxEXT = NULL;
+PFNGLRESETHISTOGRAMEXTPROC glad_glResetHistogramEXT = NULL;
+PFNGLRESETMINMAXEXTPROC glad_glResetMinmaxEXT = NULL;
+PFNGLINDEXFUNCEXTPROC glad_glIndexFuncEXT = NULL;
+PFNGLINDEXMATERIALEXTPROC glad_glIndexMaterialEXT = NULL;
+PFNGLAPPLYTEXTUREEXTPROC glad_glApplyTextureEXT = NULL;
+PFNGLTEXTURELIGHTEXTPROC glad_glTextureLightEXT = NULL;
+PFNGLTEXTUREMATERIALEXTPROC glad_glTextureMaterialEXT = NULL;
+PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT = NULL;
+PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT = NULL;
+PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT = NULL;
+PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT = NULL;
+PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT = NULL;
+PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT = NULL;
+PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT = NULL;
+PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT = NULL;
+PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT = NULL;
+PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT = NULL;
+PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT = NULL;
+PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT = NULL;
+PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT = NULL;
+PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT = NULL;
+PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT = NULL;
+PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT = NULL;
+PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT = NULL;
+PFNGLTEXSTORAGEMEM1DEXTPROC glad_glTexStorageMem1DEXT = NULL;
+PFNGLTEXTURESTORAGEMEM1DEXTPROC glad_glTextureStorageMem1DEXT = NULL;
+PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT = NULL;
+PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC glad_glImportMemoryWin32HandleEXT = NULL;
+PFNGLIMPORTMEMORYWIN32NAMEEXTPROC glad_glImportMemoryWin32NameEXT = NULL;
+PFNGLMULTIDRAWARRAYSEXTPROC glad_glMultiDrawArraysEXT = NULL;
+PFNGLMULTIDRAWELEMENTSEXTPROC glad_glMultiDrawElementsEXT = NULL;
+PFNGLSAMPLEMASKEXTPROC glad_glSampleMaskEXT = NULL;
+PFNGLSAMPLEPATTERNEXTPROC glad_glSamplePatternEXT = NULL;
+PFNGLCOLORTABLEEXTPROC glad_glColorTableEXT = NULL;
+PFNGLGETCOLORTABLEEXTPROC glad_glGetColorTableEXT = NULL;
+PFNGLGETCOLORTABLEPARAMETERIVEXTPROC glad_glGetColorTableParameterivEXT = NULL;
+PFNGLGETCOLORTABLEPARAMETERFVEXTPROC glad_glGetColorTableParameterfvEXT = NULL;
+PFNGLPIXELTRANSFORMPARAMETERIEXTPROC glad_glPixelTransformParameteriEXT = NULL;
+PFNGLPIXELTRANSFORMPARAMETERFEXTPROC glad_glPixelTransformParameterfEXT = NULL;
+PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC glad_glPixelTransformParameterivEXT = NULL;
+PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC glad_glPixelTransformParameterfvEXT = NULL;
+PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC glad_glGetPixelTransformParameterivEXT = NULL;
+PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC glad_glGetPixelTransformParameterfvEXT = NULL;
+PFNGLPOINTPARAMETERFEXTPROC glad_glPointParameterfEXT = NULL;
+PFNGLPOINTPARAMETERFVEXTPROC glad_glPointParameterfvEXT = NULL;
+PFNGLPOLYGONOFFSETEXTPROC glad_glPolygonOffsetEXT = NULL;
+PFNGLPOLYGONOFFSETCLAMPEXTPROC glad_glPolygonOffsetClampEXT = NULL;
+PFNGLPROVOKINGVERTEXEXTPROC glad_glProvokingVertexEXT = NULL;
+PFNGLRASTERSAMPLESEXTPROC glad_glRasterSamplesEXT = NULL;
+PFNGLSECONDARYCOLOR3BEXTPROC glad_glSecondaryColor3bEXT = NULL;
+PFNGLSECONDARYCOLOR3BVEXTPROC glad_glSecondaryColor3bvEXT = NULL;
+PFNGLSECONDARYCOLOR3DEXTPROC glad_glSecondaryColor3dEXT = NULL;
+PFNGLSECONDARYCOLOR3DVEXTPROC glad_glSecondaryColor3dvEXT = NULL;
+PFNGLSECONDARYCOLOR3FEXTPROC glad_glSecondaryColor3fEXT = NULL;
+PFNGLSECONDARYCOLOR3FVEXTPROC glad_glSecondaryColor3fvEXT = NULL;
+PFNGLSECONDARYCOLOR3IEXTPROC glad_glSecondaryColor3iEXT = NULL;
+PFNGLSECONDARYCOLOR3IVEXTPROC glad_glSecondaryColor3ivEXT = NULL;
+PFNGLSECONDARYCOLOR3SEXTPROC glad_glSecondaryColor3sEXT = NULL;
+PFNGLSECONDARYCOLOR3SVEXTPROC glad_glSecondaryColor3svEXT = NULL;
+PFNGLSECONDARYCOLOR3UBEXTPROC glad_glSecondaryColor3ubEXT = NULL;
+PFNGLSECONDARYCOLOR3UBVEXTPROC glad_glSecondaryColor3ubvEXT = NULL;
+PFNGLSECONDARYCOLOR3UIEXTPROC glad_glSecondaryColor3uiEXT = NULL;
+PFNGLSECONDARYCOLOR3UIVEXTPROC glad_glSecondaryColor3uivEXT = NULL;
+PFNGLSECONDARYCOLOR3USEXTPROC glad_glSecondaryColor3usEXT = NULL;
+PFNGLSECONDARYCOLOR3USVEXTPROC glad_glSecondaryColor3usvEXT = NULL;
+PFNGLSECONDARYCOLORPOINTEREXTPROC glad_glSecondaryColorPointerEXT = NULL;
+PFNGLGENSEMAPHORESEXTPROC glad_glGenSemaphoresEXT = NULL;
+PFNGLDELETESEMAPHORESEXTPROC glad_glDeleteSemaphoresEXT = NULL;
+PFNGLISSEMAPHOREEXTPROC glad_glIsSemaphoreEXT = NULL;
+PFNGLSEMAPHOREPARAMETERUI64VEXTPROC glad_glSemaphoreParameterui64vEXT = NULL;
+PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC glad_glGetSemaphoreParameterui64vEXT = NULL;
+PFNGLWAITSEMAPHOREEXTPROC glad_glWaitSemaphoreEXT = NULL;
+PFNGLSIGNALSEMAPHOREEXTPROC glad_glSignalSemaphoreEXT = NULL;
+PFNGLIMPORTSEMAPHOREFDEXTPROC glad_glImportSemaphoreFdEXT = NULL;
+PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC glad_glImportSemaphoreWin32HandleEXT = NULL;
+PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC glad_glImportSemaphoreWin32NameEXT = NULL;
+PFNGLUSESHADERPROGRAMEXTPROC glad_glUseShaderProgramEXT = NULL;
+PFNGLACTIVEPROGRAMEXTPROC glad_glActiveProgramEXT = NULL;
+PFNGLCREATESHADERPROGRAMEXTPROC glad_glCreateShaderProgramEXT = NULL;
+PFNGLACTIVESHADERPROGRAMEXTPROC glad_glActiveShaderProgramEXT = NULL;
+PFNGLBINDPROGRAMPIPELINEEXTPROC glad_glBindProgramPipelineEXT = NULL;
+PFNGLCREATESHADERPROGRAMVEXTPROC glad_glCreateShaderProgramvEXT = NULL;
+PFNGLDELETEPROGRAMPIPELINESEXTPROC glad_glDeleteProgramPipelinesEXT = NULL;
+PFNGLGENPROGRAMPIPELINESEXTPROC glad_glGenProgramPipelinesEXT = NULL;
+PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC glad_glGetProgramPipelineInfoLogEXT = NULL;
+PFNGLGETPROGRAMPIPELINEIVEXTPROC glad_glGetProgramPipelineivEXT = NULL;
+PFNGLISPROGRAMPIPELINEEXTPROC glad_glIsProgramPipelineEXT = NULL;
+PFNGLUSEPROGRAMSTAGESEXTPROC glad_glUseProgramStagesEXT = NULL;
+PFNGLVALIDATEPROGRAMPIPELINEEXTPROC glad_glValidateProgramPipelineEXT = NULL;
+PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC glad_glFramebufferFetchBarrierEXT = NULL;
+PFNGLBINDIMAGETEXTUREEXTPROC glad_glBindImageTextureEXT = NULL;
+PFNGLMEMORYBARRIEREXTPROC glad_glMemoryBarrierEXT = NULL;
+PFNGLSTENCILCLEARTAGEXTPROC glad_glStencilClearTagEXT = NULL;
+PFNGLACTIVESTENCILFACEEXTPROC glad_glActiveStencilFaceEXT = NULL;
+PFNGLTEXSUBIMAGE1DEXTPROC glad_glTexSubImage1DEXT = NULL;
+PFNGLTEXSUBIMAGE2DEXTPROC glad_glTexSubImage2DEXT = NULL;
+PFNGLTEXIMAGE3DEXTPROC glad_glTexImage3DEXT = NULL;
+PFNGLTEXSUBIMAGE3DEXTPROC glad_glTexSubImage3DEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glad_glFramebufferTextureLayerEXT = NULL;
+PFNGLTEXBUFFEREXTPROC glad_glTexBufferEXT = NULL;
+PFNGLTEXPARAMETERIIVEXTPROC glad_glTexParameterIivEXT = NULL;
+PFNGLTEXPARAMETERIUIVEXTPROC glad_glTexParameterIuivEXT = NULL;
+PFNGLGETTEXPARAMETERIIVEXTPROC glad_glGetTexParameterIivEXT = NULL;
+PFNGLGETTEXPARAMETERIUIVEXTPROC glad_glGetTexParameterIuivEXT = NULL;
+PFNGLCLEARCOLORIIEXTPROC glad_glClearColorIiEXT = NULL;
+PFNGLCLEARCOLORIUIEXTPROC glad_glClearColorIuiEXT = NULL;
+PFNGLARETEXTURESRESIDENTEXTPROC glad_glAreTexturesResidentEXT = NULL;
+PFNGLBINDTEXTUREEXTPROC glad_glBindTextureEXT = NULL;
+PFNGLDELETETEXTURESEXTPROC glad_glDeleteTexturesEXT = NULL;
+PFNGLGENTEXTURESEXTPROC glad_glGenTexturesEXT = NULL;
+PFNGLISTEXTUREEXTPROC glad_glIsTextureEXT = NULL;
+PFNGLPRIORITIZETEXTURESEXTPROC glad_glPrioritizeTexturesEXT = NULL;
+PFNGLTEXTURENORMALEXTPROC glad_glTextureNormalEXT = NULL;
+PFNGLGETQUERYOBJECTI64VEXTPROC glad_glGetQueryObjecti64vEXT = NULL;
+PFNGLGETQUERYOBJECTUI64VEXTPROC glad_glGetQueryObjectui64vEXT = NULL;
+PFNGLBEGINTRANSFORMFEEDBACKEXTPROC glad_glBeginTransformFeedbackEXT = NULL;
+PFNGLENDTRANSFORMFEEDBACKEXTPROC glad_glEndTransformFeedbackEXT = NULL;
+PFNGLBINDBUFFERRANGEEXTPROC glad_glBindBufferRangeEXT = NULL;
+PFNGLBINDBUFFEROFFSETEXTPROC glad_glBindBufferOffsetEXT = NULL;
+PFNGLBINDBUFFERBASEEXTPROC glad_glBindBufferBaseEXT = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC glad_glTransformFeedbackVaryingsEXT = NULL;
+PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC glad_glGetTransformFeedbackVaryingEXT = NULL;
+PFNGLARRAYELEMENTEXTPROC glad_glArrayElementEXT = NULL;
+PFNGLCOLORPOINTEREXTPROC glad_glColorPointerEXT = NULL;
+PFNGLDRAWARRAYSEXTPROC glad_glDrawArraysEXT = NULL;
+PFNGLEDGEFLAGPOINTEREXTPROC glad_glEdgeFlagPointerEXT = NULL;
+PFNGLGETPOINTERVEXTPROC glad_glGetPointervEXT = NULL;
+PFNGLINDEXPOINTEREXTPROC glad_glIndexPointerEXT = NULL;
+PFNGLNORMALPOINTEREXTPROC glad_glNormalPointerEXT = NULL;
+PFNGLTEXCOORDPOINTEREXTPROC glad_glTexCoordPointerEXT = NULL;
+PFNGLVERTEXPOINTEREXTPROC glad_glVertexPointerEXT = NULL;
+PFNGLVERTEXATTRIBL1DEXTPROC glad_glVertexAttribL1dEXT = NULL;
+PFNGLVERTEXATTRIBL2DEXTPROC glad_glVertexAttribL2dEXT = NULL;
+PFNGLVERTEXATTRIBL3DEXTPROC glad_glVertexAttribL3dEXT = NULL;
+PFNGLVERTEXATTRIBL4DEXTPROC glad_glVertexAttribL4dEXT = NULL;
+PFNGLVERTEXATTRIBL1DVEXTPROC glad_glVertexAttribL1dvEXT = NULL;
+PFNGLVERTEXATTRIBL2DVEXTPROC glad_glVertexAttribL2dvEXT = NULL;
+PFNGLVERTEXATTRIBL3DVEXTPROC glad_glVertexAttribL3dvEXT = NULL;
+PFNGLVERTEXATTRIBL4DVEXTPROC glad_glVertexAttribL4dvEXT = NULL;
+PFNGLVERTEXATTRIBLPOINTEREXTPROC glad_glVertexAttribLPointerEXT = NULL;
+PFNGLGETVERTEXATTRIBLDVEXTPROC glad_glGetVertexAttribLdvEXT = NULL;
+PFNGLBEGINVERTEXSHADEREXTPROC glad_glBeginVertexShaderEXT = NULL;
+PFNGLENDVERTEXSHADEREXTPROC glad_glEndVertexShaderEXT = NULL;
+PFNGLBINDVERTEXSHADEREXTPROC glad_glBindVertexShaderEXT = NULL;
+PFNGLGENVERTEXSHADERSEXTPROC glad_glGenVertexShadersEXT = NULL;
+PFNGLDELETEVERTEXSHADEREXTPROC glad_glDeleteVertexShaderEXT = NULL;
+PFNGLSHADEROP1EXTPROC glad_glShaderOp1EXT = NULL;
+PFNGLSHADEROP2EXTPROC glad_glShaderOp2EXT = NULL;
+PFNGLSHADEROP3EXTPROC glad_glShaderOp3EXT = NULL;
+PFNGLSWIZZLEEXTPROC glad_glSwizzleEXT = NULL;
+PFNGLWRITEMASKEXTPROC glad_glWriteMaskEXT = NULL;
+PFNGLINSERTCOMPONENTEXTPROC glad_glInsertComponentEXT = NULL;
+PFNGLEXTRACTCOMPONENTEXTPROC glad_glExtractComponentEXT = NULL;
+PFNGLGENSYMBOLSEXTPROC glad_glGenSymbolsEXT = NULL;
+PFNGLSETINVARIANTEXTPROC glad_glSetInvariantEXT = NULL;
+PFNGLSETLOCALCONSTANTEXTPROC glad_glSetLocalConstantEXT = NULL;
+PFNGLVARIANTBVEXTPROC glad_glVariantbvEXT = NULL;
+PFNGLVARIANTSVEXTPROC glad_glVariantsvEXT = NULL;
+PFNGLVARIANTIVEXTPROC glad_glVariantivEXT = NULL;
+PFNGLVARIANTFVEXTPROC glad_glVariantfvEXT = NULL;
+PFNGLVARIANTDVEXTPROC glad_glVariantdvEXT = NULL;
+PFNGLVARIANTUBVEXTPROC glad_glVariantubvEXT = NULL;
+PFNGLVARIANTUSVEXTPROC glad_glVariantusvEXT = NULL;
+PFNGLVARIANTUIVEXTPROC glad_glVariantuivEXT = NULL;
+PFNGLVARIANTPOINTEREXTPROC glad_glVariantPointerEXT = NULL;
+PFNGLENABLEVARIANTCLIENTSTATEEXTPROC glad_glEnableVariantClientStateEXT = NULL;
+PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC glad_glDisableVariantClientStateEXT = NULL;
+PFNGLBINDLIGHTPARAMETEREXTPROC glad_glBindLightParameterEXT = NULL;
+PFNGLBINDMATERIALPARAMETEREXTPROC glad_glBindMaterialParameterEXT = NULL;
+PFNGLBINDTEXGENPARAMETEREXTPROC glad_glBindTexGenParameterEXT = NULL;
+PFNGLBINDTEXTUREUNITPARAMETEREXTPROC glad_glBindTextureUnitParameterEXT = NULL;
+PFNGLBINDPARAMETEREXTPROC glad_glBindParameterEXT = NULL;
+PFNGLISVARIANTENABLEDEXTPROC glad_glIsVariantEnabledEXT = NULL;
+PFNGLGETVARIANTBOOLEANVEXTPROC glad_glGetVariantBooleanvEXT = NULL;
+PFNGLGETVARIANTINTEGERVEXTPROC glad_glGetVariantIntegervEXT = NULL;
+PFNGLGETVARIANTFLOATVEXTPROC glad_glGetVariantFloatvEXT = NULL;
+PFNGLGETVARIANTPOINTERVEXTPROC glad_glGetVariantPointervEXT = NULL;
+PFNGLGETINVARIANTBOOLEANVEXTPROC glad_glGetInvariantBooleanvEXT = NULL;
+PFNGLGETINVARIANTINTEGERVEXTPROC glad_glGetInvariantIntegervEXT = NULL;
+PFNGLGETINVARIANTFLOATVEXTPROC glad_glGetInvariantFloatvEXT = NULL;
+PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC glad_glGetLocalConstantBooleanvEXT = NULL;
+PFNGLGETLOCALCONSTANTINTEGERVEXTPROC glad_glGetLocalConstantIntegervEXT = NULL;
+PFNGLGETLOCALCONSTANTFLOATVEXTPROC glad_glGetLocalConstantFloatvEXT = NULL;
+PFNGLVERTEXWEIGHTFEXTPROC glad_glVertexWeightfEXT = NULL;
+PFNGLVERTEXWEIGHTFVEXTPROC glad_glVertexWeightfvEXT = NULL;
+PFNGLVERTEXWEIGHTPOINTEREXTPROC glad_glVertexWeightPointerEXT = NULL;
+PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC glad_glAcquireKeyedMutexWin32EXT = NULL;
+PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC glad_glReleaseKeyedMutexWin32EXT = NULL;
+PFNGLWINDOWRECTANGLESEXTPROC glad_glWindowRectanglesEXT = NULL;
+PFNGLIMPORTSYNCEXTPROC glad_glImportSyncEXT = NULL;
+PFNGLFRAMETERMINATORGREMEDYPROC glad_glFrameTerminatorGREMEDY = NULL;
+PFNGLSTRINGMARKERGREMEDYPROC glad_glStringMarkerGREMEDY = NULL;
+PFNGLIMAGETRANSFORMPARAMETERIHPPROC glad_glImageTransformParameteriHP = NULL;
+PFNGLIMAGETRANSFORMPARAMETERFHPPROC glad_glImageTransformParameterfHP = NULL;
+PFNGLIMAGETRANSFORMPARAMETERIVHPPROC glad_glImageTransformParameterivHP = NULL;
+PFNGLIMAGETRANSFORMPARAMETERFVHPPROC glad_glImageTransformParameterfvHP = NULL;
+PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC glad_glGetImageTransformParameterivHP = NULL;
+PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC glad_glGetImageTransformParameterfvHP = NULL;
+PFNGLMULTIMODEDRAWARRAYSIBMPROC glad_glMultiModeDrawArraysIBM = NULL;
+PFNGLMULTIMODEDRAWELEMENTSIBMPROC glad_glMultiModeDrawElementsIBM = NULL;
+PFNGLFLUSHSTATICDATAIBMPROC glad_glFlushStaticDataIBM = NULL;
+PFNGLCOLORPOINTERLISTIBMPROC glad_glColorPointerListIBM = NULL;
+PFNGLSECONDARYCOLORPOINTERLISTIBMPROC glad_glSecondaryColorPointerListIBM = NULL;
+PFNGLEDGEFLAGPOINTERLISTIBMPROC glad_glEdgeFlagPointerListIBM = NULL;
+PFNGLFOGCOORDPOINTERLISTIBMPROC glad_glFogCoordPointerListIBM = NULL;
+PFNGLINDEXPOINTERLISTIBMPROC glad_glIndexPointerListIBM = NULL;
+PFNGLNORMALPOINTERLISTIBMPROC glad_glNormalPointerListIBM = NULL;
+PFNGLTEXCOORDPOINTERLISTIBMPROC glad_glTexCoordPointerListIBM = NULL;
+PFNGLVERTEXPOINTERLISTIBMPROC glad_glVertexPointerListIBM = NULL;
+PFNGLBLENDFUNCSEPARATEINGRPROC glad_glBlendFuncSeparateINGR = NULL;
+PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC glad_glApplyFramebufferAttachmentCMAAINTEL = NULL;
+PFNGLSYNCTEXTUREINTELPROC glad_glSyncTextureINTEL = NULL;
+PFNGLUNMAPTEXTURE2DINTELPROC glad_glUnmapTexture2DINTEL = NULL;
+PFNGLMAPTEXTURE2DINTELPROC glad_glMapTexture2DINTEL = NULL;
+PFNGLVERTEXPOINTERVINTELPROC glad_glVertexPointervINTEL = NULL;
+PFNGLNORMALPOINTERVINTELPROC glad_glNormalPointervINTEL = NULL;
+PFNGLCOLORPOINTERVINTELPROC glad_glColorPointervINTEL = NULL;
+PFNGLTEXCOORDPOINTERVINTELPROC glad_glTexCoordPointervINTEL = NULL;
+PFNGLBEGINPERFQUERYINTELPROC glad_glBeginPerfQueryINTEL = NULL;
+PFNGLCREATEPERFQUERYINTELPROC glad_glCreatePerfQueryINTEL = NULL;
+PFNGLDELETEPERFQUERYINTELPROC glad_glDeletePerfQueryINTEL = NULL;
+PFNGLENDPERFQUERYINTELPROC glad_glEndPerfQueryINTEL = NULL;
+PFNGLGETFIRSTPERFQUERYIDINTELPROC glad_glGetFirstPerfQueryIdINTEL = NULL;
+PFNGLGETNEXTPERFQUERYIDINTELPROC glad_glGetNextPerfQueryIdINTEL = NULL;
+PFNGLGETPERFCOUNTERINFOINTELPROC glad_glGetPerfCounterInfoINTEL = NULL;
+PFNGLGETPERFQUERYDATAINTELPROC glad_glGetPerfQueryDataINTEL = NULL;
+PFNGLGETPERFQUERYIDBYNAMEINTELPROC glad_glGetPerfQueryIdByNameINTEL = NULL;
+PFNGLGETPERFQUERYINFOINTELPROC glad_glGetPerfQueryInfoINTEL = NULL;
+PFNGLBLENDBARRIERKHRPROC glad_glBlendBarrierKHR = NULL;
+PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL;
+PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL;
+PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL;
+PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL;
+PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL;
+PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL;
+PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL;
+PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL;
+PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL;
+PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL;
+PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;
+PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR = NULL;
+PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR = NULL;
+PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR = NULL;
+PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR = NULL;
+PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR = NULL;
+PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR = NULL;
+PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR = NULL;
+PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR = NULL;
+PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR = NULL;
+PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR = NULL;
+PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR = NULL;
+PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glad_glMaxShaderCompilerThreadsKHR = NULL;
+PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus = NULL;
+PFNGLREADNPIXELSPROC glad_glReadnPixels = NULL;
+PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv = NULL;
+PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv = NULL;
+PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv = NULL;
+PFNGLGETGRAPHICSRESETSTATUSKHRPROC glad_glGetGraphicsResetStatusKHR = NULL;
+PFNGLREADNPIXELSKHRPROC glad_glReadnPixelsKHR = NULL;
+PFNGLGETNUNIFORMFVKHRPROC glad_glGetnUniformfvKHR = NULL;
+PFNGLGETNUNIFORMIVKHRPROC glad_glGetnUniformivKHR = NULL;
+PFNGLGETNUNIFORMUIVKHRPROC glad_glGetnUniformuivKHR = NULL;
+PFNGLRESIZEBUFFERSMESAPROC glad_glResizeBuffersMESA = NULL;
+PFNGLWINDOWPOS2DMESAPROC glad_glWindowPos2dMESA = NULL;
+PFNGLWINDOWPOS2DVMESAPROC glad_glWindowPos2dvMESA = NULL;
+PFNGLWINDOWPOS2FMESAPROC glad_glWindowPos2fMESA = NULL;
+PFNGLWINDOWPOS2FVMESAPROC glad_glWindowPos2fvMESA = NULL;
+PFNGLWINDOWPOS2IMESAPROC glad_glWindowPos2iMESA = NULL;
+PFNGLWINDOWPOS2IVMESAPROC glad_glWindowPos2ivMESA = NULL;
+PFNGLWINDOWPOS2SMESAPROC glad_glWindowPos2sMESA = NULL;
+PFNGLWINDOWPOS2SVMESAPROC glad_glWindowPos2svMESA = NULL;
+PFNGLWINDOWPOS3DMESAPROC glad_glWindowPos3dMESA = NULL;
+PFNGLWINDOWPOS3DVMESAPROC glad_glWindowPos3dvMESA = NULL;
+PFNGLWINDOWPOS3FMESAPROC glad_glWindowPos3fMESA = NULL;
+PFNGLWINDOWPOS3FVMESAPROC glad_glWindowPos3fvMESA = NULL;
+PFNGLWINDOWPOS3IMESAPROC glad_glWindowPos3iMESA = NULL;
+PFNGLWINDOWPOS3IVMESAPROC glad_glWindowPos3ivMESA = NULL;
+PFNGLWINDOWPOS3SMESAPROC glad_glWindowPos3sMESA = NULL;
+PFNGLWINDOWPOS3SVMESAPROC glad_glWindowPos3svMESA = NULL;
+PFNGLWINDOWPOS4DMESAPROC glad_glWindowPos4dMESA = NULL;
+PFNGLWINDOWPOS4DVMESAPROC glad_glWindowPos4dvMESA = NULL;
+PFNGLWINDOWPOS4FMESAPROC glad_glWindowPos4fMESA = NULL;
+PFNGLWINDOWPOS4FVMESAPROC glad_glWindowPos4fvMESA = NULL;
+PFNGLWINDOWPOS4IMESAPROC glad_glWindowPos4iMESA = NULL;
+PFNGLWINDOWPOS4IVMESAPROC glad_glWindowPos4ivMESA = NULL;
+PFNGLWINDOWPOS4SMESAPROC glad_glWindowPos4sMESA = NULL;
+PFNGLWINDOWPOS4SVMESAPROC glad_glWindowPos4svMESA = NULL;
+PFNGLBEGINCONDITIONALRENDERNVXPROC glad_glBeginConditionalRenderNVX = NULL;
+PFNGLENDCONDITIONALRENDERNVXPROC glad_glEndConditionalRenderNVX = NULL;
+PFNGLLGPUNAMEDBUFFERSUBDATANVXPROC glad_glLGPUNamedBufferSubDataNVX = NULL;
+PFNGLLGPUCOPYIMAGESUBDATANVXPROC glad_glLGPUCopyImageSubDataNVX = NULL;
+PFNGLLGPUINTERLOCKNVXPROC glad_glLGPUInterlockNVX = NULL;
+PFNGLALPHATOCOVERAGEDITHERCONTROLNVPROC glad_glAlphaToCoverageDitherControlNV = NULL;
+PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC glad_glMultiDrawArraysIndirectBindlessNV = NULL;
+PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC glad_glMultiDrawElementsIndirectBindlessNV = NULL;
+PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC glad_glMultiDrawArraysIndirectBindlessCountNV = NULL;
+PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC glad_glMultiDrawElementsIndirectBindlessCountNV = NULL;
+PFNGLGETTEXTUREHANDLENVPROC glad_glGetTextureHandleNV = NULL;
+PFNGLGETTEXTURESAMPLERHANDLENVPROC glad_glGetTextureSamplerHandleNV = NULL;
+PFNGLMAKETEXTUREHANDLERESIDENTNVPROC glad_glMakeTextureHandleResidentNV = NULL;
+PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC glad_glMakeTextureHandleNonResidentNV = NULL;
+PFNGLGETIMAGEHANDLENVPROC glad_glGetImageHandleNV = NULL;
+PFNGLMAKEIMAGEHANDLERESIDENTNVPROC glad_glMakeImageHandleResidentNV = NULL;
+PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC glad_glMakeImageHandleNonResidentNV = NULL;
+PFNGLUNIFORMHANDLEUI64NVPROC glad_glUniformHandleui64NV = NULL;
+PFNGLUNIFORMHANDLEUI64VNVPROC glad_glUniformHandleui64vNV = NULL;
+PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC glad_glProgramUniformHandleui64NV = NULL;
+PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC glad_glProgramUniformHandleui64vNV = NULL;
+PFNGLISTEXTUREHANDLERESIDENTNVPROC glad_glIsTextureHandleResidentNV = NULL;
+PFNGLISIMAGEHANDLERESIDENTNVPROC glad_glIsImageHandleResidentNV = NULL;
+PFNGLBLENDPARAMETERINVPROC glad_glBlendParameteriNV = NULL;
+PFNGLBLENDBARRIERNVPROC glad_glBlendBarrierNV = NULL;
+PFNGLVIEWPORTPOSITIONWSCALENVPROC glad_glViewportPositionWScaleNV = NULL;
+PFNGLCREATESTATESNVPROC glad_glCreateStatesNV = NULL;
+PFNGLDELETESTATESNVPROC glad_glDeleteStatesNV = NULL;
+PFNGLISSTATENVPROC glad_glIsStateNV = NULL;
+PFNGLSTATECAPTURENVPROC glad_glStateCaptureNV = NULL;
+PFNGLGETCOMMANDHEADERNVPROC glad_glGetCommandHeaderNV = NULL;
+PFNGLGETSTAGEINDEXNVPROC glad_glGetStageIndexNV = NULL;
+PFNGLDRAWCOMMANDSNVPROC glad_glDrawCommandsNV = NULL;
+PFNGLDRAWCOMMANDSADDRESSNVPROC glad_glDrawCommandsAddressNV = NULL;
+PFNGLDRAWCOMMANDSSTATESNVPROC glad_glDrawCommandsStatesNV = NULL;
+PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC glad_glDrawCommandsStatesAddressNV = NULL;
+PFNGLCREATECOMMANDLISTSNVPROC glad_glCreateCommandListsNV = NULL;
+PFNGLDELETECOMMANDLISTSNVPROC glad_glDeleteCommandListsNV = NULL;
+PFNGLISCOMMANDLISTNVPROC glad_glIsCommandListNV = NULL;
+PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC glad_glListDrawCommandsStatesClientNV = NULL;
+PFNGLCOMMANDLISTSEGMENTSNVPROC glad_glCommandListSegmentsNV = NULL;
+PFNGLCOMPILECOMMANDLISTNVPROC glad_glCompileCommandListNV = NULL;
+PFNGLCALLCOMMANDLISTNVPROC glad_glCallCommandListNV = NULL;
+PFNGLBEGINCONDITIONALRENDERNVPROC glad_glBeginConditionalRenderNV = NULL;
+PFNGLENDCONDITIONALRENDERNVPROC glad_glEndConditionalRenderNV = NULL;
+PFNGLSUBPIXELPRECISIONBIASNVPROC glad_glSubpixelPrecisionBiasNV = NULL;
+PFNGLCONSERVATIVERASTERPARAMETERFNVPROC glad_glConservativeRasterParameterfNV = NULL;
+PFNGLCONSERVATIVERASTERPARAMETERINVPROC glad_glConservativeRasterParameteriNV = NULL;
+PFNGLCOPYIMAGESUBDATANVPROC glad_glCopyImageSubDataNV = NULL;
+PFNGLDEPTHRANGEDNVPROC glad_glDepthRangedNV = NULL;
+PFNGLCLEARDEPTHDNVPROC glad_glClearDepthdNV = NULL;
+PFNGLDEPTHBOUNDSDNVPROC glad_glDepthBoundsdNV = NULL;
+PFNGLDRAWTEXTURENVPROC glad_glDrawTextureNV = NULL;
+PFNGLDRAWVKIMAGENVPROC glad_glDrawVkImageNV = NULL;
+PFNGLGETVKPROCADDRNVPROC glad_glGetVkProcAddrNV = NULL;
+PFNGLWAITVKSEMAPHORENVPROC glad_glWaitVkSemaphoreNV = NULL;
+PFNGLSIGNALVKSEMAPHORENVPROC glad_glSignalVkSemaphoreNV = NULL;
+PFNGLSIGNALVKFENCENVPROC glad_glSignalVkFenceNV = NULL;
+PFNGLMAPCONTROLPOINTSNVPROC glad_glMapControlPointsNV = NULL;
+PFNGLMAPPARAMETERIVNVPROC glad_glMapParameterivNV = NULL;
+PFNGLMAPPARAMETERFVNVPROC glad_glMapParameterfvNV = NULL;
+PFNGLGETMAPCONTROLPOINTSNVPROC glad_glGetMapControlPointsNV = NULL;
+PFNGLGETMAPPARAMETERIVNVPROC glad_glGetMapParameterivNV = NULL;
+PFNGLGETMAPPARAMETERFVNVPROC glad_glGetMapParameterfvNV = NULL;
+PFNGLGETMAPATTRIBPARAMETERIVNVPROC glad_glGetMapAttribParameterivNV = NULL;
+PFNGLGETMAPATTRIBPARAMETERFVNVPROC glad_glGetMapAttribParameterfvNV = NULL;
+PFNGLEVALMAPSNVPROC glad_glEvalMapsNV = NULL;
+PFNGLGETMULTISAMPLEFVNVPROC glad_glGetMultisamplefvNV = NULL;
+PFNGLSAMPLEMASKINDEXEDNVPROC glad_glSampleMaskIndexedNV = NULL;
+PFNGLTEXRENDERBUFFERNVPROC glad_glTexRenderbufferNV = NULL;
+PFNGLDELETEFENCESNVPROC glad_glDeleteFencesNV = NULL;
+PFNGLGENFENCESNVPROC glad_glGenFencesNV = NULL;
+PFNGLISFENCENVPROC glad_glIsFenceNV = NULL;
+PFNGLTESTFENCENVPROC glad_glTestFenceNV = NULL;
+PFNGLGETFENCEIVNVPROC glad_glGetFenceivNV = NULL;
+PFNGLFINISHFENCENVPROC glad_glFinishFenceNV = NULL;
+PFNGLSETFENCENVPROC glad_glSetFenceNV = NULL;
+PFNGLFRAGMENTCOVERAGECOLORNVPROC glad_glFragmentCoverageColorNV = NULL;
+PFNGLPROGRAMNAMEDPARAMETER4FNVPROC glad_glProgramNamedParameter4fNV = NULL;
+PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC glad_glProgramNamedParameter4fvNV = NULL;
+PFNGLPROGRAMNAMEDPARAMETER4DNVPROC glad_glProgramNamedParameter4dNV = NULL;
+PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC glad_glProgramNamedParameter4dvNV = NULL;
+PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC glad_glGetProgramNamedParameterfvNV = NULL;
+PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC glad_glGetProgramNamedParameterdvNV = NULL;
+PFNGLCOVERAGEMODULATIONTABLENVPROC glad_glCoverageModulationTableNV = NULL;
+PFNGLGETCOVERAGEMODULATIONTABLENVPROC glad_glGetCoverageModulationTableNV = NULL;
+PFNGLCOVERAGEMODULATIONNVPROC glad_glCoverageModulationNV = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC glad_glRenderbufferStorageMultisampleCoverageNV = NULL;
+PFNGLPROGRAMVERTEXLIMITNVPROC glad_glProgramVertexLimitNV = NULL;
+PFNGLFRAMEBUFFERTEXTUREEXTPROC glad_glFramebufferTextureEXT = NULL;
+PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC glad_glFramebufferTextureFaceEXT = NULL;
+PFNGLRENDERGPUMASKNVPROC glad_glRenderGpuMaskNV = NULL;
+PFNGLMULTICASTBUFFERSUBDATANVPROC glad_glMulticastBufferSubDataNV = NULL;
+PFNGLMULTICASTCOPYBUFFERSUBDATANVPROC glad_glMulticastCopyBufferSubDataNV = NULL;
+PFNGLMULTICASTCOPYIMAGESUBDATANVPROC glad_glMulticastCopyImageSubDataNV = NULL;
+PFNGLMULTICASTBLITFRAMEBUFFERNVPROC glad_glMulticastBlitFramebufferNV = NULL;
+PFNGLMULTICASTFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glMulticastFramebufferSampleLocationsfvNV = NULL;
+PFNGLMULTICASTBARRIERNVPROC glad_glMulticastBarrierNV = NULL;
+PFNGLMULTICASTWAITSYNCNVPROC glad_glMulticastWaitSyncNV = NULL;
+PFNGLMULTICASTGETQUERYOBJECTIVNVPROC glad_glMulticastGetQueryObjectivNV = NULL;
+PFNGLMULTICASTGETQUERYOBJECTUIVNVPROC glad_glMulticastGetQueryObjectuivNV = NULL;
+PFNGLMULTICASTGETQUERYOBJECTI64VNVPROC glad_glMulticastGetQueryObjecti64vNV = NULL;
+PFNGLMULTICASTGETQUERYOBJECTUI64VNVPROC glad_glMulticastGetQueryObjectui64vNV = NULL;
+PFNGLPROGRAMLOCALPARAMETERI4INVPROC glad_glProgramLocalParameterI4iNV = NULL;
+PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC glad_glProgramLocalParameterI4ivNV = NULL;
+PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC glad_glProgramLocalParametersI4ivNV = NULL;
+PFNGLPROGRAMLOCALPARAMETERI4UINVPROC glad_glProgramLocalParameterI4uiNV = NULL;
+PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC glad_glProgramLocalParameterI4uivNV = NULL;
+PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC glad_glProgramLocalParametersI4uivNV = NULL;
+PFNGLPROGRAMENVPARAMETERI4INVPROC glad_glProgramEnvParameterI4iNV = NULL;
+PFNGLPROGRAMENVPARAMETERI4IVNVPROC glad_glProgramEnvParameterI4ivNV = NULL;
+PFNGLPROGRAMENVPARAMETERSI4IVNVPROC glad_glProgramEnvParametersI4ivNV = NULL;
+PFNGLPROGRAMENVPARAMETERI4UINVPROC glad_glProgramEnvParameterI4uiNV = NULL;
+PFNGLPROGRAMENVPARAMETERI4UIVNVPROC glad_glProgramEnvParameterI4uivNV = NULL;
+PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC glad_glProgramEnvParametersI4uivNV = NULL;
+PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC glad_glGetProgramLocalParameterIivNV = NULL;
+PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC glad_glGetProgramLocalParameterIuivNV = NULL;
+PFNGLGETPROGRAMENVPARAMETERIIVNVPROC glad_glGetProgramEnvParameterIivNV = NULL;
+PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC glad_glGetProgramEnvParameterIuivNV = NULL;
+PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC glad_glProgramSubroutineParametersuivNV = NULL;
+PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC glad_glGetProgramSubroutineParameteruivNV = NULL;
+PFNGLVERTEX2HNVPROC glad_glVertex2hNV = NULL;
+PFNGLVERTEX2HVNVPROC glad_glVertex2hvNV = NULL;
+PFNGLVERTEX3HNVPROC glad_glVertex3hNV = NULL;
+PFNGLVERTEX3HVNVPROC glad_glVertex3hvNV = NULL;
+PFNGLVERTEX4HNVPROC glad_glVertex4hNV = NULL;
+PFNGLVERTEX4HVNVPROC glad_glVertex4hvNV = NULL;
+PFNGLNORMAL3HNVPROC glad_glNormal3hNV = NULL;
+PFNGLNORMAL3HVNVPROC glad_glNormal3hvNV = NULL;
+PFNGLCOLOR3HNVPROC glad_glColor3hNV = NULL;
+PFNGLCOLOR3HVNVPROC glad_glColor3hvNV = NULL;
+PFNGLCOLOR4HNVPROC glad_glColor4hNV = NULL;
+PFNGLCOLOR4HVNVPROC glad_glColor4hvNV = NULL;
+PFNGLTEXCOORD1HNVPROC glad_glTexCoord1hNV = NULL;
+PFNGLTEXCOORD1HVNVPROC glad_glTexCoord1hvNV = NULL;
+PFNGLTEXCOORD2HNVPROC glad_glTexCoord2hNV = NULL;
+PFNGLTEXCOORD2HVNVPROC glad_glTexCoord2hvNV = NULL;
+PFNGLTEXCOORD3HNVPROC glad_glTexCoord3hNV = NULL;
+PFNGLTEXCOORD3HVNVPROC glad_glTexCoord3hvNV = NULL;
+PFNGLTEXCOORD4HNVPROC glad_glTexCoord4hNV = NULL;
+PFNGLTEXCOORD4HVNVPROC glad_glTexCoord4hvNV = NULL;
+PFNGLMULTITEXCOORD1HNVPROC glad_glMultiTexCoord1hNV = NULL;
+PFNGLMULTITEXCOORD1HVNVPROC glad_glMultiTexCoord1hvNV = NULL;
+PFNGLMULTITEXCOORD2HNVPROC glad_glMultiTexCoord2hNV = NULL;
+PFNGLMULTITEXCOORD2HVNVPROC glad_glMultiTexCoord2hvNV = NULL;
+PFNGLMULTITEXCOORD3HNVPROC glad_glMultiTexCoord3hNV = NULL;
+PFNGLMULTITEXCOORD3HVNVPROC glad_glMultiTexCoord3hvNV = NULL;
+PFNGLMULTITEXCOORD4HNVPROC glad_glMultiTexCoord4hNV = NULL;
+PFNGLMULTITEXCOORD4HVNVPROC glad_glMultiTexCoord4hvNV = NULL;
+PFNGLFOGCOORDHNVPROC glad_glFogCoordhNV = NULL;
+PFNGLFOGCOORDHVNVPROC glad_glFogCoordhvNV = NULL;
+PFNGLSECONDARYCOLOR3HNVPROC glad_glSecondaryColor3hNV = NULL;
+PFNGLSECONDARYCOLOR3HVNVPROC glad_glSecondaryColor3hvNV = NULL;
+PFNGLVERTEXWEIGHTHNVPROC glad_glVertexWeighthNV = NULL;
+PFNGLVERTEXWEIGHTHVNVPROC glad_glVertexWeighthvNV = NULL;
+PFNGLVERTEXATTRIB1HNVPROC glad_glVertexAttrib1hNV = NULL;
+PFNGLVERTEXATTRIB1HVNVPROC glad_glVertexAttrib1hvNV = NULL;
+PFNGLVERTEXATTRIB2HNVPROC glad_glVertexAttrib2hNV = NULL;
+PFNGLVERTEXATTRIB2HVNVPROC glad_glVertexAttrib2hvNV = NULL;
+PFNGLVERTEXATTRIB3HNVPROC glad_glVertexAttrib3hNV = NULL;
+PFNGLVERTEXATTRIB3HVNVPROC glad_glVertexAttrib3hvNV = NULL;
+PFNGLVERTEXATTRIB4HNVPROC glad_glVertexAttrib4hNV = NULL;
+PFNGLVERTEXATTRIB4HVNVPROC glad_glVertexAttrib4hvNV = NULL;
+PFNGLVERTEXATTRIBS1HVNVPROC glad_glVertexAttribs1hvNV = NULL;
+PFNGLVERTEXATTRIBS2HVNVPROC glad_glVertexAttribs2hvNV = NULL;
+PFNGLVERTEXATTRIBS3HVNVPROC glad_glVertexAttribs3hvNV = NULL;
+PFNGLVERTEXATTRIBS4HVNVPROC glad_glVertexAttribs4hvNV = NULL;
+PFNGLGETINTERNALFORMATSAMPLEIVNVPROC glad_glGetInternalformatSampleivNV = NULL;
+PFNGLGENOCCLUSIONQUERIESNVPROC glad_glGenOcclusionQueriesNV = NULL;
+PFNGLDELETEOCCLUSIONQUERIESNVPROC glad_glDeleteOcclusionQueriesNV = NULL;
+PFNGLISOCCLUSIONQUERYNVPROC glad_glIsOcclusionQueryNV = NULL;
+PFNGLBEGINOCCLUSIONQUERYNVPROC glad_glBeginOcclusionQueryNV = NULL;
+PFNGLENDOCCLUSIONQUERYNVPROC glad_glEndOcclusionQueryNV = NULL;
+PFNGLGETOCCLUSIONQUERYIVNVPROC glad_glGetOcclusionQueryivNV = NULL;
+PFNGLGETOCCLUSIONQUERYUIVNVPROC glad_glGetOcclusionQueryuivNV = NULL;
+PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC glad_glProgramBufferParametersfvNV = NULL;
+PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC glad_glProgramBufferParametersIivNV = NULL;
+PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC glad_glProgramBufferParametersIuivNV = NULL;
+PFNGLGENPATHSNVPROC glad_glGenPathsNV = NULL;
+PFNGLDELETEPATHSNVPROC glad_glDeletePathsNV = NULL;
+PFNGLISPATHNVPROC glad_glIsPathNV = NULL;
+PFNGLPATHCOMMANDSNVPROC glad_glPathCommandsNV = NULL;
+PFNGLPATHCOORDSNVPROC glad_glPathCoordsNV = NULL;
+PFNGLPATHSUBCOMMANDSNVPROC glad_glPathSubCommandsNV = NULL;
+PFNGLPATHSUBCOORDSNVPROC glad_glPathSubCoordsNV = NULL;
+PFNGLPATHSTRINGNVPROC glad_glPathStringNV = NULL;
+PFNGLPATHGLYPHSNVPROC glad_glPathGlyphsNV = NULL;
+PFNGLPATHGLYPHRANGENVPROC glad_glPathGlyphRangeNV = NULL;
+PFNGLWEIGHTPATHSNVPROC glad_glWeightPathsNV = NULL;
+PFNGLCOPYPATHNVPROC glad_glCopyPathNV = NULL;
+PFNGLINTERPOLATEPATHSNVPROC glad_glInterpolatePathsNV = NULL;
+PFNGLTRANSFORMPATHNVPROC glad_glTransformPathNV = NULL;
+PFNGLPATHPARAMETERIVNVPROC glad_glPathParameterivNV = NULL;
+PFNGLPATHPARAMETERINVPROC glad_glPathParameteriNV = NULL;
+PFNGLPATHPARAMETERFVNVPROC glad_glPathParameterfvNV = NULL;
+PFNGLPATHPARAMETERFNVPROC glad_glPathParameterfNV = NULL;
+PFNGLPATHDASHARRAYNVPROC glad_glPathDashArrayNV = NULL;
+PFNGLPATHSTENCILFUNCNVPROC glad_glPathStencilFuncNV = NULL;
+PFNGLPATHSTENCILDEPTHOFFSETNVPROC glad_glPathStencilDepthOffsetNV = NULL;
+PFNGLSTENCILFILLPATHNVPROC glad_glStencilFillPathNV = NULL;
+PFNGLSTENCILSTROKEPATHNVPROC glad_glStencilStrokePathNV = NULL;
+PFNGLSTENCILFILLPATHINSTANCEDNVPROC glad_glStencilFillPathInstancedNV = NULL;
+PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC glad_glStencilStrokePathInstancedNV = NULL;
+PFNGLPATHCOVERDEPTHFUNCNVPROC glad_glPathCoverDepthFuncNV = NULL;
+PFNGLCOVERFILLPATHNVPROC glad_glCoverFillPathNV = NULL;
+PFNGLCOVERSTROKEPATHNVPROC glad_glCoverStrokePathNV = NULL;
+PFNGLCOVERFILLPATHINSTANCEDNVPROC glad_glCoverFillPathInstancedNV = NULL;
+PFNGLCOVERSTROKEPATHINSTANCEDNVPROC glad_glCoverStrokePathInstancedNV = NULL;
+PFNGLGETPATHPARAMETERIVNVPROC glad_glGetPathParameterivNV = NULL;
+PFNGLGETPATHPARAMETERFVNVPROC glad_glGetPathParameterfvNV = NULL;
+PFNGLGETPATHCOMMANDSNVPROC glad_glGetPathCommandsNV = NULL;
+PFNGLGETPATHCOORDSNVPROC glad_glGetPathCoordsNV = NULL;
+PFNGLGETPATHDASHARRAYNVPROC glad_glGetPathDashArrayNV = NULL;
+PFNGLGETPATHMETRICSNVPROC glad_glGetPathMetricsNV = NULL;
+PFNGLGETPATHMETRICRANGENVPROC glad_glGetPathMetricRangeNV = NULL;
+PFNGLGETPATHSPACINGNVPROC glad_glGetPathSpacingNV = NULL;
+PFNGLISPOINTINFILLPATHNVPROC glad_glIsPointInFillPathNV = NULL;
+PFNGLISPOINTINSTROKEPATHNVPROC glad_glIsPointInStrokePathNV = NULL;
+PFNGLGETPATHLENGTHNVPROC glad_glGetPathLengthNV = NULL;
+PFNGLPOINTALONGPATHNVPROC glad_glPointAlongPathNV = NULL;
+PFNGLMATRIXLOAD3X2FNVPROC glad_glMatrixLoad3x2fNV = NULL;
+PFNGLMATRIXLOAD3X3FNVPROC glad_glMatrixLoad3x3fNV = NULL;
+PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC glad_glMatrixLoadTranspose3x3fNV = NULL;
+PFNGLMATRIXMULT3X2FNVPROC glad_glMatrixMult3x2fNV = NULL;
+PFNGLMATRIXMULT3X3FNVPROC glad_glMatrixMult3x3fNV = NULL;
+PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC glad_glMatrixMultTranspose3x3fNV = NULL;
+PFNGLSTENCILTHENCOVERFILLPATHNVPROC glad_glStencilThenCoverFillPathNV = NULL;
+PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC glad_glStencilThenCoverStrokePathNV = NULL;
+PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC glad_glStencilThenCoverFillPathInstancedNV = NULL;
+PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC glad_glStencilThenCoverStrokePathInstancedNV = NULL;
+PFNGLPATHGLYPHINDEXRANGENVPROC glad_glPathGlyphIndexRangeNV = NULL;
+PFNGLPATHGLYPHINDEXARRAYNVPROC glad_glPathGlyphIndexArrayNV = NULL;
+PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC glad_glPathMemoryGlyphIndexArrayNV = NULL;
+PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC glad_glProgramPathFragmentInputGenNV = NULL;
+PFNGLGETPROGRAMRESOURCEFVNVPROC glad_glGetProgramResourcefvNV = NULL;
+PFNGLPATHCOLORGENNVPROC glad_glPathColorGenNV = NULL;
+PFNGLPATHTEXGENNVPROC glad_glPathTexGenNV = NULL;
+PFNGLPATHFOGGENNVPROC glad_glPathFogGenNV = NULL;
+PFNGLGETPATHCOLORGENIVNVPROC glad_glGetPathColorGenivNV = NULL;
+PFNGLGETPATHCOLORGENFVNVPROC glad_glGetPathColorGenfvNV = NULL;
+PFNGLGETPATHTEXGENIVNVPROC glad_glGetPathTexGenivNV = NULL;
+PFNGLGETPATHTEXGENFVNVPROC glad_glGetPathTexGenfvNV = NULL;
+PFNGLPIXELDATARANGENVPROC glad_glPixelDataRangeNV = NULL;
+PFNGLFLUSHPIXELDATARANGENVPROC glad_glFlushPixelDataRangeNV = NULL;
+PFNGLPOINTPARAMETERINVPROC glad_glPointParameteriNV = NULL;
+PFNGLPOINTPARAMETERIVNVPROC glad_glPointParameterivNV = NULL;
+PFNGLPRESENTFRAMEKEYEDNVPROC glad_glPresentFrameKeyedNV = NULL;
+PFNGLPRESENTFRAMEDUALFILLNVPROC glad_glPresentFrameDualFillNV = NULL;
+PFNGLGETVIDEOIVNVPROC glad_glGetVideoivNV = NULL;
+PFNGLGETVIDEOUIVNVPROC glad_glGetVideouivNV = NULL;
+PFNGLGETVIDEOI64VNVPROC glad_glGetVideoi64vNV = NULL;
+PFNGLGETVIDEOUI64VNVPROC glad_glGetVideoui64vNV = NULL;
+PFNGLPRIMITIVERESTARTNVPROC glad_glPrimitiveRestartNV = NULL;
+PFNGLPRIMITIVERESTARTINDEXNVPROC glad_glPrimitiveRestartIndexNV = NULL;
+PFNGLQUERYRESOURCENVPROC glad_glQueryResourceNV = NULL;
+PFNGLGENQUERYRESOURCETAGNVPROC glad_glGenQueryResourceTagNV = NULL;
+PFNGLDELETEQUERYRESOURCETAGNVPROC glad_glDeleteQueryResourceTagNV = NULL;
+PFNGLQUERYRESOURCETAGNVPROC glad_glQueryResourceTagNV = NULL;
+PFNGLCOMBINERPARAMETERFVNVPROC glad_glCombinerParameterfvNV = NULL;
+PFNGLCOMBINERPARAMETERFNVPROC glad_glCombinerParameterfNV = NULL;
+PFNGLCOMBINERPARAMETERIVNVPROC glad_glCombinerParameterivNV = NULL;
+PFNGLCOMBINERPARAMETERINVPROC glad_glCombinerParameteriNV = NULL;
+PFNGLCOMBINERINPUTNVPROC glad_glCombinerInputNV = NULL;
+PFNGLCOMBINEROUTPUTNVPROC glad_glCombinerOutputNV = NULL;
+PFNGLFINALCOMBINERINPUTNVPROC glad_glFinalCombinerInputNV = NULL;
+PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC glad_glGetCombinerInputParameterfvNV = NULL;
+PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC glad_glGetCombinerInputParameterivNV = NULL;
+PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC glad_glGetCombinerOutputParameterfvNV = NULL;
+PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC glad_glGetCombinerOutputParameterivNV = NULL;
+PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC glad_glGetFinalCombinerInputParameterfvNV = NULL;
+PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC glad_glGetFinalCombinerInputParameterivNV = NULL;
+PFNGLCOMBINERSTAGEPARAMETERFVNVPROC glad_glCombinerStageParameterfvNV = NULL;
+PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC glad_glGetCombinerStageParameterfvNV = NULL;
+PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glFramebufferSampleLocationsfvNV = NULL;
+PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC glad_glNamedFramebufferSampleLocationsfvNV = NULL;
+PFNGLRESOLVEDEPTHVALUESNVPROC glad_glResolveDepthValuesNV = NULL;
+PFNGLMAKEBUFFERRESIDENTNVPROC glad_glMakeBufferResidentNV = NULL;
+PFNGLMAKEBUFFERNONRESIDENTNVPROC glad_glMakeBufferNonResidentNV = NULL;
+PFNGLISBUFFERRESIDENTNVPROC glad_glIsBufferResidentNV = NULL;
+PFNGLMAKENAMEDBUFFERRESIDENTNVPROC glad_glMakeNamedBufferResidentNV = NULL;
+PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC glad_glMakeNamedBufferNonResidentNV = NULL;
+PFNGLISNAMEDBUFFERRESIDENTNVPROC glad_glIsNamedBufferResidentNV = NULL;
+PFNGLGETBUFFERPARAMETERUI64VNVPROC glad_glGetBufferParameterui64vNV = NULL;
+PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC glad_glGetNamedBufferParameterui64vNV = NULL;
+PFNGLGETINTEGERUI64VNVPROC glad_glGetIntegerui64vNV = NULL;
+PFNGLUNIFORMUI64NVPROC glad_glUniformui64NV = NULL;
+PFNGLUNIFORMUI64VNVPROC glad_glUniformui64vNV = NULL;
+PFNGLPROGRAMUNIFORMUI64NVPROC glad_glProgramUniformui64NV = NULL;
+PFNGLPROGRAMUNIFORMUI64VNVPROC glad_glProgramUniformui64vNV = NULL;
+PFNGLTEXTUREBARRIERNVPROC glad_glTextureBarrierNV = NULL;
+PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC glad_glTexImage2DMultisampleCoverageNV = NULL;
+PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC glad_glTexImage3DMultisampleCoverageNV = NULL;
+PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC glad_glTextureImage2DMultisampleNV = NULL;
+PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC glad_glTextureImage3DMultisampleNV = NULL;
+PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC glad_glTextureImage2DMultisampleCoverageNV = NULL;
+PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC glad_glTextureImage3DMultisampleCoverageNV = NULL;
+PFNGLBEGINTRANSFORMFEEDBACKNVPROC glad_glBeginTransformFeedbackNV = NULL;
+PFNGLENDTRANSFORMFEEDBACKNVPROC glad_glEndTransformFeedbackNV = NULL;
+PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC glad_glTransformFeedbackAttribsNV = NULL;
+PFNGLBINDBUFFERRANGENVPROC glad_glBindBufferRangeNV = NULL;
+PFNGLBINDBUFFEROFFSETNVPROC glad_glBindBufferOffsetNV = NULL;
+PFNGLBINDBUFFERBASENVPROC glad_glBindBufferBaseNV = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC glad_glTransformFeedbackVaryingsNV = NULL;
+PFNGLACTIVEVARYINGNVPROC glad_glActiveVaryingNV = NULL;
+PFNGLGETVARYINGLOCATIONNVPROC glad_glGetVaryingLocationNV = NULL;
+PFNGLGETACTIVEVARYINGNVPROC glad_glGetActiveVaryingNV = NULL;
+PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC glad_glGetTransformFeedbackVaryingNV = NULL;
+PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC glad_glTransformFeedbackStreamAttribsNV = NULL;
+PFNGLBINDTRANSFORMFEEDBACKNVPROC glad_glBindTransformFeedbackNV = NULL;
+PFNGLDELETETRANSFORMFEEDBACKSNVPROC glad_glDeleteTransformFeedbacksNV = NULL;
+PFNGLGENTRANSFORMFEEDBACKSNVPROC glad_glGenTransformFeedbacksNV = NULL;
+PFNGLISTRANSFORMFEEDBACKNVPROC glad_glIsTransformFeedbackNV = NULL;
+PFNGLPAUSETRANSFORMFEEDBACKNVPROC glad_glPauseTransformFeedbackNV = NULL;
+PFNGLRESUMETRANSFORMFEEDBACKNVPROC glad_glResumeTransformFeedbackNV = NULL;
+PFNGLDRAWTRANSFORMFEEDBACKNVPROC glad_glDrawTransformFeedbackNV = NULL;
+PFNGLVDPAUINITNVPROC glad_glVDPAUInitNV = NULL;
+PFNGLVDPAUFININVPROC glad_glVDPAUFiniNV = NULL;
+PFNGLVDPAUREGISTERVIDEOSURFACENVPROC glad_glVDPAURegisterVideoSurfaceNV = NULL;
+PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC glad_glVDPAURegisterOutputSurfaceNV = NULL;
+PFNGLVDPAUISSURFACENVPROC glad_glVDPAUIsSurfaceNV = NULL;
+PFNGLVDPAUUNREGISTERSURFACENVPROC glad_glVDPAUUnregisterSurfaceNV = NULL;
+PFNGLVDPAUGETSURFACEIVNVPROC glad_glVDPAUGetSurfaceivNV = NULL;
+PFNGLVDPAUSURFACEACCESSNVPROC glad_glVDPAUSurfaceAccessNV = NULL;
+PFNGLVDPAUMAPSURFACESNVPROC glad_glVDPAUMapSurfacesNV = NULL;
+PFNGLVDPAUUNMAPSURFACESNVPROC glad_glVDPAUUnmapSurfacesNV = NULL;
+PFNGLFLUSHVERTEXARRAYRANGENVPROC glad_glFlushVertexArrayRangeNV = NULL;
+PFNGLVERTEXARRAYRANGENVPROC glad_glVertexArrayRangeNV = NULL;
+PFNGLVERTEXATTRIBL1I64NVPROC glad_glVertexAttribL1i64NV = NULL;
+PFNGLVERTEXATTRIBL2I64NVPROC glad_glVertexAttribL2i64NV = NULL;
+PFNGLVERTEXATTRIBL3I64NVPROC glad_glVertexAttribL3i64NV = NULL;
+PFNGLVERTEXATTRIBL4I64NVPROC glad_glVertexAttribL4i64NV = NULL;
+PFNGLVERTEXATTRIBL1I64VNVPROC glad_glVertexAttribL1i64vNV = NULL;
+PFNGLVERTEXATTRIBL2I64VNVPROC glad_glVertexAttribL2i64vNV = NULL;
+PFNGLVERTEXATTRIBL3I64VNVPROC glad_glVertexAttribL3i64vNV = NULL;
+PFNGLVERTEXATTRIBL4I64VNVPROC glad_glVertexAttribL4i64vNV = NULL;
+PFNGLVERTEXATTRIBL1UI64NVPROC glad_glVertexAttribL1ui64NV = NULL;
+PFNGLVERTEXATTRIBL2UI64NVPROC glad_glVertexAttribL2ui64NV = NULL;
+PFNGLVERTEXATTRIBL3UI64NVPROC glad_glVertexAttribL3ui64NV = NULL;
+PFNGLVERTEXATTRIBL4UI64NVPROC glad_glVertexAttribL4ui64NV = NULL;
+PFNGLVERTEXATTRIBL1UI64VNVPROC glad_glVertexAttribL1ui64vNV = NULL;
+PFNGLVERTEXATTRIBL2UI64VNVPROC glad_glVertexAttribL2ui64vNV = NULL;
+PFNGLVERTEXATTRIBL3UI64VNVPROC glad_glVertexAttribL3ui64vNV = NULL;
+PFNGLVERTEXATTRIBL4UI64VNVPROC glad_glVertexAttribL4ui64vNV = NULL;
+PFNGLGETVERTEXATTRIBLI64VNVPROC glad_glGetVertexAttribLi64vNV = NULL;
+PFNGLGETVERTEXATTRIBLUI64VNVPROC glad_glGetVertexAttribLui64vNV = NULL;
+PFNGLVERTEXATTRIBLFORMATNVPROC glad_glVertexAttribLFormatNV = NULL;
+PFNGLBUFFERADDRESSRANGENVPROC glad_glBufferAddressRangeNV = NULL;
+PFNGLVERTEXFORMATNVPROC glad_glVertexFormatNV = NULL;
+PFNGLNORMALFORMATNVPROC glad_glNormalFormatNV = NULL;
+PFNGLCOLORFORMATNVPROC glad_glColorFormatNV = NULL;
+PFNGLINDEXFORMATNVPROC glad_glIndexFormatNV = NULL;
+PFNGLTEXCOORDFORMATNVPROC glad_glTexCoordFormatNV = NULL;
+PFNGLEDGEFLAGFORMATNVPROC glad_glEdgeFlagFormatNV = NULL;
+PFNGLSECONDARYCOLORFORMATNVPROC glad_glSecondaryColorFormatNV = NULL;
+PFNGLFOGCOORDFORMATNVPROC glad_glFogCoordFormatNV = NULL;
+PFNGLVERTEXATTRIBFORMATNVPROC glad_glVertexAttribFormatNV = NULL;
+PFNGLVERTEXATTRIBIFORMATNVPROC glad_glVertexAttribIFormatNV = NULL;
+PFNGLGETINTEGERUI64I_VNVPROC glad_glGetIntegerui64i_vNV = NULL;
+PFNGLAREPROGRAMSRESIDENTNVPROC glad_glAreProgramsResidentNV = NULL;
+PFNGLBINDPROGRAMNVPROC glad_glBindProgramNV = NULL;
+PFNGLDELETEPROGRAMSNVPROC glad_glDeleteProgramsNV = NULL;
+PFNGLEXECUTEPROGRAMNVPROC glad_glExecuteProgramNV = NULL;
+PFNGLGENPROGRAMSNVPROC glad_glGenProgramsNV = NULL;
+PFNGLGETPROGRAMPARAMETERDVNVPROC glad_glGetProgramParameterdvNV = NULL;
+PFNGLGETPROGRAMPARAMETERFVNVPROC glad_glGetProgramParameterfvNV = NULL;
+PFNGLGETPROGRAMIVNVPROC glad_glGetProgramivNV = NULL;
+PFNGLGETPROGRAMSTRINGNVPROC glad_glGetProgramStringNV = NULL;
+PFNGLGETTRACKMATRIXIVNVPROC glad_glGetTrackMatrixivNV = NULL;
+PFNGLGETVERTEXATTRIBDVNVPROC glad_glGetVertexAttribdvNV = NULL;
+PFNGLGETVERTEXATTRIBFVNVPROC glad_glGetVertexAttribfvNV = NULL;
+PFNGLGETVERTEXATTRIBIVNVPROC glad_glGetVertexAttribivNV = NULL;
+PFNGLGETVERTEXATTRIBPOINTERVNVPROC glad_glGetVertexAttribPointervNV = NULL;
+PFNGLISPROGRAMNVPROC glad_glIsProgramNV = NULL;
+PFNGLLOADPROGRAMNVPROC glad_glLoadProgramNV = NULL;
+PFNGLPROGRAMPARAMETER4DNVPROC glad_glProgramParameter4dNV = NULL;
+PFNGLPROGRAMPARAMETER4DVNVPROC glad_glProgramParameter4dvNV = NULL;
+PFNGLPROGRAMPARAMETER4FNVPROC glad_glProgramParameter4fNV = NULL;
+PFNGLPROGRAMPARAMETER4FVNVPROC glad_glProgramParameter4fvNV = NULL;
+PFNGLPROGRAMPARAMETERS4DVNVPROC glad_glProgramParameters4dvNV = NULL;
+PFNGLPROGRAMPARAMETERS4FVNVPROC glad_glProgramParameters4fvNV = NULL;
+PFNGLREQUESTRESIDENTPROGRAMSNVPROC glad_glRequestResidentProgramsNV = NULL;
+PFNGLTRACKMATRIXNVPROC glad_glTrackMatrixNV = NULL;
+PFNGLVERTEXATTRIBPOINTERNVPROC glad_glVertexAttribPointerNV = NULL;
+PFNGLVERTEXATTRIB1DNVPROC glad_glVertexAttrib1dNV = NULL;
+PFNGLVERTEXATTRIB1DVNVPROC glad_glVertexAttrib1dvNV = NULL;
+PFNGLVERTEXATTRIB1FNVPROC glad_glVertexAttrib1fNV = NULL;
+PFNGLVERTEXATTRIB1FVNVPROC glad_glVertexAttrib1fvNV = NULL;
+PFNGLVERTEXATTRIB1SNVPROC glad_glVertexAttrib1sNV = NULL;
+PFNGLVERTEXATTRIB1SVNVPROC glad_glVertexAttrib1svNV = NULL;
+PFNGLVERTEXATTRIB2DNVPROC glad_glVertexAttrib2dNV = NULL;
+PFNGLVERTEXATTRIB2DVNVPROC glad_glVertexAttrib2dvNV = NULL;
+PFNGLVERTEXATTRIB2FNVPROC glad_glVertexAttrib2fNV = NULL;
+PFNGLVERTEXATTRIB2FVNVPROC glad_glVertexAttrib2fvNV = NULL;
+PFNGLVERTEXATTRIB2SNVPROC glad_glVertexAttrib2sNV = NULL;
+PFNGLVERTEXATTRIB2SVNVPROC glad_glVertexAttrib2svNV = NULL;
+PFNGLVERTEXATTRIB3DNVPROC glad_glVertexAttrib3dNV = NULL;
+PFNGLVERTEXATTRIB3DVNVPROC glad_glVertexAttrib3dvNV = NULL;
+PFNGLVERTEXATTRIB3FNVPROC glad_glVertexAttrib3fNV = NULL;
+PFNGLVERTEXATTRIB3FVNVPROC glad_glVertexAttrib3fvNV = NULL;
+PFNGLVERTEXATTRIB3SNVPROC glad_glVertexAttrib3sNV = NULL;
+PFNGLVERTEXATTRIB3SVNVPROC glad_glVertexAttrib3svNV = NULL;
+PFNGLVERTEXATTRIB4DNVPROC glad_glVertexAttrib4dNV = NULL;
+PFNGLVERTEXATTRIB4DVNVPROC glad_glVertexAttrib4dvNV = NULL;
+PFNGLVERTEXATTRIB4FNVPROC glad_glVertexAttrib4fNV = NULL;
+PFNGLVERTEXATTRIB4FVNVPROC glad_glVertexAttrib4fvNV = NULL;
+PFNGLVERTEXATTRIB4SNVPROC glad_glVertexAttrib4sNV = NULL;
+PFNGLVERTEXATTRIB4SVNVPROC glad_glVertexAttrib4svNV = NULL;
+PFNGLVERTEXATTRIB4UBNVPROC glad_glVertexAttrib4ubNV = NULL;
+PFNGLVERTEXATTRIB4UBVNVPROC glad_glVertexAttrib4ubvNV = NULL;
+PFNGLVERTEXATTRIBS1DVNVPROC glad_glVertexAttribs1dvNV = NULL;
+PFNGLVERTEXATTRIBS1FVNVPROC glad_glVertexAttribs1fvNV = NULL;
+PFNGLVERTEXATTRIBS1SVNVPROC glad_glVertexAttribs1svNV = NULL;
+PFNGLVERTEXATTRIBS2DVNVPROC glad_glVertexAttribs2dvNV = NULL;
+PFNGLVERTEXATTRIBS2FVNVPROC glad_glVertexAttribs2fvNV = NULL;
+PFNGLVERTEXATTRIBS2SVNVPROC glad_glVertexAttribs2svNV = NULL;
+PFNGLVERTEXATTRIBS3DVNVPROC glad_glVertexAttribs3dvNV = NULL;
+PFNGLVERTEXATTRIBS3FVNVPROC glad_glVertexAttribs3fvNV = NULL;
+PFNGLVERTEXATTRIBS3SVNVPROC glad_glVertexAttribs3svNV = NULL;
+PFNGLVERTEXATTRIBS4DVNVPROC glad_glVertexAttribs4dvNV = NULL;
+PFNGLVERTEXATTRIBS4FVNVPROC glad_glVertexAttribs4fvNV = NULL;
+PFNGLVERTEXATTRIBS4SVNVPROC glad_glVertexAttribs4svNV = NULL;
+PFNGLVERTEXATTRIBS4UBVNVPROC glad_glVertexAttribs4ubvNV = NULL;
+PFNGLVERTEXATTRIBI1IEXTPROC glad_glVertexAttribI1iEXT = NULL;
+PFNGLVERTEXATTRIBI2IEXTPROC glad_glVertexAttribI2iEXT = NULL;
+PFNGLVERTEXATTRIBI3IEXTPROC glad_glVertexAttribI3iEXT = NULL;
+PFNGLVERTEXATTRIBI4IEXTPROC glad_glVertexAttribI4iEXT = NULL;
+PFNGLVERTEXATTRIBI1UIEXTPROC glad_glVertexAttribI1uiEXT = NULL;
+PFNGLVERTEXATTRIBI2UIEXTPROC glad_glVertexAttribI2uiEXT = NULL;
+PFNGLVERTEXATTRIBI3UIEXTPROC glad_glVertexAttribI3uiEXT = NULL;
+PFNGLVERTEXATTRIBI4UIEXTPROC glad_glVertexAttribI4uiEXT = NULL;
+PFNGLVERTEXATTRIBI1IVEXTPROC glad_glVertexAttribI1ivEXT = NULL;
+PFNGLVERTEXATTRIBI2IVEXTPROC glad_glVertexAttribI2ivEXT = NULL;
+PFNGLVERTEXATTRIBI3IVEXTPROC glad_glVertexAttribI3ivEXT = NULL;
+PFNGLVERTEXATTRIBI4IVEXTPROC glad_glVertexAttribI4ivEXT = NULL;
+PFNGLVERTEXATTRIBI1UIVEXTPROC glad_glVertexAttribI1uivEXT = NULL;
+PFNGLVERTEXATTRIBI2UIVEXTPROC glad_glVertexAttribI2uivEXT = NULL;
+PFNGLVERTEXATTRIBI3UIVEXTPROC glad_glVertexAttribI3uivEXT = NULL;
+PFNGLVERTEXATTRIBI4UIVEXTPROC glad_glVertexAttribI4uivEXT = NULL;
+PFNGLVERTEXATTRIBI4BVEXTPROC glad_glVertexAttribI4bvEXT = NULL;
+PFNGLVERTEXATTRIBI4SVEXTPROC glad_glVertexAttribI4svEXT = NULL;
+PFNGLVERTEXATTRIBI4UBVEXTPROC glad_glVertexAttribI4ubvEXT = NULL;
+PFNGLVERTEXATTRIBI4USVEXTPROC glad_glVertexAttribI4usvEXT = NULL;
+PFNGLVERTEXATTRIBIPOINTEREXTPROC glad_glVertexAttribIPointerEXT = NULL;
+PFNGLGETVERTEXATTRIBIIVEXTPROC glad_glGetVertexAttribIivEXT = NULL;
+PFNGLGETVERTEXATTRIBIUIVEXTPROC glad_glGetVertexAttribIuivEXT = NULL;
+PFNGLBEGINVIDEOCAPTURENVPROC glad_glBeginVideoCaptureNV = NULL;
+PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC glad_glBindVideoCaptureStreamBufferNV = NULL;
+PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC glad_glBindVideoCaptureStreamTextureNV = NULL;
+PFNGLENDVIDEOCAPTURENVPROC glad_glEndVideoCaptureNV = NULL;
+PFNGLGETVIDEOCAPTUREIVNVPROC glad_glGetVideoCaptureivNV = NULL;
+PFNGLGETVIDEOCAPTURESTREAMIVNVPROC glad_glGetVideoCaptureStreamivNV = NULL;
+PFNGLGETVIDEOCAPTURESTREAMFVNVPROC glad_glGetVideoCaptureStreamfvNV = NULL;
+PFNGLGETVIDEOCAPTURESTREAMDVNVPROC glad_glGetVideoCaptureStreamdvNV = NULL;
+PFNGLVIDEOCAPTURENVPROC glad_glVideoCaptureNV = NULL;
+PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC glad_glVideoCaptureStreamParameterivNV = NULL;
+PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC glad_glVideoCaptureStreamParameterfvNV = NULL;
+PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC glad_glVideoCaptureStreamParameterdvNV = NULL;
+PFNGLVIEWPORTSWIZZLENVPROC glad_glViewportSwizzleNV = NULL;
+PFNGLMULTITEXCOORD1BOESPROC glad_glMultiTexCoord1bOES = NULL;
+PFNGLMULTITEXCOORD1BVOESPROC glad_glMultiTexCoord1bvOES = NULL;
+PFNGLMULTITEXCOORD2BOESPROC glad_glMultiTexCoord2bOES = NULL;
+PFNGLMULTITEXCOORD2BVOESPROC glad_glMultiTexCoord2bvOES = NULL;
+PFNGLMULTITEXCOORD3BOESPROC glad_glMultiTexCoord3bOES = NULL;
+PFNGLMULTITEXCOORD3BVOESPROC glad_glMultiTexCoord3bvOES = NULL;
+PFNGLMULTITEXCOORD4BOESPROC glad_glMultiTexCoord4bOES = NULL;
+PFNGLMULTITEXCOORD4BVOESPROC glad_glMultiTexCoord4bvOES = NULL;
+PFNGLTEXCOORD1BOESPROC glad_glTexCoord1bOES = NULL;
+PFNGLTEXCOORD1BVOESPROC glad_glTexCoord1bvOES = NULL;
+PFNGLTEXCOORD2BOESPROC glad_glTexCoord2bOES = NULL;
+PFNGLTEXCOORD2BVOESPROC glad_glTexCoord2bvOES = NULL;
+PFNGLTEXCOORD3BOESPROC glad_glTexCoord3bOES = NULL;
+PFNGLTEXCOORD3BVOESPROC glad_glTexCoord3bvOES = NULL;
+PFNGLTEXCOORD4BOESPROC glad_glTexCoord4bOES = NULL;
+PFNGLTEXCOORD4BVOESPROC glad_glTexCoord4bvOES = NULL;
+PFNGLVERTEX2BOESPROC glad_glVertex2bOES = NULL;
+PFNGLVERTEX2BVOESPROC glad_glVertex2bvOES = NULL;
+PFNGLVERTEX3BOESPROC glad_glVertex3bOES = NULL;
+PFNGLVERTEX3BVOESPROC glad_glVertex3bvOES = NULL;
+PFNGLVERTEX4BOESPROC glad_glVertex4bOES = NULL;
+PFNGLVERTEX4BVOESPROC glad_glVertex4bvOES = NULL;
+PFNGLALPHAFUNCXOESPROC glad_glAlphaFuncxOES = NULL;
+PFNGLCLEARCOLORXOESPROC glad_glClearColorxOES = NULL;
+PFNGLCLEARDEPTHXOESPROC glad_glClearDepthxOES = NULL;
+PFNGLCLIPPLANEXOESPROC glad_glClipPlanexOES = NULL;
+PFNGLCOLOR4XOESPROC glad_glColor4xOES = NULL;
+PFNGLDEPTHRANGEXOESPROC glad_glDepthRangexOES = NULL;
+PFNGLFOGXOESPROC glad_glFogxOES = NULL;
+PFNGLFOGXVOESPROC glad_glFogxvOES = NULL;
+PFNGLFRUSTUMXOESPROC glad_glFrustumxOES = NULL;
+PFNGLGETCLIPPLANEXOESPROC glad_glGetClipPlanexOES = NULL;
+PFNGLGETFIXEDVOESPROC glad_glGetFixedvOES = NULL;
+PFNGLGETTEXENVXVOESPROC glad_glGetTexEnvxvOES = NULL;
+PFNGLGETTEXPARAMETERXVOESPROC glad_glGetTexParameterxvOES = NULL;
+PFNGLLIGHTMODELXOESPROC glad_glLightModelxOES = NULL;
+PFNGLLIGHTMODELXVOESPROC glad_glLightModelxvOES = NULL;
+PFNGLLIGHTXOESPROC glad_glLightxOES = NULL;
+PFNGLLIGHTXVOESPROC glad_glLightxvOES = NULL;
+PFNGLLINEWIDTHXOESPROC glad_glLineWidthxOES = NULL;
+PFNGLLOADMATRIXXOESPROC glad_glLoadMatrixxOES = NULL;
+PFNGLMATERIALXOESPROC glad_glMaterialxOES = NULL;
+PFNGLMATERIALXVOESPROC glad_glMaterialxvOES = NULL;
+PFNGLMULTMATRIXXOESPROC glad_glMultMatrixxOES = NULL;
+PFNGLMULTITEXCOORD4XOESPROC glad_glMultiTexCoord4xOES = NULL;
+PFNGLNORMAL3XOESPROC glad_glNormal3xOES = NULL;
+PFNGLORTHOXOESPROC glad_glOrthoxOES = NULL;
+PFNGLPOINTPARAMETERXVOESPROC glad_glPointParameterxvOES = NULL;
+PFNGLPOINTSIZEXOESPROC glad_glPointSizexOES = NULL;
+PFNGLPOLYGONOFFSETXOESPROC glad_glPolygonOffsetxOES = NULL;
+PFNGLROTATEXOESPROC glad_glRotatexOES = NULL;
+PFNGLSCALEXOESPROC glad_glScalexOES = NULL;
+PFNGLTEXENVXOESPROC glad_glTexEnvxOES = NULL;
+PFNGLTEXENVXVOESPROC glad_glTexEnvxvOES = NULL;
+PFNGLTEXPARAMETERXOESPROC glad_glTexParameterxOES = NULL;
+PFNGLTEXPARAMETERXVOESPROC glad_glTexParameterxvOES = NULL;
+PFNGLTRANSLATEXOESPROC glad_glTranslatexOES = NULL;
+PFNGLGETLIGHTXVOESPROC glad_glGetLightxvOES = NULL;
+PFNGLGETMATERIALXVOESPROC glad_glGetMaterialxvOES = NULL;
+PFNGLPOINTPARAMETERXOESPROC glad_glPointParameterxOES = NULL;
+PFNGLSAMPLECOVERAGEXOESPROC glad_glSampleCoveragexOES = NULL;
+PFNGLACCUMXOESPROC glad_glAccumxOES = NULL;
+PFNGLBITMAPXOESPROC glad_glBitmapxOES = NULL;
+PFNGLBLENDCOLORXOESPROC glad_glBlendColorxOES = NULL;
+PFNGLCLEARACCUMXOESPROC glad_glClearAccumxOES = NULL;
+PFNGLCOLOR3XOESPROC glad_glColor3xOES = NULL;
+PFNGLCOLOR3XVOESPROC glad_glColor3xvOES = NULL;
+PFNGLCOLOR4XVOESPROC glad_glColor4xvOES = NULL;
+PFNGLCONVOLUTIONPARAMETERXOESPROC glad_glConvolutionParameterxOES = NULL;
+PFNGLCONVOLUTIONPARAMETERXVOESPROC glad_glConvolutionParameterxvOES = NULL;
+PFNGLEVALCOORD1XOESPROC glad_glEvalCoord1xOES = NULL;
+PFNGLEVALCOORD1XVOESPROC glad_glEvalCoord1xvOES = NULL;
+PFNGLEVALCOORD2XOESPROC glad_glEvalCoord2xOES = NULL;
+PFNGLEVALCOORD2XVOESPROC glad_glEvalCoord2xvOES = NULL;
+PFNGLFEEDBACKBUFFERXOESPROC glad_glFeedbackBufferxOES = NULL;
+PFNGLGETCONVOLUTIONPARAMETERXVOESPROC glad_glGetConvolutionParameterxvOES = NULL;
+PFNGLGETHISTOGRAMPARAMETERXVOESPROC glad_glGetHistogramParameterxvOES = NULL;
+PFNGLGETLIGHTXOESPROC glad_glGetLightxOES = NULL;
+PFNGLGETMAPXVOESPROC glad_glGetMapxvOES = NULL;
+PFNGLGETMATERIALXOESPROC glad_glGetMaterialxOES = NULL;
+PFNGLGETPIXELMAPXVPROC glad_glGetPixelMapxv = NULL;
+PFNGLGETTEXGENXVOESPROC glad_glGetTexGenxvOES = NULL;
+PFNGLGETTEXLEVELPARAMETERXVOESPROC glad_glGetTexLevelParameterxvOES = NULL;
+PFNGLINDEXXOESPROC glad_glIndexxOES = NULL;
+PFNGLINDEXXVOESPROC glad_glIndexxvOES = NULL;
+PFNGLLOADTRANSPOSEMATRIXXOESPROC glad_glLoadTransposeMatrixxOES = NULL;
+PFNGLMAP1XOESPROC glad_glMap1xOES = NULL;
+PFNGLMAP2XOESPROC glad_glMap2xOES = NULL;
+PFNGLMAPGRID1XOESPROC glad_glMapGrid1xOES = NULL;
+PFNGLMAPGRID2XOESPROC glad_glMapGrid2xOES = NULL;
+PFNGLMULTTRANSPOSEMATRIXXOESPROC glad_glMultTransposeMatrixxOES = NULL;
+PFNGLMULTITEXCOORD1XOESPROC glad_glMultiTexCoord1xOES = NULL;
+PFNGLMULTITEXCOORD1XVOESPROC glad_glMultiTexCoord1xvOES = NULL;
+PFNGLMULTITEXCOORD2XOESPROC glad_glMultiTexCoord2xOES = NULL;
+PFNGLMULTITEXCOORD2XVOESPROC glad_glMultiTexCoord2xvOES = NULL;
+PFNGLMULTITEXCOORD3XOESPROC glad_glMultiTexCoord3xOES = NULL;
+PFNGLMULTITEXCOORD3XVOESPROC glad_glMultiTexCoord3xvOES = NULL;
+PFNGLMULTITEXCOORD4XVOESPROC glad_glMultiTexCoord4xvOES = NULL;
+PFNGLNORMAL3XVOESPROC glad_glNormal3xvOES = NULL;
+PFNGLPASSTHROUGHXOESPROC glad_glPassThroughxOES = NULL;
+PFNGLPIXELMAPXPROC glad_glPixelMapx = NULL;
+PFNGLPIXELSTOREXPROC glad_glPixelStorex = NULL;
+PFNGLPIXELTRANSFERXOESPROC glad_glPixelTransferxOES = NULL;
+PFNGLPIXELZOOMXOESPROC glad_glPixelZoomxOES = NULL;
+PFNGLPRIORITIZETEXTURESXOESPROC glad_glPrioritizeTexturesxOES = NULL;
+PFNGLRASTERPOS2XOESPROC glad_glRasterPos2xOES = NULL;
+PFNGLRASTERPOS2XVOESPROC glad_glRasterPos2xvOES = NULL;
+PFNGLRASTERPOS3XOESPROC glad_glRasterPos3xOES = NULL;
+PFNGLRASTERPOS3XVOESPROC glad_glRasterPos3xvOES = NULL;
+PFNGLRASTERPOS4XOESPROC glad_glRasterPos4xOES = NULL;
+PFNGLRASTERPOS4XVOESPROC glad_glRasterPos4xvOES = NULL;
+PFNGLRECTXOESPROC glad_glRectxOES = NULL;
+PFNGLRECTXVOESPROC glad_glRectxvOES = NULL;
+PFNGLTEXCOORD1XOESPROC glad_glTexCoord1xOES = NULL;
+PFNGLTEXCOORD1XVOESPROC glad_glTexCoord1xvOES = NULL;
+PFNGLTEXCOORD2XOESPROC glad_glTexCoord2xOES = NULL;
+PFNGLTEXCOORD2XVOESPROC glad_glTexCoord2xvOES = NULL;
+PFNGLTEXCOORD3XOESPROC glad_glTexCoord3xOES = NULL;
+PFNGLTEXCOORD3XVOESPROC glad_glTexCoord3xvOES = NULL;
+PFNGLTEXCOORD4XOESPROC glad_glTexCoord4xOES = NULL;
+PFNGLTEXCOORD4XVOESPROC glad_glTexCoord4xvOES = NULL;
+PFNGLTEXGENXOESPROC glad_glTexGenxOES = NULL;
+PFNGLTEXGENXVOESPROC glad_glTexGenxvOES = NULL;
+PFNGLVERTEX2XOESPROC glad_glVertex2xOES = NULL;
+PFNGLVERTEX2XVOESPROC glad_glVertex2xvOES = NULL;
+PFNGLVERTEX3XOESPROC glad_glVertex3xOES = NULL;
+PFNGLVERTEX3XVOESPROC glad_glVertex3xvOES = NULL;
+PFNGLVERTEX4XOESPROC glad_glVertex4xOES = NULL;
+PFNGLVERTEX4XVOESPROC glad_glVertex4xvOES = NULL;
+PFNGLQUERYMATRIXXOESPROC glad_glQueryMatrixxOES = NULL;
+PFNGLCLEARDEPTHFOESPROC glad_glClearDepthfOES = NULL;
+PFNGLCLIPPLANEFOESPROC glad_glClipPlanefOES = NULL;
+PFNGLDEPTHRANGEFOESPROC glad_glDepthRangefOES = NULL;
+PFNGLFRUSTUMFOESPROC glad_glFrustumfOES = NULL;
+PFNGLGETCLIPPLANEFOESPROC glad_glGetClipPlanefOES = NULL;
+PFNGLORTHOFOESPROC glad_glOrthofOES = NULL;
+PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR = NULL;
+PFNGLHINTPGIPROC glad_glHintPGI = NULL;
+PFNGLDETAILTEXFUNCSGISPROC glad_glDetailTexFuncSGIS = NULL;
+PFNGLGETDETAILTEXFUNCSGISPROC glad_glGetDetailTexFuncSGIS = NULL;
+PFNGLFOGFUNCSGISPROC glad_glFogFuncSGIS = NULL;
+PFNGLGETFOGFUNCSGISPROC glad_glGetFogFuncSGIS = NULL;
+PFNGLSAMPLEMASKSGISPROC glad_glSampleMaskSGIS = NULL;
+PFNGLSAMPLEPATTERNSGISPROC glad_glSamplePatternSGIS = NULL;
+PFNGLPIXELTEXGENPARAMETERISGISPROC glad_glPixelTexGenParameteriSGIS = NULL;
+PFNGLPIXELTEXGENPARAMETERIVSGISPROC glad_glPixelTexGenParameterivSGIS = NULL;
+PFNGLPIXELTEXGENPARAMETERFSGISPROC glad_glPixelTexGenParameterfSGIS = NULL;
+PFNGLPIXELTEXGENPARAMETERFVSGISPROC glad_glPixelTexGenParameterfvSGIS = NULL;
+PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC glad_glGetPixelTexGenParameterivSGIS = NULL;
+PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC glad_glGetPixelTexGenParameterfvSGIS = NULL;
+PFNGLPOINTPARAMETERFSGISPROC glad_glPointParameterfSGIS = NULL;
+PFNGLPOINTPARAMETERFVSGISPROC glad_glPointParameterfvSGIS = NULL;
+PFNGLSHARPENTEXFUNCSGISPROC glad_glSharpenTexFuncSGIS = NULL;
+PFNGLGETSHARPENTEXFUNCSGISPROC glad_glGetSharpenTexFuncSGIS = NULL;
+PFNGLTEXIMAGE4DSGISPROC glad_glTexImage4DSGIS = NULL;
+PFNGLTEXSUBIMAGE4DSGISPROC glad_glTexSubImage4DSGIS = NULL;
+PFNGLTEXTURECOLORMASKSGISPROC glad_glTextureColorMaskSGIS = NULL;
+PFNGLGETTEXFILTERFUNCSGISPROC glad_glGetTexFilterFuncSGIS = NULL;
+PFNGLTEXFILTERFUNCSGISPROC glad_glTexFilterFuncSGIS = NULL;
+PFNGLASYNCMARKERSGIXPROC glad_glAsyncMarkerSGIX = NULL;
+PFNGLFINISHASYNCSGIXPROC glad_glFinishAsyncSGIX = NULL;
+PFNGLPOLLASYNCSGIXPROC glad_glPollAsyncSGIX = NULL;
+PFNGLGENASYNCMARKERSSGIXPROC glad_glGenAsyncMarkersSGIX = NULL;
+PFNGLDELETEASYNCMARKERSSGIXPROC glad_glDeleteAsyncMarkersSGIX = NULL;
+PFNGLISASYNCMARKERSGIXPROC glad_glIsAsyncMarkerSGIX = NULL;
+PFNGLFLUSHRASTERSGIXPROC glad_glFlushRasterSGIX = NULL;
+PFNGLFRAGMENTCOLORMATERIALSGIXPROC glad_glFragmentColorMaterialSGIX = NULL;
+PFNGLFRAGMENTLIGHTFSGIXPROC glad_glFragmentLightfSGIX = NULL;
+PFNGLFRAGMENTLIGHTFVSGIXPROC glad_glFragmentLightfvSGIX = NULL;
+PFNGLFRAGMENTLIGHTISGIXPROC glad_glFragmentLightiSGIX = NULL;
+PFNGLFRAGMENTLIGHTIVSGIXPROC glad_glFragmentLightivSGIX = NULL;
+PFNGLFRAGMENTLIGHTMODELFSGIXPROC glad_glFragmentLightModelfSGIX = NULL;
+PFNGLFRAGMENTLIGHTMODELFVSGIXPROC glad_glFragmentLightModelfvSGIX = NULL;
+PFNGLFRAGMENTLIGHTMODELISGIXPROC glad_glFragmentLightModeliSGIX = NULL;
+PFNGLFRAGMENTLIGHTMODELIVSGIXPROC glad_glFragmentLightModelivSGIX = NULL;
+PFNGLFRAGMENTMATERIALFSGIXPROC glad_glFragmentMaterialfSGIX = NULL;
+PFNGLFRAGMENTMATERIALFVSGIXPROC glad_glFragmentMaterialfvSGIX = NULL;
+PFNGLFRAGMENTMATERIALISGIXPROC glad_glFragmentMaterialiSGIX = NULL;
+PFNGLFRAGMENTMATERIALIVSGIXPROC glad_glFragmentMaterialivSGIX = NULL;
+PFNGLGETFRAGMENTLIGHTFVSGIXPROC glad_glGetFragmentLightfvSGIX = NULL;
+PFNGLGETFRAGMENTLIGHTIVSGIXPROC glad_glGetFragmentLightivSGIX = NULL;
+PFNGLGETFRAGMENTMATERIALFVSGIXPROC glad_glGetFragmentMaterialfvSGIX = NULL;
+PFNGLGETFRAGMENTMATERIALIVSGIXPROC glad_glGetFragmentMaterialivSGIX = NULL;
+PFNGLLIGHTENVISGIXPROC glad_glLightEnviSGIX = NULL;
+PFNGLFRAMEZOOMSGIXPROC glad_glFrameZoomSGIX = NULL;
+PFNGLIGLOOINTERFACESGIXPROC glad_glIglooInterfaceSGIX = NULL;
+PFNGLGETINSTRUMENTSSGIXPROC glad_glGetInstrumentsSGIX = NULL;
+PFNGLINSTRUMENTSBUFFERSGIXPROC glad_glInstrumentsBufferSGIX = NULL;
+PFNGLPOLLINSTRUMENTSSGIXPROC glad_glPollInstrumentsSGIX = NULL;
+PFNGLREADINSTRUMENTSSGIXPROC glad_glReadInstrumentsSGIX = NULL;
+PFNGLSTARTINSTRUMENTSSGIXPROC glad_glStartInstrumentsSGIX = NULL;
+PFNGLSTOPINSTRUMENTSSGIXPROC glad_glStopInstrumentsSGIX = NULL;
+PFNGLGETLISTPARAMETERFVSGIXPROC glad_glGetListParameterfvSGIX = NULL;
+PFNGLGETLISTPARAMETERIVSGIXPROC glad_glGetListParameterivSGIX = NULL;
+PFNGLLISTPARAMETERFSGIXPROC glad_glListParameterfSGIX = NULL;
+PFNGLLISTPARAMETERFVSGIXPROC glad_glListParameterfvSGIX = NULL;
+PFNGLLISTPARAMETERISGIXPROC glad_glListParameteriSGIX = NULL;
+PFNGLLISTPARAMETERIVSGIXPROC glad_glListParameterivSGIX = NULL;
+PFNGLPIXELTEXGENSGIXPROC glad_glPixelTexGenSGIX = NULL;
+PFNGLDEFORMATIONMAP3DSGIXPROC glad_glDeformationMap3dSGIX = NULL;
+PFNGLDEFORMATIONMAP3FSGIXPROC glad_glDeformationMap3fSGIX = NULL;
+PFNGLDEFORMSGIXPROC glad_glDeformSGIX = NULL;
+PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC glad_glLoadIdentityDeformationMapSGIX = NULL;
+PFNGLREFERENCEPLANESGIXPROC glad_glReferencePlaneSGIX = NULL;
+PFNGLSPRITEPARAMETERFSGIXPROC glad_glSpriteParameterfSGIX = NULL;
+PFNGLSPRITEPARAMETERFVSGIXPROC glad_glSpriteParameterfvSGIX = NULL;
+PFNGLSPRITEPARAMETERISGIXPROC glad_glSpriteParameteriSGIX = NULL;
+PFNGLSPRITEPARAMETERIVSGIXPROC glad_glSpriteParameterivSGIX = NULL;
+PFNGLTAGSAMPLEBUFFERSGIXPROC glad_glTagSampleBufferSGIX = NULL;
+PFNGLCOLORTABLESGIPROC glad_glColorTableSGI = NULL;
+PFNGLCOLORTABLEPARAMETERFVSGIPROC glad_glColorTableParameterfvSGI = NULL;
+PFNGLCOLORTABLEPARAMETERIVSGIPROC glad_glColorTableParameterivSGI = NULL;
+PFNGLCOPYCOLORTABLESGIPROC glad_glCopyColorTableSGI = NULL;
+PFNGLGETCOLORTABLESGIPROC glad_glGetColorTableSGI = NULL;
+PFNGLGETCOLORTABLEPARAMETERFVSGIPROC glad_glGetColorTableParameterfvSGI = NULL;
+PFNGLGETCOLORTABLEPARAMETERIVSGIPROC glad_glGetColorTableParameterivSGI = NULL;
+PFNGLFINISHTEXTURESUNXPROC glad_glFinishTextureSUNX = NULL;
+PFNGLGLOBALALPHAFACTORBSUNPROC glad_glGlobalAlphaFactorbSUN = NULL;
+PFNGLGLOBALALPHAFACTORSSUNPROC glad_glGlobalAlphaFactorsSUN = NULL;
+PFNGLGLOBALALPHAFACTORISUNPROC glad_glGlobalAlphaFactoriSUN = NULL;
+PFNGLGLOBALALPHAFACTORFSUNPROC glad_glGlobalAlphaFactorfSUN = NULL;
+PFNGLGLOBALALPHAFACTORDSUNPROC glad_glGlobalAlphaFactordSUN = NULL;
+PFNGLGLOBALALPHAFACTORUBSUNPROC glad_glGlobalAlphaFactorubSUN = NULL;
+PFNGLGLOBALALPHAFACTORUSSUNPROC glad_glGlobalAlphaFactorusSUN = NULL;
+PFNGLGLOBALALPHAFACTORUISUNPROC glad_glGlobalAlphaFactoruiSUN = NULL;
+PFNGLDRAWMESHARRAYSSUNPROC glad_glDrawMeshArraysSUN = NULL;
+PFNGLREPLACEMENTCODEUISUNPROC glad_glReplacementCodeuiSUN = NULL;
+PFNGLREPLACEMENTCODEUSSUNPROC glad_glReplacementCodeusSUN = NULL;
+PFNGLREPLACEMENTCODEUBSUNPROC glad_glReplacementCodeubSUN = NULL;
+PFNGLREPLACEMENTCODEUIVSUNPROC glad_glReplacementCodeuivSUN = NULL;
+PFNGLREPLACEMENTCODEUSVSUNPROC glad_glReplacementCodeusvSUN = NULL;
+PFNGLREPLACEMENTCODEUBVSUNPROC glad_glReplacementCodeubvSUN = NULL;
+PFNGLREPLACEMENTCODEPOINTERSUNPROC glad_glReplacementCodePointerSUN = NULL;
+PFNGLCOLOR4UBVERTEX2FSUNPROC glad_glColor4ubVertex2fSUN = NULL;
+PFNGLCOLOR4UBVERTEX2FVSUNPROC glad_glColor4ubVertex2fvSUN = NULL;
+PFNGLCOLOR4UBVERTEX3FSUNPROC glad_glColor4ubVertex3fSUN = NULL;
+PFNGLCOLOR4UBVERTEX3FVSUNPROC glad_glColor4ubVertex3fvSUN = NULL;
+PFNGLCOLOR3FVERTEX3FSUNPROC glad_glColor3fVertex3fSUN = NULL;
+PFNGLCOLOR3FVERTEX3FVSUNPROC glad_glColor3fVertex3fvSUN = NULL;
+PFNGLNORMAL3FVERTEX3FSUNPROC glad_glNormal3fVertex3fSUN = NULL;
+PFNGLNORMAL3FVERTEX3FVSUNPROC glad_glNormal3fVertex3fvSUN = NULL;
+PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC glad_glColor4fNormal3fVertex3fSUN = NULL;
+PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC glad_glColor4fNormal3fVertex3fvSUN = NULL;
+PFNGLTEXCOORD2FVERTEX3FSUNPROC glad_glTexCoord2fVertex3fSUN = NULL;
+PFNGLTEXCOORD2FVERTEX3FVSUNPROC glad_glTexCoord2fVertex3fvSUN = NULL;
+PFNGLTEXCOORD4FVERTEX4FSUNPROC glad_glTexCoord4fVertex4fSUN = NULL;
+PFNGLTEXCOORD4FVERTEX4FVSUNPROC glad_glTexCoord4fVertex4fvSUN = NULL;
+PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC glad_glTexCoord2fColor4ubVertex3fSUN = NULL;
+PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC glad_glTexCoord2fColor4ubVertex3fvSUN = NULL;
+PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC glad_glTexCoord2fColor3fVertex3fSUN = NULL;
+PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC glad_glTexCoord2fColor3fVertex3fvSUN = NULL;
+PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC glad_glTexCoord2fNormal3fVertex3fSUN = NULL;
+PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC glad_glTexCoord2fNormal3fVertex3fvSUN = NULL;
+PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC glad_glTexCoord2fColor4fNormal3fVertex3fSUN = NULL;
+PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC glad_glTexCoord2fColor4fNormal3fVertex3fvSUN = NULL;
+PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC glad_glTexCoord4fColor4fNormal3fVertex4fSUN = NULL;
+PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC glad_glTexCoord4fColor4fNormal3fVertex4fvSUN = NULL;
+PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC glad_glReplacementCodeuiVertex3fSUN = NULL;
+PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC glad_glReplacementCodeuiVertex3fvSUN = NULL;
+PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC glad_glReplacementCodeuiColor4ubVertex3fSUN = NULL;
+PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC glad_glReplacementCodeuiColor4ubVertex3fvSUN = NULL;
+PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC glad_glReplacementCodeuiColor3fVertex3fSUN = NULL;
+PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC glad_glReplacementCodeuiColor3fVertex3fvSUN = NULL;
+PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC glad_glReplacementCodeuiNormal3fVertex3fSUN = NULL;
+PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC glad_glReplacementCodeuiNormal3fVertex3fvSUN = NULL;
+PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC glad_glReplacementCodeuiColor4fNormal3fVertex3fSUN = NULL;
+PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC glad_glReplacementCodeuiColor4fNormal3fVertex3fvSUN = NULL;
+PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC glad_glReplacementCodeuiTexCoord2fVertex3fSUN = NULL;
+PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC glad_glReplacementCodeuiTexCoord2fVertex3fvSUN = NULL;
+PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC glad_glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN = NULL;
+PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC glad_glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN = NULL;
+PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC glad_glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN = NULL;
+PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC glad_glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN = NULL;
static void load_GL_VERSION_1_0(GLADloadproc load) {
if(!GLAD_GL_VERSION_1_0) return;
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
@@ -4453,6 +4457,11 @@ static void load_GL_AMD_draw_buffers_blend(GLADloadproc load) {
glad_glBlendEquationIndexedAMD = (PFNGLBLENDEQUATIONINDEXEDAMDPROC)load("glBlendEquationIndexedAMD");
glad_glBlendEquationSeparateIndexedAMD = (PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC)load("glBlendEquationSeparateIndexedAMD");
}
+static void load_GL_AMD_framebuffer_multisample_advanced(GLADloadproc load) {
+ if(!GLAD_GL_AMD_framebuffer_multisample_advanced) return;
+ glad_glRenderbufferStorageMultisampleAdvancedAMD = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC)load("glRenderbufferStorageMultisampleAdvancedAMD");
+ glad_glNamedRenderbufferStorageMultisampleAdvancedAMD = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC)load("glNamedRenderbufferStorageMultisampleAdvancedAMD");
+}
static void load_GL_AMD_framebuffer_sample_positions(GLADloadproc load) {
if(!GLAD_GL_AMD_framebuffer_sample_positions) return;
glad_glFramebufferSamplePositionsfvAMD = (PFNGLFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC)load("glFramebufferSamplePositionsfvAMD");
@@ -7812,6 +7821,7 @@ static int find_extensionsGL(void) {
GLAD_GL_AMD_debug_output = has_ext("GL_AMD_debug_output");
GLAD_GL_AMD_depth_clamp_separate = has_ext("GL_AMD_depth_clamp_separate");
GLAD_GL_AMD_draw_buffers_blend = has_ext("GL_AMD_draw_buffers_blend");
+ GLAD_GL_AMD_framebuffer_multisample_advanced = has_ext("GL_AMD_framebuffer_multisample_advanced");
GLAD_GL_AMD_framebuffer_sample_positions = has_ext("GL_AMD_framebuffer_sample_positions");
GLAD_GL_AMD_gcn_shader = has_ext("GL_AMD_gcn_shader");
GLAD_GL_AMD_gpu_shader_half_float = has_ext("GL_AMD_gpu_shader_half_float");
@@ -8473,6 +8483,7 @@ int gladLoadGLLoader(GLADloadproc load) {
load_GL_3DFX_tbuffer(load);
load_GL_AMD_debug_output(load);
load_GL_AMD_draw_buffers_blend(load);
+ load_GL_AMD_framebuffer_multisample_advanced(load);
load_GL_AMD_framebuffer_sample_positions(load);
load_GL_AMD_gpu_shader_int64(load);
load_GL_AMD_interleaved_elements(load);
diff --git a/externals/mbedtls b/externals/mbedtls
new file mode 160000
+Subproject d409b75a4cf75a5b358b352c75826ddbca44db5
diff --git a/externals/opus b/externals/opus
new file mode 160000
+Subproject b2871922a12abb49579512d604cabc471a59ad9
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 85354f43e..a88551fbc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,6 +3,7 @@ include_directories(.)
add_subdirectory(common)
add_subdirectory(core)
+add_subdirectory(audio_core)
add_subdirectory(video_core)
add_subdirectory(input_common)
add_subdirectory(tests)
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
new file mode 100644
index 000000000..82e4850f7
--- /dev/null
+++ b/src/audio_core/CMakeLists.txt
@@ -0,0 +1,31 @@
+add_library(audio_core STATIC
+ algorithm/filter.cpp
+ algorithm/filter.h
+ algorithm/interpolate.cpp
+ algorithm/interpolate.h
+ audio_out.cpp
+ audio_out.h
+ audio_renderer.cpp
+ audio_renderer.h
+ buffer.h
+ codec.cpp
+ codec.h
+ null_sink.h
+ sink.h
+ sink_details.cpp
+ sink_details.h
+ sink_stream.h
+ stream.cpp
+ stream.h
+
+ $<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h>
+)
+
+create_target_directory_groups(audio_core)
+
+target_link_libraries(audio_core PUBLIC common core)
+
+if(ENABLE_CUBEB)
+ target_link_libraries(audio_core PRIVATE cubeb)
+ target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1)
+endif()
diff --git a/src/audio_core/algorithm/filter.cpp b/src/audio_core/algorithm/filter.cpp
new file mode 100644
index 000000000..403b8503f
--- /dev/null
+++ b/src/audio_core/algorithm/filter.cpp
@@ -0,0 +1,79 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#define _USE_MATH_DEFINES
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <vector>
+#include "audio_core/algorithm/filter.h"
+#include "common/common_types.h"
+
+namespace AudioCore {
+
+Filter Filter::LowPass(double cutoff, double Q) {
+ const double w0 = 2.0 * M_PI * cutoff;
+ const double sin_w0 = std::sin(w0);
+ const double cos_w0 = std::cos(w0);
+ const double alpha = sin_w0 / (2 * Q);
+
+ const double a0 = 1 + alpha;
+ const double a1 = -2.0 * cos_w0;
+ const double a2 = 1 - alpha;
+ const double b0 = 0.5 * (1 - cos_w0);
+ const double b1 = 1.0 * (1 - cos_w0);
+ const double b2 = 0.5 * (1 - cos_w0);
+
+ return {a0, a1, a2, b0, b1, b2};
+}
+
+Filter::Filter() : Filter(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) {}
+
+Filter::Filter(double a0, double a1, double a2, double b0, double b1, double b2)
+ : a1(a1 / a0), a2(a2 / a0), b0(b0 / a0), b1(b1 / a0), b2(b2 / a0) {}
+
+void Filter::Process(std::vector<s16>& signal) {
+ const size_t num_frames = signal.size() / 2;
+ for (size_t i = 0; i < num_frames; i++) {
+ std::rotate(in.begin(), in.end() - 1, in.end());
+ std::rotate(out.begin(), out.end() - 1, out.end());
+
+ for (size_t ch = 0; ch < channel_count; ch++) {
+ in[0][ch] = signal[i * channel_count + ch];
+
+ out[0][ch] = b0 * in[0][ch] + b1 * in[1][ch] + b2 * in[2][ch] - a1 * out[1][ch] -
+ a2 * out[2][ch];
+
+ signal[i * 2 + ch] = std::clamp(out[0][ch], -32768.0, 32767.0);
+ }
+ }
+}
+
+/// Calculates the appropriate Q for each biquad in a cascading filter.
+/// @param total_count The total number of biquads to be cascaded.
+/// @param index 0-index of the biquad to calculate the Q value for.
+static double CascadingBiquadQ(size_t total_count, size_t index) {
+ const double pole = M_PI * (2 * index + 1) / (4.0 * total_count);
+ return 1.0 / (2.0 * std::cos(pole));
+}
+
+CascadingFilter CascadingFilter::LowPass(double cutoff, size_t cascade_size) {
+ std::vector<Filter> cascade(cascade_size);
+ for (size_t i = 0; i < cascade_size; i++) {
+ cascade[i] = Filter::LowPass(cutoff, CascadingBiquadQ(cascade_size, i));
+ }
+ return CascadingFilter{std::move(cascade)};
+}
+
+CascadingFilter::CascadingFilter() = default;
+CascadingFilter::CascadingFilter(std::vector<Filter> filters) : filters(std::move(filters)) {}
+
+void CascadingFilter::Process(std::vector<s16>& signal) {
+ for (auto& filter : filters) {
+ filter.Process(signal);
+ }
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/algorithm/filter.h b/src/audio_core/algorithm/filter.h
new file mode 100644
index 000000000..a41beef98
--- /dev/null
+++ b/src/audio_core/algorithm/filter.h
@@ -0,0 +1,62 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <vector>
+#include "common/common_types.h"
+
+namespace AudioCore {
+
+/// Digital biquad filter:
+///
+/// b0 + b1 z^-1 + b2 z^-2
+/// H(z) = ------------------------
+/// a0 + a1 z^-1 + b2 z^-2
+class Filter {
+public:
+ /// Creates a low-pass filter.
+ /// @param cutoff Determines the cutoff frequency. A value from 0.0 to 1.0.
+ /// @param Q Determines the quality factor of this filter.
+ static Filter LowPass(double cutoff, double Q = 0.7071);
+
+ /// Passthrough filter.
+ Filter();
+
+ Filter(double a0, double a1, double a2, double b0, double b1, double b2);
+
+ void Process(std::vector<s16>& signal);
+
+private:
+ static constexpr size_t channel_count = 2;
+
+ /// Coefficients are in normalized form (a0 = 1.0).
+ double a1, a2, b0, b1, b2;
+ /// Input History
+ std::array<std::array<double, channel_count>, 3> in;
+ /// Output History
+ std::array<std::array<double, channel_count>, 3> out;
+};
+
+/// Cascade filters to build up higher-order filters from lower-order ones.
+class CascadingFilter {
+public:
+ /// Creates a cascading low-pass filter.
+ /// @param cutoff Determines the cutoff frequency. A value from 0.0 to 1.0.
+ /// @param cascade_size Number of biquads in cascade.
+ static CascadingFilter LowPass(double cutoff, size_t cascade_size);
+
+ /// Passthrough.
+ CascadingFilter();
+
+ explicit CascadingFilter(std::vector<Filter> filters);
+
+ void Process(std::vector<s16>& signal);
+
+private:
+ std::vector<Filter> filters;
+};
+
+} // namespace AudioCore
diff --git a/src/audio_core/algorithm/interpolate.cpp b/src/audio_core/algorithm/interpolate.cpp
new file mode 100644
index 000000000..11459821f
--- /dev/null
+++ b/src/audio_core/algorithm/interpolate.cpp
@@ -0,0 +1,71 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#define _USE_MATH_DEFINES
+
+#include <algorithm>
+#include <cmath>
+#include <vector>
+#include "audio_core/algorithm/interpolate.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+
+namespace AudioCore {
+
+/// The Lanczos kernel
+static double Lanczos(size_t a, double x) {
+ if (x == 0.0)
+ return 1.0;
+ const double px = M_PI * x;
+ return a * std::sin(px) * std::sin(px / a) / (px * px);
+}
+
+std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input, double ratio) {
+ if (input.size() < 2)
+ return {};
+
+ if (ratio <= 0) {
+ LOG_CRITICAL(Audio, "Nonsensical interpolation ratio {}", ratio);
+ ratio = 1.0;
+ }
+
+ if (ratio != state.current_ratio) {
+ const double cutoff_frequency = std::min(0.5 / ratio, 0.5 * ratio);
+ state.nyquist = CascadingFilter::LowPass(std::clamp(cutoff_frequency, 0.0, 0.4), 3);
+ state.current_ratio = ratio;
+ }
+ state.nyquist.Process(input);
+
+ constexpr size_t taps = InterpolationState::lanczos_taps;
+ const size_t num_frames = input.size() / 2;
+
+ std::vector<s16> output;
+ output.reserve(static_cast<size_t>(input.size() / ratio + 4));
+
+ double& pos = state.position;
+ auto& h = state.history;
+ for (size_t i = 0; i < num_frames; ++i) {
+ std::rotate(h.begin(), h.end() - 1, h.end());
+ h[0][0] = input[i * 2 + 0];
+ h[0][1] = input[i * 2 + 1];
+
+ while (pos <= 1.0) {
+ double l = 0.0;
+ double r = 0.0;
+ for (size_t j = 0; j < h.size(); j++) {
+ l += Lanczos(taps, pos + j - taps + 1) * h[j][0];
+ r += Lanczos(taps, pos + j - taps + 1) * h[j][1];
+ }
+ output.emplace_back(static_cast<s16>(std::clamp(l, -32768.0, 32767.0)));
+ output.emplace_back(static_cast<s16>(std::clamp(r, -32768.0, 32767.0)));
+
+ pos += ratio;
+ }
+ pos -= 1.0;
+ }
+
+ return output;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/algorithm/interpolate.h b/src/audio_core/algorithm/interpolate.h
new file mode 100644
index 000000000..c79c2eef4
--- /dev/null
+++ b/src/audio_core/algorithm/interpolate.h
@@ -0,0 +1,43 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <vector>
+#include "audio_core/algorithm/filter.h"
+#include "common/common_types.h"
+
+namespace AudioCore {
+
+struct InterpolationState {
+ static constexpr size_t lanczos_taps = 4;
+ static constexpr size_t history_size = lanczos_taps * 2 - 1;
+
+ double current_ratio = 0.0;
+ CascadingFilter nyquist;
+ std::array<std::array<s16, 2>, history_size> history = {};
+ double position = 0;
+};
+
+/// Interpolates input signal to produce output signal.
+/// @param input The signal to interpolate.
+/// @param ratio Interpolation ratio.
+/// ratio > 1.0 results in fewer output samples.
+/// ratio < 1.0 results in more output samples.
+/// @returns Output signal.
+std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input, double ratio);
+
+/// Interpolates input signal to produce output signal.
+/// @param input The signal to interpolate.
+/// @param input_rate The sample rate of input.
+/// @param output_rate The desired sample rate of the output.
+/// @returns Output signal.
+inline std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
+ u32 input_rate, u32 output_rate) {
+ const double ratio = static_cast<double>(input_rate) / static_cast<double>(output_rate);
+ return Interpolate(state, std::move(input), ratio);
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp
new file mode 100644
index 000000000..12632a95c
--- /dev/null
+++ b/src/audio_core/audio_out.cpp
@@ -0,0 +1,58 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/audio_out.h"
+#include "audio_core/sink.h"
+#include "audio_core/sink_details.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/settings.h"
+
+namespace AudioCore {
+
+/// Returns the stream format from the specified number of channels
+static Stream::Format ChannelsToStreamFormat(u32 num_channels) {
+ switch (num_channels) {
+ case 1:
+ return Stream::Format::Mono16;
+ case 2:
+ return Stream::Format::Stereo16;
+ case 6:
+ return Stream::Format::Multi51Channel16;
+ }
+
+ LOG_CRITICAL(Audio, "Unimplemented num_channels={}", num_channels);
+ UNREACHABLE();
+ return {};
+}
+
+StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, std::string&& name,
+ Stream::ReleaseCallback&& release_callback) {
+ if (!sink) {
+ const SinkDetails& sink_details = GetSinkDetails(Settings::values.sink_id);
+ sink = sink_details.factory(Settings::values.audio_device_id);
+ }
+
+ return std::make_shared<Stream>(
+ sample_rate, ChannelsToStreamFormat(num_channels), std::move(release_callback),
+ sink->AcquireSinkStream(sample_rate, num_channels, name), std::move(name));
+}
+
+std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream, size_t max_count) {
+ return stream->GetTagsAndReleaseBuffers(max_count);
+}
+
+void AudioOut::StartStream(StreamPtr stream) {
+ stream->Play();
+}
+
+void AudioOut::StopStream(StreamPtr stream) {
+ stream->Stop();
+}
+
+bool AudioOut::QueueBuffer(StreamPtr stream, Buffer::Tag tag, std::vector<s16>&& data) {
+ return stream->QueueBuffer(std::make_shared<Buffer>(tag, std::move(data)));
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/audio_out.h b/src/audio_core/audio_out.h
new file mode 100644
index 000000000..39b7e656b
--- /dev/null
+++ b/src/audio_core/audio_out.h
@@ -0,0 +1,43 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "audio_core/buffer.h"
+#include "audio_core/sink.h"
+#include "audio_core/stream.h"
+#include "common/common_types.h"
+
+namespace AudioCore {
+
+/**
+ * Represents an audio playback interface, used to open and play audio streams
+ */
+class AudioOut {
+public:
+ /// Opens a new audio stream
+ StreamPtr OpenStream(u32 sample_rate, u32 num_channels, std::string&& name,
+ Stream::ReleaseCallback&& release_callback);
+
+ /// Returns a vector of recently released buffers specified by tag for the specified stream
+ std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, size_t max_count);
+
+ /// Starts an audio stream for playback
+ void StartStream(StreamPtr stream);
+
+ /// Stops an audio stream that is currently playing
+ void StopStream(StreamPtr stream);
+
+ /// Queues a buffer into the specified audio stream, returns true on success
+ bool QueueBuffer(StreamPtr stream, Buffer::Tag tag, std::vector<s16>&& data);
+
+private:
+ SinkPtr sink;
+};
+
+} // namespace AudioCore
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
new file mode 100644
index 000000000..397b107f5
--- /dev/null
+++ b/src/audio_core/audio_renderer.cpp
@@ -0,0 +1,249 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/algorithm/interpolate.h"
+#include "audio_core/audio_renderer.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/memory.h"
+
+namespace AudioCore {
+
+constexpr u32 STREAM_SAMPLE_RATE{48000};
+constexpr u32 STREAM_NUM_CHANNELS{2};
+
+AudioRenderer::AudioRenderer(AudioRendererParameter params,
+ Kernel::SharedPtr<Kernel::Event> buffer_event)
+ : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) {
+
+ audio_core = std::make_unique<AudioCore::AudioOut>();
+ stream = audio_core->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer",
+ [=]() { buffer_event->Signal(); });
+ audio_core->StartStream(stream);
+
+ QueueMixedBuffer(0);
+ QueueMixedBuffer(1);
+ QueueMixedBuffer(2);
+}
+
+u32 AudioRenderer::GetSampleRate() const {
+ return worker_params.sample_rate;
+}
+
+u32 AudioRenderer::GetSampleCount() const {
+ return worker_params.sample_count;
+}
+
+u32 AudioRenderer::GetMixBufferCount() const {
+ return worker_params.mix_buffer_count;
+}
+
+std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
+ // Copy UpdateDataHeader struct
+ UpdateDataHeader config{};
+ std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader));
+ u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
+
+ // Copy MemoryPoolInfo structs
+ std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
+ std::memcpy(mem_pool_info.data(),
+ input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size,
+ memory_pool_count * sizeof(MemoryPoolInfo));
+
+ // Copy VoiceInfo structs
+ size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size +
+ config.voice_resource_size};
+ for (auto& voice : voices) {
+ std::memcpy(&voice.Info(), input_params.data() + offset, sizeof(VoiceInfo));
+ offset += sizeof(VoiceInfo);
+ }
+
+ // Update voices
+ for (auto& voice : voices) {
+ voice.UpdateState();
+ if (!voice.GetInfo().is_in_use) {
+ continue;
+ }
+ if (voice.GetInfo().is_new) {
+ voice.SetWaveIndex(voice.GetInfo().wave_buffer_head);
+ }
+ }
+
+ // Update memory pool state
+ std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
+ for (size_t index = 0; index < memory_pool.size(); ++index) {
+ if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
+ memory_pool[index].state = MemoryPoolStates::Attached;
+ } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
+ memory_pool[index].state = MemoryPoolStates::Detached;
+ }
+ }
+
+ // Release previous buffers and queue next ones for playback
+ ReleaseAndQueueBuffers();
+
+ // Copy output header
+ UpdateDataHeader response_data{worker_params};
+ std::vector<u8> output_params(response_data.total_size);
+ std::memcpy(output_params.data(), &response_data, sizeof(UpdateDataHeader));
+
+ // Copy output memory pool entries
+ std::memcpy(output_params.data() + sizeof(UpdateDataHeader), memory_pool.data(),
+ response_data.memory_pools_size);
+
+ // Copy output voice status
+ size_t voice_out_status_offset{sizeof(UpdateDataHeader) + response_data.memory_pools_size};
+ for (const auto& voice : voices) {
+ std::memcpy(output_params.data() + voice_out_status_offset, &voice.GetOutStatus(),
+ sizeof(VoiceOutStatus));
+ voice_out_status_offset += sizeof(VoiceOutStatus);
+ }
+
+ return output_params;
+}
+
+void AudioRenderer::VoiceState::SetWaveIndex(size_t index) {
+ wave_index = index & 3;
+ is_refresh_pending = true;
+}
+
+std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(size_t sample_count) {
+ if (!IsPlaying()) {
+ return {};
+ }
+
+ if (is_refresh_pending) {
+ RefreshBuffer();
+ }
+
+ const size_t max_size{samples.size() - offset};
+ const size_t dequeue_offset{offset};
+ size_t size{sample_count * STREAM_NUM_CHANNELS};
+ if (size > max_size) {
+ size = max_size;
+ }
+
+ out_status.played_sample_count += size / STREAM_NUM_CHANNELS;
+ offset += size;
+
+ const auto& wave_buffer{info.wave_buffer[wave_index]};
+ if (offset == samples.size()) {
+ offset = 0;
+
+ if (!wave_buffer.is_looping) {
+ SetWaveIndex(wave_index + 1);
+ }
+
+ out_status.wave_buffer_consumed++;
+
+ if (wave_buffer.end_of_stream) {
+ info.play_state = PlayState::Paused;
+ }
+ }
+
+ return {samples.begin() + dequeue_offset, samples.begin() + dequeue_offset + size};
+}
+
+void AudioRenderer::VoiceState::UpdateState() {
+ if (is_in_use && !info.is_in_use) {
+ // No longer in use, reset state
+ is_refresh_pending = true;
+ wave_index = 0;
+ offset = 0;
+ out_status = {};
+ }
+ is_in_use = info.is_in_use;
+}
+
+void AudioRenderer::VoiceState::RefreshBuffer() {
+ std::vector<s16> new_samples(info.wave_buffer[wave_index].buffer_sz / sizeof(s16));
+ Memory::ReadBlock(info.wave_buffer[wave_index].buffer_addr, new_samples.data(),
+ info.wave_buffer[wave_index].buffer_sz);
+
+ switch (static_cast<Codec::PcmFormat>(info.sample_format)) {
+ case Codec::PcmFormat::Int16: {
+ // PCM16 is played as-is
+ break;
+ }
+ case Codec::PcmFormat::Adpcm: {
+ // Decode ADPCM to PCM16
+ Codec::ADPCM_Coeff coeffs;
+ Memory::ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff));
+ new_samples = Codec::DecodeADPCM(reinterpret_cast<u8*>(new_samples.data()),
+ new_samples.size() * sizeof(s16), coeffs, adpcm_state);
+ break;
+ }
+ default:
+ LOG_CRITICAL(Audio, "Unimplemented sample_format={}", info.sample_format);
+ UNREACHABLE();
+ break;
+ }
+
+ switch (info.channel_count) {
+ case 1:
+ // 1 channel is upsampled to 2 channel
+ samples.resize(new_samples.size() * 2);
+ for (size_t index = 0; index < new_samples.size(); ++index) {
+ samples[index * 2] = new_samples[index];
+ samples[index * 2 + 1] = new_samples[index];
+ }
+ break;
+ case 2: {
+ // 2 channel is played as is
+ samples = std::move(new_samples);
+ break;
+ }
+ default:
+ LOG_CRITICAL(Audio, "Unimplemented channel_count={}", info.channel_count);
+ UNREACHABLE();
+ break;
+ }
+
+ samples = Interpolate(interp_state, std::move(samples), Info().sample_rate, STREAM_SAMPLE_RATE);
+
+ is_refresh_pending = false;
+}
+
+static constexpr s16 ClampToS16(s32 value) {
+ return static_cast<s16>(std::clamp(value, -32768, 32767));
+}
+
+void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
+ constexpr size_t BUFFER_SIZE{512};
+ std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels());
+
+ for (auto& voice : voices) {
+ if (!voice.IsPlaying()) {
+ continue;
+ }
+
+ size_t offset{};
+ s64 samples_remaining{BUFFER_SIZE};
+ while (samples_remaining > 0) {
+ const std::vector<s16> samples{voice.DequeueSamples(samples_remaining)};
+
+ if (samples.empty()) {
+ break;
+ }
+
+ samples_remaining -= samples.size() / stream->GetNumChannels();
+
+ for (const auto& sample : samples) {
+ const s32 buffer_sample{buffer[offset]};
+ buffer[offset++] =
+ ClampToS16(buffer_sample + static_cast<s32>(sample * voice.GetInfo().volume));
+ }
+ }
+ }
+ audio_core->QueueBuffer(stream, tag, std::move(buffer));
+}
+
+void AudioRenderer::ReleaseAndQueueBuffers() {
+ const auto released_buffers{audio_core->GetTagsAndReleaseBuffers(stream, 2)};
+ for (const auto& tag : released_buffers) {
+ QueueMixedBuffer(tag);
+ }
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
new file mode 100644
index 000000000..eba67f28e
--- /dev/null
+++ b/src/audio_core/audio_renderer.h
@@ -0,0 +1,211 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "audio_core/algorithm/interpolate.h"
+#include "audio_core/audio_out.h"
+#include "audio_core/codec.h"
+#include "audio_core/stream.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/hle/kernel/event.h"
+
+namespace AudioCore {
+
+enum class PlayState : u8 {
+ Started = 0,
+ Stopped = 1,
+ Paused = 2,
+};
+
+struct AudioRendererParameter {
+ u32_le sample_rate;
+ u32_le sample_count;
+ u32_le mix_buffer_count;
+ u32_le unknown_c;
+ u32_le voice_count;
+ u32_le sink_count;
+ u32_le effect_count;
+ u32_le unknown_1c;
+ u8 unknown_20;
+ INSERT_PADDING_BYTES(3);
+ u32_le splitter_count;
+ u32_le unknown_2c;
+ INSERT_PADDING_WORDS(1);
+ u32_le revision;
+};
+static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size");
+
+enum class MemoryPoolStates : u32 { // Should be LE
+ Invalid = 0x0,
+ Unknown = 0x1,
+ RequestDetach = 0x2,
+ Detached = 0x3,
+ RequestAttach = 0x4,
+ Attached = 0x5,
+ Released = 0x6,
+};
+
+struct MemoryPoolEntry {
+ MemoryPoolStates state;
+ u32_le unknown_4;
+ u32_le unknown_8;
+ u32_le unknown_c;
+};
+static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
+
+struct MemoryPoolInfo {
+ u64_le pool_address;
+ u64_le pool_size;
+ MemoryPoolStates pool_state;
+ INSERT_PADDING_WORDS(3); // Unknown
+};
+static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
+struct BiquadFilter {
+ u8 enable;
+ INSERT_PADDING_BYTES(1);
+ std::array<s16_le, 3> numerator;
+ std::array<s16_le, 2> denominator;
+};
+static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");
+
+struct WaveBuffer {
+ u64_le buffer_addr;
+ u64_le buffer_sz;
+ s32_le start_sample_offset;
+ s32_le end_sample_offset;
+ u8 is_looping;
+ u8 end_of_stream;
+ u8 sent_to_server;
+ INSERT_PADDING_BYTES(5);
+ u64 context_addr;
+ u64 context_sz;
+ INSERT_PADDING_BYTES(8);
+};
+static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
+
+struct VoiceInfo {
+ u32_le id;
+ u32_le node_id;
+ u8 is_new;
+ u8 is_in_use;
+ PlayState play_state;
+ u8 sample_format;
+ u32_le sample_rate;
+ u32_le priority;
+ u32_le sorting_order;
+ u32_le channel_count;
+ float_le pitch;
+ float_le volume;
+ std::array<BiquadFilter, 2> biquad_filter;
+ u32_le wave_buffer_count;
+ u32_le wave_buffer_head;
+ INSERT_PADDING_WORDS(1);
+ u64_le additional_params_addr;
+ u64_le additional_params_sz;
+ u32_le mix_id;
+ u32_le splitter_info_id;
+ std::array<WaveBuffer, 4> wave_buffer;
+ std::array<u32_le, 6> voice_channel_resource_ids;
+ INSERT_PADDING_BYTES(24);
+};
+static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");
+
+struct VoiceOutStatus {
+ u64_le played_sample_count;
+ u32_le wave_buffer_consumed;
+ u32_le voice_drops_count;
+};
+static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
+
+struct UpdateDataHeader {
+ UpdateDataHeader() {}
+
+ explicit UpdateDataHeader(const AudioRendererParameter& config) {
+ revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
+ behavior_size = 0xb0;
+ memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
+ voices_size = config.voice_count * 0x10;
+ voice_resource_size = 0x0;
+ effects_size = config.effect_count * 0x10;
+ mixes_size = 0x0;
+ sinks_size = config.sink_count * 0x20;
+ performance_manager_size = 0x10;
+ total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size + voices_size +
+ effects_size + sinks_size + performance_manager_size;
+ }
+
+ u32_le revision;
+ u32_le behavior_size;
+ u32_le memory_pools_size;
+ u32_le voices_size;
+ u32_le voice_resource_size;
+ u32_le effects_size;
+ u32_le mixes_size;
+ u32_le sinks_size;
+ u32_le performance_manager_size;
+ INSERT_PADDING_WORDS(6);
+ u32_le total_size;
+};
+static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");
+
+class AudioRenderer {
+public:
+ AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event);
+ std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
+ void QueueMixedBuffer(Buffer::Tag tag);
+ void ReleaseAndQueueBuffers();
+ u32 GetSampleRate() const;
+ u32 GetSampleCount() const;
+ u32 GetMixBufferCount() const;
+
+private:
+ class VoiceState {
+ public:
+ bool IsPlaying() const {
+ return is_in_use && info.play_state == PlayState::Started;
+ }
+
+ const VoiceOutStatus& GetOutStatus() const {
+ return out_status;
+ }
+
+ const VoiceInfo& GetInfo() const {
+ return info;
+ }
+
+ VoiceInfo& Info() {
+ return info;
+ }
+
+ void SetWaveIndex(size_t index);
+ std::vector<s16> DequeueSamples(size_t sample_count);
+ void UpdateState();
+ void RefreshBuffer();
+
+ private:
+ bool is_in_use{};
+ bool is_refresh_pending{};
+ size_t wave_index{};
+ size_t offset{};
+ Codec::ADPCMState adpcm_state{};
+ InterpolationState interp_state{};
+ std::vector<s16> samples;
+ VoiceOutStatus out_status{};
+ VoiceInfo info{};
+ };
+
+ AudioRendererParameter worker_params;
+ Kernel::SharedPtr<Kernel::Event> buffer_event;
+ std::vector<VoiceState> voices;
+ std::unique_ptr<AudioCore::AudioOut> audio_core;
+ AudioCore::StreamPtr stream;
+};
+
+} // namespace AudioCore
diff --git a/src/audio_core/buffer.h b/src/audio_core/buffer.h
new file mode 100644
index 000000000..a323b23ec
--- /dev/null
+++ b/src/audio_core/buffer.h
@@ -0,0 +1,45 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "common/common_types.h"
+
+namespace AudioCore {
+
+/**
+ * Represents a buffer of audio samples to be played in an audio stream
+ */
+class Buffer {
+public:
+ using Tag = u64;
+
+ Buffer(Tag tag, std::vector<s16>&& samples) : tag{tag}, samples{std::move(samples)} {}
+
+ /// Returns the raw audio data for the buffer
+ std::vector<s16>& Samples() {
+ return samples;
+ }
+
+ /// Returns the raw audio data for the buffer
+ const std::vector<s16>& GetSamples() const {
+ return samples;
+ }
+
+ /// Returns the buffer tag, this is provided by the game to the audout service
+ Tag GetTag() const {
+ return tag;
+ }
+
+private:
+ Tag tag;
+ std::vector<s16> samples;
+};
+
+using BufferPtr = std::shared_ptr<Buffer>;
+
+} // namespace AudioCore
diff --git a/src/audio_core/codec.cpp b/src/audio_core/codec.cpp
new file mode 100644
index 000000000..c3021403f
--- /dev/null
+++ b/src/audio_core/codec.cpp
@@ -0,0 +1,77 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+
+#include "audio_core/codec.h"
+
+namespace AudioCore::Codec {
+
+std::vector<s16> DecodeADPCM(const u8* const data, size_t size, const ADPCM_Coeff& coeff,
+ ADPCMState& state) {
+ // GC-ADPCM with scale factor and variable coefficients.
+ // Frames are 8 bytes long containing 14 samples each.
+ // Samples are 4 bits (one nibble) long.
+
+ constexpr size_t FRAME_LEN = 8;
+ constexpr size_t SAMPLES_PER_FRAME = 14;
+ constexpr std::array<int, 16> SIGNED_NIBBLES = {
+ {0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}};
+
+ const size_t sample_count = (size / FRAME_LEN) * SAMPLES_PER_FRAME;
+ const size_t ret_size =
+ sample_count % 2 == 0 ? sample_count : sample_count + 1; // Ensure multiple of two.
+ std::vector<s16> ret(ret_size);
+
+ int yn1 = state.yn1, yn2 = state.yn2;
+
+ const size_t NUM_FRAMES =
+ (sample_count + (SAMPLES_PER_FRAME - 1)) / SAMPLES_PER_FRAME; // Round up.
+ for (size_t framei = 0; framei < NUM_FRAMES; framei++) {
+ const int frame_header = data[framei * FRAME_LEN];
+ const int scale = 1 << (frame_header & 0xF);
+ const int idx = (frame_header >> 4) & 0x7;
+
+ // Coefficients are fixed point with 11 bits fractional part.
+ const int coef1 = coeff[idx * 2 + 0];
+ const int coef2 = coeff[idx * 2 + 1];
+
+ // Decodes an audio sample. One nibble produces one sample.
+ const auto decode_sample = [&](const int nibble) -> s16 {
+ const int xn = nibble * scale;
+ // We first transform everything into 11 bit fixed point, perform the second order
+ // digital filter, then transform back.
+ // 0x400 == 0.5 in 11 bit fixed point.
+ // Filter: y[n] = x[n] + 0.5 + c1 * y[n-1] + c2 * y[n-2]
+ int val = ((xn << 11) + 0x400 + coef1 * yn1 + coef2 * yn2) >> 11;
+ // Clamp to output range.
+ val = std::clamp<s32>(val, -32768, 32767);
+ // Advance output feedback.
+ yn2 = yn1;
+ yn1 = val;
+ return static_cast<s16>(val);
+ };
+
+ size_t outputi = framei * SAMPLES_PER_FRAME;
+ size_t datai = framei * FRAME_LEN + 1;
+ for (size_t i = 0; i < SAMPLES_PER_FRAME && outputi < sample_count; i += 2) {
+ const s16 sample1 = decode_sample(SIGNED_NIBBLES[data[datai] >> 4]);
+ ret[outputi] = sample1;
+ outputi++;
+
+ const s16 sample2 = decode_sample(SIGNED_NIBBLES[data[datai] & 0xF]);
+ ret[outputi] = sample2;
+ outputi++;
+
+ datai++;
+ }
+ }
+
+ state.yn1 = yn1;
+ state.yn2 = yn2;
+
+ return ret;
+}
+
+} // namespace AudioCore::Codec
diff --git a/src/audio_core/codec.h b/src/audio_core/codec.h
new file mode 100644
index 000000000..3f845c42c
--- /dev/null
+++ b/src/audio_core/codec.h
@@ -0,0 +1,44 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <vector>
+
+#include "common/common_types.h"
+
+namespace AudioCore::Codec {
+
+enum class PcmFormat : u32 {
+ Invalid = 0,
+ Int8 = 1,
+ Int16 = 2,
+ Int24 = 3,
+ Int32 = 4,
+ PcmFloat = 5,
+ Adpcm = 6,
+};
+
+/// See: Codec::DecodeADPCM
+struct ADPCMState {
+ // Two historical samples from previous processed buffer,
+ // required for ADPCM decoding
+ s16 yn1; ///< y[n-1]
+ s16 yn2; ///< y[n-2]
+};
+
+using ADPCM_Coeff = std::array<s16, 16>;
+
+/**
+ * @param data Pointer to buffer that contains ADPCM data to decode
+ * @param size Size of buffer in bytes
+ * @param coeff ADPCM coefficients
+ * @param state ADPCM state, this is updated with new state
+ * @return Decoded stereo signed PCM16 data, sample_count in length
+ */
+std::vector<s16> DecodeADPCM(const u8* const data, size_t size, const ADPCM_Coeff& coeff,
+ ADPCMState& state);
+
+}; // namespace AudioCore::Codec
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
new file mode 100644
index 000000000..5a1177d0c
--- /dev/null
+++ b/src/audio_core/cubeb_sink.cpp
@@ -0,0 +1,206 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <cstring>
+#include <mutex>
+
+#include "audio_core/cubeb_sink.h"
+#include "audio_core/stream.h"
+#include "common/logging/log.h"
+
+namespace AudioCore {
+
+class SinkStreamImpl final : public SinkStream {
+public:
+ SinkStreamImpl(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
+ const std::string& name)
+ : ctx{ctx}, num_channels{num_channels_} {
+
+ if (num_channels == 6) {
+ // 6-channel audio does not seem to work with cubeb + SDL, so we downsample this to 2
+ // channel for now
+ is_6_channel = true;
+ num_channels = 2;
+ }
+
+ cubeb_stream_params params{};
+ params.rate = sample_rate;
+ params.channels = num_channels;
+ params.format = CUBEB_SAMPLE_S16NE;
+ params.layout = num_channels == 1 ? CUBEB_LAYOUT_MONO : CUBEB_LAYOUT_STEREO;
+
+ u32 minimum_latency{};
+ if (cubeb_get_min_latency(ctx, &params, &minimum_latency) != CUBEB_OK) {
+ LOG_CRITICAL(Audio_Sink, "Error getting minimum latency");
+ }
+
+ if (cubeb_stream_init(ctx, &stream_backend, name.c_str(), nullptr, nullptr, output_device,
+ &params, std::max(512u, minimum_latency),
+ &SinkStreamImpl::DataCallback, &SinkStreamImpl::StateCallback,
+ this) != CUBEB_OK) {
+ LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream");
+ return;
+ }
+
+ if (cubeb_stream_start(stream_backend) != CUBEB_OK) {
+ LOG_CRITICAL(Audio_Sink, "Error starting cubeb stream");
+ return;
+ }
+ }
+
+ ~SinkStreamImpl() {
+ if (!ctx) {
+ return;
+ }
+
+ if (cubeb_stream_stop(stream_backend) != CUBEB_OK) {
+ LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream");
+ }
+
+ cubeb_stream_destroy(stream_backend);
+ }
+
+ void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) override {
+ if (!ctx) {
+ return;
+ }
+
+ std::lock_guard lock{queue_mutex};
+
+ queue.reserve(queue.size() + samples.size() * GetNumChannels());
+
+ if (is_6_channel) {
+ // Downsample 6 channels to 2
+ const size_t sample_count_copy_size = samples.size() * 2;
+ queue.reserve(sample_count_copy_size);
+ for (size_t i = 0; i < samples.size(); i += num_channels) {
+ queue.push_back(samples[i]);
+ queue.push_back(samples[i + 1]);
+ }
+ } else {
+ // Copy as-is
+ std::copy(samples.begin(), samples.end(), std::back_inserter(queue));
+ }
+ }
+
+ u32 GetNumChannels() const {
+ return num_channels;
+ }
+
+private:
+ std::vector<std::string> device_list;
+
+ cubeb* ctx{};
+ cubeb_stream* stream_backend{};
+ u32 num_channels{};
+ bool is_6_channel{};
+
+ std::mutex queue_mutex;
+ std::vector<s16> queue;
+
+ static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
+ void* output_buffer, long num_frames);
+ static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state);
+};
+
+CubebSink::CubebSink(std::string target_device_name) {
+ if (cubeb_init(&ctx, "yuzu", nullptr) != CUBEB_OK) {
+ LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
+ return;
+ }
+
+ if (target_device_name != auto_device_name && !target_device_name.empty()) {
+ cubeb_device_collection collection;
+ if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
+ LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
+ } else {
+ const auto collection_end{collection.device + collection.count};
+ const auto device{std::find_if(collection.device, collection_end,
+ [&](const cubeb_device_info& device) {
+ return target_device_name == device.friendly_name;
+ })};
+ if (device != collection_end) {
+ output_device = device->devid;
+ }
+ cubeb_device_collection_destroy(ctx, &collection);
+ }
+ }
+}
+
+CubebSink::~CubebSink() {
+ if (!ctx) {
+ return;
+ }
+
+ for (auto& sink_stream : sink_streams) {
+ sink_stream.reset();
+ }
+
+ cubeb_destroy(ctx);
+}
+
+SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels,
+ const std::string& name) {
+ sink_streams.push_back(
+ std::make_unique<SinkStreamImpl>(ctx, sample_rate, num_channels, output_device, name));
+ return *sink_streams.back();
+}
+
+long SinkStreamImpl::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
+ void* output_buffer, long num_frames) {
+ SinkStreamImpl* impl = static_cast<SinkStreamImpl*>(user_data);
+ u8* buffer = reinterpret_cast<u8*>(output_buffer);
+
+ if (!impl) {
+ return {};
+ }
+
+ std::lock_guard lock{impl->queue_mutex};
+
+ const size_t frames_to_write{
+ std::min(impl->queue.size() / impl->GetNumChannels(), static_cast<size_t>(num_frames))};
+
+ memcpy(buffer, impl->queue.data(), frames_to_write * sizeof(s16) * impl->GetNumChannels());
+ impl->queue.erase(impl->queue.begin(),
+ impl->queue.begin() + frames_to_write * impl->GetNumChannels());
+
+ if (frames_to_write < num_frames) {
+ // Fill the rest of the frames with silence
+ memset(buffer + frames_to_write * sizeof(s16) * impl->GetNumChannels(), 0,
+ (num_frames - frames_to_write) * sizeof(s16) * impl->GetNumChannels());
+ }
+
+ return num_frames;
+}
+
+void SinkStreamImpl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {}
+
+std::vector<std::string> ListCubebSinkDevices() {
+ std::vector<std::string> device_list;
+ cubeb* ctx;
+
+ if (cubeb_init(&ctx, "Citra Device Enumerator", nullptr) != CUBEB_OK) {
+ LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
+ return {};
+ }
+
+ cubeb_device_collection collection;
+ if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
+ LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
+ } else {
+ for (size_t i = 0; i < collection.count; i++) {
+ const cubeb_device_info& device = collection.device[i];
+ if (device.friendly_name) {
+ device_list.emplace_back(device.friendly_name);
+ }
+ }
+ cubeb_device_collection_destroy(ctx, &collection);
+ }
+
+ cubeb_destroy(ctx);
+ return device_list;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/cubeb_sink.h b/src/audio_core/cubeb_sink.h
new file mode 100644
index 000000000..59cbf05e9
--- /dev/null
+++ b/src/audio_core/cubeb_sink.h
@@ -0,0 +1,32 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <cubeb/cubeb.h>
+
+#include "audio_core/sink.h"
+
+namespace AudioCore {
+
+class CubebSink final : public Sink {
+public:
+ explicit CubebSink(std::string device_id);
+ ~CubebSink() override;
+
+ SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels,
+ const std::string& name) override;
+
+private:
+ cubeb* ctx{};
+ cubeb_devid output_device{};
+ std::vector<SinkStreamPtr> sink_streams;
+};
+
+std::vector<std::string> ListCubebSinkDevices();
+
+} // namespace AudioCore
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
new file mode 100644
index 000000000..f235d93e5
--- /dev/null
+++ b/src/audio_core/null_sink.h
@@ -0,0 +1,27 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "audio_core/sink.h"
+
+namespace AudioCore {
+
+class NullSink final : public Sink {
+public:
+ explicit NullSink(std::string){};
+ ~NullSink() override = default;
+
+ SinkStream& AcquireSinkStream(u32 /*sample_rate*/, u32 /*num_channels*/,
+ const std::string& /*name*/) override {
+ return null_sink_stream;
+ }
+
+private:
+ struct NullSinkStreamImpl final : SinkStream {
+ void EnqueueSamples(u32 /*num_channels*/, const std::vector<s16>& /*samples*/) override {}
+ } null_sink_stream;
+};
+
+} // namespace AudioCore
diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h
new file mode 100644
index 000000000..95c7b2b6e
--- /dev/null
+++ b/src/audio_core/sink.h
@@ -0,0 +1,31 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "audio_core/sink_stream.h"
+#include "common/common_types.h"
+
+namespace AudioCore {
+
+constexpr char auto_device_name[] = "auto";
+
+/**
+ * This class is an interface for an audio sink. An audio sink accepts samples in stereo signed
+ * PCM16 format to be output. Sinks *do not* handle resampling and expect the correct sample rate.
+ * They are dumb outputs.
+ */
+class Sink {
+public:
+ virtual ~Sink() = default;
+ virtual SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels,
+ const std::string& name) = 0;
+};
+
+using SinkPtr = std::unique_ptr<Sink>;
+
+} // namespace AudioCore
diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp
new file mode 100644
index 000000000..955ba20fb
--- /dev/null
+++ b/src/audio_core/sink_details.cpp
@@ -0,0 +1,44 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+#include "audio_core/null_sink.h"
+#include "audio_core/sink_details.h"
+#ifdef HAVE_CUBEB
+#include "audio_core/cubeb_sink.h"
+#endif
+#include "common/logging/log.h"
+
+namespace AudioCore {
+
+// g_sink_details is ordered in terms of desirability, with the best choice at the top.
+const std::vector<SinkDetails> g_sink_details = {
+#ifdef HAVE_CUBEB
+ SinkDetails{"cubeb", &std::make_unique<CubebSink, std::string>, &ListCubebSinkDevices},
+#endif
+ SinkDetails{"null", &std::make_unique<NullSink, std::string>,
+ [] { return std::vector<std::string>{"null"}; }},
+};
+
+const SinkDetails& GetSinkDetails(std::string sink_id) {
+ auto iter =
+ std::find_if(g_sink_details.begin(), g_sink_details.end(),
+ [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
+
+ if (sink_id == "auto" || iter == g_sink_details.end()) {
+ if (sink_id != "auto") {
+ LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id {}", sink_id);
+ }
+ // Auto-select.
+ // g_sink_details is ordered in terms of desirability, with the best choice at the front.
+ iter = g_sink_details.begin();
+ }
+
+ return *iter;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h
new file mode 100644
index 000000000..ea666c554
--- /dev/null
+++ b/src/audio_core/sink_details.h
@@ -0,0 +1,35 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace AudioCore {
+
+class Sink;
+
+struct SinkDetails {
+ using FactoryFn = std::function<std::unique_ptr<Sink>(std::string)>;
+ using ListDevicesFn = std::function<std::vector<std::string>()>;
+
+ SinkDetails(const char* id_, FactoryFn factory_, ListDevicesFn list_devices_)
+ : id(id_), factory(std::move(factory_)), list_devices(std::move(list_devices_)) {}
+
+ /// Name for this sink.
+ const char* id;
+ /// A method to call to construct an instance of this type of sink.
+ FactoryFn factory;
+ /// A method to call to list available devices.
+ ListDevicesFn list_devices;
+};
+
+extern const std::vector<SinkDetails> g_sink_details;
+
+const SinkDetails& GetSinkDetails(std::string sink_id);
+
+} // namespace AudioCore
diff --git a/src/audio_core/sink_stream.h b/src/audio_core/sink_stream.h
new file mode 100644
index 000000000..41b6736d8
--- /dev/null
+++ b/src/audio_core/sink_stream.h
@@ -0,0 +1,32 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "common/common_types.h"
+
+namespace AudioCore {
+
+/**
+ * Accepts samples in stereo signed PCM16 format to be output. Sinks *do not* handle resampling and
+ * expect the correct sample rate. They are dumb outputs.
+ */
+class SinkStream {
+public:
+ virtual ~SinkStream() = default;
+
+ /**
+ * Feed stereo samples to sink.
+ * @param num_channels Number of channels used.
+ * @param samples Samples in interleaved stereo PCM16 format.
+ */
+ virtual void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) = 0;
+};
+
+using SinkStreamPtr = std::unique_ptr<SinkStream>;
+
+} // namespace AudioCore
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
new file mode 100644
index 000000000..ad9e2915c
--- /dev/null
+++ b/src/audio_core/stream.cpp
@@ -0,0 +1,127 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <cmath>
+
+#include "audio_core/sink.h"
+#include "audio_core/sink_details.h"
+#include "audio_core/stream.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/core_timing.h"
+#include "core/core_timing_util.h"
+#include "core/settings.h"
+
+namespace AudioCore {
+
+constexpr size_t MaxAudioBufferCount{32};
+
+u32 Stream::GetNumChannels() const {
+ switch (format) {
+ case Format::Mono16:
+ return 1;
+ case Format::Stereo16:
+ return 2;
+ case Format::Multi51Channel16:
+ return 6;
+ }
+ LOG_CRITICAL(Audio, "Unimplemented format={}", static_cast<u32>(format));
+ UNREACHABLE();
+ return {};
+}
+
+Stream::Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback,
+ SinkStream& sink_stream, std::string&& name_)
+ : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)},
+ sink_stream{sink_stream}, name{std::move(name_)} {
+
+ release_event = CoreTiming::RegisterEvent(
+ name, [this](u64 userdata, int cycles_late) { ReleaseActiveBuffer(); });
+}
+
+void Stream::Play() {
+ state = State::Playing;
+ PlayNextBuffer();
+}
+
+void Stream::Stop() {
+ ASSERT_MSG(false, "Unimplemented");
+}
+
+s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
+ const size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
+ return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
+}
+
+static void VolumeAdjustSamples(std::vector<s16>& samples) {
+ const float volume{std::clamp(Settings::values.volume, 0.0f, 1.0f)};
+
+ if (volume == 1.0f) {
+ return;
+ }
+
+ // Implementation of a volume slider with a dynamic range of 60 dB
+ const float volume_scale_factor{std::exp(6.90775f * volume) * 0.001f};
+ for (auto& sample : samples) {
+ sample = static_cast<s16>(sample * volume_scale_factor);
+ }
+}
+
+void Stream::PlayNextBuffer() {
+ if (!IsPlaying()) {
+ // Ensure we are in playing state before playing the next buffer
+ return;
+ }
+
+ if (active_buffer) {
+ // Do not queue a new buffer if we are already playing a buffer
+ return;
+ }
+
+ if (queued_buffers.empty()) {
+ // No queued buffers - we are effectively paused
+ return;
+ }
+
+ active_buffer = queued_buffers.front();
+ queued_buffers.pop();
+
+ VolumeAdjustSamples(active_buffer->Samples());
+ sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
+
+ CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
+}
+
+void Stream::ReleaseActiveBuffer() {
+ ASSERT(active_buffer);
+ released_buffers.push(std::move(active_buffer));
+ release_callback();
+ PlayNextBuffer();
+}
+
+bool Stream::QueueBuffer(BufferPtr&& buffer) {
+ if (queued_buffers.size() < MaxAudioBufferCount) {
+ queued_buffers.push(std::move(buffer));
+ PlayNextBuffer();
+ return true;
+ }
+ return false;
+}
+
+bool Stream::ContainsBuffer(Buffer::Tag tag) const {
+ ASSERT_MSG(false, "Unimplemented");
+ return {};
+}
+
+std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(size_t max_count) {
+ std::vector<Buffer::Tag> tags;
+ for (size_t count = 0; count < max_count && !released_buffers.empty(); ++count) {
+ tags.push_back(released_buffers.front()->GetTag());
+ released_buffers.pop();
+ }
+ return tags;
+}
+
+} // namespace AudioCore
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
new file mode 100644
index 000000000..049b92ca9
--- /dev/null
+++ b/src/audio_core/stream.h
@@ -0,0 +1,102 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+#include <queue>
+
+#include "audio_core/buffer.h"
+#include "audio_core/sink_stream.h"
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "core/core_timing.h"
+
+namespace AudioCore {
+
+/**
+ * Represents an audio stream, which is a sequence of queued buffers, to be outputed by AudioOut
+ */
+class Stream {
+public:
+ /// Audio format of the stream
+ enum class Format {
+ Mono16,
+ Stereo16,
+ Multi51Channel16,
+ };
+
+ /// Callback function type, used to change guest state on a buffer being released
+ using ReleaseCallback = std::function<void()>;
+
+ Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback,
+ SinkStream& sink_stream, std::string&& name_);
+
+ /// Plays the audio stream
+ void Play();
+
+ /// Stops the audio stream
+ void Stop();
+
+ /// Queues a buffer into the audio stream, returns true on success
+ bool QueueBuffer(BufferPtr&& buffer);
+
+ /// Returns true if the audio stream contains a buffer with the specified tag
+ bool ContainsBuffer(Buffer::Tag tag) const;
+
+ /// Returns a vector of recently released buffers specified by tag
+ std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(size_t max_count);
+
+ /// Returns true if the stream is currently playing
+ bool IsPlaying() const {
+ return state == State::Playing;
+ }
+
+ /// Returns the number of queued buffers
+ size_t GetQueueSize() const {
+ return queued_buffers.size();
+ }
+
+ /// Gets the sample rate
+ u32 GetSampleRate() const {
+ return sample_rate;
+ }
+
+ /// Gets the number of channels
+ u32 GetNumChannels() const;
+
+private:
+ /// Current state of the stream
+ enum class State {
+ Stopped,
+ Playing,
+ };
+
+ /// Plays the next queued buffer in the audio stream, starting playback if necessary
+ void PlayNextBuffer();
+
+ /// Releases the actively playing buffer, signalling that it has been completed
+ void ReleaseActiveBuffer();
+
+ /// Gets the number of core cycles when the specified buffer will be released
+ s64 GetBufferReleaseCycles(const Buffer& buffer) const;
+
+ u32 sample_rate; ///< Sample rate of the stream
+ Format format; ///< Format of the stream
+ ReleaseCallback release_callback; ///< Buffer release callback for the stream
+ State state{State::Stopped}; ///< Playback state of the stream
+ CoreTiming::EventType* release_event{}; ///< Core timing release event for the stream
+ BufferPtr active_buffer; ///< Actively playing buffer in the stream
+ std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream
+ std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream
+ SinkStream& sink_stream; ///< Output sink for the stream
+ std::string name; ///< Name of the stream, must be unique
+};
+
+using StreamPtr = std::shared_ptr<Stream>;
+
+} // namespace AudioCore
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index d5d4f6f82..d9424ea91 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -29,8 +29,6 @@ add_library(common STATIC
assert.h
bit_field.h
bit_set.h
- break_points.cpp
- break_points.h
cityhash.cpp
cityhash.h
color.h
@@ -40,6 +38,8 @@ add_library(common STATIC
file_util.cpp
file_util.h
hash.h
+ hex_util.cpp
+ hex_util.h
logging/backend.cpp
logging/backend.h
logging/filter.cpp
diff --git a/src/common/alignment.h b/src/common/alignment.h
index b77da4a92..b9dd38746 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -9,13 +9,13 @@ namespace Common {
template <typename T>
constexpr T AlignUp(T value, size_t size) {
- static_assert(std::is_unsigned<T>::value, "T must be an unsigned value.");
+ static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>(value + (size - value % size) % size);
}
template <typename T>
constexpr T AlignDown(T value, size_t size) {
- static_assert(std::is_unsigned<T>::value, "T must be an unsigned value.");
+ static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>(value - value % size);
}
diff --git a/src/common/bit_set.h b/src/common/bit_set.h
index 84e3cbe58..5a197d8c1 100644
--- a/src/common/bit_set.h
+++ b/src/common/bit_set.h
@@ -96,7 +96,7 @@ static inline int LeastSignificantSetBit(u64 val) {
template <typename IntTy>
class BitSet {
- static_assert(!std::is_signed<IntTy>::value, "BitSet should not be used with signed types");
+ static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
public:
// A reference to a particular bit, returned from operator[].
diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp
deleted file mode 100644
index fa367a4ca..000000000
--- a/src/common/break_points.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <algorithm>
-#include <sstream>
-#include "common/break_points.h"
-
-bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const {
- auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; };
- auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
- return it != m_BreakPoints.end();
-}
-
-bool BreakPoints::IsTempBreakPoint(u32 iAddress) const {
- auto cond = [&iAddress](const TBreakPoint& bp) {
- return bp.iAddress == iAddress && bp.bTemporary;
- };
- auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
- return it != m_BreakPoints.end();
-}
-
-BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const {
- TBreakPointsStr bps;
- for (auto breakpoint : m_BreakPoints) {
- if (!breakpoint.bTemporary) {
- std::stringstream bp;
- bp << std::hex << breakpoint.iAddress << " " << (breakpoint.bOn ? "n" : "");
- bps.push_back(bp.str());
- }
- }
-
- return bps;
-}
-
-void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) {
- for (auto bps_item : bps) {
- TBreakPoint bp;
- std::stringstream bpstr;
- bpstr << std::hex << bps_item;
- bpstr >> bp.iAddress;
- bp.bOn = bps_item.find("n") != bps_item.npos;
- bp.bTemporary = false;
- Add(bp);
- }
-}
-
-void BreakPoints::Add(const TBreakPoint& bp) {
- if (!IsAddressBreakPoint(bp.iAddress)) {
- m_BreakPoints.push_back(bp);
- // if (jit)
- // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
- }
-}
-
-void BreakPoints::Add(u32 em_address, bool temp) {
- if (!IsAddressBreakPoint(em_address)) // only add new addresses
- {
- TBreakPoint pt; // breakpoint settings
- pt.bOn = true;
- pt.bTemporary = temp;
- pt.iAddress = em_address;
-
- m_BreakPoints.push_back(pt);
-
- // if (jit)
- // jit->GetBlockCache()->InvalidateICache(em_address, 4);
- }
-}
-
-void BreakPoints::Remove(u32 em_address) {
- auto cond = [&em_address](const TBreakPoint& bp) { return bp.iAddress == em_address; };
- auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
- if (it != m_BreakPoints.end())
- m_BreakPoints.erase(it);
-}
-
-void BreakPoints::Clear() {
- // if (jit)
- //{
- // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(),
- // [](const TBreakPoint& bp)
- // {
- // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
- // }
- // );
- //}
-
- m_BreakPoints.clear();
-}
diff --git a/src/common/break_points.h b/src/common/break_points.h
deleted file mode 100644
index e15b9f842..000000000
--- a/src/common/break_points.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <string>
-#include <vector>
-#include "common/common_types.h"
-
-class DebugInterface;
-
-struct TBreakPoint {
- u32 iAddress;
- bool bOn;
- bool bTemporary;
-};
-
-// Code breakpoints.
-class BreakPoints {
-public:
- typedef std::vector<TBreakPoint> TBreakPoints;
- typedef std::vector<std::string> TBreakPointsStr;
-
- const TBreakPoints& GetBreakPoints() {
- return m_BreakPoints;
- }
-
- TBreakPointsStr GetStrings() const;
- void AddFromStrings(const TBreakPointsStr& bps);
-
- // is address breakpoint
- bool IsAddressBreakPoint(u32 iAddress) const;
- bool IsTempBreakPoint(u32 iAddress) const;
-
- // Add BreakPoint
- void Add(u32 em_address, bool temp = false);
- void Add(const TBreakPoint& bp);
-
- // Remove Breakpoint
- void Remove(u32 iAddress);
- void Clear();
-
- void DeleteByAddress(u32 Address);
-
-private:
- TBreakPoints m_BreakPoints;
- u32 m_iBreakOnCount;
-};
diff --git a/src/common/color.h b/src/common/color.h
index 24a445dac..0379040be 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -4,6 +4,8 @@
#pragma once
+#include <cstring>
+
#include "common/common_types.h"
#include "common/swap.h"
#include "common/vector_math.h"
@@ -55,7 +57,7 @@ constexpr u8 Convert8To6(u8 value) {
* @param bytes Pointer to encoded source color
* @return Result color decoded as Math::Vec4<u8>
*/
-inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) {
+inline Math::Vec4<u8> DecodeRGBA8(const u8* bytes) {
return {bytes[3], bytes[2], bytes[1], bytes[0]};
}
@@ -64,7 +66,7 @@ inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) {
* @param bytes Pointer to encoded source color
* @return Result color decoded as Math::Vec4<u8>
*/
-inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) {
+inline Math::Vec4<u8> DecodeRGB8(const u8* bytes) {
return {bytes[2], bytes[1], bytes[0], 255};
}
@@ -73,7 +75,7 @@ inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) {
* @param bytes Pointer to encoded source color
* @return Result color decoded as Math::Vec4<u8>
*/
-inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) {
+inline Math::Vec4<u8> DecodeRG8(const u8* bytes) {
return {bytes[1], bytes[0], 0, 255};
}
@@ -82,8 +84,9 @@ inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) {
* @param bytes Pointer to encoded source color
* @return Result color decoded as Math::Vec4<u8>
*/
-inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
- const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes);
+inline Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
+ u16_le pixel;
+ std::memcpy(&pixel, bytes, sizeof(pixel));
return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
Convert5To8(pixel & 0x1F), 255};
}
@@ -93,8 +96,9 @@ inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
* @param bytes Pointer to encoded source color
* @return Result color decoded as Math::Vec4<u8>
*/
-inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
- const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes);
+inline Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
+ u16_le pixel;
+ std::memcpy(&pixel, bytes, sizeof(pixel));
return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1)};
}
@@ -104,8 +108,9 @@ inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
* @param bytes Pointer to encoded source color
* @return Result color decoded as Math::Vec4<u8>
*/
-inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) {
- const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes);
+inline Math::Vec4<u8> DecodeRGBA4(const u8* bytes) {
+ u16_le pixel;
+ std::memcpy(&pixel, bytes, sizeof(pixel));
return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)};
}
@@ -116,7 +121,9 @@ inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) {
* @return Depth value as an u32
*/
inline u32 DecodeD16(const u8* bytes) {
- return *reinterpret_cast<const u16_le*>(bytes);
+ u16_le data;
+ std::memcpy(&data, bytes, sizeof(data));
+ return data;
}
/**
@@ -133,7 +140,7 @@ inline u32 DecodeD24(const u8* bytes) {
* @param bytes Pointer to encoded source values
* @return Resulting values stored as a Math::Vec2
*/
-inline const Math::Vec2<u32> DecodeD24S8(const u8* bytes) {
+inline Math::Vec2<u32> DecodeD24S8(const u8* bytes) {
return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
}
@@ -175,8 +182,10 @@ inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) {
* @param bytes Destination pointer to store encoded color
*/
inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) {
- *reinterpret_cast<u16_le*>(bytes) =
+ const u16_le data =
(Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b());
+
+ std::memcpy(bytes, &data, sizeof(data));
}
/**
@@ -185,9 +194,10 @@ inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) {
* @param bytes Destination pointer to store encoded color
*/
inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) {
- *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) |
- (Convert8To5(color.g()) << 6) |
- (Convert8To5(color.b()) << 1) | Convert8To1(color.a());
+ const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) |
+ (Convert8To5(color.b()) << 1) | Convert8To1(color.a());
+
+ std::memcpy(bytes, &data, sizeof(data));
}
/**
@@ -196,9 +206,10 @@ inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) {
* @param bytes Destination pointer to store encoded color
*/
inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) {
- *reinterpret_cast<u16_le*>(bytes) = (Convert8To4(color.r()) << 12) |
- (Convert8To4(color.g()) << 8) |
- (Convert8To4(color.b()) << 4) | Convert8To4(color.a());
+ const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) |
+ (Convert8To4(color.b()) << 4) | Convert8To4(color.a());
+
+ std::memcpy(bytes, &data, sizeof(data));
}
/**
@@ -207,7 +218,8 @@ inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) {
* @param bytes Pointer where to store the encoded value
*/
inline void EncodeD16(u32 value, u8* bytes) {
- *reinterpret_cast<u16_le*>(bytes) = value & 0xFFFF;
+ const u16_le data = static_cast<u16>(value);
+ std::memcpy(bytes, &data, sizeof(data));
}
/**
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 93f1c0044..8b0d34da6 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -6,7 +6,7 @@
#include <string>
-#if !defined(ARCHITECTURE_x86_64) && !defined(ARCHITECTURE_ARM)
+#if !defined(ARCHITECTURE_x86_64)
#include <cstdlib> // for exit
#endif
#include "common/common_types.h"
@@ -32,8 +32,6 @@
#ifdef ARCHITECTURE_x86_64
#define Crash() __asm__ __volatile__("int $3")
-#elif defined(ARCHITECTURE_ARM)
-#define Crash() __asm__ __volatile__("trap")
#else
#define Crash() exit(1)
#endif
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index 6799a357a..df2ce80b1 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -32,6 +32,7 @@
#define SDMC_DIR "sdmc"
#define NAND_DIR "nand"
#define SYSDATA_DIR "sysdata"
+#define KEYS_DIR "keys"
#define LOG_DIR "log"
// Filenames
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index b8dd92b65..b30a67ff9 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -706,6 +706,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
paths.emplace(UserPath::SDMCDir, user_path + SDMC_DIR DIR_SEP);
paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
+ paths.emplace(UserPath::KeysDir, user_path + KEYS_DIR DIR_SEP);
// TODO: Put the logs in a better location for each OS
paths.emplace(UserPath::LogDir, user_path + LOG_DIR DIR_SEP);
}
@@ -736,6 +737,25 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
return paths[path];
}
+std::string GetHactoolConfigurationPath() {
+#ifdef _WIN32
+ PWSTR pw_local_path = nullptr;
+ if (SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, &pw_local_path) != S_OK)
+ return "";
+ std::string local_path = Common::UTF16ToUTF8(pw_local_path);
+ CoTaskMemFree(pw_local_path);
+ return local_path + "\\.switch";
+#else
+ return GetHomeDirectory() + "/.switch";
+#endif
+}
+
+std::string GetNANDRegistrationDir(bool system) {
+ if (system)
+ return GetUserPath(UserPath::NANDDir) + "system/Contents/registered/";
+ return GetUserPath(UserPath::NANDDir) + "user/Contents/registered/";
+}
+
size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) {
return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
}
@@ -870,11 +890,21 @@ std::string_view RemoveTrailingSlash(std::string_view path) {
return path;
}
-std::string SanitizePath(std::string_view path_) {
+std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) {
std::string path(path_);
- std::replace(path.begin(), path.end(), '\\', '/');
+ char type1 = directory_separator == DirectorySeparator::BackwardSlash ? '/' : '\\';
+ char type2 = directory_separator == DirectorySeparator::BackwardSlash ? '\\' : '/';
+
+ if (directory_separator == DirectorySeparator::PlatformDefault) {
+#ifdef _WIN32
+ type1 = '/';
+ type2 = '\\';
+#endif
+ }
+
+ std::replace(path.begin(), path.end(), type1, type2);
path.erase(std::unique(path.begin(), path.end(),
- [](char c1, char c2) { return c1 == '/' && c2 == '/'; }),
+ [type2](char c1, char c2) { return c1 == type2 && c2 == type2; }),
path.end());
return std::string(RemoveTrailingSlash(path));
}
diff --git a/src/common/file_util.h b/src/common/file_util.h
index bc9272d89..2f13d0b6b 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -8,6 +8,7 @@
#include <cstdio>
#include <fstream>
#include <functional>
+#include <limits>
#include <string>
#include <string_view>
#include <type_traits>
@@ -23,6 +24,7 @@ namespace FileUtil {
enum class UserPath {
CacheDir,
ConfigDir,
+ KeysDir,
LogDir,
NANDDir,
RootDir,
@@ -125,6 +127,10 @@ bool SetCurrentDir(const std::string& directory);
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
+std::string GetHactoolConfigurationPath();
+
+std::string GetNANDRegistrationDir(bool system = false);
+
// Returns the path to where the sys file are
std::string GetSysDirectory();
@@ -178,8 +184,12 @@ std::vector<T> SliceVector(const std::vector<T>& vector, size_t first, size_t la
return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
}
-// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'.
-std::string SanitizePath(std::string_view path);
+enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault };
+
+// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
+// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
+std::string SanitizePath(std::string_view path,
+ DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
// simple wrapper for cstdlib file functions to
// hopefully will make error checking easier
@@ -204,39 +214,42 @@ public:
template <typename T>
size_t ReadArray(T* data, size_t length) const {
- static_assert(std::is_trivially_copyable<T>(),
+ static_assert(std::is_trivially_copyable_v<T>,
"Given array does not consist of trivially copyable objects");
- if (!IsOpen())
- return -1;
+ if (!IsOpen()) {
+ return std::numeric_limits<size_t>::max();
+ }
return std::fread(data, sizeof(T), length, m_file);
}
template <typename T>
size_t WriteArray(const T* data, size_t length) {
- static_assert(std::is_trivially_copyable<T>(),
+ static_assert(std::is_trivially_copyable_v<T>,
"Given array does not consist of trivially copyable objects");
- if (!IsOpen())
- return -1;
+ if (!IsOpen()) {
+ return std::numeric_limits<size_t>::max();
+ }
+
return std::fwrite(data, sizeof(T), length, m_file);
}
template <typename T>
size_t ReadBytes(T* data, size_t length) const {
- static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable");
+ static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
return ReadArray(reinterpret_cast<char*>(data), length);
}
template <typename T>
size_t WriteBytes(const T* data, size_t length) {
- static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable");
+ static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
return WriteArray(reinterpret_cast<const char*>(data), length);
}
template <typename T>
size_t WriteObject(const T& object) {
- static_assert(!std::is_pointer<T>::value, "Given object is a pointer");
+ static_assert(!std::is_pointer_v<T>, "WriteObject arguments must not be a pointer");
return WriteArray(&object, 1);
}
diff --git a/src/common/hash.h b/src/common/hash.h
index 73c326980..2c761e545 100644
--- a/src/common/hash.h
+++ b/src/common/hash.h
@@ -28,7 +28,7 @@ static inline u64 ComputeHash64(const void* data, size_t len) {
*/
template <typename T>
static inline u64 ComputeStructHash64(const T& data) {
- static_assert(std::is_trivially_copyable<T>(),
+ static_assert(std::is_trivially_copyable_v<T>,
"Type passed to ComputeStructHash64 must be trivially copyable");
return ComputeHash64(&data, sizeof(data));
}
@@ -38,7 +38,7 @@ template <typename T>
struct HashableStruct {
// In addition to being trivially copyable, T must also have a trivial default constructor,
// because any member initialization would be overridden by memset
- static_assert(std::is_trivial<T>(), "Type passed to HashableStruct must be trivial");
+ static_assert(std::is_trivial_v<T>, "Type passed to HashableStruct must be trivial");
/*
* We use a union because "implicitly-defined copy/move constructor for a union X copies the
* object representation of X." and "implicitly-defined copy assignment operator for a union X
diff --git a/src/common/hex_util.cpp b/src/common/hex_util.cpp
new file mode 100644
index 000000000..609144def
--- /dev/null
+++ b/src/common/hex_util.cpp
@@ -0,0 +1,31 @@
+// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/hex_util.h"
+
+namespace Common {
+
+u8 ToHexNibble(char c1) {
+ if (c1 >= 65 && c1 <= 70)
+ return c1 - 55;
+ if (c1 >= 97 && c1 <= 102)
+ return c1 - 87;
+ if (c1 >= 48 && c1 <= 57)
+ return c1 - 48;
+ throw std::logic_error("Invalid hex digit");
+}
+
+std::array<u8, 16> operator""_array16(const char* str, size_t len) {
+ if (len != 32)
+ throw std::logic_error("Not of correct size.");
+ return HexStringToArray<16>(str);
+}
+
+std::array<u8, 32> operator""_array32(const char* str, size_t len) {
+ if (len != 64)
+ throw std::logic_error("Not of correct size.");
+ return HexStringToArray<32>(str);
+}
+
+} // namespace Common
diff --git a/src/common/hex_util.h b/src/common/hex_util.h
new file mode 100644
index 000000000..5fb79bb72
--- /dev/null
+++ b/src/common/hex_util.h
@@ -0,0 +1,41 @@
+// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <cstddef>
+#include <string>
+#include <fmt/format.h>
+#include "common/common_types.h"
+
+namespace Common {
+
+u8 ToHexNibble(char c1);
+
+template <size_t Size, bool le = false>
+std::array<u8, Size> HexStringToArray(std::string_view str) {
+ std::array<u8, Size> out{};
+ if constexpr (le) {
+ for (size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2)
+ out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
+ } else {
+ for (size_t i = 0; i < 2 * Size; i += 2)
+ out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
+ }
+ return out;
+}
+
+template <size_t Size>
+std::string HexArrayToString(std::array<u8, Size> array, bool upper = true) {
+ std::string out;
+ for (u8 c : array)
+ out += fmt::format(upper ? "{:02X}" : "{:02x}", c);
+ return out;
+}
+
+std::array<u8, 0x10> operator"" _array16(const char* str, size_t len);
+std::array<u8, 0x20> operator"" _array32(const char* str, size_t len);
+
+} // namespace Common
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 59b999935..1323f8d0f 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -168,25 +168,49 @@ void FileBackend::Write(const Entry& entry) {
SUB(Service, AM) \
SUB(Service, AOC) \
SUB(Service, APM) \
+ SUB(Service, ARP) \
SUB(Service, BCAT) \
+ SUB(Service, BPC) \
+ SUB(Service, BTDRV) \
+ SUB(Service, BTM) \
+ SUB(Service, Capture) \
+ SUB(Service, ERPT) \
+ SUB(Service, ETicket) \
+ SUB(Service, EUPLD) \
SUB(Service, Fatal) \
+ SUB(Service, FGM) \
SUB(Service, Friend) \
SUB(Service, FS) \
+ SUB(Service, GRC) \
SUB(Service, HID) \
+ SUB(Service, LBL) \
+ SUB(Service, LDN) \
+ SUB(Service, LDR) \
SUB(Service, LM) \
+ SUB(Service, Migration) \
+ SUB(Service, Mii) \
SUB(Service, MM) \
+ SUB(Service, NCM) \
+ SUB(Service, NFC) \
SUB(Service, NFP) \
SUB(Service, NIFM) \
+ SUB(Service, NIM) \
SUB(Service, NS) \
SUB(Service, NVDRV) \
+ SUB(Service, PCIE) \
SUB(Service, PCTL) \
+ SUB(Service, PCV) \
+ SUB(Service, PM) \
SUB(Service, PREPO) \
+ SUB(Service, PSC) \
SUB(Service, SET) \
SUB(Service, SM) \
SUB(Service, SPL) \
SUB(Service, SSL) \
SUB(Service, Time) \
+ SUB(Service, USB) \
SUB(Service, VI) \
+ SUB(Service, WLAN) \
CLS(HW) \
SUB(HW, Memory) \
SUB(HW, LCD) \
@@ -203,6 +227,7 @@ void FileBackend::Write(const Entry& entry) {
CLS(Input) \
CLS(Network) \
CLS(Loader) \
+ CLS(Crypto) \
CLS(WebService)
// GetClassName is a macro defined by Windows.h, grrr...
@@ -277,13 +302,14 @@ Backend* GetBackend(std::string_view backend_name) {
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
unsigned int line_num, const char* function, const char* format,
const fmt::format_args& args) {
- auto filter = Impl::Instance().GetGlobalFilter();
+ auto& instance = Impl::Instance();
+ const auto& filter = instance.GetGlobalFilter();
if (!filter.CheckMessage(log_class, log_level))
return;
Entry entry =
CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args));
- Impl::Instance().PushEntry(std::move(entry));
+ instance.PushEntry(std::move(entry));
}
} // namespace Log
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index e7115933f..e12f47f8f 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -54,26 +54,50 @@ enum class Class : ClassType {
Service_AM, ///< The AM (Applet manager) service
Service_AOC, ///< The AOC (AddOn Content) service
Service_APM, ///< The APM (Performance) service
+ Service_ARP, ///< The ARP service
Service_Audio, ///< The Audio (Audio control) service
Service_BCAT, ///< The BCAT service
+ Service_BPC, ///< The BPC service
+ Service_BTDRV, ///< The Bluetooth driver service
+ Service_BTM, ///< The BTM service
+ Service_Capture, ///< The capture service
+ Service_ERPT, ///< The error reporting service
+ Service_ETicket, ///< The ETicket service
+ Service_EUPLD, ///< The error upload service
Service_Fatal, ///< The Fatal service
+ Service_FGM, ///< The FGM service
Service_Friend, ///< The friend service
Service_FS, ///< The FS (Filesystem) service
+ Service_GRC, ///< The game recording service
Service_HID, ///< The HID (Human interface device) service
+ Service_LBL, ///< The LBL (LCD backlight) service
+ Service_LDN, ///< The LDN (Local domain network) service
+ Service_LDR, ///< The loader service
Service_LM, ///< The LM (Logger) service
+ Service_Migration, ///< The migration service
+ Service_Mii, ///< The Mii service
Service_MM, ///< The MM (Multimedia) service
+ Service_NCM, ///< The NCM service
+ Service_NFC, ///< The NFC (Near-field communication) service
Service_NFP, ///< The NFP service
Service_NIFM, ///< The NIFM (Network interface) service
+ Service_NIM, ///< The NIM service
Service_NS, ///< The NS services
Service_NVDRV, ///< The NVDRV (Nvidia driver) service
+ Service_PCIE, ///< The PCIe service
Service_PCTL, ///< The PCTL (Parental control) service
+ Service_PCV, ///< The PCV service
+ Service_PM, ///< The PM service
Service_PREPO, ///< The PREPO (Play report) service
+ Service_PSC, ///< The PSC service
Service_SET, ///< The SET (Settings) service
Service_SM, ///< The SM (Service manager) service
Service_SPL, ///< The SPL service
Service_SSL, ///< The SSL service
Service_Time, ///< The time service
+ Service_USB, ///< The USB (Universal Serial Bus) service
Service_VI, ///< The VI (Video interface) service
+ Service_WLAN, ///< The WLAN (Wireless local area network) service
HW, ///< Low-level hardware emulation
HW_Memory, ///< Memory-map and address translation
HW_LCD, ///< LCD register emulation
@@ -88,6 +112,7 @@ enum class Class : ClassType {
Audio_DSP, ///< The HLE implementation of the DSP
Audio_Sink, ///< Emulator audio output backend
Loader, ///< ROM loader
+ Crypto, ///< Cryptographic engine/functions
Input, ///< Input emulation
Network, ///< Network emulation
WebService, ///< Interface to yuzu Web Services
diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h
index c587faefb..9609cec7c 100644
--- a/src/common/logging/text_formatter.h
+++ b/src/common/logging/text_formatter.h
@@ -5,6 +5,7 @@
#pragma once
#include <cstddef>
+#include <string>
namespace Log {
diff --git a/src/common/math_util.h b/src/common/math_util.h
index c6a83c953..343cdd902 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -19,12 +19,12 @@ inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start
template <class T>
struct Rectangle {
- T left;
- T top;
- T right;
- T bottom;
+ T left{};
+ T top{};
+ T right{};
+ T bottom{};
- Rectangle() {}
+ Rectangle() = default;
Rectangle(T left, T top, T right, T bottom)
: left(left), top(top), right(right), bottom(bottom) {}
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index 217a87098..3fa8a3bc4 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -4,7 +4,7 @@
#include <cstddef>
#ifdef _WIN32
-#include <Windows.h>
+#include <windows.h>
#else
#include <cerrno>
#include <cstring>
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 1f0456aee..0ca663032 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -2,12 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <cctype>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <boost/range/algorithm/transform.hpp>
#include "common/common_paths.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -24,13 +24,15 @@ namespace Common {
/// Make a string lowercase
std::string ToLower(std::string str) {
- boost::transform(str, str.begin(), ::tolower);
+ std::transform(str.begin(), str.end(), str.begin(),
+ [](unsigned char c) { return std::tolower(c); });
return str;
}
/// Make a string uppercase
std::string ToUpper(std::string str) {
- boost::transform(str, str.begin(), ::toupper);
+ std::transform(str.begin(), str.end(), str.begin(),
+ [](unsigned char c) { return std::toupper(c); });
return str;
}
diff --git a/src/common/swap.h b/src/common/swap.h
index fc7af4280..32af0b6ac 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -69,7 +69,7 @@ inline u32 swap32(u32 _data) {
inline u64 swap64(u64 _data) {
return _byteswap_uint64(_data);
}
-#elif ARCHITECTURE_ARM
+#elif defined(ARCHITECTURE_ARM) && (__ARM_ARCH >= 6)
inline u16 swap16(u16 _data) {
u32 data = _data;
__asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data));
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 38a450d69..133122c5f 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -16,7 +16,7 @@ struct ThreadQueueList {
// (dynamically resizable) circular buffers to remove their overhead when
// inserting and popping.
- typedef unsigned int Priority;
+ using Priority = unsigned int;
// Number of priority levels. (Valid levels are [0..NUM_QUEUES).)
static const Priority NUM_QUEUES = N;
@@ -26,9 +26,9 @@ struct ThreadQueueList {
}
// Only for debugging, returns priority level.
- Priority contains(const T& uid) {
+ Priority contains(const T& uid) const {
for (Priority i = 0; i < NUM_QUEUES; ++i) {
- Queue& cur = queues[i];
+ const Queue& cur = queues[i];
if (std::find(cur.data.cbegin(), cur.data.cend(), uid) != cur.data.cend()) {
return i;
}
@@ -37,8 +37,8 @@ struct ThreadQueueList {
return -1;
}
- T get_first() {
- Queue* cur = first;
+ T get_first() const {
+ const Queue* cur = first;
while (cur != nullptr) {
if (!cur->data.empty()) {
return cur->data.front();
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index a0c731e8c..edf13bc49 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -33,9 +33,11 @@ public:
bool Empty() const {
return !read_ptr->next.load();
}
+
T& Front() const {
return read_ptr->current;
}
+
template <typename Arg>
void Push(Arg&& t) {
// create the element, add it to the queue
@@ -108,15 +110,41 @@ private:
// single reader, multiple writer queue
template <typename T, bool NeedSize = true>
-class MPSCQueue : public SPSCQueue<T, NeedSize> {
+class MPSCQueue {
public:
+ u32 Size() const {
+ return spsc_queue.Size();
+ }
+
+ bool Empty() const {
+ return spsc_queue.Empty();
+ }
+
+ T& Front() const {
+ return spsc_queue.Front();
+ }
+
template <typename Arg>
void Push(Arg&& t) {
std::lock_guard<std::mutex> lock(write_lock);
- SPSCQueue<T, NeedSize>::Push(t);
+ spsc_queue.Push(t);
+ }
+
+ void Pop() {
+ return spsc_queue.Pop();
+ }
+
+ bool Pop(T& t) {
+ return spsc_queue.Pop(t);
+ }
+
+ // not thread-safe
+ void Clear() {
+ spsc_queue.Clear();
}
private:
+ SPSCQueue<T, NeedSize> spsc_queue;
std::mutex write_lock;
};
} // namespace Common
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index f0c5b1a43..2dc15e434 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -3,31 +3,16 @@
// Refer to the license.txt file included.
#include <ctime>
-
#include <fmt/format.h>
-
-#ifdef _WIN32
-#include <windows.h>
-// windows.h needs to be included before other windows headers
-#include <mmsystem.h>
-#include <sys/timeb.h>
-#else
-#include <sys/time.h>
-#endif
#include "common/common_types.h"
#include "common/string_util.h"
#include "common/timer.h"
namespace Common {
-u32 Timer::GetTimeMs() {
-#ifdef _WIN32
- return timeGetTime();
-#else
- struct timeval t;
- (void)gettimeofday(&t, nullptr);
- return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000));
-#endif
+std::chrono::milliseconds Timer::GetTimeMs() {
+ return std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::system_clock::now().time_since_epoch());
}
// --------------------------------------------
@@ -63,7 +48,7 @@ void Timer::Update() {
// -------------------------------------
// Get the number of milliseconds since the last Update()
-u64 Timer::GetTimeDifference() {
+std::chrono::milliseconds Timer::GetTimeDifference() {
return GetTimeMs() - m_LastTime;
}
@@ -74,11 +59,11 @@ void Timer::AddTimeDifference() {
}
// Get the time elapsed since the Start()
-u64 Timer::GetTimeElapsed() {
+std::chrono::milliseconds Timer::GetTimeElapsed() {
// If we have not started yet, return 1 (because then I don't
// have to change the FPS calculation in CoreRerecording.cpp .
- if (m_StartTime == 0)
- return 1;
+ if (m_StartTime.count() == 0)
+ return std::chrono::milliseconds(1);
// Return the final timer time if the timer is stopped
if (!m_Running)
@@ -90,49 +75,34 @@ u64 Timer::GetTimeElapsed() {
// Get the formatted time elapsed since the Start()
std::string Timer::GetTimeElapsedFormatted() const {
// If we have not started yet, return zero
- if (m_StartTime == 0)
+ if (m_StartTime.count() == 0)
return "00:00:00:000";
// The number of milliseconds since the start.
// Use a different value if the timer is stopped.
- u64 Milliseconds;
+ std::chrono::milliseconds Milliseconds;
if (m_Running)
Milliseconds = GetTimeMs() - m_StartTime;
else
Milliseconds = m_LastTime - m_StartTime;
// Seconds
- u32 Seconds = (u32)(Milliseconds / 1000);
+ std::chrono::seconds Seconds = std::chrono::duration_cast<std::chrono::seconds>(Milliseconds);
// Minutes
- u32 Minutes = Seconds / 60;
+ std::chrono::minutes Minutes = std::chrono::duration_cast<std::chrono::minutes>(Milliseconds);
// Hours
- u32 Hours = Minutes / 60;
+ std::chrono::hours Hours = std::chrono::duration_cast<std::chrono::hours>(Milliseconds);
- std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours, Minutes % 60, Seconds % 60,
- Milliseconds % 1000);
+ std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours.count(), Minutes.count() % 60,
+ Seconds.count() % 60, Milliseconds.count() % 1000);
return TmpStr;
}
-// Get current time
-void Timer::IncreaseResolution() {
-#ifdef _WIN32
- timeBeginPeriod(1);
-#endif
-}
-
-void Timer::RestoreResolution() {
-#ifdef _WIN32
- timeEndPeriod(1);
-#endif
-}
-
// Get the number of seconds since January 1 1970
-u64 Timer::GetTimeSinceJan1970() {
- time_t ltime;
- time(&ltime);
- return ((u64)ltime);
+std::chrono::seconds Timer::GetTimeSinceJan1970() {
+ return std::chrono::duration_cast<std::chrono::seconds>(GetTimeMs());
}
-u64 Timer::GetLocalTimeSinceJan1970() {
+std::chrono::seconds Timer::GetLocalTimeSinceJan1970() {
time_t sysTime, tzDiff, tzDST;
struct tm* gmTime;
@@ -149,7 +119,7 @@ u64 Timer::GetLocalTimeSinceJan1970() {
gmTime = gmtime(&sysTime);
tzDiff = sysTime - mktime(gmTime);
- return (u64)(sysTime + tzDiff + tzDST);
+ return std::chrono::seconds(sysTime + tzDiff + tzDST);
}
// Return the current time formatted as Minutes:Seconds:Milliseconds
@@ -164,30 +134,16 @@ std::string Timer::GetTimeFormatted() {
strftime(tmp, 6, "%M:%S", gmTime);
-// Now tack on the milliseconds
-#ifdef _WIN32
- struct timeb tp;
- (void)::ftime(&tp);
- return fmt::format("{}:{:03}", tmp, tp.millitm);
-#else
- struct timeval t;
- (void)gettimeofday(&t, nullptr);
- return fmt::format("{}:{:03}", tmp, static_cast<int>(t.tv_usec / 1000));
-#endif
+ u64 milliseconds = static_cast<u64>(GetTimeMs().count()) % 1000;
+ return fmt::format("{}:{:03}", tmp, milliseconds);
}
// Returns a timestamp with decimals for precise time comparisons
// ----------------
double Timer::GetDoubleTime() {
-#ifdef _WIN32
- struct timeb tp;
- (void)::ftime(&tp);
-#else
- struct timeval t;
- (void)gettimeofday(&t, nullptr);
-#endif
// Get continuous timestamp
- u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970();
+ u64 TmpSeconds = static_cast<u64>(Common::Timer::GetTimeSinceJan1970().count());
+ double ms = static_cast<u64>(GetTimeMs().count()) % 1000;
// Remove a few years. We only really want enough seconds to make
// sure that we are detecting actual actions, perhaps 60 seconds is
@@ -196,12 +152,7 @@ double Timer::GetDoubleTime() {
TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60);
// Make a smaller integer that fits in the double
- u32 Seconds = (u32)TmpSeconds;
-#ifdef _WIN32
- double ms = tp.millitm / 1000.0 / 1000.0;
-#else
- double ms = t.tv_usec / 1000000.0;
-#endif
+ u32 Seconds = static_cast<u32>(TmpSeconds);
double TmpTime = Seconds + ms;
return TmpTime;
diff --git a/src/common/timer.h b/src/common/timer.h
index 78d37426b..27b521baa 100644
--- a/src/common/timer.h
+++ b/src/common/timer.h
@@ -4,6 +4,7 @@
#pragma once
+#include <chrono>
#include <string>
#include "common/common_types.h"
@@ -18,24 +19,22 @@ public:
// The time difference is always returned in milliseconds, regardless of alternative internal
// representation
- u64 GetTimeDifference();
+ std::chrono::milliseconds GetTimeDifference();
void AddTimeDifference();
- static void IncreaseResolution();
- static void RestoreResolution();
- static u64 GetTimeSinceJan1970();
- static u64 GetLocalTimeSinceJan1970();
+ static std::chrono::seconds GetTimeSinceJan1970();
+ static std::chrono::seconds GetLocalTimeSinceJan1970();
static double GetDoubleTime();
static std::string GetTimeFormatted();
std::string GetTimeElapsedFormatted() const;
- u64 GetTimeElapsed();
+ std::chrono::milliseconds GetTimeElapsed();
- static u32 GetTimeMs();
+ static std::chrono::milliseconds GetTimeMs();
private:
- u64 m_LastTime;
- u64 m_StartTime;
+ std::chrono::milliseconds m_LastTime;
+ std::chrono::milliseconds m_StartTime;
bool m_Running;
};
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index cca43bd4c..8feb49941 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -43,139 +43,135 @@ template <typename T>
class Vec4;
template <typename T>
-static inline Vec2<T> MakeVec(const T& x, const T& y);
-template <typename T>
-static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z);
-template <typename T>
-static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w);
-
-template <typename T>
class Vec2 {
public:
T x{};
T y{};
- Vec2() = default;
- Vec2(const T& _x, const T& _y) : x(_x), y(_y) {}
+ constexpr Vec2() = default;
+ constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {}
template <typename T2>
- Vec2<T2> Cast() const {
- return Vec2<T2>((T2)x, (T2)y);
+ constexpr Vec2<T2> Cast() const {
+ return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y));
}
- static Vec2 AssignToAll(const T& f) {
- return Vec2<T>(f, f);
+ static constexpr Vec2 AssignToAll(const T& f) {
+ return Vec2{f, f};
}
- Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
- return MakeVec(x + other.x, y + other.y);
+ constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
+ return {x + other.x, y + other.y};
}
- void operator+=(const Vec2& other) {
+ constexpr Vec2& operator+=(const Vec2& other) {
x += other.x;
y += other.y;
+ return *this;
}
- Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
- return MakeVec(x - other.x, y - other.y);
+ constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
+ return {x - other.x, y - other.y};
}
- void operator-=(const Vec2& other) {
+ constexpr Vec2& operator-=(const Vec2& other) {
x -= other.x;
y -= other.y;
+ return *this;
}
template <typename U = T>
- Vec2<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const {
- return MakeVec(-x, -y);
+ constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
+ return {-x, -y};
}
- Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
- return MakeVec(x * other.x, y * other.y);
+ constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
+ return {x * other.x, y * other.y};
}
+
template <typename V>
- Vec2<decltype(T{} * V{})> operator*(const V& f) const {
- return MakeVec(x * f, y * f);
+ constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
+ return {x * f, y * f};
}
+
template <typename V>
- void operator*=(const V& f) {
+ constexpr Vec2& operator*=(const V& f) {
*this = *this * f;
+ return *this;
}
+
template <typename V>
- Vec2<decltype(T{} / V{})> operator/(const V& f) const {
- return MakeVec(x / f, y / f);
+ constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
+ return {x / f, y / f};
}
+
template <typename V>
- void operator/=(const V& f) {
+ constexpr Vec2& operator/=(const V& f) {
*this = *this / f;
+ return *this;
}
- T Length2() const {
+ constexpr T Length2() const {
return x * x + y * y;
}
// Only implemented for T=float
float Length() const;
- void SetLength(const float l);
- Vec2 WithLength(const float l) const;
- float Distance2To(Vec2& other);
- Vec2 Normalized() const;
float Normalize(); // returns the previous length, which is often useful
- T& operator[](int i) // allow vector[1] = 3 (vector.y=3)
- {
+ constexpr T& operator[](std::size_t i) {
return *((&x) + i);
}
- T operator[](const int i) const {
+ constexpr const T& operator[](std::size_t i) const {
return *((&x) + i);
}
- void SetZero() {
+ constexpr void SetZero() {
x = 0;
y = 0;
}
// Common aliases: UV (texel coordinates), ST (texture coordinates)
- T& u() {
+ constexpr T& u() {
return x;
}
- T& v() {
+ constexpr T& v() {
return y;
}
- T& s() {
+ constexpr T& s() {
return x;
}
- T& t() {
+ constexpr T& t() {
return y;
}
- const T& u() const {
+ constexpr const T& u() const {
return x;
}
- const T& v() const {
+ constexpr const T& v() const {
return y;
}
- const T& s() const {
+ constexpr const T& s() const {
return x;
}
- const T& t() const {
+ constexpr const T& t() const {
return y;
}
// swizzlers - create a subvector of specific components
- const Vec2 yx() const {
+ constexpr Vec2 yx() const {
return Vec2(y, x);
}
- const Vec2 vu() const {
+ constexpr Vec2 vu() const {
return Vec2(y, x);
}
- const Vec2 ts() const {
+ constexpr Vec2 ts() const {
return Vec2(y, x);
}
};
template <typename T, typename V>
-Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
+constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
return Vec2<T>(f * vec.x, f * vec.y);
}
-typedef Vec2<float> Vec2f;
+using Vec2f = Vec2<float>;
template <>
inline float Vec2<float>::Length() const {
@@ -196,147 +192,151 @@ public:
T y{};
T z{};
- Vec3() = default;
- Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {}
+ constexpr Vec3() = default;
+ constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {}
template <typename T2>
- Vec3<T2> Cast() const {
- return MakeVec<T2>((T2)x, (T2)y, (T2)z);
+ constexpr Vec3<T2> Cast() const {
+ return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z));
}
- // Only implemented for T=int and T=float
- static Vec3 FromRGB(unsigned int rgb);
- unsigned int ToRGB() const; // alpha bits set to zero
-
- static Vec3 AssignToAll(const T& f) {
- return MakeVec(f, f, f);
+ static constexpr Vec3 AssignToAll(const T& f) {
+ return Vec3(f, f, f);
}
- Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
- return MakeVec(x + other.x, y + other.y, z + other.z);
+ constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
+ return {x + other.x, y + other.y, z + other.z};
}
- void operator+=(const Vec3& other) {
+
+ constexpr Vec3& operator+=(const Vec3& other) {
x += other.x;
y += other.y;
z += other.z;
+ return *this;
}
- Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
- return MakeVec(x - other.x, y - other.y, z - other.z);
+
+ constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
+ return {x - other.x, y - other.y, z - other.z};
}
- void operator-=(const Vec3& other) {
+
+ constexpr Vec3& operator-=(const Vec3& other) {
x -= other.x;
y -= other.y;
z -= other.z;
+ return *this;
}
template <typename U = T>
- Vec3<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const {
- return MakeVec(-x, -y, -z);
+ constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
+ return {-x, -y, -z};
}
- Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
- return MakeVec(x * other.x, y * other.y, z * other.z);
+
+ constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
+ return {x * other.x, y * other.y, z * other.z};
}
+
template <typename V>
- Vec3<decltype(T{} * V{})> operator*(const V& f) const {
- return MakeVec(x * f, y * f, z * f);
+ constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
+ return {x * f, y * f, z * f};
}
+
template <typename V>
- void operator*=(const V& f) {
+ constexpr Vec3& operator*=(const V& f) {
*this = *this * f;
+ return *this;
}
template <typename V>
- Vec3<decltype(T{} / V{})> operator/(const V& f) const {
- return MakeVec(x / f, y / f, z / f);
+ constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
+ return {x / f, y / f, z / f};
}
+
template <typename V>
- void operator/=(const V& f) {
+ constexpr Vec3& operator/=(const V& f) {
*this = *this / f;
+ return *this;
}
- T Length2() const {
+ constexpr T Length2() const {
return x * x + y * y + z * z;
}
// Only implemented for T=float
float Length() const;
- void SetLength(const float l);
- Vec3 WithLength(const float l) const;
- float Distance2To(Vec3& other);
Vec3 Normalized() const;
float Normalize(); // returns the previous length, which is often useful
- T& operator[](int i) // allow vector[2] = 3 (vector.z=3)
- {
+ constexpr T& operator[](std::size_t i) {
return *((&x) + i);
}
- T operator[](const int i) const {
+
+ constexpr const T& operator[](std::size_t i) const {
return *((&x) + i);
}
- void SetZero() {
+ constexpr void SetZero() {
x = 0;
y = 0;
z = 0;
}
// Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates)
- T& u() {
+ constexpr T& u() {
return x;
}
- T& v() {
+ constexpr T& v() {
return y;
}
- T& w() {
+ constexpr T& w() {
return z;
}
- T& r() {
+ constexpr T& r() {
return x;
}
- T& g() {
+ constexpr T& g() {
return y;
}
- T& b() {
+ constexpr T& b() {
return z;
}
- T& s() {
+ constexpr T& s() {
return x;
}
- T& t() {
+ constexpr T& t() {
return y;
}
- T& q() {
+ constexpr T& q() {
return z;
}
- const T& u() const {
+ constexpr const T& u() const {
return x;
}
- const T& v() const {
+ constexpr const T& v() const {
return y;
}
- const T& w() const {
+ constexpr const T& w() const {
return z;
}
- const T& r() const {
+ constexpr const T& r() const {
return x;
}
- const T& g() const {
+ constexpr const T& g() const {
return y;
}
- const T& b() const {
+ constexpr const T& b() const {
return z;
}
- const T& s() const {
+ constexpr const T& s() const {
return x;
}
- const T& t() const {
+ constexpr const T& t() const {
return y;
}
- const T& q() const {
+ constexpr const T& q() const {
return z;
}
@@ -345,7 +345,7 @@ public:
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
// component names (x<->r) and permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
- const Vec2<T> name() const { \
+ constexpr Vec2<T> name() const { \
return Vec2<T>(a, b); \
}
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
@@ -366,7 +366,7 @@ public:
};
template <typename T, typename V>
-Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
+constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
}
@@ -387,7 +387,7 @@ inline float Vec3<float>::Normalize() {
return length;
}
-typedef Vec3<float> Vec3f;
+using Vec3f = Vec3<float>;
template <typename T>
class Vec4 {
@@ -397,86 +397,88 @@ public:
T z{};
T w{};
- Vec4() = default;
- Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {}
+ constexpr Vec4() = default;
+ constexpr Vec4(const T& x_, const T& y_, const T& z_, const T& w_)
+ : x(x_), y(y_), z(z_), w(w_) {}
template <typename T2>
- Vec4<T2> Cast() const {
- return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w);
+ constexpr Vec4<T2> Cast() const {
+ return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z),
+ static_cast<T2>(w));
}
- // Only implemented for T=int and T=float
- static Vec4 FromRGBA(unsigned int rgba);
- unsigned int ToRGBA() const;
-
- static Vec4 AssignToAll(const T& f) {
- return Vec4<T>(f, f, f, f);
+ static constexpr Vec4 AssignToAll(const T& f) {
+ return Vec4(f, f, f, f);
}
- Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
- return MakeVec(x + other.x, y + other.y, z + other.z, w + other.w);
+ constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
+ return {x + other.x, y + other.y, z + other.z, w + other.w};
}
- void operator+=(const Vec4& other) {
+
+ constexpr Vec4& operator+=(const Vec4& other) {
x += other.x;
y += other.y;
z += other.z;
w += other.w;
+ return *this;
}
- Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
- return MakeVec(x - other.x, y - other.y, z - other.z, w - other.w);
+
+ constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
+ return {x - other.x, y - other.y, z - other.z, w - other.w};
}
- void operator-=(const Vec4& other) {
+
+ constexpr Vec4& operator-=(const Vec4& other) {
x -= other.x;
y -= other.y;
z -= other.z;
w -= other.w;
+ return *this;
}
template <typename U = T>
- Vec4<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const {
- return MakeVec(-x, -y, -z, -w);
+ constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
+ return {-x, -y, -z, -w};
}
- Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
- return MakeVec(x * other.x, y * other.y, z * other.z, w * other.w);
+
+ constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
+ return {x * other.x, y * other.y, z * other.z, w * other.w};
}
+
template <typename V>
- Vec4<decltype(T{} * V{})> operator*(const V& f) const {
- return MakeVec(x * f, y * f, z * f, w * f);
+ constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
+ return {x * f, y * f, z * f, w * f};
}
+
template <typename V>
- void operator*=(const V& f) {
+ constexpr Vec4& operator*=(const V& f) {
*this = *this * f;
+ return *this;
}
+
template <typename V>
- Vec4<decltype(T{} / V{})> operator/(const V& f) const {
- return MakeVec(x / f, y / f, z / f, w / f);
+ constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
+ return {x / f, y / f, z / f, w / f};
}
+
template <typename V>
- void operator/=(const V& f) {
+ constexpr Vec4& operator/=(const V& f) {
*this = *this / f;
+ return *this;
}
- T Length2() const {
+ constexpr T Length2() const {
return x * x + y * y + z * z + w * w;
}
- // Only implemented for T=float
- float Length() const;
- void SetLength(const float l);
- Vec4 WithLength(const float l) const;
- float Distance2To(Vec4& other);
- Vec4 Normalized() const;
- float Normalize(); // returns the previous length, which is often useful
-
- T& operator[](int i) // allow vector[2] = 3 (vector.z=3)
- {
+ constexpr T& operator[](std::size_t i) {
return *((&x) + i);
}
- T operator[](const int i) const {
+
+ constexpr const T& operator[](std::size_t i) const {
return *((&x) + i);
}
- void SetZero() {
+ constexpr void SetZero() {
x = 0;
y = 0;
z = 0;
@@ -484,29 +486,29 @@ public:
}
// Common alias: RGBA (colors)
- T& r() {
+ constexpr T& r() {
return x;
}
- T& g() {
+ constexpr T& g() {
return y;
}
- T& b() {
+ constexpr T& b() {
return z;
}
- T& a() {
+ constexpr T& a() {
return w;
}
- const T& r() const {
+ constexpr const T& r() const {
return x;
}
- const T& g() const {
+ constexpr const T& g() const {
return y;
}
- const T& b() const {
+ constexpr const T& b() const {
return z;
}
- const T& a() const {
+ constexpr const T& a() const {
return w;
}
@@ -518,7 +520,7 @@ public:
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
// permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
- const Vec2<T> name() const { \
+ constexpr Vec2<T> name() const { \
return Vec2<T>(a, b); \
}
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
@@ -545,7 +547,7 @@ public:
#undef _DEFINE_SWIZZLER2
#define _DEFINE_SWIZZLER3(a, b, c, name) \
- const Vec3<T> name() const { \
+ constexpr Vec3<T> name() const { \
return Vec3<T>(a, b, c); \
}
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
@@ -579,51 +581,51 @@ public:
};
template <typename T, typename V>
-Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
- return MakeVec(f * vec.x, f * vec.y, f * vec.z, f * vec.w);
+constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
+ return {f * vec.x, f * vec.y, f * vec.z, f * vec.w};
}
-typedef Vec4<float> Vec4f;
+using Vec4f = Vec4<float>;
template <typename T>
-static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {
+constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {
return a.x * b.x + a.y * b.y;
}
template <typename T>
-static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
+constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
template <typename T>
-static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
+constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
template <typename T>
-static inline Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) {
- return MakeVec(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
+constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) {
+ return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
// linear interpolation via float: 0.0=begin, 1.0=end
template <typename X>
-static inline decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
- const float t) {
+constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
+ const float t) {
return begin * (1.f - t) + end * t;
}
// linear interpolation via int: 0=begin, base=end
template <typename X, int base>
-static inline decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end,
- const int t) {
+constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end,
+ const int t) {
return (begin * (base - t) + end * t) / base;
}
// bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second
// interpolation.
template <typename X>
-inline auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s,
- const float t) {
+constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s,
+ const float t) {
auto y0 = Lerp(x00, x01, s);
auto y1 = Lerp(x10, x11, s);
return Lerp(y0, y1, t);
@@ -631,42 +633,42 @@ inline auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x1
// Utility vector factories
template <typename T>
-static inline Vec2<T> MakeVec(const T& x, const T& y) {
+constexpr Vec2<T> MakeVec(const T& x, const T& y) {
return Vec2<T>{x, y};
}
template <typename T>
-static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
+constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
return Vec3<T>{x, y, z};
}
template <typename T>
-static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
+constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
return MakeVec(x, y, zw[0], zw[1]);
}
template <typename T>
-static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
+constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
return MakeVec(xy[0], xy[1], z);
}
template <typename T>
-static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
+constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
return MakeVec(x, yz[0], yz[1]);
}
template <typename T>
-static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
+constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
return Vec4<T>{x, y, z, w};
}
template <typename T>
-static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
+constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
return MakeVec(xy[0], xy[1], z, w);
}
template <typename T>
-static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
+constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
return MakeVec(x, yz[0], yz[1], w);
}
@@ -674,17 +676,17 @@ static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error
// out soon enough due to misuse of the returned structure.
template <typename T>
-static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
+constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
return MakeVec(xy[0], xy[1], zw[0], zw[1]);
}
template <typename T>
-static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
+constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
return MakeVec(xyz[0], xyz[1], xyz[2], w);
}
template <typename T>
-static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
+constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
return MakeVec(x, yzw[0], yzw[1], yzw[2]);
}
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
index fd3fbdd4b..927da9187 100644
--- a/src/common/x64/xbyak_abi.h
+++ b/src/common/x64/xbyak_abi.h
@@ -9,10 +9,9 @@
#include "common/assert.h"
#include "common/bit_set.h"
-namespace Common {
-namespace X64 {
+namespace Common::X64 {
-int RegToIndex(const Xbyak::Reg& reg) {
+inline int RegToIndex(const Xbyak::Reg& reg) {
using Kind = Xbyak::Reg::Kind;
ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
"RegSet only support GPRs and XMM registers.");
@@ -152,8 +151,8 @@ constexpr size_t ABI_SHADOW_SPACE = 0;
#endif
-void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_frame_size,
- s32* out_subtraction, s32* out_xmm_offset) {
+inline void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_frame_size,
+ s32* out_subtraction, s32* out_xmm_offset) {
int count = (regs & ABI_ALL_GPRS).Count();
rsp_alignment -= count * 8;
size_t subtraction = 0;
@@ -174,8 +173,8 @@ void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_f
*out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
}
-size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
- size_t rsp_alignment, size_t needed_frame_size = 0) {
+inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
+ size_t rsp_alignment, size_t needed_frame_size = 0) {
s32 subtraction, xmm_offset;
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
@@ -195,8 +194,8 @@ size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs
return ABI_SHADOW_SPACE;
}
-void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, size_t rsp_alignment,
- size_t needed_frame_size = 0) {
+inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
+ size_t rsp_alignment, size_t needed_frame_size = 0) {
s32 subtraction, xmm_offset;
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
@@ -217,5 +216,4 @@ void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, s
}
}
-} // namespace X64
-} // namespace Common
+} // namespace Common::X64
diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h
index 0f52f704b..02323a017 100644
--- a/src/common/x64/xbyak_util.h
+++ b/src/common/x64/xbyak_util.h
@@ -8,8 +8,7 @@
#include <xbyak.h>
#include "common/x64/xbyak_abi.h"
-namespace Common {
-namespace X64 {
+namespace Common::X64 {
// Constants for use with cmpps/cmpss
enum {
@@ -34,7 +33,7 @@ inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
template <typename T>
inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
- static_assert(std::is_pointer<T>(), "Argument must be a (function) pointer.");
+ static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");
size_t addr = reinterpret_cast<size_t>(f);
if (IsWithin2G(code, addr)) {
code.call(f);
@@ -45,5 +44,4 @@ inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
}
}
-} // namespace X64
-} // namespace Common
+} // namespace Common::X64
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 2e2de59b1..67ad6109a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -12,6 +12,18 @@ add_library(core STATIC
core_timing.h
core_timing_util.cpp
core_timing_util.h
+ crypto/aes_util.cpp
+ crypto/aes_util.h
+ crypto/encryption_layer.cpp
+ crypto/encryption_layer.h
+ crypto/key_manager.cpp
+ crypto/key_manager.h
+ crypto/ctr_encryption_layer.cpp
+ crypto/ctr_encryption_layer.h
+ file_sys/bis_factory.cpp
+ file_sys/bis_factory.h
+ file_sys/card_image.cpp
+ file_sys/card_image.h
file_sys/content_archive.cpp
file_sys/content_archive.h
file_sys/control_metadata.cpp
@@ -19,10 +31,16 @@ add_library(core STATIC
file_sys/directory.h
file_sys/errors.h
file_sys/mode.h
+ file_sys/nca_metadata.cpp
+ file_sys/nca_metadata.h
file_sys/partition_filesystem.cpp
file_sys/partition_filesystem.h
file_sys/program_metadata.cpp
file_sys/program_metadata.h
+ file_sys/registered_cache.cpp
+ file_sys/registered_cache.h
+ file_sys/romfs.cpp
+ file_sys/romfs.h
file_sys/romfs_factory.cpp
file_sys/romfs_factory.h
file_sys/savedata_factory.cpp
@@ -31,10 +49,14 @@ add_library(core STATIC
file_sys/sdmc_factory.h
file_sys/vfs.cpp
file_sys/vfs.h
+ file_sys/vfs_concat.cpp
+ file_sys/vfs_concat.h
file_sys/vfs_offset.cpp
file_sys/vfs_offset.h
file_sys/vfs_real.cpp
file_sys/vfs_real.h
+ file_sys/vfs_vector.cpp
+ file_sys/vfs_vector.h
frontend/emu_window.cpp
frontend/emu_window.h
frontend/framebuffer_layout.cpp
@@ -59,12 +81,10 @@ add_library(core STATIC
hle/kernel/hle_ipc.h
hle/kernel/kernel.cpp
hle/kernel/kernel.h
- hle/kernel/memory.cpp
- hle/kernel/memory.h
hle/kernel/mutex.cpp
hle/kernel/mutex.h
- hle/kernel/object_address_table.cpp
- hle/kernel/object_address_table.h
+ hle/kernel/object.cpp
+ hle/kernel/object.h
hle/kernel/process.cpp
hle/kernel/process.h
hle/kernel/resource_limit.cpp
@@ -92,8 +112,6 @@ add_library(core STATIC
hle/lock.cpp
hle/lock.h
hle/result.h
- hle/romfs.cpp
- hle/romfs.h
hle/service/acc/acc.cpp
hle/service/acc/acc.h
hle/service/acc/acc_aa.cpp
@@ -110,23 +128,41 @@ add_library(core STATIC
hle/service/am/applet_ae.h
hle/service/am/applet_oe.cpp
hle/service/am/applet_oe.h
+ hle/service/am/idle.cpp
+ hle/service/am/idle.h
+ hle/service/am/omm.cpp
+ hle/service/am/omm.h
+ hle/service/am/spsm.cpp
+ hle/service/am/spsm.h
hle/service/aoc/aoc_u.cpp
hle/service/aoc/aoc_u.h
hle/service/apm/apm.cpp
hle/service/apm/apm.h
hle/service/apm/interface.cpp
hle/service/apm/interface.h
+ hle/service/arp/arp.cpp
+ hle/service/arp/arp.h
+ hle/service/audio/audctl.cpp
+ hle/service/audio/audctl.h
+ hle/service/audio/auddbg.cpp
+ hle/service/audio/auddbg.h
+ hle/service/audio/audin_a.cpp
+ hle/service/audio/audin_a.h
hle/service/audio/audin_u.cpp
hle/service/audio/audin_u.h
hle/service/audio/audio.cpp
hle/service/audio/audio.h
+ hle/service/audio/audout_a.cpp
+ hle/service/audio/audout_a.h
hle/service/audio/audout_u.cpp
hle/service/audio/audout_u.h
+ hle/service/audio/audrec_a.cpp
+ hle/service/audio/audrec_a.h
hle/service/audio/audrec_u.cpp
hle/service/audio/audrec_u.h
+ hle/service/audio/audren_a.cpp
+ hle/service/audio/audren_a.h
hle/service/audio/audren_u.cpp
- hle/service/audio/audren_u.cpp
- hle/service/audio/audren_u.h
hle/service/audio/audren_u.h
hle/service/audio/codecctl.cpp
hle/service/audio/codecctl.h
@@ -136,6 +172,14 @@ add_library(core STATIC
hle/service/bcat/bcat.h
hle/service/bcat/module.cpp
hle/service/bcat/module.h
+ hle/service/bpc/bpc.cpp
+ hle/service/bpc/bpc.h
+ hle/service/btdrv/btdrv.cpp
+ hle/service/btdrv/btdrv.h
+ hle/service/btm/btm.cpp
+ hle/service/btm/btm.h
+ hle/service/caps/caps.cpp
+ hle/service/caps/caps.h
hle/service/erpt/erpt.cpp
hle/service/erpt/erpt.h
hle/service/es/es.cpp
@@ -150,26 +194,52 @@ add_library(core STATIC
hle/service/fatal/fatal_u.h
hle/service/filesystem/filesystem.cpp
hle/service/filesystem/filesystem.h
+ hle/service/filesystem/fsp_ldr.cpp
+ hle/service/filesystem/fsp_ldr.h
+ hle/service/filesystem/fsp_pr.cpp
+ hle/service/filesystem/fsp_pr.h
hle/service/filesystem/fsp_srv.cpp
hle/service/filesystem/fsp_srv.h
+ hle/service/fgm/fgm.cpp
+ hle/service/fgm/fgm.h
hle/service/friend/friend.cpp
hle/service/friend/friend.h
hle/service/friend/interface.cpp
hle/service/friend/interface.h
+ hle/service/grc/grc.cpp
+ hle/service/grc/grc.h
hle/service/hid/hid.cpp
hle/service/hid/hid.h
+ hle/service/hid/irs.cpp
+ hle/service/hid/irs.h
+ hle/service/hid/xcd.cpp
+ hle/service/hid/xcd.h
+ hle/service/lbl/lbl.cpp
+ hle/service/lbl/lbl.h
+ hle/service/ldn/ldn.cpp
+ hle/service/ldn/ldn.h
hle/service/ldr/ldr.cpp
hle/service/ldr/ldr.h
hle/service/lm/lm.cpp
hle/service/lm/lm.h
+ hle/service/mig/mig.cpp
+ hle/service/mig/mig.h
+ hle/service/mii/mii.cpp
+ hle/service/mii/mii.h
hle/service/mm/mm_u.cpp
hle/service/mm/mm_u.h
+ hle/service/ncm/ncm.cpp
+ hle/service/ncm/ncm.h
+ hle/service/nfc/nfc.cpp
+ hle/service/nfc/nfc.h
hle/service/nfp/nfp.cpp
hle/service/nfp/nfp.h
hle/service/nfp/nfp_user.cpp
hle/service/nfp/nfp_user.h
hle/service/nifm/nifm.cpp
hle/service/nifm/nifm.h
+ hle/service/nim/nim.cpp
+ hle/service/nim/nim.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
hle/service/ns/pl_u.cpp
@@ -187,6 +257,10 @@ add_library(core STATIC
hle/service/nvdrv/devices/nvhost_gpu.h
hle/service/nvdrv/devices/nvhost_nvdec.cpp
hle/service/nvdrv/devices/nvhost_nvdec.h
+ hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+ hle/service/nvdrv/devices/nvhost_nvjpg.h
+ hle/service/nvdrv/devices/nvhost_vic.cpp
+ hle/service/nvdrv/devices/nvhost_vic.h
hle/service/nvdrv/devices/nvmap.cpp
hle/service/nvdrv/devices/nvmap.h
hle/service/nvdrv/interface.cpp
@@ -199,14 +273,20 @@ add_library(core STATIC
hle/service/nvflinger/buffer_queue.h
hle/service/nvflinger/nvflinger.cpp
hle/service/nvflinger/nvflinger.h
+ hle/service/pcie/pcie.cpp
+ hle/service/pcie/pcie.h
hle/service/pctl/module.cpp
hle/service/pctl/module.h
hle/service/pctl/pctl.cpp
hle/service/pctl/pctl.h
+ hle/service/pcv/pcv.cpp
+ hle/service/pcv/pcv.h
hle/service/pm/pm.cpp
hle/service/pm/pm.h
hle/service/prepo/prepo.cpp
hle/service/prepo/prepo.h
+ hle/service/psc/psc.cpp
+ hle/service/psc/psc.h
hle/service/service.cpp
hle/service/service.h
hle/service/set/set.cpp
@@ -225,6 +305,8 @@ add_library(core STATIC
hle/service/sm/sm.h
hle/service/sockets/bsd.cpp
hle/service/sockets/bsd.h
+ hle/service/sockets/ethc.cpp
+ hle/service/sockets/ethc.h
hle/service/sockets/nsd.cpp
hle/service/sockets/nsd.h
hle/service/sockets/sfdnsres.cpp
@@ -243,6 +325,8 @@ add_library(core STATIC
hle/service/time/interface.h
hle/service/time/time.cpp
hle/service/time/time.h
+ hle/service/usb/usb.cpp
+ hle/service/usb/usb.h
hle/service/vi/vi.cpp
hle/service/vi/vi.h
hle/service/vi/vi_m.cpp
@@ -251,10 +335,8 @@ add_library(core STATIC
hle/service/vi/vi_s.h
hle/service/vi/vi_u.cpp
hle/service/vi/vi_u.h
- hw/hw.cpp
- hw/hw.h
- hw/lcd.cpp
- hw/lcd.h
+ hle/service/wlan/wlan.cpp
+ hle/service/wlan/wlan.h
loader/deconstructed_rom_directory.cpp
loader/deconstructed_rom_directory.h
loader/elf.cpp
@@ -269,6 +351,8 @@ add_library(core STATIC
loader/nro.h
loader/nso.cpp
loader/nso.h
+ loader/xci.cpp
+ loader/xci.h
memory.cpp
memory.h
memory_hook.cpp
@@ -287,8 +371,8 @@ add_library(core STATIC
create_target_directory_groups(core)
-target_link_libraries(core PUBLIC common PRIVATE video_core)
-target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static unicorn)
+target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
+target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn)
if (ARCHITECTURE_x86_64)
target_sources(core PRIVATE
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 57b8634b9..2c817d7d1 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -10,7 +10,7 @@
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/core.h"
#include "core/core_timing.h"
-#include "core/hle/kernel/memory.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
@@ -86,7 +86,16 @@ public:
}
void AddTicks(u64 ticks) override {
- CoreTiming::AddTicks(ticks - num_interpreted_instructions);
+ // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
+ // rough approximation of the amount of executed ticks in the system, it may be thrown off
+ // if not all cores are doing a similar amount of work. Instead of doing this, we should
+ // device a way so that timing is consistent across all cores without increasing the ticks 4
+ // times.
+ u64 amortized_ticks = (ticks - num_interpreted_instructions) / Core::NUM_CPU_CORES;
+ // Always execute at least one tick.
+ amortized_ticks = std::max<u64>(amortized_ticks, 1);
+
+ CoreTiming::AddTicks(amortized_ticks);
num_interpreted_instructions = 0;
}
u64 GetTicksRemaining() override {
@@ -125,6 +134,9 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
config.dczid_el0 = 4;
config.ctr_el0 = 0x8444c004;
+ // Unpredictable instructions
+ config.define_unpredictable_behaviour = true;
+
return std::make_unique<Dynarmic::A64::Jit>(config);
}
@@ -139,14 +151,12 @@ void ARM_Dynarmic::Step() {
}
ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index)
- : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)),
- jit(MakeJit()), exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(
- exclusive_monitor)},
- core_index{core_index} {
- ARM_Interface::ThreadContext ctx;
+ : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index},
+ exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} {
+ ThreadContext ctx;
inner_unicorn.SaveContext(ctx);
- LoadContext(ctx);
PageTableChanged();
+ LoadContext(ctx);
}
ARM_Dynarmic::~ARM_Dynarmic() = default;
@@ -205,7 +215,7 @@ u64 ARM_Dynarmic::GetTlsAddress() const {
return cb->tpidrro_el0;
}
-void ARM_Dynarmic::SetTlsAddress(u64 address) {
+void ARM_Dynarmic::SetTlsAddress(VAddr address) {
cb->tpidrro_el0 = address;
}
@@ -217,7 +227,7 @@ void ARM_Dynarmic::SetTPIDR_EL0(u64 value) {
cb->tpidr_el0 = value;
}
-void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
+void ARM_Dynarmic::SaveContext(ThreadContext& ctx) {
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC();
@@ -226,7 +236,7 @@ void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
ctx.fpscr = jit->GetFpcr();
}
-void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
+void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);
@@ -236,9 +246,7 @@ void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
}
void ARM_Dynarmic::PrepareReschedule() {
- if (jit->IsExecuting()) {
- jit->HaltExecution();
- }
+ jit->HaltExecution();
}
void ARM_Dynarmic::ClearInstructionCache() {
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index 4c11f35a4..6bc349460 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -203,7 +203,7 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
}
Kernel::Thread* thread = Kernel::GetCurrentThread();
SaveContext(thread->context);
- if (last_bkpt_hit || (num_instructions == 1)) {
+ if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) {
last_bkpt_hit = false;
GDBStub::Break();
GDBStub::SendTrap(thread, 5);
diff --git a/src/core/core.cpp b/src/core/core.cpp
index b7f4b4532..28038ff6f 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -5,6 +5,7 @@
#include <memory>
#include <utility>
#include "common/logging/log.h"
+#include "common/string_util.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/gdbstub/gdbstub.h"
@@ -15,11 +16,11 @@
#include "core/hle/service/service.h"
#include "core/hle/service/sm/controller.h"
#include "core/hle/service/sm/sm.h"
-#include "core/hw/hw.h"
#include "core/loader/loader.h"
-#include "core/memory_setup.h"
#include "core/settings.h"
+#include "file_sys/vfs_concat.h"
#include "file_sys/vfs_real.h"
+#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
namespace Core {
@@ -63,7 +64,6 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
// execute. Otherwise, get out of the loop function.
if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) {
- GDBStub::SetCpuStepFlag(false);
tight_loop = false;
} else {
return ResultStatus::Success;
@@ -79,6 +79,10 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
}
}
+ if (GDBStub::IsServerEnabled()) {
+ GDBStub::SetCpuStepFlag(false);
+ }
+
return status;
}
@@ -86,8 +90,39 @@ System::ResultStatus System::SingleStep() {
return RunLoop(false);
}
-System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) {
- app_loader = Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(filepath));
+static FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
+ const std::string& path) {
+ // To account for split 00+01+etc files.
+ std::string dir_name;
+ std::string filename;
+ Common::SplitPath(path, &dir_name, &filename, nullptr);
+ if (filename == "00") {
+ const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read);
+ std::vector<FileSys::VirtualFile> concat;
+ for (u8 i = 0; i < 0x10; ++i) {
+ auto next = dir->GetFile(fmt::format("{:02X}", i));
+ if (next != nullptr)
+ concat.push_back(std::move(next));
+ else {
+ next = dir->GetFile(fmt::format("{:02x}", i));
+ if (next != nullptr)
+ concat.push_back(std::move(next));
+ else
+ break;
+ }
+ }
+
+ if (concat.empty())
+ return nullptr;
+
+ return FileSys::ConcatenateFiles(concat, dir->GetName());
+ }
+
+ return vfs->OpenFile(path, FileSys::Mode::Read);
+}
+
+System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
+ app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
@@ -100,19 +135,11 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(system_mode.second));
- switch (system_mode.second) {
- case Loader::ResultStatus::ErrorEncrypted:
- return ResultStatus::ErrorLoader_ErrorEncrypted;
- case Loader::ResultStatus::ErrorInvalidFormat:
- return ResultStatus::ErrorLoader_ErrorInvalidFormat;
- case Loader::ResultStatus::ErrorUnsupportedArch:
- return ResultStatus::ErrorUnsupportedArch;
- default:
+ if (system_mode.second != Loader::ResultStatus::Success)
return ResultStatus::ErrorSystemMode;
- }
}
- ResultStatus init_result{Init(emu_window, system_mode.first.get())};
+ ResultStatus init_result{Init(emu_window)};
if (init_result != ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
@@ -125,15 +152,9 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
System::Shutdown();
- switch (load_result) {
- case Loader::ResultStatus::ErrorEncrypted:
- return ResultStatus::ErrorLoader_ErrorEncrypted;
- case Loader::ResultStatus::ErrorInvalidFormat:
- return ResultStatus::ErrorLoader_ErrorInvalidFormat;
- case Loader::ResultStatus::ErrorUnsupportedArch:
- return ResultStatus::ErrorUnsupportedArch;
- default:
- return ResultStatus::ErrorLoader;
+ if (load_result != Loader::ResultStatus::Success) {
+ return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
+ static_cast<u32>(load_result));
}
}
status = ResultStatus::Success;
@@ -163,11 +184,15 @@ Cpu& System::CpuCore(size_t core_index) {
return *cpu_cores[core_index];
}
-System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
+System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
LOG_DEBUG(HW_Memory, "initialized OK");
CoreTiming::Init();
+ // Create a default fs if one doesn't already exist.
+ if (virtual_filesystem == nullptr)
+ virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
+
current_process = Kernel::Process::Create("main");
cpu_barrier = std::make_shared<CpuBarrier>();
@@ -176,19 +201,20 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index);
}
- gpu_core = std::make_unique<Tegra::GPU>();
telemetry_session = std::make_unique<Core::TelemetrySession>();
service_manager = std::make_shared<Service::SM::ServiceManager>();
- HW::Init();
- Kernel::Init(system_mode);
- Service::Init(service_manager);
+ Kernel::Init();
+ Service::Init(service_manager, virtual_filesystem);
GDBStub::Init();
- if (!VideoCore::Init(emu_window)) {
+ renderer = VideoCore::CreateRenderer(emu_window);
+ if (!renderer->Init()) {
return ResultStatus::ErrorVideoCore;
}
+ gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
+
// Create threads for CPU cores 1-3, and build thread_to_cpu map
// CPU core 0 is run on the main thread
thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
@@ -220,11 +246,10 @@ void System::Shutdown() {
perf_results.frametime * 1000.0);
// Shutdown emulation session
- VideoCore::Shutdown();
+ renderer.reset();
GDBStub::Shutdown();
Service::Shutdown();
Kernel::Shutdown();
- HW::Shutdown();
service_manager.reset();
telemetry_session.reset();
gpu_core.reset();
diff --git a/src/core/core.h b/src/core/core.h
index c123fe401..790e23cae 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -11,26 +11,41 @@
#include "common/common_types.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core_cpu.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/scheduler.h"
#include "core/loader/loader.h"
#include "core/memory.h"
#include "core/perf_stats.h"
#include "core/telemetry_session.h"
+#include "file_sys/vfs_real.h"
+#include "hle/service/filesystem/filesystem.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/gpu.h"
-class EmuWindow;
class ARM_Interface;
+namespace Core::Frontend {
+class EmuWindow;
+}
+
namespace Service::SM {
class ServiceManager;
}
+namespace VideoCore {
+class RendererBase;
+}
+
namespace Core {
class System {
public:
+ System(const System&) = delete;
+ System& operator=(const System&) = delete;
+
+ System(System&&) = delete;
+ System& operator=(System&&) = delete;
+
~System();
/**
@@ -43,19 +58,15 @@ public:
/// Enumeration representing the return values of the System Initialize and Load process.
enum class ResultStatus : u32 {
- Success, ///< Succeeded
- ErrorNotInitialized, ///< Error trying to use core prior to initialization
- ErrorGetLoader, ///< Error finding the correct application loader
- ErrorSystemMode, ///< Error determining the system mode
- ErrorLoader, ///< Error loading the specified application
- ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
- ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
- /// invalid format
- ErrorSystemFiles, ///< Error in finding system files
- ErrorSharedFont, ///< Error in finding shared font
- ErrorVideoCore, ///< Error in the video core
- ErrorUnsupportedArch, ///< Unsupported Architecture (32-Bit ROMs)
- ErrorUnknown ///< Any other error
+ Success, ///< Succeeded
+ ErrorNotInitialized, ///< Error trying to use core prior to initialization
+ ErrorGetLoader, ///< Error finding the correct application loader
+ ErrorSystemMode, ///< Error determining the system mode
+ ErrorSystemFiles, ///< Error in finding system files
+ ErrorSharedFont, ///< Error in finding shared font
+ ErrorVideoCore, ///< Error in the video core
+ ErrorUnknown, ///< Any other error
+ ErrorLoader, ///< The base for loader errors (too many to repeat)
};
/**
@@ -76,16 +87,28 @@ public:
*/
ResultStatus SingleStep();
+ /**
+ * Invalidate the CPU instruction caches
+ * This function should only be used by GDB Stub to support breakpoints, memory updates and
+ * step/continue commands.
+ */
+ void InvalidateCpuInstructionCaches() {
+ for (auto& cpu : cpu_cores) {
+ cpu->ArmInterface().ClearInstructionCache();
+ }
+ }
+
/// Shutdown the emulated system.
void Shutdown();
/**
* Load an executable application.
- * @param emu_window Pointer to the host-system window used for video output and keyboard input.
+ * @param emu_window Reference to the host-system window used for video output and keyboard
+ * input.
* @param filepath String path to the executable application to load on the host file system.
* @returns ResultStatus code, indicating if the operation succeeded.
*/
- ResultStatus Load(EmuWindow* emu_window, const std::string& filepath);
+ ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath);
/**
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
@@ -126,11 +149,26 @@ public:
/// Gets a CPU interface to the CPU core with the specified index
Cpu& CpuCore(size_t core_index);
- /// Gets the GPU interface
+ /// Gets a mutable reference to the GPU interface
Tegra::GPU& GPU() {
return *gpu_core;
}
+ /// Gets an immutable reference to the GPU interface.
+ const Tegra::GPU& GPU() const {
+ return *gpu_core;
+ }
+
+ /// Gets a mutable reference to the renderer.
+ VideoCore::RendererBase& Renderer() {
+ return *renderer;
+ }
+
+ /// Gets an immutable reference to the renderer.
+ const VideoCore::RendererBase& Renderer() const {
+ return *renderer;
+ }
+
/// Gets the scheduler for the CPU core that is currently running
Kernel::Scheduler& CurrentScheduler() {
return *CurrentCpuCore().Scheduler();
@@ -178,6 +216,14 @@ public:
return debug_context;
}
+ void SetFilesystem(FileSys::VirtualFilesystem vfs) {
+ virtual_filesystem = std::move(vfs);
+ }
+
+ FileSys::VirtualFilesystem GetFilesystem() const {
+ return virtual_filesystem;
+ }
+
private:
System();
@@ -186,14 +232,17 @@ private:
/**
* Initialize the emulated system.
- * @param emu_window Pointer to the host-system window used for video output and keyboard input.
- * @param system_mode The system mode.
+ * @param emu_window Reference to the host-system window used for video output and keyboard
+ * input.
* @return ResultStatus code, indicating if the operation succeeded.
*/
- ResultStatus Init(EmuWindow* emu_window, u32 system_mode);
+ ResultStatus Init(Frontend::EmuWindow& emu_window);
+ /// RealVfsFilesystem instance
+ FileSys::VirtualFilesystem virtual_filesystem;
/// AppLoader used to load the current executing application
std::unique_ptr<Loader::AppLoader> app_loader;
+ std::unique_ptr<VideoCore::RendererBase> renderer;
std::unique_ptr<Tegra::GPU> gpu_core;
std::shared_ptr<Tegra::DebugContext> debug_context;
Kernel::SharedPtr<Kernel::Process> current_process;
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 54e15a701..b042ee02b 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -12,9 +12,9 @@
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/lock.h"
#include "core/settings.h"
namespace Core {
@@ -91,6 +91,7 @@ void Cpu::RunLoop(bool tight_loop) {
LOG_TRACE(Core, "Core-{} idling", core_index);
if (IsMainCore()) {
+ // TODO(Subv): Only let CoreTiming idle if all 4 cores are idling.
CoreTiming::Idle();
CoreTiming::Advance();
}
@@ -126,6 +127,8 @@ void Cpu::Reschedule() {
}
reschedule_pending = false;
+ // Lock the global kernel mutex when we manipulate the HLE state
+ std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
scheduler->Reschedule();
}
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index 976952903..56cdae194 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -79,7 +79,7 @@ private:
std::shared_ptr<CpuBarrier> cpu_barrier;
std::shared_ptr<Kernel::Scheduler> scheduler;
- bool reschedule_pending{};
+ std::atomic<bool> reschedule_pending = false;
size_t core_index;
};
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index a1b6f96f1..7953c8720 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -56,6 +56,9 @@ static u64 event_fifo_id;
// to the event_queue by the emu thread
static Common::MPSCQueue<Event, false> ts_queue;
+// the queue for unscheduling the events from other threads threadsafe
+static Common::MPSCQueue<std::pair<const EventType*, u64>, false> unschedule_queue;
+
constexpr int MAX_SLICE_LENGTH = 20000;
static s64 idled_cycles;
@@ -135,13 +138,11 @@ void ClearPendingEvents() {
void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
ASSERT(event_type != nullptr);
s64 timeout = GetTicks() + cycles_into_future;
-
// If this event needs to be scheduled before the next advance(), force one early
if (!is_global_timer_sane)
ForceExceptionCheck(cycles_into_future);
-
event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
- std::push_heap(event_queue.begin(), event_queue.end(), std::greater<Event>());
+ std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
@@ -156,10 +157,14 @@ void UnscheduleEvent(const EventType* event_type, u64 userdata) {
// Removing random items breaks the invariant so we have to re-establish it.
if (itr != event_queue.end()) {
event_queue.erase(itr, event_queue.end());
- std::make_heap(event_queue.begin(), event_queue.end(), std::greater<Event>());
+ std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
}
+void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) {
+ unschedule_queue.Push(std::make_pair(event_type, userdata));
+}
+
void RemoveEvent(const EventType* event_type) {
auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
[&](const Event& e) { return e.type == event_type; });
@@ -167,7 +172,7 @@ void RemoveEvent(const EventType* event_type) {
// Removing random items breaks the invariant so we have to re-establish it.
if (itr != event_queue.end()) {
event_queue.erase(itr, event_queue.end());
- std::make_heap(event_queue.begin(), event_queue.end(), std::greater<Event>());
+ std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
}
@@ -190,12 +195,15 @@ void MoveEvents() {
for (Event ev; ts_queue.Pop(ev);) {
ev.fifo_order = event_fifo_id++;
event_queue.emplace_back(std::move(ev));
- std::push_heap(event_queue.begin(), event_queue.end(), std::greater<Event>());
+ std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
}
void Advance() {
MoveEvents();
+ for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) {
+ UnscheduleEvent(ev.first, ev.second);
+ }
int cycles_executed = slice_length - downcount;
global_timer += cycles_executed;
@@ -205,7 +213,7 @@ void Advance() {
while (!event_queue.empty() && event_queue.front().time <= global_timer) {
Event evt = std::move(event_queue.front());
- std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<Event>());
+ std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
event_queue.pop_back();
evt.type->callback(evt.userdata, static_cast<int>(global_timer - evt.time));
}
@@ -226,8 +234,8 @@ void Idle() {
downcount = 0;
}
-u64 GetGlobalTimeUs() {
- return GetTicks() * 1000000 / BASE_CLOCK_RATE;
+std::chrono::microseconds GetGlobalTimeUs() {
+ return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE};
}
int GetDowncount() {
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 7fe6380ad..9ed757bd7 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -17,12 +17,17 @@
* ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
*/
+#include <chrono>
#include <functional>
#include <string>
#include "common/common_types.h"
namespace CoreTiming {
+struct EventType;
+
+using TimedCallback = std::function<void(u64 userdata, int cycles_late)>;
+
/**
* CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
* required to end slice -1 and start slice 0 before the first cycle of code is executed.
@@ -30,8 +35,6 @@ namespace CoreTiming {
void Init();
void Shutdown();
-typedef std::function<void(u64 userdata, int cycles_late)> TimedCallback;
-
/**
* This should only be called from the emu thread, if you are calling it any other thread, you are
* doing something evil
@@ -40,8 +43,6 @@ u64 GetTicks();
u64 GetIdleTicks();
void AddTicks(u64 ticks);
-struct EventType;
-
/**
* Returns the event_type identifier. if name is not unique, it will assert.
*/
@@ -64,6 +65,7 @@ void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 user
void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata);
void UnscheduleEvent(const EventType* event_type, u64 userdata);
+void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata);
/// We only permit one event of each type in the queue at a time.
void RemoveEvent(const EventType* event_type);
@@ -86,7 +88,7 @@ void ClearPendingEvents();
void ForceExceptionCheck(s64 cycles);
-u64 GetGlobalTimeUs();
+std::chrono::microseconds GetGlobalTimeUs();
int GetDowncount();
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp
new file mode 100644
index 000000000..a9876c83e
--- /dev/null
+++ b/src/core/crypto/aes_util.cpp
@@ -0,0 +1,115 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <mbedtls/cipher.h>
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/crypto/aes_util.h"
+#include "core/crypto/key_manager.h"
+
+namespace Core::Crypto {
+namespace {
+std::vector<u8> CalculateNintendoTweak(size_t sector_id) {
+ std::vector<u8> out(0x10);
+ for (size_t i = 0xF; i <= 0xF; --i) {
+ out[i] = sector_id & 0xFF;
+ sector_id >>= 8;
+ }
+ return out;
+}
+} // Anonymous namespace
+
+static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR),
+ "CTR has incorrect value.");
+static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB),
+ "ECB has incorrect value.");
+static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS),
+ "XTS has incorrect value.");
+
+// Structure to hide mbedtls types from header file
+struct CipherContext {
+ mbedtls_cipher_context_t encryption_context;
+ mbedtls_cipher_context_t decryption_context;
+};
+
+template <typename Key, size_t KeySize>
+Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
+ : ctx(std::make_unique<CipherContext>()) {
+ mbedtls_cipher_init(&ctx->encryption_context);
+ mbedtls_cipher_init(&ctx->decryption_context);
+
+ ASSERT_MSG((mbedtls_cipher_setup(
+ &ctx->encryption_context,
+ mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) ||
+ mbedtls_cipher_setup(
+ &ctx->decryption_context,
+ mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode)))) == 0,
+ "Failed to initialize mbedtls ciphers.");
+
+ ASSERT(
+ !mbedtls_cipher_setkey(&ctx->encryption_context, key.data(), KeySize * 8, MBEDTLS_ENCRYPT));
+ ASSERT(
+ !mbedtls_cipher_setkey(&ctx->decryption_context, key.data(), KeySize * 8, MBEDTLS_DECRYPT));
+ //"Failed to set key on mbedtls ciphers.");
+}
+
+template <typename Key, size_t KeySize>
+AESCipher<Key, KeySize>::~AESCipher() {
+ mbedtls_cipher_free(&ctx->encryption_context);
+ mbedtls_cipher_free(&ctx->decryption_context);
+}
+
+template <typename Key, size_t KeySize>
+void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
+ ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
+ mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
+ "Failed to set IV on mbedtls ciphers.");
+}
+
+template <typename Key, size_t KeySize>
+void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) const {
+ auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
+
+ mbedtls_cipher_reset(context);
+
+ size_t written = 0;
+ if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) {
+ mbedtls_cipher_update(context, src, size, dest, &written);
+ if (written != size) {
+ LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
+ size, written);
+ }
+ } else {
+ const auto block_size = mbedtls_cipher_get_block_size(context);
+
+ for (size_t offset = 0; offset < size; offset += block_size) {
+ auto length = std::min<size_t>(block_size, size - offset);
+ mbedtls_cipher_update(context, src + offset, length, dest + offset, &written);
+ if (written != length) {
+ LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
+ length, written);
+ }
+ }
+ }
+
+ mbedtls_cipher_finish(context, nullptr, nullptr);
+}
+
+template <typename Key, size_t KeySize>
+void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id,
+ size_t sector_size, Op op) {
+ if (size % sector_size > 0) {
+ LOG_CRITICAL(Crypto, "Data size must be a multiple of sector size.");
+ return;
+ }
+
+ for (size_t i = 0; i < size; i += sector_size) {
+ SetIV(CalculateNintendoTweak(sector_id++));
+ Transcode<u8, u8>(src + i, sector_size, dest + i, op);
+ }
+}
+
+template class AESCipher<Key128>;
+template class AESCipher<Key256>;
+} // namespace Core::Crypto \ No newline at end of file
diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h
new file mode 100644
index 000000000..8ce9d6612
--- /dev/null
+++ b/src/core/crypto/aes_util.h
@@ -0,0 +1,64 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <type_traits>
+#include <vector>
+#include "common/common_types.h"
+#include "core/file_sys/vfs.h"
+
+namespace Core::Crypto {
+
+struct CipherContext;
+
+enum class Mode {
+ CTR = 11,
+ ECB = 2,
+ XTS = 70,
+};
+
+enum class Op {
+ Encrypt,
+ Decrypt,
+};
+
+template <typename Key, size_t KeySize = sizeof(Key)>
+class AESCipher {
+ static_assert(std::is_same_v<Key, std::array<u8, KeySize>>, "Key must be std::array of u8.");
+ static_assert(KeySize == 0x10 || KeySize == 0x20, "KeySize must be 128 or 256.");
+
+public:
+ AESCipher(Key key, Mode mode);
+
+ ~AESCipher();
+
+ void SetIV(std::vector<u8> iv);
+
+ template <typename Source, typename Dest>
+ void Transcode(const Source* src, size_t size, Dest* dest, Op op) const {
+ static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>,
+ "Transcode source and destination types must be trivially copyable.");
+ Transcode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), op);
+ }
+
+ void Transcode(const u8* src, size_t size, u8* dest, Op op) const;
+
+ template <typename Source, typename Dest>
+ void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id,
+ size_t sector_size, Op op) {
+ static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>,
+ "XTSTranscode source and destination types must be trivially copyable.");
+ XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id,
+ sector_size, op);
+ }
+
+ void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size,
+ Op op);
+
+private:
+ std::unique_ptr<CipherContext> ctx;
+};
+} // namespace Core::Crypto
diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp
new file mode 100644
index 000000000..106db02b3
--- /dev/null
+++ b/src/core/crypto/ctr_encryption_layer.cpp
@@ -0,0 +1,56 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cstring>
+#include "common/assert.h"
+#include "core/crypto/ctr_encryption_layer.h"
+
+namespace Core::Crypto {
+
+CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset)
+ : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
+ iv(16, 0) {}
+
+size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const {
+ if (length == 0)
+ return 0;
+
+ const auto sector_offset = offset & 0xF;
+ if (sector_offset == 0) {
+ UpdateIV(base_offset + offset);
+ std::vector<u8> raw = base->ReadBytes(length, offset);
+ if (raw.size() != length)
+ return Read(data, raw.size(), offset);
+ cipher.Transcode(raw.data(), length, data, Op::Decrypt);
+ return length;
+ }
+
+ // offset does not fall on block boundary (0x10)
+ std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset);
+ UpdateIV(base_offset + offset - sector_offset);
+ cipher.Transcode(block.data(), block.size(), block.data(), Op::Decrypt);
+ size_t read = 0x10 - sector_offset;
+
+ if (length + sector_offset < 0x10) {
+ std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read));
+ return read;
+ }
+ std::memcpy(data, block.data() + sector_offset, read);
+ return read + Read(data + read, length - read, offset + read);
+}
+
+void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) {
+ const auto length = std::min(iv_.size(), iv.size());
+ iv.assign(iv_.cbegin(), iv_.cbegin() + length);
+}
+
+void CTREncryptionLayer::UpdateIV(size_t offset) const {
+ offset >>= 4;
+ for (size_t i = 0; i < 8; ++i) {
+ iv[16 - i - 1] = offset & 0xFF;
+ offset >>= 8;
+ }
+ cipher.SetIV(iv);
+}
+} // namespace Core::Crypto
diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h
new file mode 100644
index 000000000..11b8683c7
--- /dev/null
+++ b/src/core/crypto/ctr_encryption_layer.h
@@ -0,0 +1,33 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include "core/crypto/aes_util.h"
+#include "core/crypto/encryption_layer.h"
+#include "core/crypto/key_manager.h"
+
+namespace Core::Crypto {
+
+// Sits on top of a VirtualFile and provides CTR-mode AES decription.
+class CTREncryptionLayer : public EncryptionLayer {
+public:
+ CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset);
+
+ size_t Read(u8* data, size_t length, size_t offset) const override;
+
+ void SetIV(const std::vector<u8>& iv);
+
+private:
+ size_t base_offset;
+
+ // Must be mutable as operations modify cipher contexts.
+ mutable AESCipher<Key128> cipher;
+ mutable std::vector<u8> iv;
+
+ void UpdateIV(size_t offset) const;
+};
+
+} // namespace Core::Crypto
diff --git a/src/core/crypto/encryption_layer.cpp b/src/core/crypto/encryption_layer.cpp
new file mode 100644
index 000000000..4204527e3
--- /dev/null
+++ b/src/core/crypto/encryption_layer.cpp
@@ -0,0 +1,42 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/crypto/encryption_layer.h"
+
+namespace Core::Crypto {
+
+EncryptionLayer::EncryptionLayer(FileSys::VirtualFile base_) : base(std::move(base_)) {}
+
+std::string EncryptionLayer::GetName() const {
+ return base->GetName();
+}
+
+size_t EncryptionLayer::GetSize() const {
+ return base->GetSize();
+}
+
+bool EncryptionLayer::Resize(size_t new_size) {
+ return false;
+}
+
+std::shared_ptr<FileSys::VfsDirectory> EncryptionLayer::GetContainingDirectory() const {
+ return base->GetContainingDirectory();
+}
+
+bool EncryptionLayer::IsWritable() const {
+ return false;
+}
+
+bool EncryptionLayer::IsReadable() const {
+ return true;
+}
+
+size_t EncryptionLayer::Write(const u8* data, size_t length, size_t offset) {
+ return 0;
+}
+
+bool EncryptionLayer::Rename(std::string_view name) {
+ return base->Rename(name);
+}
+} // namespace Core::Crypto
diff --git a/src/core/crypto/encryption_layer.h b/src/core/crypto/encryption_layer.h
new file mode 100644
index 000000000..7f05af9b4
--- /dev/null
+++ b/src/core/crypto/encryption_layer.h
@@ -0,0 +1,33 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/file_sys/vfs.h"
+
+namespace Core::Crypto {
+
+// Basically non-functional class that implements all of the methods that are irrelevant to an
+// EncryptionLayer. Reduces duplicate code.
+class EncryptionLayer : public FileSys::VfsFile {
+public:
+ explicit EncryptionLayer(FileSys::VirtualFile base);
+
+ size_t Read(u8* data, size_t length, size_t offset) const override = 0;
+
+ std::string GetName() const override;
+ size_t GetSize() const override;
+ bool Resize(size_t new_size) override;
+ std::shared_ptr<FileSys::VfsDirectory> GetContainingDirectory() const override;
+ bool IsWritable() const override;
+ bool IsReadable() const override;
+ size_t Write(const u8* data, size_t length, size_t offset) override;
+ bool Rename(std::string_view name) override;
+
+protected:
+ FileSys::VirtualFile base;
+};
+
+} // namespace Core::Crypto
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
new file mode 100644
index 000000000..db8b22c85
--- /dev/null
+++ b/src/core/crypto/key_manager.cpp
@@ -0,0 +1,177 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <array>
+#include <fstream>
+#include <locale>
+#include <sstream>
+#include <string_view>
+#include "common/common_paths.h"
+#include "common/file_util.h"
+#include "common/hex_util.h"
+#include "common/logging/log.h"
+#include "core/crypto/key_manager.h"
+#include "core/settings.h"
+
+namespace Core::Crypto {
+
+KeyManager::KeyManager() {
+ // Initialize keys
+ const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath();
+ const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
+ if (Settings::values.use_dev_keys) {
+ dev_mode = true;
+ AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false);
+ } else {
+ dev_mode = false;
+ AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "prod.keys", false);
+ }
+
+ AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "title.keys", true);
+}
+
+void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
+ std::ifstream file(filename);
+ if (!file.is_open())
+ return;
+
+ std::string line;
+ while (std::getline(file, line)) {
+ std::vector<std::string> out;
+ std::stringstream stream(line);
+ std::string item;
+ while (std::getline(stream, item, '='))
+ out.push_back(std::move(item));
+
+ if (out.size() != 2)
+ continue;
+
+ out[0].erase(std::remove(out[0].begin(), out[0].end(), ' '), out[0].end());
+ out[1].erase(std::remove(out[1].begin(), out[1].end(), ' '), out[1].end());
+
+ if (is_title_keys) {
+ auto rights_id_raw = Common::HexStringToArray<16>(out[0]);
+ u128 rights_id{};
+ std::memcpy(rights_id.data(), rights_id_raw.data(), rights_id_raw.size());
+ Key128 key = Common::HexStringToArray<16>(out[1]);
+ SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
+ } else {
+ std::transform(out[0].begin(), out[0].end(), out[0].begin(), ::tolower);
+ if (s128_file_id.find(out[0]) != s128_file_id.end()) {
+ const auto index = s128_file_id.at(out[0]);
+ Key128 key = Common::HexStringToArray<16>(out[1]);
+ SetKey(index.type, key, index.field1, index.field2);
+ } else if (s256_file_id.find(out[0]) != s256_file_id.end()) {
+ const auto index = s256_file_id.at(out[0]);
+ Key256 key = Common::HexStringToArray<32>(out[1]);
+ SetKey(index.type, key, index.field1, index.field2);
+ }
+ }
+ }
+}
+
+void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
+ const std::string& filename, bool title) {
+ if (FileUtil::Exists(dir1 + DIR_SEP + filename))
+ LoadFromFile(dir1 + DIR_SEP + filename, title);
+ else if (FileUtil::Exists(dir2 + DIR_SEP + filename))
+ LoadFromFile(dir2 + DIR_SEP + filename, title);
+}
+
+bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) const {
+ return s128_keys.find({id, field1, field2}) != s128_keys.end();
+}
+
+bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) const {
+ return s256_keys.find({id, field1, field2}) != s256_keys.end();
+}
+
+Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) const {
+ if (!HasKey(id, field1, field2))
+ return {};
+ return s128_keys.at({id, field1, field2});
+}
+
+Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const {
+ if (!HasKey(id, field1, field2))
+ return {};
+ return s256_keys.at({id, field1, field2});
+}
+
+void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
+ s128_keys[{id, field1, field2}] = key;
+}
+
+void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
+ s256_keys[{id, field1, field2}] = key;
+}
+
+bool KeyManager::KeyFileExists(bool title) {
+ const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath();
+ const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
+ if (title) {
+ return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "title.keys") ||
+ FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "title.keys");
+ }
+
+ if (Settings::values.use_dev_keys) {
+ return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") ||
+ FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys");
+ }
+
+ return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") ||
+ FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys");
+}
+
+const std::unordered_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
+ {"master_key_00", {S128KeyType::Master, 0, 0}},
+ {"master_key_01", {S128KeyType::Master, 1, 0}},
+ {"master_key_02", {S128KeyType::Master, 2, 0}},
+ {"master_key_03", {S128KeyType::Master, 3, 0}},
+ {"master_key_04", {S128KeyType::Master, 4, 0}},
+ {"package1_key_00", {S128KeyType::Package1, 0, 0}},
+ {"package1_key_01", {S128KeyType::Package1, 1, 0}},
+ {"package1_key_02", {S128KeyType::Package1, 2, 0}},
+ {"package1_key_03", {S128KeyType::Package1, 3, 0}},
+ {"package1_key_04", {S128KeyType::Package1, 4, 0}},
+ {"package2_key_00", {S128KeyType::Package2, 0, 0}},
+ {"package2_key_01", {S128KeyType::Package2, 1, 0}},
+ {"package2_key_02", {S128KeyType::Package2, 2, 0}},
+ {"package2_key_03", {S128KeyType::Package2, 3, 0}},
+ {"package2_key_04", {S128KeyType::Package2, 4, 0}},
+ {"titlekek_00", {S128KeyType::Titlekek, 0, 0}},
+ {"titlekek_01", {S128KeyType::Titlekek, 1, 0}},
+ {"titlekek_02", {S128KeyType::Titlekek, 2, 0}},
+ {"titlekek_03", {S128KeyType::Titlekek, 3, 0}},
+ {"titlekek_04", {S128KeyType::Titlekek, 4, 0}},
+ {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
+ {"key_area_key_application_00",
+ {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Application)}},
+ {"key_area_key_application_01",
+ {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Application)}},
+ {"key_area_key_application_02",
+ {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Application)}},
+ {"key_area_key_application_03",
+ {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Application)}},
+ {"key_area_key_application_04",
+ {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Application)}},
+ {"key_area_key_ocean_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Ocean)}},
+ {"key_area_key_ocean_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Ocean)}},
+ {"key_area_key_ocean_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Ocean)}},
+ {"key_area_key_ocean_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Ocean)}},
+ {"key_area_key_ocean_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Ocean)}},
+ {"key_area_key_system_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::System)}},
+ {"key_area_key_system_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::System)}},
+ {"key_area_key_system_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::System)}},
+ {"key_area_key_system_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::System)}},
+ {"key_area_key_system_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::System)}},
+};
+
+const std::unordered_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = {
+ {"header_key", {S256KeyType::Header, 0, 0}},
+ {"sd_card_save_key", {S256KeyType::SDSave, 0, 0}},
+ {"sd_card_nca_key", {S256KeyType::SDNCA, 0, 0}},
+};
+} // namespace Core::Crypto
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
new file mode 100644
index 000000000..0c62d4421
--- /dev/null
+++ b/src/core/crypto/key_manager.h
@@ -0,0 +1,117 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <vector>
+#include <fmt/format.h>
+#include "common/common_types.h"
+
+namespace Core::Crypto {
+
+using Key128 = std::array<u8, 0x10>;
+using Key256 = std::array<u8, 0x20>;
+using SHA256Hash = std::array<u8, 0x20>;
+
+static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big.");
+static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big.");
+
+enum class S256KeyType : u64 {
+ Header, //
+ SDSave, //
+ SDNCA, //
+};
+
+enum class S128KeyType : u64 {
+ Master, // f1=crypto revision
+ Package1, // f1=crypto revision
+ Package2, // f1=crypto revision
+ Titlekek, // f1=crypto revision
+ ETicketRSAKek, //
+ KeyArea, // f1=crypto revision f2=type {app, ocean, system}
+ SDSeed, //
+ Titlekey, // f1=rights id LSB f2=rights id MSB
+};
+
+enum class KeyAreaKeyType : u8 {
+ Application,
+ Ocean,
+ System,
+};
+
+template <typename KeyType>
+struct KeyIndex {
+ KeyType type;
+ u64 field1;
+ u64 field2;
+
+ std::string DebugInfo() const {
+ u8 key_size = 16;
+ if constexpr (std::is_same_v<KeyType, S256KeyType>)
+ key_size = 32;
+ return fmt::format("key_size={:02X}, key={:02X}, field1={:016X}, field2={:016X}", key_size,
+ static_cast<u8>(type), field1, field2);
+ }
+};
+
+// The following two (== and hash) are so KeyIndex can be a key in unordered_map
+
+template <typename KeyType>
+bool operator==(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) {
+ return std::tie(lhs.type, lhs.field1, lhs.field2) == std::tie(rhs.type, rhs.field1, rhs.field2);
+}
+
+template <typename KeyType>
+bool operator!=(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) {
+ return !operator==(lhs, rhs);
+}
+
+} // namespace Core::Crypto
+
+namespace std {
+template <typename KeyType>
+struct hash<Core::Crypto::KeyIndex<KeyType>> {
+ size_t operator()(const Core::Crypto::KeyIndex<KeyType>& k) const {
+ using std::hash;
+
+ return ((hash<u64>()(static_cast<u64>(k.type)) ^ (hash<u64>()(k.field1) << 1)) >> 1) ^
+ (hash<u64>()(k.field2) << 1);
+ }
+};
+} // namespace std
+
+namespace Core::Crypto {
+
+class KeyManager {
+public:
+ KeyManager();
+
+ bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const;
+ bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const;
+
+ Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const;
+ Key256 GetKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const;
+
+ void SetKey(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
+ void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
+
+ static bool KeyFileExists(bool title);
+
+private:
+ std::unordered_map<KeyIndex<S128KeyType>, Key128> s128_keys;
+ std::unordered_map<KeyIndex<S256KeyType>, Key256> s256_keys;
+
+ bool dev_mode;
+ void LoadFromFile(const std::string& filename, bool is_title_keys);
+ void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
+ const std::string& filename, bool title);
+
+ static const std::unordered_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
+ static const std::unordered_map<std::string, KeyIndex<S256KeyType>> s256_file_id;
+};
+} // namespace Core::Crypto
diff --git a/src/core/crypto/sha_util.cpp b/src/core/crypto/sha_util.cpp
new file mode 100644
index 000000000..180008a85
--- /dev/null
+++ b/src/core/crypto/sha_util.cpp
@@ -0,0 +1,5 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+namespace Crypto {} // namespace Crypto
diff --git a/src/core/crypto/sha_util.h b/src/core/crypto/sha_util.h
new file mode 100644
index 000000000..fa3fa9d33
--- /dev/null
+++ b/src/core/crypto/sha_util.h
@@ -0,0 +1,20 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/assert.h"
+#include "core/file_sys/vfs.h"
+#include "key_manager.h"
+#include "mbedtls/cipher.h"
+
+namespace Crypto {
+typedef std::array<u8, 0x20> SHA256Hash;
+
+inline SHA256Hash operator"" _HASH(const char* data, size_t len) {
+ if (len != 0x40)
+ return {};
+}
+
+} // namespace Crypto
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
new file mode 100644
index 000000000..ae4e33800
--- /dev/null
+++ b/src/core/file_sys/bis_factory.cpp
@@ -0,0 +1,31 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/file_sys/bis_factory.h"
+
+namespace FileSys {
+
+static VirtualDir GetOrCreateDirectory(const VirtualDir& dir, std::string_view path) {
+ const auto res = dir->GetDirectoryRelative(path);
+ if (res == nullptr)
+ return dir->CreateDirectoryRelative(path);
+ return res;
+}
+
+BISFactory::BISFactory(VirtualDir nand_root_)
+ : nand_root(std::move(nand_root_)),
+ sysnand_cache(std::make_shared<RegisteredCache>(
+ GetOrCreateDirectory(nand_root, "/system/Contents/registered"))),
+ usrnand_cache(std::make_shared<RegisteredCache>(
+ GetOrCreateDirectory(nand_root, "/user/Contents/registered"))) {}
+
+std::shared_ptr<RegisteredCache> BISFactory::GetSystemNANDContents() const {
+ return sysnand_cache;
+}
+
+std::shared_ptr<RegisteredCache> BISFactory::GetUserNANDContents() const {
+ return usrnand_cache;
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
new file mode 100644
index 000000000..a970a5e2e
--- /dev/null
+++ b/src/core/file_sys/bis_factory.h
@@ -0,0 +1,30 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include "core/loader/loader.h"
+#include "registered_cache.h"
+
+namespace FileSys {
+
+/// File system interface to the Built-In Storage
+/// This is currently missing accessors to BIS partitions, but seemed like a good place for the NAND
+/// registered caches.
+class BISFactory {
+public:
+ explicit BISFactory(VirtualDir nand_root);
+
+ std::shared_ptr<RegisteredCache> GetSystemNANDContents() const;
+ std::shared_ptr<RegisteredCache> GetUserNANDContents() const;
+
+private:
+ VirtualDir nand_root;
+
+ std::shared_ptr<RegisteredCache> sysnand_cache;
+ std::shared_ptr<RegisteredCache> usrnand_cache;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
new file mode 100644
index 000000000..1d7c7fb10
--- /dev/null
+++ b/src/core/file_sys/card_image.cpp
@@ -0,0 +1,162 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <array>
+#include <string>
+
+#include <fmt/ostream.h>
+
+#include "common/logging/log.h"
+#include "core/file_sys/card_image.h"
+#include "core/file_sys/partition_filesystem.h"
+#include "core/file_sys/vfs_offset.h"
+#include "core/loader/loader.h"
+
+namespace FileSys {
+
+constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure", "logo"};
+
+XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
+ if (file->ReadObject(&header) != sizeof(GamecardHeader)) {
+ status = Loader::ResultStatus::ErrorBadXCIHeader;
+ return;
+ }
+
+ if (header.magic != Common::MakeMagic('H', 'E', 'A', 'D')) {
+ status = Loader::ResultStatus::ErrorBadXCIHeader;
+ return;
+ }
+
+ PartitionFilesystem main_hfs(
+ std::make_shared<OffsetVfsFile>(file, header.hfs_size, header.hfs_offset));
+
+ if (main_hfs.GetStatus() != Loader::ResultStatus::Success) {
+ status = main_hfs.GetStatus();
+ return;
+ }
+
+ for (XCIPartition partition :
+ {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) {
+ auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]);
+ if (raw != nullptr)
+ partitions[static_cast<size_t>(partition)] = std::make_shared<PartitionFilesystem>(raw);
+ }
+
+ auto result = AddNCAFromPartition(XCIPartition::Secure);
+ if (result != Loader::ResultStatus::Success) {
+ status = result;
+ return;
+ }
+
+ result = AddNCAFromPartition(XCIPartition::Update);
+ if (result != Loader::ResultStatus::Success) {
+ status = result;
+ return;
+ }
+
+ result = AddNCAFromPartition(XCIPartition::Normal);
+ if (result != Loader::ResultStatus::Success) {
+ status = result;
+ return;
+ }
+
+ if (GetFormatVersion() >= 0x2) {
+ result = AddNCAFromPartition(XCIPartition::Logo);
+ if (result != Loader::ResultStatus::Success) {
+ status = result;
+ return;
+ }
+ }
+
+ status = Loader::ResultStatus::Success;
+}
+
+Loader::ResultStatus XCI::GetStatus() const {
+ return status;
+}
+
+VirtualDir XCI::GetPartition(XCIPartition partition) const {
+ return partitions[static_cast<size_t>(partition)];
+}
+
+VirtualDir XCI::GetSecurePartition() const {
+ return GetPartition(XCIPartition::Secure);
+}
+
+VirtualDir XCI::GetNormalPartition() const {
+ return GetPartition(XCIPartition::Normal);
+}
+
+VirtualDir XCI::GetUpdatePartition() const {
+ return GetPartition(XCIPartition::Update);
+}
+
+VirtualDir XCI::GetLogoPartition() const {
+ return GetPartition(XCIPartition::Logo);
+}
+
+const std::vector<std::shared_ptr<NCA>>& XCI::GetNCAs() const {
+ return ncas;
+}
+
+std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const {
+ const auto iter =
+ std::find_if(ncas.begin(), ncas.end(),
+ [type](const std::shared_ptr<NCA>& nca) { return nca->GetType() == type; });
+ return iter == ncas.end() ? nullptr : *iter;
+}
+
+VirtualFile XCI::GetNCAFileByType(NCAContentType type) const {
+ auto nca = GetNCAByType(type);
+ if (nca != nullptr)
+ return nca->GetBaseFile();
+ return nullptr;
+}
+
+std::vector<VirtualFile> XCI::GetFiles() const {
+ return {};
+}
+
+std::vector<VirtualDir> XCI::GetSubdirectories() const {
+ return {};
+}
+
+std::string XCI::GetName() const {
+ return file->GetName();
+}
+
+VirtualDir XCI::GetParentDirectory() const {
+ return file->GetContainingDirectory();
+}
+
+bool XCI::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
+ return false;
+}
+
+Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
+ if (partitions[static_cast<size_t>(part)] == nullptr) {
+ return Loader::ResultStatus::ErrorXCIMissingPartition;
+ }
+
+ for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) {
+ if (file->GetExtension() != "nca")
+ continue;
+ auto nca = std::make_shared<NCA>(file);
+ if (nca->GetStatus() == Loader::ResultStatus::Success) {
+ ncas.push_back(std::move(nca));
+ } else {
+ const u16 error_id = static_cast<u16>(nca->GetStatus());
+ LOG_CRITICAL(Loader, "Could not load NCA {}/{}, failed with error code {:04X} ({})",
+ partition_names[static_cast<size_t>(part)], nca->GetName(), error_id,
+ nca->GetStatus());
+ }
+ }
+
+ return Loader::ResultStatus::Success;
+}
+
+u8 XCI::GetFormatVersion() const {
+ return GetLogoPartition() == nullptr ? 0x1 : 0x2;
+}
+} // namespace FileSys
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
new file mode 100644
index 000000000..a03d5264e
--- /dev/null
+++ b/src/core/file_sys/card_image.h
@@ -0,0 +1,97 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <vector>
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/file_sys/content_archive.h"
+#include "core/file_sys/vfs.h"
+#include "core/loader/loader.h"
+
+namespace FileSys {
+
+enum class GamecardSize : u8 {
+ S_1GB = 0xFA,
+ S_2GB = 0xF8,
+ S_4GB = 0xF0,
+ S_8GB = 0xE0,
+ S_16GB = 0xE1,
+ S_32GB = 0xE2,
+};
+
+struct GamecardInfo {
+ std::array<u8, 0x70> data;
+};
+static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size.");
+
+struct GamecardHeader {
+ std::array<u8, 0x100> signature;
+ u32_le magic;
+ u32_le secure_area_start;
+ u32_le backup_area_start;
+ u8 kek_index;
+ GamecardSize size;
+ u8 header_version;
+ u8 flags;
+ u64_le package_id;
+ u64_le valid_data_end;
+ u128 info_iv;
+ u64_le hfs_offset;
+ u64_le hfs_size;
+ std::array<u8, 0x20> hfs_header_hash;
+ std::array<u8, 0x20> initial_data_hash;
+ u32_le secure_mode_flag;
+ u32_le title_key_flag;
+ u32_le key_flag;
+ u32_le normal_area_end;
+ GamecardInfo info;
+};
+static_assert(sizeof(GamecardHeader) == 0x200, "GamecardHeader has incorrect size.");
+
+enum class XCIPartition : u8 { Update, Normal, Secure, Logo };
+
+class XCI : public ReadOnlyVfsDirectory {
+public:
+ explicit XCI(VirtualFile file);
+
+ Loader::ResultStatus GetStatus() const;
+
+ u8 GetFormatVersion() const;
+
+ VirtualDir GetPartition(XCIPartition partition) const;
+ VirtualDir GetSecurePartition() const;
+ VirtualDir GetNormalPartition() const;
+ VirtualDir GetUpdatePartition() const;
+ VirtualDir GetLogoPartition() const;
+
+ const std::vector<std::shared_ptr<NCA>>& GetNCAs() const;
+ std::shared_ptr<NCA> GetNCAByType(NCAContentType type) const;
+ VirtualFile GetNCAFileByType(NCAContentType type) const;
+
+ std::vector<VirtualFile> GetFiles() const override;
+
+ std::vector<VirtualDir> GetSubdirectories() const override;
+
+ std::string GetName() const override;
+
+ VirtualDir GetParentDirectory() const override;
+
+protected:
+ bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
+
+private:
+ Loader::ResultStatus AddNCAFromPartition(XCIPartition part);
+
+ VirtualFile file;
+ GamecardHeader header{};
+
+ Loader::ResultStatus status;
+
+ std::vector<VirtualDir> partitions;
+ std::vector<std::shared_ptr<NCA>> ncas;
+};
+} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index d6b20c047..47afcad9b 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -4,9 +4,12 @@
#include <algorithm>
#include <utility>
-
+#include <boost/optional.hpp>
#include "common/logging/log.h"
+#include "core/crypto/aes_util.h"
+#include "core/crypto/ctr_encryption_layer.h"
#include "core/file_sys/content_archive.h"
+#include "core/file_sys/romfs.h"
#include "core/file_sys/vfs_offset.h"
#include "core/loader/loader.h"
@@ -28,11 +31,19 @@ enum class NCASectionFilesystemType : u8 {
struct NCASectionHeaderBlock {
INSERT_PADDING_BYTES(3);
NCASectionFilesystemType filesystem_type;
- u8 crypto_type;
+ NCASectionCryptoType crypto_type;
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size.");
+struct NCASectionRaw {
+ NCASectionHeaderBlock header;
+ std::array<u8, 0x138> block_data;
+ std::array<u8, 0x8> section_ctr;
+ INSERT_PADDING_BYTES(0xB8);
+};
+static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size.");
+
struct PFS0Superblock {
NCASectionHeaderBlock header_block;
std::array<u8, 0x20> hash;
@@ -42,79 +53,258 @@ struct PFS0Superblock {
u64_le hash_table_size;
u64_le pfs0_header_offset;
u64_le pfs0_size;
- INSERT_PADDING_BYTES(432);
+ INSERT_PADDING_BYTES(0x1B0);
};
static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size.");
-struct IVFCLevel {
- u64_le offset;
- u64_le size;
- u32_le block_size;
- u32_le reserved;
-};
-static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size.");
-
struct RomFSSuperblock {
NCASectionHeaderBlock header_block;
- u32_le magic;
- u32_le magic_number;
- INSERT_PADDING_BYTES(8);
- std::array<IVFCLevel, 6> levels;
- INSERT_PADDING_BYTES(64);
+ IVFCHeader ivfc;
+ INSERT_PADDING_BYTES(0x118);
+};
+static_assert(sizeof(RomFSSuperblock) == 0x200, "RomFSSuperblock has incorrect size.");
+
+union NCASectionHeader {
+ NCASectionRaw raw;
+ PFS0Superblock pfs0;
+ RomFSSuperblock romfs;
};
-static_assert(sizeof(RomFSSuperblock) == 0xE8, "RomFSSuperblock has incorrect size.");
+static_assert(sizeof(NCASectionHeader) == 0x200, "NCASectionHeader has incorrect size.");
+
+bool IsValidNCA(const NCAHeader& header) {
+ // TODO(DarkLordZach): Add NCA2/NCA0 support.
+ return header.magic == Common::MakeMagic('N', 'C', 'A', '3');
+}
+
+u8 NCA::GetCryptoRevision() const {
+ u8 master_key_id = header.crypto_type;
+ if (header.crypto_type_2 > master_key_id)
+ master_key_id = header.crypto_type_2;
+ if (master_key_id > 0)
+ --master_key_id;
+ return master_key_id;
+}
+
+boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const {
+ const auto master_key_id = GetCryptoRevision();
+
+ if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index))
+ return boost::none;
+
+ std::vector<u8> key_area(header.key_area.begin(), header.key_area.end());
+ Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
+ keys.GetKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index),
+ Core::Crypto::Mode::ECB);
+ cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt);
+
+ Core::Crypto::Key128 out;
+ if (type == NCASectionCryptoType::XTS)
+ std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin());
+ else if (type == NCASectionCryptoType::CTR)
+ std::copy(key_area.begin() + 0x20, key_area.begin() + 0x30, out.begin());
+ else
+ LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}",
+ static_cast<u8>(type));
+ u128 out_128{};
+ memcpy(out_128.data(), out.data(), 16);
+ LOG_DEBUG(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}",
+ master_key_id, header.key_index, out_128[1], out_128[0]);
+
+ return out;
+}
+
+boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
+ const auto master_key_id = GetCryptoRevision();
+
+ u128 rights_id{};
+ memcpy(rights_id.data(), header.rights_id.data(), 16);
+ if (rights_id == u128{}) {
+ status = Loader::ResultStatus::ErrorInvalidRightsID;
+ return boost::none;
+ }
+
+ auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
+ if (titlekey == Core::Crypto::Key128{}) {
+ status = Loader::ResultStatus::ErrorMissingTitlekey;
+ return boost::none;
+ }
+
+ if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
+ status = Loader::ResultStatus::ErrorMissingTitlekek;
+ return boost::none;
+ }
+
+ Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
+ keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id), Core::Crypto::Mode::ECB);
+ cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(), Core::Crypto::Op::Decrypt);
+
+ return titlekey;
+}
+
+VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting_offset) {
+ if (!encrypted)
+ return in;
+
+ switch (s_header.raw.header.crypto_type) {
+ case NCASectionCryptoType::NONE:
+ LOG_DEBUG(Crypto, "called with mode=NONE");
+ return in;
+ case NCASectionCryptoType::CTR:
+ LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
+ {
+ boost::optional<Core::Crypto::Key128> key = boost::none;
+ if (has_rights_id) {
+ status = Loader::ResultStatus::Success;
+ key = GetTitlekey();
+ if (key == boost::none) {
+ if (status == Loader::ResultStatus::Success)
+ status = Loader::ResultStatus::ErrorMissingTitlekey;
+ return nullptr;
+ }
+ } else {
+ key = GetKeyAreaKey(NCASectionCryptoType::CTR);
+ if (key == boost::none) {
+ status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
+ return nullptr;
+ }
+ }
+
+ auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(
+ std::move(in), key.value(), starting_offset);
+ std::vector<u8> iv(16);
+ for (u8 i = 0; i < 8; ++i)
+ iv[i] = s_header.raw.section_ctr[0x8 - i - 1];
+ out->SetIV(iv);
+ return std::static_pointer_cast<VfsFile>(out);
+ }
+ case NCASectionCryptoType::XTS:
+ // TODO(DarkLordZach): Implement XTSEncryptionLayer.
+ default:
+ LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}",
+ static_cast<u8>(s_header.raw.header.crypto_type));
+ return nullptr;
+ }
+}
NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
- if (sizeof(NCAHeader) != file->ReadObject(&header))
- LOG_CRITICAL(Loader, "File reader errored out during header read.");
+ status = Loader::ResultStatus::Success;
- if (!IsValidNCA(header)) {
- status = Loader::ResultStatus::ErrorInvalidFormat;
+ if (file == nullptr) {
+ status = Loader::ResultStatus::ErrorNullFile;
return;
}
- std::ptrdiff_t number_sections =
+ if (sizeof(NCAHeader) != file->ReadObject(&header)) {
+ LOG_ERROR(Loader, "File reader errored out during header read.");
+ status = Loader::ResultStatus::ErrorBadNCAHeader;
+ return;
+ }
+
+ encrypted = false;
+
+ if (!IsValidNCA(header)) {
+ if (header.magic == Common::MakeMagic('N', 'C', 'A', '2')) {
+ status = Loader::ResultStatus::ErrorNCA2;
+ return;
+ }
+ if (header.magic == Common::MakeMagic('N', 'C', 'A', '0')) {
+ status = Loader::ResultStatus::ErrorNCA0;
+ return;
+ }
+
+ NCAHeader dec_header{};
+ Core::Crypto::AESCipher<Core::Crypto::Key256> cipher(
+ keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS);
+ cipher.XTSTranscode(&header, sizeof(NCAHeader), &dec_header, 0, 0x200,
+ Core::Crypto::Op::Decrypt);
+ if (IsValidNCA(dec_header)) {
+ header = dec_header;
+ encrypted = true;
+ } else {
+ if (dec_header.magic == Common::MakeMagic('N', 'C', 'A', '2')) {
+ status = Loader::ResultStatus::ErrorNCA2;
+ return;
+ }
+ if (dec_header.magic == Common::MakeMagic('N', 'C', 'A', '0')) {
+ status = Loader::ResultStatus::ErrorNCA0;
+ return;
+ }
+
+ if (!keys.HasKey(Core::Crypto::S256KeyType::Header))
+ status = Loader::ResultStatus::ErrorMissingHeaderKey;
+ else
+ status = Loader::ResultStatus::ErrorIncorrectHeaderKey;
+ return;
+ }
+ }
+
+ has_rights_id = std::find_if_not(header.rights_id.begin(), header.rights_id.end(),
+ [](char c) { return c == '\0'; }) != header.rights_id.end();
+
+ const std::ptrdiff_t number_sections =
std::count_if(std::begin(header.section_tables), std::end(header.section_tables),
[](NCASectionTableEntry entry) { return entry.media_offset > 0; });
+ std::vector<NCASectionHeader> sections(number_sections);
+ const auto length_sections = SECTION_HEADER_SIZE * number_sections;
+
+ if (encrypted) {
+ auto raw = file->ReadBytes(length_sections, SECTION_HEADER_OFFSET);
+ Core::Crypto::AESCipher<Core::Crypto::Key256> cipher(
+ keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS);
+ cipher.XTSTranscode(raw.data(), length_sections, sections.data(), 2, SECTION_HEADER_SIZE,
+ Core::Crypto::Op::Decrypt);
+ } else {
+ file->ReadBytes(sections.data(), length_sections, SECTION_HEADER_OFFSET);
+ }
+
for (std::ptrdiff_t i = 0; i < number_sections; ++i) {
- // Seek to beginning of this section.
- NCASectionHeaderBlock block{};
- if (sizeof(NCASectionHeaderBlock) !=
- file->ReadObject(&block, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE))
- LOG_CRITICAL(Loader, "File reader errored out during header read.");
-
- if (block.filesystem_type == NCASectionFilesystemType::ROMFS) {
- RomFSSuperblock sb{};
- if (sizeof(RomFSSuperblock) !=
- file->ReadObject(&sb, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE))
- LOG_CRITICAL(Loader, "File reader errored out during header read.");
+ auto section = sections[i];
+ if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) {
const size_t romfs_offset =
header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER +
- sb.levels[IVFC_MAX_LEVEL - 1].offset;
- const size_t romfs_size = sb.levels[IVFC_MAX_LEVEL - 1].size;
- files.emplace_back(std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset));
- romfs = files.back();
- } else if (block.filesystem_type == NCASectionFilesystemType::PFS0) {
- PFS0Superblock sb{};
- // Seek back to beginning of this section.
- if (sizeof(PFS0Superblock) !=
- file->ReadObject(&sb, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE))
- LOG_CRITICAL(Loader, "File reader errored out during header read.");
-
+ section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset;
+ const size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size;
+ auto dec =
+ Decrypt(section, std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset),
+ romfs_offset);
+ if (dec != nullptr) {
+ files.push_back(std::move(dec));
+ romfs = files.back();
+ } else {
+ if (status != Loader::ResultStatus::Success)
+ return;
+ if (has_rights_id)
+ status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek;
+ else
+ status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey;
+ return;
+ }
+ } else if (section.raw.header.filesystem_type == NCASectionFilesystemType::PFS0) {
u64 offset = (static_cast<u64>(header.section_tables[i].media_offset) *
MEDIA_OFFSET_MULTIPLIER) +
- sb.pfs0_header_offset;
+ section.pfs0.pfs0_header_offset;
u64 size = MEDIA_OFFSET_MULTIPLIER * (header.section_tables[i].media_end_offset -
header.section_tables[i].media_offset);
- auto npfs = std::make_shared<PartitionFilesystem>(
- std::make_shared<OffsetVfsFile>(file, size, offset));
+ auto dec =
+ Decrypt(section, std::make_shared<OffsetVfsFile>(file, size, offset), offset);
+ if (dec != nullptr) {
+ auto npfs = std::make_shared<PartitionFilesystem>(std::move(dec));
- if (npfs->GetStatus() == Loader::ResultStatus::Success) {
- dirs.emplace_back(npfs);
- if (IsDirectoryExeFS(dirs.back()))
- exefs = dirs.back();
+ if (npfs->GetStatus() == Loader::ResultStatus::Success) {
+ dirs.push_back(std::move(npfs));
+ if (IsDirectoryExeFS(dirs.back()))
+ exefs = dirs.back();
+ }
+ } else {
+ if (status != Loader::ResultStatus::Success)
+ return;
+ if (has_rights_id)
+ status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek;
+ else
+ status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey;
+ return;
}
}
}
@@ -164,6 +354,10 @@ VirtualDir NCA::GetExeFS() const {
return exefs;
}
+VirtualFile NCA::GetBaseFile() const {
+ return file;
+}
+
bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
return false;
}
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 0b8b9db61..b82e65ad5 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -8,14 +8,19 @@
#include <memory>
#include <string>
#include <vector>
-
+#include <boost/optional.hpp>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
+#include "control_metadata.h"
+#include "core/crypto/key_manager.h"
#include "core/file_sys/partition_filesystem.h"
+#include "core/loader/loader.h"
namespace FileSys {
+union NCASectionHeader;
+
enum class NCAContentType : u8 {
Program = 0,
Meta = 1,
@@ -24,6 +29,13 @@ enum class NCAContentType : u8 {
Data = 4,
};
+enum class NCASectionCryptoType : u8 {
+ NONE = 1,
+ XTS = 2,
+ CTR = 3,
+ BKTR = 4,
+};
+
struct NCASectionTableEntry {
u32_le media_offset;
u32_le media_end_offset;
@@ -48,7 +60,7 @@ struct NCAHeader {
std::array<u8, 0x10> rights_id;
std::array<NCASectionTableEntry, 0x4> section_tables;
std::array<std::array<u8, 0x20>, 0x4> hash_tables;
- std::array<std::array<u8, 0x10>, 0x4> key_area;
+ std::array<u8, 0x40> key_area;
INSERT_PADDING_BYTES(0xC0);
};
static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size.");
@@ -58,10 +70,7 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) {
return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr;
}
-inline bool IsValidNCA(const NCAHeader& header) {
- return header.magic == Common::MakeMagic('N', 'C', 'A', '2') ||
- header.magic == Common::MakeMagic('N', 'C', 'A', '3');
-}
+bool IsValidNCA(const NCAHeader& header);
// An implementation of VfsDirectory that represents a Nintendo Content Archive (NCA) conatiner.
// After construction, use GetStatus to determine if the file is valid and ready to be used.
@@ -81,10 +90,17 @@ public:
VirtualFile GetRomFS() const;
VirtualDir GetExeFS() const;
+ VirtualFile GetBaseFile() const;
+
protected:
bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
private:
+ u8 GetCryptoRevision() const;
+ boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const;
+ boost::optional<Core::Crypto::Key128> GetTitlekey();
+ VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset);
+
std::vector<VirtualDir> dirs;
std::vector<VirtualFile> files;
@@ -93,8 +109,13 @@ private:
VirtualFile file;
NCAHeader header{};
+ bool has_rights_id{};
Loader::ResultStatus status{};
+
+ bool encrypted;
+
+ Core::Crypto::KeyManager keys;
};
} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 3ddc9f162..ae21ad5b9 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -16,7 +16,7 @@ std::string LanguageEntry::GetDeveloperName() const {
return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), 0x100);
}
-NACP::NACP(VirtualFile file_) : file(std::move(file_)), raw(std::make_unique<RawNACP>()) {
+NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) {
file->ReadObject(raw.get());
}
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index cc3b745f7..8c2cc1a2a 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -62,6 +62,13 @@ enum class Language : u8 {
Chinese = 14,
};
+static constexpr std::array<const char*, 15> LANGUAGE_NAMES = {
+ "AmericanEnglish", "BritishEnglish", "Japanese",
+ "French", "German", "LatinAmericanSpanish",
+ "Spanish", "Italian", "Dutch",
+ "CanadianFrench", "Portugese", "Russian",
+ "Korean", "Taiwanese", "Chinese"};
+
// A class representing the format used by NX metadata files, typically named Control.nacp.
// These store application name, dev name, title id, and other miscellaneous data.
class NACP {
@@ -74,7 +81,6 @@ public:
std::string GetVersionString() const;
private:
- VirtualFile file;
std::unique_ptr<RawNACP> raw;
};
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h
index 213ce1826..3759e743a 100644
--- a/src/core/file_sys/directory.h
+++ b/src/core/file_sys/directory.h
@@ -4,8 +4,9 @@
#pragma once
-#include <array>
#include <cstddef>
+#include <iterator>
+#include <string_view>
#include "common/common_funcs.h"
#include "common/common_types.h"
@@ -21,9 +22,14 @@ enum EntryType : u8 {
// Structure of a directory entry, from
// http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry
-const size_t FILENAME_LENGTH = 0x300;
struct Entry {
- char filename[FILENAME_LENGTH];
+ Entry(std::string_view view, EntryType entry_type, u64 entry_size)
+ : type{entry_type}, file_size{entry_size} {
+ const size_t copy_size = view.copy(filename, std::size(filename) - 1);
+ filename[copy_size] = '\0';
+ }
+
+ char filename[0x300];
INSERT_PADDING_BYTES(4);
EntryType type;
INSERT_PADDING_BYTES(3);
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
new file mode 100644
index 000000000..449244444
--- /dev/null
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -0,0 +1,131 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cstring>
+#include "common/common_funcs.h"
+#include "common/logging/log.h"
+#include "common/swap.h"
+#include "content_archive.h"
+#include "core/file_sys/nca_metadata.h"
+
+namespace FileSys {
+
+bool operator>=(TitleType lhs, TitleType rhs) {
+ return static_cast<size_t>(lhs) >= static_cast<size_t>(rhs);
+}
+
+bool operator<=(TitleType lhs, TitleType rhs) {
+ return static_cast<size_t>(lhs) <= static_cast<size_t>(rhs);
+}
+
+CNMT::CNMT(VirtualFile file) {
+ if (file->ReadObject(&header) != sizeof(CNMTHeader))
+ return;
+
+ // If type is {Application, Update, AOC} has opt-header.
+ if (header.type >= TitleType::Application && header.type <= TitleType::AOC) {
+ if (file->ReadObject(&opt_header, sizeof(CNMTHeader)) != sizeof(OptionalHeader)) {
+ LOG_WARNING(Loader, "Failed to read optional header.");
+ }
+ }
+
+ for (u16 i = 0; i < header.number_content_entries; ++i) {
+ auto& next = content_records.emplace_back(ContentRecord{});
+ if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(ContentRecord) +
+ header.table_offset) != sizeof(ContentRecord)) {
+ content_records.erase(content_records.end() - 1);
+ }
+ }
+
+ for (u16 i = 0; i < header.number_meta_entries; ++i) {
+ auto& next = meta_records.emplace_back(MetaRecord{});
+ if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(MetaRecord) +
+ header.table_offset) != sizeof(MetaRecord)) {
+ meta_records.erase(meta_records.end() - 1);
+ }
+ }
+}
+
+CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records,
+ std::vector<MetaRecord> meta_records)
+ : header(std::move(header)), opt_header(std::move(opt_header)),
+ content_records(std::move(content_records)), meta_records(std::move(meta_records)) {}
+
+u64 CNMT::GetTitleID() const {
+ return header.title_id;
+}
+
+u32 CNMT::GetTitleVersion() const {
+ return header.title_version;
+}
+
+TitleType CNMT::GetType() const {
+ return header.type;
+}
+
+const std::vector<ContentRecord>& CNMT::GetContentRecords() const {
+ return content_records;
+}
+
+const std::vector<MetaRecord>& CNMT::GetMetaRecords() const {
+ return meta_records;
+}
+
+bool CNMT::UnionRecords(const CNMT& other) {
+ bool change = false;
+ for (const auto& rec : other.content_records) {
+ const auto iter = std::find_if(content_records.begin(), content_records.end(),
+ [&rec](const ContentRecord& r) {
+ return r.nca_id == rec.nca_id && r.type == rec.type;
+ });
+ if (iter == content_records.end()) {
+ content_records.emplace_back(rec);
+ ++header.number_content_entries;
+ change = true;
+ }
+ }
+ for (const auto& rec : other.meta_records) {
+ const auto iter =
+ std::find_if(meta_records.begin(), meta_records.end(), [&rec](const MetaRecord& r) {
+ return r.title_id == rec.title_id && r.title_version == rec.title_version &&
+ r.type == rec.type;
+ });
+ if (iter == meta_records.end()) {
+ meta_records.emplace_back(rec);
+ ++header.number_meta_entries;
+ change = true;
+ }
+ }
+ return change;
+}
+
+std::vector<u8> CNMT::Serialize() const {
+ const bool has_opt_header =
+ header.type >= TitleType::Application && header.type <= TitleType::AOC;
+ const auto dead_zone = header.table_offset + sizeof(CNMTHeader);
+ std::vector<u8> out(
+ std::max(sizeof(CNMTHeader) + (has_opt_header ? sizeof(OptionalHeader) : 0), dead_zone) +
+ content_records.size() * sizeof(ContentRecord) + meta_records.size() * sizeof(MetaRecord));
+ memcpy(out.data(), &header, sizeof(CNMTHeader));
+
+ // Optional Header
+ if (has_opt_header) {
+ memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader));
+ }
+
+ auto offset = header.table_offset;
+
+ for (const auto& rec : content_records) {
+ memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord));
+ offset += sizeof(ContentRecord);
+ }
+
+ for (const auto& rec : meta_records) {
+ memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(MetaRecord));
+ offset += sizeof(MetaRecord);
+ }
+
+ return out;
+}
+} // namespace FileSys
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
new file mode 100644
index 000000000..88e66d4da
--- /dev/null
+++ b/src/core/file_sys/nca_metadata.h
@@ -0,0 +1,111 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cstring>
+#include <memory>
+#include <vector>
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/file_sys/vfs.h"
+
+namespace FileSys {
+class CNMT;
+
+struct CNMTHeader;
+struct OptionalHeader;
+
+enum class TitleType : u8 {
+ SystemProgram = 0x01,
+ SystemDataArchive = 0x02,
+ SystemUpdate = 0x03,
+ FirmwarePackageA = 0x04,
+ FirmwarePackageB = 0x05,
+ Application = 0x80,
+ Update = 0x81,
+ AOC = 0x82,
+ DeltaTitle = 0x83,
+};
+
+bool operator>=(TitleType lhs, TitleType rhs);
+bool operator<=(TitleType lhs, TitleType rhs);
+
+enum class ContentRecordType : u8 {
+ Meta = 0,
+ Program = 1,
+ Data = 2,
+ Control = 3,
+ Manual = 4,
+ Legal = 5,
+ Patch = 6,
+};
+
+struct ContentRecord {
+ std::array<u8, 0x20> hash;
+ std::array<u8, 0x10> nca_id;
+ std::array<u8, 0x6> size;
+ ContentRecordType type;
+ INSERT_PADDING_BYTES(1);
+};
+static_assert(sizeof(ContentRecord) == 0x38, "ContentRecord has incorrect size.");
+
+constexpr ContentRecord EMPTY_META_CONTENT_RECORD{{}, {}, {}, ContentRecordType::Meta, {}};
+
+struct MetaRecord {
+ u64_le title_id;
+ u32_le title_version;
+ TitleType type;
+ u8 install_byte;
+ INSERT_PADDING_BYTES(2);
+};
+static_assert(sizeof(MetaRecord) == 0x10, "MetaRecord has incorrect size.");
+
+struct OptionalHeader {
+ u64_le title_id;
+ u64_le minimum_version;
+};
+static_assert(sizeof(OptionalHeader) == 0x10, "OptionalHeader has incorrect size.");
+
+struct CNMTHeader {
+ u64_le title_id;
+ u32_le title_version;
+ TitleType type;
+ INSERT_PADDING_BYTES(1);
+ u16_le table_offset;
+ u16_le number_content_entries;
+ u16_le number_meta_entries;
+ INSERT_PADDING_BYTES(12);
+};
+static_assert(sizeof(CNMTHeader) == 0x20, "CNMTHeader has incorrect size.");
+
+// A class representing the format used by NCA metadata files, typically named {}.cnmt.nca or
+// meta0.ncd. These describe which NCA's belong with which titles in the registered cache.
+class CNMT {
+public:
+ explicit CNMT(VirtualFile file);
+ CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records,
+ std::vector<MetaRecord> meta_records);
+
+ u64 GetTitleID() const;
+ u32 GetTitleVersion() const;
+ TitleType GetType() const;
+
+ const std::vector<ContentRecord>& GetContentRecords() const;
+ const std::vector<MetaRecord>& GetMetaRecords() const;
+
+ bool UnionRecords(const CNMT& other);
+ std::vector<u8> Serialize() const;
+
+private:
+ CNMTHeader header;
+ OptionalHeader opt_header;
+ std::vector<ContentRecord> content_records;
+ std::vector<MetaRecord> meta_records;
+
+ // TODO(DarkLordZach): According to switchbrew, for Patch-type there is additional data
+ // after the table. This is not documented, unfortunately.
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 521e21078..c377edc9c 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -24,19 +24,19 @@ bool PartitionFilesystem::Header::HasValidMagicValue() const {
PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
// At least be as large as the header
if (file->GetSize() < sizeof(Header)) {
- status = Loader::ResultStatus::Error;
+ status = Loader::ResultStatus::ErrorBadPFSHeader;
return;
}
// For cartridges, HFSs can get very large, so we need to calculate the size up to
// the actual content itself instead of just blindly reading in the entire file.
if (sizeof(Header) != file->ReadObject(&pfs_header)) {
- status = Loader::ResultStatus::Error;
+ status = Loader::ResultStatus::ErrorBadPFSHeader;
return;
}
if (!pfs_header.HasValidMagicValue()) {
- status = Loader::ResultStatus::ErrorInvalidFormat;
+ status = Loader::ResultStatus::ErrorBadPFSHeader;
return;
}
@@ -51,7 +51,7 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
const size_t total_size = file_data.size();
if (total_size != metadata_size) {
- status = Loader::ResultStatus::Error;
+ status = Loader::ResultStatus::ErrorIncorrectPFSFileSize;
return;
}
@@ -97,9 +97,8 @@ void PartitionFilesystem::PrintDebugInfo() const {
LOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic);
LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries);
for (u32 i = 0; i < pfs_header.num_entries; i++) {
- LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i,
- pfs_files[i]->GetName(), pfs_files[i]->GetSize(),
- dynamic_cast<OffsetVfsFile*>(pfs_files[i].get())->GetOffset());
+ LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes)", i,
+ pfs_files[i]->GetName(), pfs_files[i]->GetSize());
}
}
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
index 7c7a75816..be7bc32a8 100644
--- a/src/core/file_sys/partition_filesystem.h
+++ b/src/core/file_sys/partition_filesystem.h
@@ -13,7 +13,7 @@
#include "core/file_sys/vfs.h"
namespace Loader {
-enum class ResultStatus;
+enum class ResultStatus : u16;
}
namespace FileSys {
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 63d4b6e4f..279f987d4 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -12,26 +12,26 @@ namespace FileSys {
Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
size_t total_size = static_cast<size_t>(file->GetSize());
if (total_size < sizeof(Header))
- return Loader::ResultStatus::Error;
+ return Loader::ResultStatus::ErrorBadNPDMHeader;
// TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable.
std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header));
if (sizeof(Header) != npdm_header_data.size())
- return Loader::ResultStatus::Error;
+ return Loader::ResultStatus::ErrorBadNPDMHeader;
std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header));
std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset);
if (sizeof(AcidHeader) != acid_header_data.size())
- return Loader::ResultStatus::Error;
+ return Loader::ResultStatus::ErrorBadACIDHeader;
std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader));
if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset))
- return Loader::ResultStatus::Error;
+ return Loader::ResultStatus::ErrorBadACIHeader;
if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset))
- return Loader::ResultStatus::Error;
+ return Loader::ResultStatus::ErrorBadFileAccessControl;
if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset))
- return Loader::ResultStatus::Error;
+ return Loader::ResultStatus::ErrorBadFileAccessHeader;
return Loader::ResultStatus::Success;
}
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 06a7315db..74a91052b 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -13,7 +13,7 @@
#include "partition_filesystem.h"
namespace Loader {
-enum class ResultStatus;
+enum class ResultStatus : u16;
}
namespace FileSys {
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
new file mode 100644
index 000000000..d25eeee34
--- /dev/null
+++ b/src/core/file_sys/registered_cache.cpp
@@ -0,0 +1,478 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <regex>
+#include <mbedtls/sha256.h>
+#include "common/assert.h"
+#include "common/hex_util.h"
+#include "common/logging/log.h"
+#include "core/crypto/encryption_layer.h"
+#include "core/file_sys/card_image.h"
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/registered_cache.h"
+#include "core/file_sys/vfs_concat.h"
+
+namespace FileSys {
+std::string RegisteredCacheEntry::DebugInfo() const {
+ return fmt::format("title_id={:016X}, content_type={:02X}", title_id, static_cast<u8>(type));
+}
+
+bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) {
+ return (lhs.title_id < rhs.title_id) || (lhs.title_id == rhs.title_id && lhs.type < rhs.type);
+}
+
+static bool FollowsTwoDigitDirFormat(std::string_view name) {
+ static const std::regex two_digit_regex("000000[0-9A-F]{2}", std::regex_constants::ECMAScript |
+ std::regex_constants::icase);
+ return std::regex_match(name.begin(), name.end(), two_digit_regex);
+}
+
+static bool FollowsNcaIdFormat(std::string_view name) {
+ static const std::regex nca_id_regex("[0-9A-F]{32}\\.nca", std::regex_constants::ECMAScript |
+ std::regex_constants::icase);
+ return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex);
+}
+
+static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bool second_hex_upper,
+ bool within_two_digit) {
+ if (!within_two_digit)
+ return fmt::format("/{}.nca", Common::HexArrayToString(nca_id, second_hex_upper));
+
+ Core::Crypto::SHA256Hash hash{};
+ mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
+ return fmt::format("/000000{:02X}/{}.nca", hash[0],
+ Common::HexArrayToString(nca_id, second_hex_upper));
+}
+
+static std::string GetCNMTName(TitleType type, u64 title_id) {
+ constexpr std::array<const char*, 9> TITLE_TYPE_NAMES{
+ "SystemProgram",
+ "SystemData",
+ "SystemUpdate",
+ "BootImagePackage",
+ "BootImagePackageSafe",
+ "Application",
+ "Patch",
+ "AddOnContent",
+ "" ///< Currently unknown 'DeltaTitle'
+ };
+
+ auto index = static_cast<size_t>(type);
+ // If the index is after the jump in TitleType, subtract it out.
+ if (index >= static_cast<size_t>(TitleType::Application)) {
+ index -= static_cast<size_t>(TitleType::Application) -
+ static_cast<size_t>(TitleType::FirmwarePackageB);
+ }
+ return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id);
+}
+
+static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
+ switch (type) {
+ case NCAContentType::Program:
+ // TODO(DarkLordZach): Differentiate between Program and Patch
+ return ContentRecordType::Program;
+ case NCAContentType::Meta:
+ return ContentRecordType::Meta;
+ case NCAContentType::Control:
+ return ContentRecordType::Control;
+ case NCAContentType::Data:
+ return ContentRecordType::Data;
+ case NCAContentType::Manual:
+ // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal.
+ return ContentRecordType::Manual;
+ default:
+ UNREACHABLE();
+ }
+}
+
+VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
+ std::string_view path) const {
+ if (dir->GetFileRelative(path) != nullptr)
+ return dir->GetFileRelative(path);
+ if (dir->GetDirectoryRelative(path) != nullptr) {
+ const auto nca_dir = dir->GetDirectoryRelative(path);
+ VirtualFile file = nullptr;
+
+ const auto files = nca_dir->GetFiles();
+ if (files.size() == 1 && files[0]->GetName() == "00") {
+ file = files[0];
+ } else {
+ std::vector<VirtualFile> concat;
+ // Since the files are a two-digit hex number, max is FF.
+ for (size_t i = 0; i < 0x100; ++i) {
+ auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
+ if (next != nullptr) {
+ concat.push_back(std::move(next));
+ } else {
+ next = nca_dir->GetFile(fmt::format("{:02x}", i));
+ if (next != nullptr)
+ concat.push_back(std::move(next));
+ else
+ break;
+ }
+ }
+
+ if (concat.empty())
+ return nullptr;
+
+ file = FileSys::ConcatenateFiles(concat);
+ }
+
+ return file;
+ }
+ return nullptr;
+}
+
+VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
+ VirtualFile file;
+ // Try all four modes of file storage:
+ // (bit 1 = uppercase/lower, bit 0 = within a two-digit dir)
+ // 00: /000000**/{:032X}.nca
+ // 01: /{:032X}.nca
+ // 10: /000000**/{:032x}.nca
+ // 11: /{:032x}.nca
+ for (u8 i = 0; i < 4; ++i) {
+ const auto path = GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0);
+ file = OpenFileOrDirectoryConcat(dir, path);
+ if (file != nullptr)
+ return file;
+ }
+ return file;
+}
+
+static boost::optional<NcaID> CheckMapForContentRecord(
+ const boost::container::flat_map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
+ if (map.find(title_id) == map.end())
+ return boost::none;
+
+ const auto& cnmt = map.at(title_id);
+
+ const auto iter = std::find_if(cnmt.GetContentRecords().begin(), cnmt.GetContentRecords().end(),
+ [type](const ContentRecord& rec) { return rec.type == type; });
+ if (iter == cnmt.GetContentRecords().end())
+ return boost::none;
+
+ return boost::make_optional(iter->nca_id);
+}
+
+boost::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id,
+ ContentRecordType type) const {
+ if (type == ContentRecordType::Meta && meta_id.find(title_id) != meta_id.end())
+ return meta_id.at(title_id);
+
+ const auto res1 = CheckMapForContentRecord(yuzu_meta, title_id, type);
+ if (res1 != boost::none)
+ return res1;
+ return CheckMapForContentRecord(meta, title_id, type);
+}
+
+std::vector<NcaID> RegisteredCache::AccumulateFiles() const {
+ std::vector<NcaID> ids;
+ for (const auto& d2_dir : dir->GetSubdirectories()) {
+ if (FollowsNcaIdFormat(d2_dir->GetName())) {
+ ids.push_back(Common::HexStringToArray<0x10, true>(d2_dir->GetName().substr(0, 0x20)));
+ continue;
+ }
+
+ if (!FollowsTwoDigitDirFormat(d2_dir->GetName()))
+ continue;
+
+ for (const auto& nca_dir : d2_dir->GetSubdirectories()) {
+ if (!FollowsNcaIdFormat(nca_dir->GetName()))
+ continue;
+
+ ids.push_back(Common::HexStringToArray<0x10, true>(nca_dir->GetName().substr(0, 0x20)));
+ }
+
+ for (const auto& nca_file : d2_dir->GetFiles()) {
+ if (!FollowsNcaIdFormat(nca_file->GetName()))
+ continue;
+
+ ids.push_back(
+ Common::HexStringToArray<0x10, true>(nca_file->GetName().substr(0, 0x20)));
+ }
+ }
+
+ for (const auto& d2_file : dir->GetFiles()) {
+ if (FollowsNcaIdFormat(d2_file->GetName()))
+ ids.push_back(Common::HexStringToArray<0x10, true>(d2_file->GetName().substr(0, 0x20)));
+ }
+ return ids;
+}
+
+void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) {
+ for (const auto& id : ids) {
+ const auto file = GetFileAtID(id);
+
+ if (file == nullptr)
+ continue;
+ const auto nca = std::make_shared<NCA>(parser(file, id));
+ if (nca->GetStatus() != Loader::ResultStatus::Success ||
+ nca->GetType() != NCAContentType::Meta) {
+ continue;
+ }
+
+ const auto section0 = nca->GetSubdirectories()[0];
+
+ for (const auto& file : section0->GetFiles()) {
+ if (file->GetExtension() != "cnmt")
+ continue;
+
+ meta.insert_or_assign(nca->GetTitleId(), CNMT(file));
+ meta_id.insert_or_assign(nca->GetTitleId(), id);
+ break;
+ }
+ }
+}
+
+void RegisteredCache::AccumulateYuzuMeta() {
+ const auto dir = this->dir->GetSubdirectory("yuzu_meta");
+ if (dir == nullptr)
+ return;
+
+ for (const auto& file : dir->GetFiles()) {
+ if (file->GetExtension() != "cnmt")
+ continue;
+
+ CNMT cnmt(file);
+ yuzu_meta.insert_or_assign(cnmt.GetTitleID(), std::move(cnmt));
+ }
+}
+
+void RegisteredCache::Refresh() {
+ if (dir == nullptr)
+ return;
+ const auto ids = AccumulateFiles();
+ ProcessFiles(ids);
+ AccumulateYuzuMeta();
+}
+
+RegisteredCache::RegisteredCache(VirtualDir dir_, RegisteredCacheParsingFunction parsing_function)
+ : dir(std::move(dir_)), parser(std::move(parsing_function)) {
+ Refresh();
+}
+
+bool RegisteredCache::HasEntry(u64 title_id, ContentRecordType type) const {
+ return GetEntryRaw(title_id, type) != nullptr;
+}
+
+bool RegisteredCache::HasEntry(RegisteredCacheEntry entry) const {
+ return GetEntryRaw(entry) != nullptr;
+}
+
+VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) const {
+ const auto id = GetNcaIDFromMetadata(title_id, type);
+ if (id == boost::none)
+ return nullptr;
+
+ return parser(GetFileAtID(id.get()), id.get());
+}
+
+VirtualFile RegisteredCache::GetEntryRaw(RegisteredCacheEntry entry) const {
+ return GetEntryRaw(entry.title_id, entry.type);
+}
+
+std::shared_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType type) const {
+ const auto raw = GetEntryRaw(title_id, type);
+ if (raw == nullptr)
+ return nullptr;
+ return std::make_shared<NCA>(raw);
+}
+
+std::shared_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
+ return GetEntry(entry.title_id, entry.type);
+}
+
+template <typename T>
+void RegisteredCache::IterateAllMetadata(
+ std::vector<T>& out, std::function<T(const CNMT&, const ContentRecord&)> proc,
+ std::function<bool(const CNMT&, const ContentRecord&)> filter) const {
+ for (const auto& kv : meta) {
+ const auto& cnmt = kv.second;
+ if (filter(cnmt, EMPTY_META_CONTENT_RECORD))
+ out.push_back(proc(cnmt, EMPTY_META_CONTENT_RECORD));
+ for (const auto& rec : cnmt.GetContentRecords()) {
+ if (GetFileAtID(rec.nca_id) != nullptr && filter(cnmt, rec)) {
+ out.push_back(proc(cnmt, rec));
+ }
+ }
+ }
+ for (const auto& kv : yuzu_meta) {
+ const auto& cnmt = kv.second;
+ for (const auto& rec : cnmt.GetContentRecords()) {
+ if (GetFileAtID(rec.nca_id) != nullptr && filter(cnmt, rec)) {
+ out.push_back(proc(cnmt, rec));
+ }
+ }
+ }
+}
+
+std::vector<RegisteredCacheEntry> RegisteredCache::ListEntries() const {
+ std::vector<RegisteredCacheEntry> out;
+ IterateAllMetadata<RegisteredCacheEntry>(
+ out,
+ [](const CNMT& c, const ContentRecord& r) {
+ return RegisteredCacheEntry{c.GetTitleID(), r.type};
+ },
+ [](const CNMT& c, const ContentRecord& r) { return true; });
+ return out;
+}
+
+std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
+ boost::optional<TitleType> title_type, boost::optional<ContentRecordType> record_type,
+ boost::optional<u64> title_id) const {
+ std::vector<RegisteredCacheEntry> out;
+ IterateAllMetadata<RegisteredCacheEntry>(
+ out,
+ [](const CNMT& c, const ContentRecord& r) {
+ return RegisteredCacheEntry{c.GetTitleID(), r.type};
+ },
+ [&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) {
+ if (title_type != boost::none && title_type.get() != c.GetType())
+ return false;
+ if (record_type != boost::none && record_type.get() != r.type)
+ return false;
+ if (title_id != boost::none && title_id.get() != c.GetTitleID())
+ return false;
+ return true;
+ });
+ return out;
+}
+
+static std::shared_ptr<NCA> GetNCAFromXCIForID(std::shared_ptr<XCI> xci, const NcaID& id) {
+ const auto filename = fmt::format("{}.nca", Common::HexArrayToString(id, false));
+ const auto iter =
+ std::find_if(xci->GetNCAs().begin(), xci->GetNCAs().end(),
+ [&filename](std::shared_ptr<NCA> nca) { return nca->GetName() == filename; });
+ return iter == xci->GetNCAs().end() ? nullptr : *iter;
+}
+
+InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists,
+ const VfsCopyFunction& copy) {
+ const auto& ncas = xci->GetNCAs();
+ const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) {
+ return nca->GetType() == NCAContentType::Meta;
+ });
+
+ if (meta_iter == ncas.end()) {
+ LOG_ERROR(Loader, "The XCI you are attempting to install does not have a metadata NCA and "
+ "is therefore malformed. Double check your encryption keys.");
+ return InstallResult::ErrorMetaFailed;
+ }
+
+ // Install Metadata File
+ const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
+ const auto meta_id = Common::HexStringToArray<16>(meta_id_raw);
+
+ const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id);
+ if (res != InstallResult::Success)
+ return res;
+
+ // Install all the other NCAs
+ const auto section0 = (*meta_iter)->GetSubdirectories()[0];
+ const auto cnmt_file = section0->GetFiles()[0];
+ const CNMT cnmt(cnmt_file);
+ for (const auto& record : cnmt.GetContentRecords()) {
+ const auto nca = GetNCAFromXCIForID(xci, record.nca_id);
+ if (nca == nullptr)
+ return InstallResult::ErrorCopyFailed;
+ const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id);
+ if (res2 != InstallResult::Success)
+ return res2;
+ }
+
+ Refresh();
+ return InstallResult::Success;
+}
+
+InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type,
+ bool overwrite_if_exists, const VfsCopyFunction& copy) {
+ CNMTHeader header{
+ nca->GetTitleId(), ///< Title ID
+ 0, ///< Ignore/Default title version
+ type, ///< Type
+ {}, ///< Padding
+ 0x10, ///< Default table offset
+ 1, ///< 1 Content Entry
+ 0, ///< No Meta Entries
+ {}, ///< Padding
+ };
+ OptionalHeader opt_header{0, 0};
+ ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca->GetType()), {}};
+ const auto& data = nca->GetBaseFile()->ReadBytes(0x100000);
+ mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0);
+ memcpy(&c_rec.nca_id, &c_rec.hash, 16);
+ const CNMT new_cnmt(header, opt_header, {c_rec}, {});
+ if (!RawInstallYuzuMeta(new_cnmt))
+ return InstallResult::ErrorMetaFailed;
+ return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
+}
+
+InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
+ bool overwrite_if_exists,
+ boost::optional<NcaID> override_id) {
+ const auto in = nca->GetBaseFile();
+ Core::Crypto::SHA256Hash hash{};
+
+ // Calculate NcaID
+ // NOTE: Because computing the SHA256 of an entire NCA is quite expensive (especially if the
+ // game is massive), we're going to cheat and only hash the first MB of the NCA.
+ // Also, for XCIs the NcaID matters, so if the override id isn't none, use that.
+ NcaID id{};
+ if (override_id == boost::none) {
+ const auto& data = in->ReadBytes(0x100000);
+ mbedtls_sha256(data.data(), data.size(), hash.data(), 0);
+ memcpy(id.data(), hash.data(), 16);
+ } else {
+ id = override_id.get();
+ }
+
+ std::string path = GetRelativePathFromNcaID(id, false, true);
+
+ if (GetFileAtID(id) != nullptr && !overwrite_if_exists) {
+ LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping...");
+ return InstallResult::ErrorAlreadyExists;
+ }
+
+ if (GetFileAtID(id) != nullptr) {
+ LOG_WARNING(Loader, "Overwriting existing NCA...");
+ VirtualDir c_dir;
+ { c_dir = dir->GetFileRelative(path)->GetContainingDirectory(); }
+ c_dir->DeleteFile(FileUtil::GetFilename(path));
+ }
+
+ auto out = dir->CreateFileRelative(path);
+ if (out == nullptr)
+ return InstallResult::ErrorCopyFailed;
+ return copy(in, out) ? InstallResult::Success : InstallResult::ErrorCopyFailed;
+}
+
+bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
+ // Reasoning behind this method can be found in the comment for InstallEntry, NCA overload.
+ const auto dir = this->dir->CreateDirectoryRelative("yuzu_meta");
+ const auto filename = GetCNMTName(cnmt.GetType(), cnmt.GetTitleID());
+ if (dir->GetFile(filename) == nullptr) {
+ auto out = dir->CreateFile(filename);
+ const auto buffer = cnmt.Serialize();
+ out->Resize(buffer.size());
+ out->WriteBytes(buffer);
+ } else {
+ auto out = dir->GetFile(filename);
+ CNMT old_cnmt(out);
+ // Returns true on change
+ if (old_cnmt.UnionRecords(cnmt)) {
+ out->Resize(0);
+ const auto buffer = old_cnmt.Serialize();
+ out->Resize(buffer.size());
+ out->WriteBytes(buffer);
+ }
+ }
+ Refresh();
+ return std::find_if(yuzu_meta.begin(), yuzu_meta.end(),
+ [&cnmt](const std::pair<u64, CNMT>& kv) {
+ return kv.second.GetType() == cnmt.GetType() &&
+ kv.second.GetTitleID() == cnmt.GetTitleID();
+ }) != yuzu_meta.end();
+}
+} // namespace FileSys
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
new file mode 100644
index 000000000..a7c51a59c
--- /dev/null
+++ b/src/core/file_sys/registered_cache.h
@@ -0,0 +1,124 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+#include <boost/container/flat_map.hpp>
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "content_archive.h"
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/vfs.h"
+
+namespace FileSys {
+class XCI;
+class CNMT;
+
+using NcaID = std::array<u8, 0x10>;
+using RegisteredCacheParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
+using VfsCopyFunction = std::function<bool(VirtualFile, VirtualFile)>;
+
+enum class InstallResult {
+ Success,
+ ErrorAlreadyExists,
+ ErrorCopyFailed,
+ ErrorMetaFailed,
+};
+
+struct RegisteredCacheEntry {
+ u64 title_id;
+ ContentRecordType type;
+
+ std::string DebugInfo() const;
+};
+
+// boost flat_map requires operator< for O(log(n)) lookups.
+bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
+
+/*
+ * A class that catalogues NCAs in the registered directory structure.
+ * Nintendo's registered format follows this structure:
+ *
+ * Root
+ * | 000000XX <- XX is the ____ two digits of the NcaID
+ * | <hash>.nca <- hash is the NcaID (first half of SHA256 over entire file) (folder)
+ * | 00
+ * | 01 <- Actual content split along 4GB boundaries. (optional)
+ *
+ * (This impl also supports substituting the nca dir for an nca file, as that's more convenient when
+ * 4GB splitting can be ignored.)
+ */
+class RegisteredCache {
+public:
+ // Parsing function defines the conversion from raw file to NCA. If there are other steps
+ // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
+ // parsing function.
+ explicit RegisteredCache(VirtualDir dir,
+ RegisteredCacheParsingFunction parsing_function =
+ [](const VirtualFile& file, const NcaID& id) { return file; });
+
+ void Refresh();
+
+ bool HasEntry(u64 title_id, ContentRecordType type) const;
+ bool HasEntry(RegisteredCacheEntry entry) const;
+
+ VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
+ VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
+
+ std::shared_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
+ std::shared_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
+
+ std::vector<RegisteredCacheEntry> ListEntries() const;
+ // If a parameter is not boost::none, it will be filtered for from all entries.
+ std::vector<RegisteredCacheEntry> ListEntriesFilter(
+ boost::optional<TitleType> title_type = boost::none,
+ boost::optional<ContentRecordType> record_type = boost::none,
+ boost::optional<u64> title_id = boost::none) const;
+
+ // Raw copies all the ncas from the xci to the csache. Does some quick checks to make sure there
+ // is a meta NCA and all of them are accessible.
+ InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false,
+ const VfsCopyFunction& copy = &VfsRawCopy);
+
+ // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this
+ // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a
+ // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there.
+ // TODO(DarkLordZach): Author real meta-type NCAs and install those.
+ InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type,
+ bool overwrite_if_exists = false,
+ const VfsCopyFunction& copy = &VfsRawCopy);
+
+private:
+ template <typename T>
+ void IterateAllMetadata(std::vector<T>& out,
+ std::function<T(const CNMT&, const ContentRecord&)> proc,
+ std::function<bool(const CNMT&, const ContentRecord&)> filter) const;
+ std::vector<NcaID> AccumulateFiles() const;
+ void ProcessFiles(const std::vector<NcaID>& ids);
+ void AccumulateYuzuMeta();
+ boost::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
+ VirtualFile GetFileAtID(NcaID id) const;
+ VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const;
+ InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
+ bool overwrite_if_exists,
+ boost::optional<NcaID> override_id = boost::none);
+ bool RawInstallYuzuMeta(const CNMT& cnmt);
+
+ VirtualDir dir;
+ RegisteredCacheParsingFunction parser;
+ // maps tid -> NcaID of meta
+ boost::container::flat_map<u64, NcaID> meta_id;
+ // maps tid -> meta
+ boost::container::flat_map<u64, CNMT> meta;
+ // maps tid -> meta for CNMT in yuzu_meta
+ boost::container::flat_map<u64, CNMT> yuzu_meta;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
new file mode 100644
index 000000000..e490c8ace
--- /dev/null
+++ b/src/core/file_sys/romfs.cpp
@@ -0,0 +1,124 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/file_sys/romfs.h"
+#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_offset.h"
+#include "core/file_sys/vfs_vector.h"
+
+namespace FileSys {
+
+constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF;
+
+struct TableLocation {
+ u64_le offset;
+ u64_le size;
+};
+static_assert(sizeof(TableLocation) == 0x10, "TableLocation has incorrect size.");
+
+struct RomFSHeader {
+ u64_le header_size;
+ TableLocation directory_hash;
+ TableLocation directory_meta;
+ TableLocation file_hash;
+ TableLocation file_meta;
+ u64_le data_offset;
+};
+static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
+
+struct DirectoryEntry {
+ u32_le sibling;
+ u32_le child_dir;
+ u32_le child_file;
+ u32_le hash;
+ u32_le name_length;
+};
+static_assert(sizeof(DirectoryEntry) == 0x14, "DirectoryEntry has incorrect size.");
+
+struct FileEntry {
+ u32_le parent;
+ u32_le sibling;
+ u64_le offset;
+ u64_le size;
+ u32_le hash;
+ u32_le name_length;
+};
+static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
+
+template <typename Entry>
+static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, size_t offset) {
+ Entry entry{};
+ if (file->ReadObject(&entry, offset) != sizeof(Entry))
+ return {};
+ std::string string(entry.name_length, '\0');
+ if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size())
+ return {};
+ return {entry, string};
+}
+
+void ProcessFile(VirtualFile file, size_t file_offset, size_t data_offset, u32 this_file_offset,
+ std::shared_ptr<VectorVfsDirectory> parent) {
+ while (true) {
+ auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset);
+
+ parent->AddFile(std::make_shared<OffsetVfsFile>(
+ file, entry.first.size, entry.first.offset + data_offset, entry.second));
+
+ if (entry.first.sibling == ROMFS_ENTRY_EMPTY)
+ break;
+
+ this_file_offset = entry.first.sibling;
+ }
+}
+
+void ProcessDirectory(VirtualFile file, size_t dir_offset, size_t file_offset, size_t data_offset,
+ u32 this_dir_offset, std::shared_ptr<VectorVfsDirectory> parent) {
+ while (true) {
+ auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset);
+ auto current = std::make_shared<VectorVfsDirectory>(
+ std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second);
+
+ if (entry.first.child_file != ROMFS_ENTRY_EMPTY) {
+ ProcessFile(file, file_offset, data_offset, entry.first.child_file, current);
+ }
+
+ if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) {
+ ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir,
+ current);
+ }
+
+ parent->AddDirectory(current);
+ if (entry.first.sibling == ROMFS_ENTRY_EMPTY)
+ break;
+ this_dir_offset = entry.first.sibling;
+ }
+}
+
+VirtualDir ExtractRomFS(VirtualFile file) {
+ RomFSHeader header{};
+ if (file->ReadObject(&header) != sizeof(RomFSHeader))
+ return nullptr;
+
+ if (header.header_size != sizeof(RomFSHeader))
+ return nullptr;
+
+ const u64 file_offset = header.file_meta.offset;
+ const u64 dir_offset = header.directory_meta.offset + 4;
+
+ auto root =
+ std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, std::vector<VirtualDir>{},
+ file->GetName(), file->GetContainingDirectory());
+
+ ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root);
+
+ VirtualDir out = std::move(root);
+
+ while (out->GetSubdirectory("") != nullptr)
+ out = out->GetSubdirectory("");
+
+ return out;
+}
+} // namespace FileSys
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h
new file mode 100644
index 000000000..03a876d22
--- /dev/null
+++ b/src/core/file_sys/romfs.h
@@ -0,0 +1,35 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include "common/common_funcs.h"
+#include "common/swap.h"
+#include "core/file_sys/vfs.h"
+
+namespace FileSys {
+
+struct IVFCLevel {
+ u64_le offset;
+ u64_le size;
+ u32_le block_size;
+ u32_le reserved;
+};
+static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size.");
+
+struct IVFCHeader {
+ u32_le magic;
+ u32_le magic_number;
+ INSERT_PADDING_BYTES(8);
+ std::array<IVFCLevel, 6> levels;
+ INSERT_PADDING_BYTES(64);
+};
+static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size.");
+
+// Converts a RomFS binary blob to VFS Filesystem
+// Returns nullptr on failure
+VirtualDir ExtractRomFS(VirtualFile file);
+
+} // namespace FileSys
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index e3a578c0f..f3cf50d5a 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -7,6 +7,7 @@
#include <memory>
#include <string>
#include "common/common_types.h"
+#include "common/swap.h"
#include "core/hle/result.h"
namespace FileSys {
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index b99a4fd5b..a5ec50b1a 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -4,12 +4,160 @@
#include <algorithm>
#include <numeric>
+#include <string>
+#include "common/common_paths.h"
#include "common/file_util.h"
#include "common/logging/backend.h"
#include "core/file_sys/vfs.h"
namespace FileSys {
+VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {}
+
+VfsFilesystem::~VfsFilesystem() = default;
+
+std::string VfsFilesystem::GetName() const {
+ return root->GetName();
+}
+
+bool VfsFilesystem::IsReadable() const {
+ return root->IsReadable();
+}
+
+bool VfsFilesystem::IsWritable() const {
+ return root->IsWritable();
+}
+
+VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
+ const auto path = FileUtil::SanitizePath(path_);
+ if (root->GetFileRelative(path) != nullptr)
+ return VfsEntryType::File;
+ if (root->GetDirectoryRelative(path) != nullptr)
+ return VfsEntryType::Directory;
+
+ return VfsEntryType::None;
+}
+
+VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
+ const auto path = FileUtil::SanitizePath(path_);
+ return root->GetFileRelative(path);
+}
+
+VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
+ const auto path = FileUtil::SanitizePath(path_);
+ return root->CreateFileRelative(path);
+}
+
+VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
+ const auto old_path = FileUtil::SanitizePath(old_path_);
+ const auto new_path = FileUtil::SanitizePath(new_path_);
+
+ // VfsDirectory impls are only required to implement copy across the current directory.
+ if (FileUtil::GetParentPath(old_path) == FileUtil::GetParentPath(new_path)) {
+ if (!root->Copy(FileUtil::GetFilename(old_path), FileUtil::GetFilename(new_path)))
+ return nullptr;
+ return OpenFile(new_path, Mode::ReadWrite);
+ }
+
+ // Do it using RawCopy. Non-default impls are encouraged to optimize this.
+ const auto old_file = OpenFile(old_path, Mode::Read);
+ if (old_file == nullptr)
+ return nullptr;
+ auto new_file = OpenFile(new_path, Mode::Read);
+ if (new_file != nullptr)
+ return nullptr;
+ new_file = CreateFile(new_path, Mode::Write);
+ if (new_file == nullptr)
+ return nullptr;
+ if (!VfsRawCopy(old_file, new_file))
+ return nullptr;
+ return new_file;
+}
+
+VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view new_path) {
+ const auto sanitized_old_path = FileUtil::SanitizePath(old_path);
+ const auto sanitized_new_path = FileUtil::SanitizePath(new_path);
+
+ // Again, non-default impls are highly encouraged to provide a more optimized version of this.
+ auto out = CopyFile(sanitized_old_path, sanitized_new_path);
+ if (out == nullptr)
+ return nullptr;
+ if (DeleteFile(sanitized_old_path))
+ return out;
+ return nullptr;
+}
+
+bool VfsFilesystem::DeleteFile(std::string_view path_) {
+ const auto path = FileUtil::SanitizePath(path_);
+ auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
+ if (parent == nullptr)
+ return false;
+ return parent->DeleteFile(FileUtil::GetFilename(path));
+}
+
+VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
+ const auto path = FileUtil::SanitizePath(path_);
+ return root->GetDirectoryRelative(path);
+}
+
+VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
+ const auto path = FileUtil::SanitizePath(path_);
+ return root->CreateDirectoryRelative(path);
+}
+
+VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) {
+ const auto old_path = FileUtil::SanitizePath(old_path_);
+ const auto new_path = FileUtil::SanitizePath(new_path_);
+
+ // Non-default impls are highly encouraged to provide a more optimized version of this.
+ auto old_dir = OpenDirectory(old_path, Mode::Read);
+ if (old_dir == nullptr)
+ return nullptr;
+ auto new_dir = OpenDirectory(new_path, Mode::Read);
+ if (new_dir != nullptr)
+ return nullptr;
+ new_dir = CreateDirectory(new_path, Mode::Write);
+ if (new_dir == nullptr)
+ return nullptr;
+
+ for (const auto& file : old_dir->GetFiles()) {
+ const auto x =
+ CopyFile(old_path + DIR_SEP + file->GetName(), new_path + DIR_SEP + file->GetName());
+ if (x == nullptr)
+ return nullptr;
+ }
+
+ for (const auto& dir : old_dir->GetSubdirectories()) {
+ const auto x =
+ CopyDirectory(old_path + DIR_SEP + dir->GetName(), new_path + DIR_SEP + dir->GetName());
+ if (x == nullptr)
+ return nullptr;
+ }
+
+ return new_dir;
+}
+
+VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_view new_path) {
+ const auto sanitized_old_path = FileUtil::SanitizePath(old_path);
+ const auto sanitized_new_path = FileUtil::SanitizePath(new_path);
+
+ // Non-default impls are highly encouraged to provide a more optimized version of this.
+ auto out = CopyDirectory(sanitized_old_path, sanitized_new_path);
+ if (out == nullptr)
+ return nullptr;
+ if (DeleteDirectory(sanitized_old_path))
+ return out;
+ return nullptr;
+}
+
+bool VfsFilesystem::DeleteDirectory(std::string_view path_) {
+ const auto path = FileUtil::SanitizePath(path_);
+ auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
+ if (parent == nullptr)
+ return false;
+ return parent->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path));
+}
+
VfsFile::~VfsFile() = default;
std::string VfsFile::GetExtension() const {
@@ -46,6 +194,13 @@ size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) {
return Write(data.data(), data.size(), offset);
}
+std::string VfsFile::GetFullPath() const {
+ if (GetContainingDirectory() == nullptr)
+ return "/" + GetName();
+
+ return GetContainingDirectory()->GetFullPath() + "/" + GetName();
+}
+
std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const {
auto vec = FileUtil::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
@@ -243,6 +398,13 @@ bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize();
}
+std::string VfsDirectory::GetFullPath() const {
+ if (IsRoot())
+ return GetName();
+
+ return GetParentDirectory()->GetFullPath() + "/" + GetName();
+}
+
bool ReadOnlyVfsDirectory::IsWritable() const {
return false;
}
@@ -270,4 +432,33 @@ bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
bool ReadOnlyVfsDirectory::Rename(std::string_view name) {
return false;
}
+
+bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size) {
+ if (file1->GetSize() != file2->GetSize())
+ return false;
+
+ std::vector<u8> f1_v(block_size);
+ std::vector<u8> f2_v(block_size);
+ for (size_t i = 0; i < file1->GetSize(); i += block_size) {
+ auto f1_vs = file1->Read(f1_v.data(), block_size, i);
+ auto f2_vs = file2->Read(f2_v.data(), block_size, i);
+
+ if (f1_vs != f2_vs)
+ return false;
+ auto iters = std::mismatch(f1_v.begin(), f1_v.end(), f2_v.begin(), f2_v.end());
+ if (iters.first != f1_v.end() && iters.second != f2_v.end())
+ return false;
+ }
+
+ return true;
+}
+
+bool VfsRawCopy(VirtualFile src, VirtualFile dest) {
+ if (src == nullptr || dest == nullptr)
+ return false;
+ if (!dest->Resize(src->GetSize()))
+ return false;
+ std::vector<u8> data = src->ReadAllBytes();
+ return dest->WriteBytes(data, 0) == data.size();
+}
} // namespace FileSys
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 4a13b8378..78a63c59b 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -11,17 +11,79 @@
#include <vector>
#include "boost/optional.hpp"
#include "common/common_types.h"
+#include "core/file_sys/mode.h"
namespace FileSys {
-struct VfsFile;
-struct VfsDirectory;
-// Convenience typedefs to use VfsDirectory and VfsFile
-using VirtualDir = std::shared_ptr<FileSys::VfsDirectory>;
-using VirtualFile = std::shared_ptr<FileSys::VfsFile>;
+class VfsDirectory;
+class VfsFile;
+class VfsFilesystem;
+
+// Convenience typedefs to use Vfs* interfaces
+using VirtualFilesystem = std::shared_ptr<VfsFilesystem>;
+using VirtualDir = std::shared_ptr<VfsDirectory>;
+using VirtualFile = std::shared_ptr<VfsFile>;
+
+// An enumeration representing what can be at the end of a path in a VfsFilesystem
+enum class VfsEntryType {
+ None,
+ File,
+ Directory,
+};
+
+// A class representing an abstract filesystem. A default implementation given the root VirtualDir
+// is provided for convenience, but if the Vfs implementation has any additional state or
+// functionality, they will need to override.
+class VfsFilesystem : NonCopyable {
+public:
+ explicit VfsFilesystem(VirtualDir root);
+ virtual ~VfsFilesystem();
+
+ // Gets the friendly name for the filesystem.
+ virtual std::string GetName() const;
+
+ // Return whether or not the user has read permissions on this filesystem.
+ virtual bool IsReadable() const;
+ // Return whether or not the user has write permission on this filesystem.
+ virtual bool IsWritable() const;
+
+ // Determine if the entry at path is non-existant, a file, or a directory.
+ virtual VfsEntryType GetEntryType(std::string_view path) const;
+
+ // Opens the file with path relative to root. If it doesn't exist, returns nullptr.
+ virtual VirtualFile OpenFile(std::string_view path, Mode perms);
+ // Creates a new, empty file at path
+ virtual VirtualFile CreateFile(std::string_view path, Mode perms);
+ // Copies the file from old_path to new_path, returning the new file on success and nullptr on
+ // failure.
+ virtual VirtualFile CopyFile(std::string_view old_path, std::string_view new_path);
+ // Moves the file from old_path to new_path, returning the moved file on success and nullptr on
+ // failure.
+ virtual VirtualFile MoveFile(std::string_view old_path, std::string_view new_path);
+ // Deletes the file with path relative to root, returing true on success.
+ virtual bool DeleteFile(std::string_view path);
+
+ // Opens the directory with path relative to root. If it doesn't exist, returns nullptr.
+ virtual VirtualDir OpenDirectory(std::string_view path, Mode perms);
+ // Creates a new, empty directory at path
+ virtual VirtualDir CreateDirectory(std::string_view path, Mode perms);
+ // Copies the directory from old_path to new_path, returning the new directory on success and
+ // nullptr on failure.
+ virtual VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path);
+ // Moves the directory from old_path to new_path, returning the moved directory on success and
+ // nullptr on failure.
+ virtual VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path);
+ // Deletes the directory with path relative to root, returing true on success.
+ virtual bool DeleteDirectory(std::string_view path);
+
+protected:
+ // Root directory in default implementation.
+ VirtualDir root;
+};
// A class representing a file in an abstract filesystem.
-struct VfsFile : NonCopyable {
+class VfsFile : NonCopyable {
+public:
virtual ~VfsFile();
// Retrieves the file name.
@@ -113,10 +175,14 @@ struct VfsFile : NonCopyable {
// Renames the file to name. Returns whether or not the operation was successsful.
virtual bool Rename(std::string_view name) = 0;
+
+ // Returns the full path of this file as a string, recursively
+ virtual std::string GetFullPath() const;
};
// A class representing a directory in an abstract filesystem.
-struct VfsDirectory : NonCopyable {
+class VfsDirectory : NonCopyable {
+public:
virtual ~VfsDirectory();
// Retrives the file located at path as if the current directory was root. Returns nullptr if
@@ -213,6 +279,17 @@ struct VfsDirectory : NonCopyable {
return ReplaceFileWithSubdirectory(file_p, std::make_shared<Directory>(file_p));
}
+ bool InterpretAsDirectory(const std::function<VirtualDir(VirtualFile)>& function,
+ const std::string& file) {
+ auto file_p = GetFile(file);
+ if (file_p == nullptr)
+ return false;
+ return ReplaceFileWithSubdirectory(file_p, function(file_p));
+ }
+
+ // Returns the full path of this directory as a string, recursively
+ virtual std::string GetFullPath() const;
+
protected:
// Backend for InterpretAsDirectory.
// Removes all references to file and adds a reference to dir in the directory's implementation.
@@ -221,7 +298,8 @@ protected:
// A convenience partial-implementation of VfsDirectory that stubs out methods that should only work
// if writable. This is to avoid redundant empty methods everywhere.
-struct ReadOnlyVfsDirectory : public VfsDirectory {
+class ReadOnlyVfsDirectory : public VfsDirectory {
+public:
bool IsWritable() const override;
bool IsReadable() const override;
std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
@@ -230,4 +308,13 @@ struct ReadOnlyVfsDirectory : public VfsDirectory {
bool DeleteFile(std::string_view name) override;
bool Rename(std::string_view name) override;
};
+
+// Compare the two files, byte-for-byte, in increments specificed by block_size
+bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x200);
+
+// A method that copies the raw data between two different implementations of VirtualFile. If you
+// are using the same implementation, it is probably better to use the Copy method in the parent
+// directory of src/dest.
+bool VfsRawCopy(VirtualFile src, VirtualFile dest);
+
} // namespace FileSys
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
new file mode 100644
index 000000000..e6bf586a3
--- /dev/null
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -0,0 +1,94 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <utility>
+
+#include "core/file_sys/vfs_concat.h"
+
+namespace FileSys {
+
+VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) {
+ if (files.empty())
+ return nullptr;
+ if (files.size() == 1)
+ return files[0];
+
+ return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
+}
+
+ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name)
+ : name(std::move(name)) {
+ size_t next_offset = 0;
+ for (const auto& file : files_) {
+ files[next_offset] = file;
+ next_offset += file->GetSize();
+ }
+}
+
+std::string ConcatenatedVfsFile::GetName() const {
+ if (files.empty())
+ return "";
+ if (!name.empty())
+ return name;
+ return files.begin()->second->GetName();
+}
+
+size_t ConcatenatedVfsFile::GetSize() const {
+ if (files.empty())
+ return 0;
+ return files.rbegin()->first + files.rbegin()->second->GetSize();
+}
+
+bool ConcatenatedVfsFile::Resize(size_t new_size) {
+ return false;
+}
+
+std::shared_ptr<VfsDirectory> ConcatenatedVfsFile::GetContainingDirectory() const {
+ if (files.empty())
+ return nullptr;
+ return files.begin()->second->GetContainingDirectory();
+}
+
+bool ConcatenatedVfsFile::IsWritable() const {
+ return false;
+}
+
+bool ConcatenatedVfsFile::IsReadable() const {
+ return true;
+}
+
+size_t ConcatenatedVfsFile::Read(u8* data, size_t length, size_t offset) const {
+ auto entry = files.end();
+ for (auto iter = files.begin(); iter != files.end(); ++iter) {
+ if (iter->first > offset) {
+ entry = --iter;
+ break;
+ }
+ }
+
+ // Check if the entry should be the last one. The loop above will make it end().
+ if (entry == files.end() && offset < files.rbegin()->first + files.rbegin()->second->GetSize())
+ --entry;
+
+ if (entry == files.end())
+ return 0;
+
+ const auto remaining = entry->second->GetSize() + offset - entry->first;
+ if (length > remaining) {
+ return entry->second->Read(data, remaining, offset - entry->first) +
+ Read(data + remaining, length - remaining, offset + remaining);
+ }
+
+ return entry->second->Read(data, length, offset - entry->first);
+}
+
+size_t ConcatenatedVfsFile::Write(const u8* data, size_t length, size_t offset) {
+ return 0;
+}
+
+bool ConcatenatedVfsFile::Rename(std::string_view name) {
+ return false;
+}
+} // namespace FileSys
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
new file mode 100644
index 000000000..686d32515
--- /dev/null
+++ b/src/core/file_sys/vfs_concat.h
@@ -0,0 +1,41 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string_view>
+#include <boost/container/flat_map.hpp>
+#include "core/file_sys/vfs.h"
+
+namespace FileSys {
+
+// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
+VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name = "");
+
+// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
+// read-only.
+class ConcatenatedVfsFile : public VfsFile {
+ friend VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name);
+
+ ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name);
+
+public:
+ std::string GetName() const override;
+ size_t GetSize() const override;
+ bool Resize(size_t new_size) override;
+ std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
+ bool IsWritable() const override;
+ bool IsReadable() const override;
+ size_t Read(u8* data, size_t length, size_t offset) const override;
+ size_t Write(const u8* data, size_t length, size_t offset) override;
+ bool Rename(std::string_view name) override;
+
+private:
+ // Maps starting offset to file -- more efficient.
+ boost::container::flat_map<u64, VirtualFile> files;
+ std::string name;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index a40331cef..847cde2f5 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -10,8 +10,9 @@
namespace FileSys {
OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, size_t size_, size_t offset_,
- std::string name_)
- : file(std::move(file_)), offset(offset_), size(size_), name(std::move(name_)) {}
+ std::string name_, VirtualDir parent_)
+ : file(file_), offset(offset_), size(size_), name(std::move(name_)),
+ parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {}
std::string OffsetVfsFile::GetName() const {
return name.empty() ? file->GetName() : name;
@@ -35,7 +36,7 @@ bool OffsetVfsFile::Resize(size_t new_size) {
}
std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const {
- return file->GetContainingDirectory();
+ return parent;
}
bool OffsetVfsFile::IsWritable() const {
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index 4f471e3ba..cb92d1570 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -15,9 +15,10 @@ namespace FileSys {
// Similar to seeking to an offset.
// If the file is writable, operations that would write past the end of the offset file will expand
// the size of this wrapper.
-struct OffsetVfsFile : public VfsFile {
+class OffsetVfsFile : public VfsFile {
+public:
OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0,
- std::string new_name = "");
+ std::string new_name = "", VirtualDir new_parent = nullptr);
std::string GetName() const override;
size_t GetSize() const override;
@@ -44,6 +45,7 @@ private:
size_t offset;
size_t size;
std::string name;
+ VirtualDir parent;
};
} // namespace FileSys
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 9ce2e1efa..0afe515f0 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -6,7 +6,7 @@
#include <cstddef>
#include <iterator>
#include <utility>
-
+#include "common/assert.h"
#include "common/common_paths.h"
#include "common/logging/log.h"
#include "core/file_sys/vfs_real.h"
@@ -29,6 +29,8 @@ static std::string ModeFlagsToString(Mode mode) {
mode_str = "a";
else if (mode & Mode::Write)
mode_str = "w";
+ else
+ UNREACHABLE_MSG("Invalid file open mode: {:02X}", static_cast<u8>(mode));
}
mode_str += "b";
@@ -36,8 +38,182 @@ static std::string ModeFlagsToString(Mode mode) {
return mode_str;
}
-RealVfsFile::RealVfsFile(const std::string& path_, Mode perms_)
- : backing(path_, ModeFlagsToString(perms_).c_str()), path(path_),
+RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {}
+
+std::string RealVfsFilesystem::GetName() const {
+ return "Real";
+}
+
+bool RealVfsFilesystem::IsReadable() const {
+ return true;
+}
+
+bool RealVfsFilesystem::IsWritable() const {
+ return true;
+}
+
+VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
+ const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
+ if (!FileUtil::Exists(path))
+ return VfsEntryType::None;
+ if (FileUtil::IsDirectory(path))
+ return VfsEntryType::Directory;
+
+ return VfsEntryType::File;
+}
+
+VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
+ const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
+ if (cache.find(path) != cache.end()) {
+ auto weak = cache[path];
+ if (!weak.expired()) {
+ return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms));
+ }
+ }
+
+ if (!FileUtil::Exists(path) && (perms & Mode::WriteAppend) != 0)
+ FileUtil::CreateEmptyFile(path);
+
+ auto backing = std::make_shared<FileUtil::IOFile>(path, ModeFlagsToString(perms).c_str());
+ cache[path] = backing;
+
+ // Cannot use make_shared as RealVfsFile constructor is private
+ return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms));
+}
+
+VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
+ const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
+ const auto path_fwd = FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash);
+ if (!FileUtil::Exists(path)) {
+ FileUtil::CreateFullPath(path_fwd);
+ if (!FileUtil::CreateEmptyFile(path))
+ return nullptr;
+ }
+ return OpenFile(path, perms);
+}
+
+VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
+ const auto old_path =
+ FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
+ const auto new_path =
+ FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
+
+ if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
+ FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path))
+ return nullptr;
+ return OpenFile(new_path, Mode::ReadWrite);
+}
+
+VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
+ const auto old_path =
+ FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
+ const auto new_path =
+ FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
+
+ if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
+ FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
+ return nullptr;
+
+ if (cache.find(old_path) != cache.end()) {
+ auto cached = cache[old_path];
+ if (!cached.expired()) {
+ auto file = cached.lock();
+ file->Open(new_path, "r+b");
+ cache.erase(old_path);
+ cache[new_path] = file;
+ }
+ }
+ return OpenFile(new_path, Mode::ReadWrite);
+}
+
+bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
+ const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
+ if (cache.find(path) != cache.end()) {
+ if (!cache[path].expired())
+ cache[path].lock()->Close();
+ cache.erase(path);
+ }
+ return FileUtil::Delete(path);
+}
+
+VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
+ const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
+ // Cannot use make_shared as RealVfsDirectory constructor is private
+ return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
+}
+
+VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
+ const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
+ const auto path_fwd = FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash);
+ if (!FileUtil::Exists(path)) {
+ FileUtil::CreateFullPath(path_fwd);
+ if (!FileUtil::CreateDir(path))
+ return nullptr;
+ }
+ // Cannot use make_shared as RealVfsDirectory constructor is private
+ return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
+}
+
+VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_,
+ std::string_view new_path_) {
+ const auto old_path =
+ FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
+ const auto new_path =
+ FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
+ if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
+ !FileUtil::IsDirectory(old_path))
+ return nullptr;
+ FileUtil::CopyDir(old_path, new_path);
+ return OpenDirectory(new_path, Mode::ReadWrite);
+}
+
+VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
+ std::string_view new_path_) {
+ const auto old_path =
+ FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
+ const auto new_path =
+ FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
+ if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
+ FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
+ return nullptr;
+
+ for (auto& kv : cache) {
+ // Path in cache starts with old_path
+ if (kv.first.rfind(old_path, 0) == 0) {
+ const auto file_old_path =
+ FileUtil::SanitizePath(kv.first, FileUtil::DirectorySeparator::PlatformDefault);
+ const auto file_new_path =
+ FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
+ FileUtil::DirectorySeparator::PlatformDefault);
+ auto cached = cache[file_old_path];
+ if (!cached.expired()) {
+ auto file = cached.lock();
+ file->Open(file_new_path, "r+b");
+ cache.erase(file_old_path);
+ cache[file_new_path] = file;
+ }
+ }
+ }
+
+ return OpenDirectory(new_path, Mode::ReadWrite);
+}
+
+bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
+ const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
+ for (auto& kv : cache) {
+ // Path in cache starts with old_path
+ if (kv.first.rfind(path, 0) == 0) {
+ if (!cache[kv.first].expired())
+ cache[kv.first].lock()->Close();
+ cache.erase(kv.first);
+ }
+ }
+ return FileUtil::DeleteDirRecursively(path);
+}
+
+RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FileUtil::IOFile> backing_,
+ const std::string& path_, Mode perms_)
+ : base(base_), backing(std::move(backing_)), path(path_),
parent_path(FileUtil::GetParentPath(path_)),
path_components(FileUtil::SplitPathComponents(path_)),
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
@@ -48,15 +224,15 @@ std::string RealVfsFile::GetName() const {
}
size_t RealVfsFile::GetSize() const {
- return backing.GetSize();
+ return backing->GetSize();
}
bool RealVfsFile::Resize(size_t new_size) {
- return backing.Resize(new_size);
+ return backing->Resize(new_size);
}
std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
- return std::make_shared<RealVfsDirectory>(parent_path, perms);
+ return base.OpenDirectory(parent_path, perms);
}
bool RealVfsFile::IsWritable() const {
@@ -68,62 +244,118 @@ bool RealVfsFile::IsReadable() const {
}
size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const {
- if (!backing.Seek(offset, SEEK_SET))
+ if (!backing->Seek(offset, SEEK_SET))
return 0;
- return backing.ReadBytes(data, length);
+ return backing->ReadBytes(data, length);
}
size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) {
- if (!backing.Seek(offset, SEEK_SET))
+ if (!backing->Seek(offset, SEEK_SET))
return 0;
- return backing.WriteBytes(data, length);
+ return backing->WriteBytes(data, length);
}
bool RealVfsFile::Rename(std::string_view name) {
- std::string name_str(name.begin(), name.end());
- const auto out = FileUtil::Rename(GetName(), name_str);
+ return base.MoveFile(path, parent_path + DIR_SEP + std::string(name)) != nullptr;
+}
+
+bool RealVfsFile::Close() {
+ return backing->Close();
+}
- path = (parent_path + DIR_SEP).append(name);
- path_components = parent_components;
- path_components.push_back(std::move(name_str));
- backing = FileUtil::IOFile(path, ModeFlagsToString(perms).c_str());
+// TODO(DarkLordZach): MSVC would not let me combine the following two functions using 'if
+// constexpr' because there is a compile error in the branch not used.
+
+template <>
+std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const {
+ if (perms == Mode::Append)
+ return {};
+
+ std::vector<VirtualFile> out;
+ FileUtil::ForeachDirectoryEntry(
+ nullptr, path,
+ [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
+ const std::string full_path = directory + DIR_SEP + filename;
+ if (!FileUtil::IsDirectory(full_path))
+ out.emplace_back(base.OpenFile(full_path, perms));
+ return true;
+ });
return out;
}
-bool RealVfsFile::Close() {
- return backing.Close();
+template <>
+std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const {
+ if (perms == Mode::Append)
+ return {};
+
+ std::vector<VirtualDir> out;
+ FileUtil::ForeachDirectoryEntry(
+ nullptr, path,
+ [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
+ const std::string full_path = directory + DIR_SEP + filename;
+ if (FileUtil::IsDirectory(full_path))
+ out.emplace_back(base.OpenDirectory(full_path, perms));
+ return true;
+ });
+
+ return out;
}
-RealVfsDirectory::RealVfsDirectory(const std::string& path_, Mode perms_)
- : path(FileUtil::RemoveTrailingSlash(path_)), parent_path(FileUtil::GetParentPath(path)),
+RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_)
+ : base(base_), path(FileUtil::RemoveTrailingSlash(path_)),
+ parent_path(FileUtil::GetParentPath(path)),
path_components(FileUtil::SplitPathComponents(path)),
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
perms(perms_) {
if (!FileUtil::Exists(path) && perms & Mode::WriteAppend)
FileUtil::CreateDir(path);
+}
- if (perms == Mode::Append)
- return;
+std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const {
+ const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
+ if (!FileUtil::Exists(full_path) || FileUtil::IsDirectory(full_path))
+ return nullptr;
+ return base.OpenFile(full_path, perms);
+}
- FileUtil::ForeachDirectoryEntry(
- nullptr, path,
- [this](u64* entries_out, const std::string& directory, const std::string& filename) {
- std::string full_path = directory + DIR_SEP + filename;
- if (FileUtil::IsDirectory(full_path))
- subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(full_path, perms));
- else
- files.emplace_back(std::make_shared<RealVfsFile>(full_path, perms));
- return true;
- });
+std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
+ const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
+ if (!FileUtil::Exists(full_path) || !FileUtil::IsDirectory(full_path))
+ return nullptr;
+ return base.OpenDirectory(full_path, perms);
+}
+
+std::shared_ptr<VfsFile> RealVfsDirectory::GetFile(std::string_view name) const {
+ return GetFileRelative(name);
+}
+
+std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view name) const {
+ return GetDirectoryRelative(name);
+}
+
+std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) {
+ const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
+ return base.CreateFile(full_path, perms);
+}
+
+std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
+ const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
+ auto parent = std::string(FileUtil::GetParentPath(full_path));
+ return base.CreateDirectory(full_path, perms);
+}
+
+bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
+ auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(name));
+ return base.DeleteDirectory(full_path);
}
std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const {
- return files;
+ return IterateEntries<RealVfsFile, VfsFile>();
}
std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const {
- return subdirectories;
+ return IterateEntries<RealVfsDirectory, VfsDirectory>();
}
bool RealVfsDirectory::IsWritable() const {
@@ -142,70 +374,41 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
if (path_components.size() <= 1)
return nullptr;
- return std::make_shared<RealVfsDirectory>(parent_path, perms);
+ return base.OpenDirectory(parent_path, perms);
}
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) {
const std::string subdir_path = (path + DIR_SEP).append(name);
-
- if (!FileUtil::CreateDir(subdir_path)) {
- return nullptr;
- }
-
- subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(subdir_path, perms));
- return subdirectories.back();
+ return base.CreateDirectory(subdir_path, perms);
}
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) {
const std::string file_path = (path + DIR_SEP).append(name);
-
- if (!FileUtil::CreateEmptyFile(file_path)) {
- return nullptr;
- }
-
- files.emplace_back(std::make_shared<RealVfsFile>(file_path, perms));
- return files.back();
+ return base.CreateFile(file_path, perms);
}
bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) {
const std::string subdir_path = (path + DIR_SEP).append(name);
-
- return FileUtil::DeleteDirRecursively(subdir_path);
+ return base.DeleteDirectory(subdir_path);
}
bool RealVfsDirectory::DeleteFile(std::string_view name) {
- const auto file = GetFile(name);
-
- if (file == nullptr) {
- return false;
- }
-
- files.erase(std::find(files.begin(), files.end(), file));
-
- auto real_file = std::static_pointer_cast<RealVfsFile>(file);
- real_file->Close();
-
const std::string file_path = (path + DIR_SEP).append(name);
- return FileUtil::Delete(file_path);
+ return base.DeleteFile(file_path);
}
bool RealVfsDirectory::Rename(std::string_view name) {
const std::string new_name = (parent_path + DIR_SEP).append(name);
+ return base.MoveFile(path, new_name) != nullptr;
+}
- return FileUtil::Rename(path, new_name);
+std::string RealVfsDirectory::GetFullPath() const {
+ auto out = path;
+ std::replace(out.begin(), out.end(), '\\', '/');
+ return out;
}
bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
- const auto iter = std::find(files.begin(), files.end(), file);
- if (iter == files.end())
- return false;
-
- const std::ptrdiff_t offset = std::distance(files.begin(), iter);
- files[offset] = files.back();
- files.pop_back();
-
- subdirectories.emplace_back(std::move(dir));
-
- return true;
+ return false;
}
} // namespace FileSys
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index 2151211c9..989803d43 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -5,19 +5,45 @@
#pragma once
#include <string_view>
-
+#include <boost/container/flat_map.hpp>
#include "common/file_util.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/vfs.h"
namespace FileSys {
+class RealVfsFilesystem : public VfsFilesystem {
+public:
+ RealVfsFilesystem();
+
+ std::string GetName() const override;
+ bool IsReadable() const override;
+ bool IsWritable() const override;
+ VfsEntryType GetEntryType(std::string_view path) const override;
+ VirtualFile OpenFile(std::string_view path, Mode perms = Mode::Read) override;
+ VirtualFile CreateFile(std::string_view path, Mode perms = Mode::ReadWrite) override;
+ VirtualFile CopyFile(std::string_view old_path, std::string_view new_path) override;
+ VirtualFile MoveFile(std::string_view old_path, std::string_view new_path) override;
+ bool DeleteFile(std::string_view path) override;
+ VirtualDir OpenDirectory(std::string_view path, Mode perms = Mode::Read) override;
+ VirtualDir CreateDirectory(std::string_view path, Mode perms = Mode::ReadWrite) override;
+ VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path) override;
+ VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path) override;
+ bool DeleteDirectory(std::string_view path) override;
+
+private:
+ boost::container::flat_map<std::string, std::weak_ptr<FileUtil::IOFile>> cache;
+};
+
// An implmentation of VfsFile that represents a file on the user's computer.
-struct RealVfsFile : public VfsFile {
- friend struct RealVfsDirectory;
+class RealVfsFile : public VfsFile {
+ friend class RealVfsDirectory;
+ friend class RealVfsFilesystem;
- RealVfsFile(const std::string& name, Mode perms = Mode::Read);
+ RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<FileUtil::IOFile> backing,
+ const std::string& path, Mode perms = Mode::Read);
+public:
std::string GetName() const override;
size_t GetSize() const override;
bool Resize(size_t new_size) override;
@@ -31,7 +57,8 @@ struct RealVfsFile : public VfsFile {
private:
bool Close();
- FileUtil::IOFile backing;
+ RealVfsFilesystem& base;
+ std::shared_ptr<FileUtil::IOFile> backing;
std::string path;
std::string parent_path;
std::vector<std::string> path_components;
@@ -40,9 +67,19 @@ private:
};
// An implementation of VfsDirectory that represents a directory on the user's computer.
-struct RealVfsDirectory : public VfsDirectory {
- RealVfsDirectory(const std::string& path, Mode perms);
+class RealVfsDirectory : public VfsDirectory {
+ friend class RealVfsFilesystem;
+ RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read);
+
+public:
+ std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override;
+ std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override;
+ std::shared_ptr<VfsFile> GetFile(std::string_view name) const override;
+ std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override;
+ std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
+ std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
+ bool DeleteSubdirectoryRecursive(std::string_view name) override;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
bool IsWritable() const override;
@@ -54,18 +91,21 @@ struct RealVfsDirectory : public VfsDirectory {
bool DeleteSubdirectory(std::string_view name) override;
bool DeleteFile(std::string_view name) override;
bool Rename(std::string_view name) override;
+ std::string GetFullPath() const override;
protected:
bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
private:
+ template <typename T, typename R>
+ std::vector<std::shared_ptr<R>> IterateEntries() const;
+
+ RealVfsFilesystem& base;
std::string path;
std::string parent_path;
std::vector<std::string> path_components;
std::vector<std::string> parent_components;
Mode perms;
- std::vector<std::shared_ptr<VfsFile>> files;
- std::vector<std::shared_ptr<VfsDirectory>> subdirectories;
};
} // namespace FileSys
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
new file mode 100644
index 000000000..98e7c4598
--- /dev/null
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -0,0 +1,86 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <utility>
+#include "core/file_sys/vfs_vector.h"
+
+namespace FileSys {
+VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
+ std::vector<VirtualDir> dirs_, std::string name_,
+ VirtualDir parent_)
+ : files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)),
+ name(std::move(name_)) {}
+
+std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const {
+ return files;
+}
+
+std::vector<std::shared_ptr<VfsDirectory>> VectorVfsDirectory::GetSubdirectories() const {
+ return dirs;
+}
+
+bool VectorVfsDirectory::IsWritable() const {
+ return false;
+}
+
+bool VectorVfsDirectory::IsReadable() const {
+ return true;
+}
+
+std::string VectorVfsDirectory::GetName() const {
+ return name;
+}
+
+std::shared_ptr<VfsDirectory> VectorVfsDirectory::GetParentDirectory() const {
+ return parent;
+}
+
+template <typename T>
+static bool FindAndRemoveVectorElement(std::vector<T>& vec, std::string_view name) {
+ const auto iter =
+ std::find_if(vec.begin(), vec.end(), [name](const T& e) { return e->GetName() == name; });
+ if (iter == vec.end())
+ return false;
+
+ vec.erase(iter);
+ return true;
+}
+
+bool VectorVfsDirectory::DeleteSubdirectory(std::string_view name) {
+ return FindAndRemoveVectorElement(dirs, name);
+}
+
+bool VectorVfsDirectory::DeleteFile(std::string_view name) {
+ return FindAndRemoveVectorElement(files, name);
+}
+
+bool VectorVfsDirectory::Rename(std::string_view name_) {
+ name = name_;
+ return true;
+}
+
+std::shared_ptr<VfsDirectory> VectorVfsDirectory::CreateSubdirectory(std::string_view name) {
+ return nullptr;
+}
+
+std::shared_ptr<VfsFile> VectorVfsDirectory::CreateFile(std::string_view name) {
+ return nullptr;
+}
+
+void VectorVfsDirectory::AddFile(VirtualFile file) {
+ files.push_back(std::move(file));
+}
+
+void VectorVfsDirectory::AddDirectory(VirtualDir dir) {
+ dirs.push_back(std::move(dir));
+}
+
+bool VectorVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
+ if (!DeleteFile(file->GetName()))
+ return false;
+ dirs.emplace_back(std::move(dir));
+ return true;
+}
+} // namespace FileSys
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
new file mode 100644
index 000000000..179f62e4b
--- /dev/null
+++ b/src/core/file_sys/vfs_vector.h
@@ -0,0 +1,45 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/file_sys/vfs.h"
+
+namespace FileSys {
+
+// An implementation of VfsDirectory that maintains two vectors for subdirectories and files.
+// Vector data is supplied upon construction.
+class VectorVfsDirectory : public VfsDirectory {
+public:
+ explicit VectorVfsDirectory(std::vector<VirtualFile> files = {},
+ std::vector<VirtualDir> dirs = {}, std::string name = "",
+ VirtualDir parent = nullptr);
+
+ std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
+ std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
+ bool IsWritable() const override;
+ bool IsReadable() const override;
+ std::string GetName() const override;
+ std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
+ bool DeleteSubdirectory(std::string_view name) override;
+ bool DeleteFile(std::string_view name) override;
+ bool Rename(std::string_view name) override;
+ std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
+ std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
+
+ virtual void AddFile(VirtualFile file);
+ virtual void AddDirectory(VirtualDir dir);
+
+protected:
+ bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
+
+private:
+ std::vector<VirtualFile> files;
+ std::vector<VirtualDir> dirs;
+
+ VirtualDir parent;
+ std::string name;
+};
+
+} // namespace FileSys
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 2d776c693..9dd493efb 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -8,6 +8,8 @@
#include "core/frontend/input.h"
#include "core/settings.h"
+namespace Core::Frontend {
+
class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>,
public std::enable_shared_from_this<TouchState> {
public:
@@ -108,3 +110,5 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height));
}
+
+} // namespace Core::Frontend
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index e8c29adfb..7006a37b3 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -10,6 +10,8 @@
#include "common/common_types.h"
#include "core/frontend/framebuffer_layout.h"
+namespace Core::Frontend {
+
/**
* Abstraction class used to provide an interface between emulation code and the frontend
* (e.g. SDL, QGLWidget, GLFW, etc...).
@@ -32,9 +34,9 @@ class EmuWindow {
public:
/// Data structure to store emuwindow configuration
struct WindowConfig {
- bool fullscreen;
- int res_width;
- int res_height;
+ bool fullscreen = false;
+ int res_width = 0;
+ int res_height = 0;
std::pair<unsigned, unsigned> min_client_area_size;
};
@@ -166,3 +168,5 @@ private:
*/
std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
};
+
+} // namespace Core::Frontend
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 5ca573652..332e5c3d0 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -37,45 +37,46 @@
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/gdbstub/gdbstub.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/scheduler.h"
#include "core/loader/loader.h"
#include "core/memory.h"
-const int GDB_BUFFER_SIZE = 10000;
+namespace GDBStub {
+namespace {
+constexpr int GDB_BUFFER_SIZE = 10000;
-const char GDB_STUB_START = '$';
-const char GDB_STUB_END = '#';
-const char GDB_STUB_ACK = '+';
-const char GDB_STUB_NACK = '-';
+constexpr char GDB_STUB_START = '$';
+constexpr char GDB_STUB_END = '#';
+constexpr char GDB_STUB_ACK = '+';
+constexpr char GDB_STUB_NACK = '-';
#ifndef SIGTRAP
-const u32 SIGTRAP = 5;
+constexpr u32 SIGTRAP = 5;
#endif
#ifndef SIGTERM
-const u32 SIGTERM = 15;
+constexpr u32 SIGTERM = 15;
#endif
#ifndef MSG_WAITALL
-const u32 MSG_WAITALL = 8;
+constexpr u32 MSG_WAITALL = 8;
#endif
-const u32 LR_REGISTER = 30;
-const u32 SP_REGISTER = 31;
-const u32 PC_REGISTER = 32;
-const u32 CPSR_REGISTER = 33;
-const u32 UC_ARM64_REG_Q0 = 34;
-const u32 FPSCR_REGISTER = 66;
+constexpr u32 LR_REGISTER = 30;
+constexpr u32 SP_REGISTER = 31;
+constexpr u32 PC_REGISTER = 32;
+constexpr u32 CPSR_REGISTER = 33;
+constexpr u32 UC_ARM64_REG_Q0 = 34;
+constexpr u32 FPSCR_REGISTER = 66;
// TODO/WiP - Used while working on support for FPU
-const u32 TODO_DUMMY_REG_997 = 997;
-const u32 TODO_DUMMY_REG_998 = 998;
+constexpr u32 TODO_DUMMY_REG_997 = 997;
+constexpr u32 TODO_DUMMY_REG_998 = 998;
// For sample XML files see the GDB source /gdb/features
// GDB also wants the l character at the start
// This XML defines what the registers are for this specific ARM device
-static const char* target_xml =
+constexpr char target_xml[] =
R"(l<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target version="1.0">
@@ -141,30 +142,28 @@ static const char* target_xml =
</target>
)";
-namespace GDBStub {
-
-static int gdbserver_socket = -1;
+int gdbserver_socket = -1;
-static u8 command_buffer[GDB_BUFFER_SIZE];
-static u32 command_length;
+u8 command_buffer[GDB_BUFFER_SIZE];
+u32 command_length;
-static u32 latest_signal = 0;
-static bool memory_break = false;
+u32 latest_signal = 0;
+bool memory_break = false;
-static Kernel::Thread* current_thread = nullptr;
-static u32 current_core = 0;
+Kernel::Thread* current_thread = nullptr;
+u32 current_core = 0;
// Binding to a port within the reserved ports range (0-1023) requires root permissions,
// so default to a port outside of that range.
-static u16 gdbstub_port = 24689;
+u16 gdbstub_port = 24689;
-static bool halt_loop = true;
-static bool step_loop = false;
-static bool send_trap = false;
+bool halt_loop = true;
+bool step_loop = false;
+bool send_trap = false;
// If set to false, the server will never be started and no
// gdbstub-related functions will be executed.
-static std::atomic<bool> server_enabled(false);
+std::atomic<bool> server_enabled(false);
#ifdef _WIN32
WSADATA InitData;
@@ -172,23 +171,26 @@ WSADATA InitData;
struct Breakpoint {
bool active;
- PAddr addr;
+ VAddr addr;
u64 len;
+ std::array<u8, 4> inst;
};
-static std::map<u64, Breakpoint> breakpoints_execute;
-static std::map<u64, Breakpoint> breakpoints_read;
-static std::map<u64, Breakpoint> breakpoints_write;
+using BreakpointMap = std::map<VAddr, Breakpoint>;
+BreakpointMap breakpoints_execute;
+BreakpointMap breakpoints_read;
+BreakpointMap breakpoints_write;
struct Module {
std::string name;
- PAddr beg;
- PAddr end;
+ VAddr beg;
+ VAddr end;
};
-static std::vector<Module> modules;
+std::vector<Module> modules;
+} // Anonymous namespace
-void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) {
+void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext) {
Module module;
if (add_elf_ext) {
Common::SplitPath(name, nullptr, &module.name, nullptr);
@@ -419,11 +421,11 @@ static u8 CalculateChecksum(const u8* buffer, size_t length) {
}
/**
- * Get the list of breakpoints for a given breakpoint type.
+ * Get the map of breakpoints for a given breakpoint type.
*
- * @param type Type of breakpoint list.
+ * @param type Type of breakpoint map.
*/
-static std::map<u64, Breakpoint>& GetBreakpointList(BreakpointType type) {
+static BreakpointMap& GetBreakpointMap(BreakpointType type) {
switch (type) {
case BreakpointType::Execute:
return breakpoints_execute;
@@ -442,20 +444,24 @@ static std::map<u64, Breakpoint>& GetBreakpointList(BreakpointType type) {
* @param type Type of breakpoint.
* @param addr Address of breakpoint.
*/
-static void RemoveBreakpoint(BreakpointType type, PAddr addr) {
- std::map<u64, Breakpoint>& p = GetBreakpointList(type);
+static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
+ BreakpointMap& p = GetBreakpointMap(type);
- auto bp = p.find(static_cast<u64>(addr));
- if (bp != p.end()) {
- LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}",
- bp->second.len, bp->second.addr, static_cast<int>(type));
- p.erase(static_cast<u64>(addr));
+ const auto bp = p.find(addr);
+ if (bp == p.end()) {
+ return;
}
+
+ LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}",
+ bp->second.len, bp->second.addr, static_cast<int>(type));
+ Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
+ Core::System::GetInstance().InvalidateCpuInstructionCaches();
+ p.erase(addr);
}
-BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type) {
- std::map<u64, Breakpoint>& p = GetBreakpointList(type);
- auto next_breakpoint = p.lower_bound(static_cast<u64>(addr));
+BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, BreakpointType type) {
+ const BreakpointMap& p = GetBreakpointMap(type);
+ const auto next_breakpoint = p.lower_bound(addr);
BreakpointAddress breakpoint;
if (next_breakpoint != p.end()) {
@@ -469,36 +475,38 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type)
return breakpoint;
}
-bool CheckBreakpoint(PAddr addr, BreakpointType type) {
+bool CheckBreakpoint(VAddr addr, BreakpointType type) {
if (!IsConnected()) {
return false;
}
- std::map<u64, Breakpoint>& p = GetBreakpointList(type);
+ const BreakpointMap& p = GetBreakpointMap(type);
+ const auto bp = p.find(addr);
- auto bp = p.find(static_cast<u64>(addr));
- if (bp != p.end()) {
- u64 len = bp->second.len;
+ if (bp == p.end()) {
+ return false;
+ }
- // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints
- // no matter if it's a 4-byte or 2-byte instruction. When you execute a
- // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on
- // two instructions instead of the single instruction you placed the breakpoint
- // on. So, as a way to make sure that execution breakpoints are only breaking
- // on the instruction that was specified, set the length of an execution
- // breakpoint to 1. This should be fine since the CPU should never begin executing
- // an instruction anywhere except the beginning of the instruction.
- if (type == BreakpointType::Execute) {
- len = 1;
- }
+ u64 len = bp->second.len;
- if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) {
- LOG_DEBUG(Debug_GDBStub,
- "Found breakpoint type {} @ {:016X}, range: {:016X}"
- " - {:016X} ({:X} bytes)",
- static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
- return true;
- }
+ // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints
+ // no matter if it's a 4-byte or 2-byte instruction. When you execute a
+ // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on
+ // two instructions instead of the single instruction you placed the breakpoint
+ // on. So, as a way to make sure that execution breakpoints are only breaking
+ // on the instruction that was specified, set the length of an execution
+ // breakpoint to 1. This should be fine since the CPU should never begin executing
+ // an instruction anywhere except the beginning of the instruction.
+ if (type == BreakpointType::Execute) {
+ len = 1;
+ }
+
+ if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) {
+ LOG_DEBUG(Debug_GDBStub,
+ "Found breakpoint type {} @ {:016X}, range: {:016X}"
+ " - {:016X} ({:X} bytes)",
+ static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
+ return true;
}
return false;
@@ -932,6 +940,7 @@ static void WriteMemory() {
GdbHexToMem(data.data(), len_pos + 1, len);
Memory::WriteBlock(addr, data.data(), len);
+ Core::System::GetInstance().InvalidateCpuInstructionCaches();
SendReply("OK");
}
@@ -951,6 +960,7 @@ static void Step() {
step_loop = true;
halt_loop = true;
send_trap = true;
+ Core::System::GetInstance().InvalidateCpuInstructionCaches();
}
/// Tell the CPU if we hit a memory breakpoint.
@@ -967,6 +977,7 @@ static void Continue() {
memory_break = false;
step_loop = false;
halt_loop = false;
+ Core::System::GetInstance().InvalidateCpuInstructionCaches();
}
/**
@@ -976,13 +987,17 @@ static void Continue() {
* @param addr Address of breakpoint.
* @param len Length of breakpoint.
*/
-static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) {
- std::map<u64, Breakpoint>& p = GetBreakpointList(type);
+static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
+ BreakpointMap& p = GetBreakpointMap(type);
Breakpoint breakpoint;
breakpoint.active = true;
breakpoint.addr = addr;
breakpoint.len = len;
+ Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
+ static constexpr std::array<u8, 4> btrap{{0xd4, 0x20, 0x7d, 0x0}};
+ Memory::WriteBlock(addr, btrap.data(), btrap.size());
+ Core::System::GetInstance().InvalidateCpuInstructionCaches();
p.insert({addr, breakpoint});
LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}",
@@ -1016,7 +1031,7 @@ static void AddBreakpoint() {
auto start_offset = command_buffer + 3;
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
- PAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
+ VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
start_offset = addr_pos + 1;
u64 len =
@@ -1065,7 +1080,7 @@ static void RemoveBreakpoint() {
auto start_offset = command_buffer + 3;
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
- PAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
+ VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
if (type == BreakpointType::Access) {
// Access is made up of Read and Write types, so add both breakpoints
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
index a6b50c26c..5a36524b2 100644
--- a/src/core/gdbstub/gdbstub.h
+++ b/src/core/gdbstub/gdbstub.h
@@ -22,7 +22,7 @@ enum class BreakpointType {
};
struct BreakpointAddress {
- PAddr address;
+ VAddr address;
BreakpointType type;
};
@@ -53,7 +53,7 @@ bool IsServerEnabled();
bool IsConnected();
/// Register module.
-void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext = true);
+void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext = true);
/**
* Signal to the gdbstub server that it should halt CPU execution.
@@ -74,7 +74,7 @@ void HandlePacket();
* @param addr Address to search from.
* @param type Type of breakpoint.
*/
-BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointType type);
+BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, GDBStub::BreakpointType type);
/**
* Check if a breakpoint of the specified type exists at the given address.
@@ -82,7 +82,7 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointTy
* @param addr Address of breakpoint.
* @param type Type of breakpoint.
*/
-bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type);
+bool CheckBreakpoint(VAddr addr, GDBStub::BreakpointType type);
/// If set to true, the CPU will halt at the beginning of the next CPU loop.
bool GetCpuHaltFlag();
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 7fb0da408..d3a734831 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -5,15 +5,18 @@
#pragma once
#include <array>
+#include <cstring>
+#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
+#include "common/assert.h"
+#include "common/common_types.h"
#include "core/hle/ipc.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
namespace IPC {
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 233fdab25..03a954a9f 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -2,15 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <vector>
+
#include "common/assert.h"
-#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/core.h"
#include "core/hle/kernel/errors.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
-#include "core/hle/lock.h"
+#include "core/hle/result.h"
#include "core/memory.h"
namespace Kernel {
@@ -30,9 +32,8 @@ static ResultCode WaitForAddress(VAddr address, s64 timeout) {
}
// Gets the threads waiting on an address.
-static void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>>& waiting_threads,
- VAddr address) {
- auto RetrieveWaitingThreads =
+static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) {
+ const auto RetrieveWaitingThreads =
[](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) {
const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
auto& thread_list = scheduler->GetThreadList();
@@ -43,16 +44,20 @@ static void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>>& waiting_t
}
};
- // Retrieve a list of all threads that are waiting for this address.
- RetrieveWaitingThreads(0, waiting_threads, address);
- RetrieveWaitingThreads(1, waiting_threads, address);
- RetrieveWaitingThreads(2, waiting_threads, address);
- RetrieveWaitingThreads(3, waiting_threads, address);
+ // Retrieve all threads that are waiting for this address.
+ std::vector<SharedPtr<Thread>> threads;
+ RetrieveWaitingThreads(0, threads, address);
+ RetrieveWaitingThreads(1, threads, address);
+ RetrieveWaitingThreads(2, threads, address);
+ RetrieveWaitingThreads(3, threads, address);
+
// Sort them by priority, such that the highest priority ones come first.
- std::sort(waiting_threads.begin(), waiting_threads.end(),
+ std::sort(threads.begin(), threads.end(),
[](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
return lhs->current_priority < rhs->current_priority;
});
+
+ return threads;
}
// Wake up num_to_wake (or all) threads in a vector.
@@ -74,9 +79,7 @@ static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num
// Signals an address being waited on.
ResultCode SignalToAddress(VAddr address, s32 num_to_wake) {
- // Get threads waiting on the address.
- std::vector<SharedPtr<Thread>> waiting_threads;
- GetThreadsWaitingOnAddress(waiting_threads, address);
+ std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
WakeThreads(waiting_threads, num_to_wake);
return RESULT_SUCCESS;
@@ -108,12 +111,11 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu
}
// Get threads waiting on the address.
- std::vector<SharedPtr<Thread>> waiting_threads;
- GetThreadsWaitingOnAddress(waiting_threads, address);
+ std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
// Determine the modified value depending on the waiting count.
s32 updated_value;
- if (waiting_threads.size() == 0) {
+ if (waiting_threads.empty()) {
updated_value = value - 1;
} else if (num_to_wake <= 0 || waiting_threads.size() <= static_cast<u32>(num_to_wake)) {
updated_value = value + 1;
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index f20f3dbc0..e3657b8e9 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -4,7 +4,9 @@
#pragma once
-#include "core/hle/result.h"
+#include "common/common_types.h"
+
+union ResultCode;
namespace Kernel {
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index fb2b6f7a3..134e41ebc 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -2,19 +2,20 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/assert.h"
+#include <tuple>
+
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/server_session.h"
namespace Kernel {
-ClientPort::ClientPort() {}
-ClientPort::~ClientPort() {}
+ClientPort::ClientPort() = default;
+ClientPort::~ClientPort() = default;
ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
// Note: Threads do not wait for the server endpoint to call
@@ -39,4 +40,12 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
return MakeResult(std::get<SharedPtr<ClientSession>>(sessions));
}
+void ClientPort::ConnectionClosed() {
+ if (active_sessions == 0) {
+ return;
+ }
+
+ --active_sessions;
+}
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index a829aeb6d..b1269ea5c 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -6,7 +6,7 @@
#include <string>
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -37,14 +37,20 @@ public:
*/
ResultVal<SharedPtr<ClientSession>> Connect();
- SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
- u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have
- u32 active_sessions; ///< Number of currently open sessions to this port
- std::string name; ///< Name of client port (optional)
+ /**
+ * Signifies that a previously active connection has been closed,
+ * decreasing the total number of active connections to this port.
+ */
+ void ConnectionClosed();
private:
ClientPort();
~ClientPort() override;
+
+ SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
+ u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have
+ u32 active_sessions = 0; ///< Number of currently open sessions to this port
+ std::string name; ///< Name of client port (optional)
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index 72773d8b1..fdffc648d 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -2,8 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/assert.h"
-
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/hle_ipc.h"
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index 2258f95bc..dabd93ed7 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -7,7 +7,7 @@
#include <memory>
#include <string>
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/result.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 9cae2369f..5623c4b6a 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -3,11 +3,9 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <map>
-#include <vector>
#include "common/assert.h"
#include "core/hle/kernel/event.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index e5c924a75..3c20c05e8 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -5,7 +5,7 @@
#pragma once
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
namespace Kernel {
@@ -31,10 +31,9 @@ public:
return HANDLE_TYPE;
}
- ResetType reset_type; ///< Current ResetType
-
- bool signaled; ///< Whether the event has already been signaled
- std::string name; ///< Name of event (optional)
+ ResetType GetResetType() const {
+ return reset_type;
+ }
bool ShouldWait(Thread* thread) const override;
void Acquire(Thread* thread) override;
@@ -47,6 +46,11 @@ public:
private:
Event();
~Event() override;
+
+ ResetType reset_type; ///< Current ResetType
+
+ bool signaled; ///< Whether the event has already been signaled
+ std::string name; ///< Name of event (optional)
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 7dd67f80f..28e21428a 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -8,7 +8,6 @@
#include "core/core.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index ba968c666..22ddda630 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -7,7 +7,7 @@
#include <array>
#include <cstddef>
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/result.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index f24392520..82a3fb5a8 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -2,17 +2,22 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <array>
+#include <sstream>
#include <utility>
#include <boost/range/algorithm_ext/erase.hpp>
+
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
+#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/server_session.h"
#include "core/memory.h"
@@ -196,7 +201,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb
return RESULT_SUCCESS;
}
-ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
+ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread) {
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
Memory::ReadBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
dst_cmdbuf.size() * sizeof(u32));
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 84727f748..f0d07f1b6 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -5,7 +5,6 @@
#pragma once
#include <array>
-#include <iterator>
#include <memory>
#include <string>
#include <type_traits>
@@ -14,7 +13,7 @@
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/ipc.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/thread.h"
@@ -133,7 +132,7 @@ public:
ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process,
HandleTable& src_table);
/// Writes data from this context back to the requesting process/thread.
- ResultCode WriteToOutgoingCommandBuffer(Thread& thread);
+ ResultCode WriteToOutgoingCommandBuffer(const Thread& thread);
u32_le GetCommand() const {
return command;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1beb98566..8c19e86d3 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -4,8 +4,6 @@
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory.h"
-#include "core/hle/kernel/object_address_table.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/thread.h"
@@ -13,12 +11,10 @@
namespace Kernel {
-unsigned int Object::next_object_id;
+std::atomic<u32> Object::next_object_id{0};
/// Initialize the kernel
-void Init(u32 system_mode) {
- Kernel::MemoryInit(system_mode);
-
+void Init() {
Kernel::ResourceLimitsInit();
Kernel::ThreadingInit();
Kernel::TimersInit();
@@ -33,13 +29,11 @@ void Init(u32 system_mode) {
void Shutdown() {
// Free all kernel objects
g_handle_table.Clear();
- g_object_address_table.Clear();
Kernel::ThreadingShutdown();
Kernel::TimersShutdown();
Kernel::ResourceLimitsShutdown();
- Kernel::MemoryShutdown();
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 402ae900f..131311472 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -4,122 +4,12 @@
#pragma once
-#include <cstddef>
-#include <string>
-#include <utility>
-#include <boost/smart_ptr/intrusive_ptr.hpp>
-#include "common/assert.h"
#include "common/common_types.h"
namespace Kernel {
-using Handle = u32;
-
-enum class HandleType : u32 {
- Unknown,
- Event,
- SharedMemory,
- Thread,
- Process,
- AddressArbiter,
- Timer,
- ResourceLimit,
- CodeSet,
- ClientPort,
- ServerPort,
- ClientSession,
- ServerSession,
-};
-
-enum class ResetType {
- OneShot,
- Sticky,
- Pulse,
-};
-
-class Object : NonCopyable {
-public:
- virtual ~Object() {}
-
- /// Returns a unique identifier for the object. For debugging purposes only.
- unsigned int GetObjectId() const {
- return object_id;
- }
-
- virtual std::string GetTypeName() const {
- return "[BAD KERNEL OBJECT TYPE]";
- }
- virtual std::string GetName() const {
- return "[UNKNOWN KERNEL OBJECT]";
- }
- virtual Kernel::HandleType GetHandleType() const = 0;
-
- /**
- * Check if a thread can wait on the object
- * @return True if a thread can wait on the object, otherwise false
- */
- bool IsWaitable() const {
- switch (GetHandleType()) {
- case HandleType::Event:
- case HandleType::Thread:
- case HandleType::Timer:
- case HandleType::ServerPort:
- case HandleType::ServerSession:
- return true;
-
- case HandleType::Unknown:
- case HandleType::SharedMemory:
- case HandleType::Process:
- case HandleType::AddressArbiter:
- case HandleType::ResourceLimit:
- case HandleType::CodeSet:
- case HandleType::ClientPort:
- case HandleType::ClientSession:
- return false;
- }
-
- UNREACHABLE();
- }
-
-public:
- static unsigned int next_object_id;
-
-private:
- friend void intrusive_ptr_add_ref(Object*);
- friend void intrusive_ptr_release(Object*);
-
- unsigned int ref_count = 0;
- unsigned int object_id = next_object_id++;
-};
-
-// Special functions used by boost::instrusive_ptr to do automatic ref-counting
-inline void intrusive_ptr_add_ref(Object* object) {
- ++object->ref_count;
-}
-
-inline void intrusive_ptr_release(Object* object) {
- if (--object->ref_count == 0) {
- delete object;
- }
-}
-
-template <typename T>
-using SharedPtr = boost::intrusive_ptr<T>;
-
-/**
- * Attempts to downcast the given Object pointer to a pointer to T.
- * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T.
- */
-template <typename T>
-inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
- if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
- return boost::static_pointer_cast<T>(std::move(object));
- }
- return nullptr;
-}
-
/// Initialize the kernel with the specified system mode.
-void Init(u32 system_mode);
+void Init();
/// Shutdown the kernel
void Shutdown();
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
deleted file mode 100644
index 94eac677c..000000000
--- a/src/core/hle/kernel/memory.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <algorithm>
-#include <cinttypes>
-#include <map>
-#include <memory>
-#include <utility>
-#include <vector>
-#include "common/assert.h"
-#include "common/common_types.h"
-#include "common/logging/log.h"
-#include "core/hle/kernel/memory.h"
-#include "core/hle/kernel/vm_manager.h"
-#include "core/hle/result.h"
-#include "core/memory.h"
-#include "core/memory_setup.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-namespace Kernel {
-
-MemoryRegionInfo memory_regions[3];
-
-/// Size of the APPLICATION, SYSTEM and BASE memory regions (respectively) for each system
-/// memory configuration type.
-static const u32 memory_region_sizes[8][3] = {
- // Old 3DS layouts
- {0x04000000, 0x02C00000, 0x01400000}, // 0
- {/* This appears to be unused. */}, // 1
- {0x06000000, 0x00C00000, 0x01400000}, // 2
- {0x05000000, 0x01C00000, 0x01400000}, // 3
- {0x04800000, 0x02400000, 0x01400000}, // 4
- {0x02000000, 0x04C00000, 0x01400000}, // 5
-
- // New 3DS layouts
- {0x07C00000, 0x06400000, 0x02000000}, // 6
- {0x0B200000, 0x02E00000, 0x02000000}, // 7
-};
-
-void MemoryInit(u32 mem_type) {
- // TODO(yuriks): On the n3DS, all o3DS configurations (<=5) are forced to 6 instead.
- ASSERT_MSG(mem_type <= 5, "New 3DS memory configuration aren't supported yet!");
- ASSERT(mem_type != 1);
-
- // The kernel allocation regions (APPLICATION, SYSTEM and BASE) are laid out in sequence, with
- // the sizes specified in the memory_region_sizes table.
- VAddr base = 0;
- for (int i = 0; i < 3; ++i) {
- memory_regions[i].base = base;
- memory_regions[i].size = memory_region_sizes[mem_type][i];
- memory_regions[i].used = 0;
- memory_regions[i].linear_heap_memory = std::make_shared<std::vector<u8>>();
- // Reserve enough space for this region of FCRAM.
- // We do not want this block of memory to be relocated when allocating from it.
- memory_regions[i].linear_heap_memory->reserve(memory_regions[i].size);
-
- base += memory_regions[i].size;
- }
-
- // We must've allocated the entire FCRAM by the end
- ASSERT(base == Memory::FCRAM_SIZE);
-}
-
-void MemoryShutdown() {
- for (auto& region : memory_regions) {
- region.base = 0;
- region.size = 0;
- region.used = 0;
- region.linear_heap_memory = nullptr;
- }
-}
-
-MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) {
- switch (region) {
- case MemoryRegion::APPLICATION:
- return &memory_regions[0];
- case MemoryRegion::SYSTEM:
- return &memory_regions[1];
- case MemoryRegion::BASE:
- return &memory_regions[2];
- default:
- UNREACHABLE();
- }
-}
-
-void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) {}
-
-void MapSharedPages(VMManager& address_space) {}
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
deleted file mode 100644
index 61e30c679..000000000
--- a/src/core/hle/kernel/memory.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-#include "common/common_types.h"
-#include "core/hle/kernel/process.h"
-
-namespace Kernel {
-
-class VMManager;
-
-struct MemoryRegionInfo {
- u64 base; // Not an address, but offset from start of FCRAM
- u64 size;
- u64 used;
-
- std::shared_ptr<std::vector<u8>> linear_heap_memory;
-};
-
-void MemoryInit(u32 mem_type);
-void MemoryShutdown();
-MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
-
-void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
-void MapSharedPages(VMManager& address_space);
-
-extern MemoryRegionInfo memory_regions[3];
-} // namespace Kernel
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index feb7b88d2..cb7f58b35 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -3,16 +3,19 @@
// Refer to the license.txt file included.
#include <map>
+#include <utility>
#include <vector>
+
#include <boost/range/algorithm_ext/erase.hpp>
+
#include "common/assert.h"
#include "core/core.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h"
-#include "core/hle/kernel/object_address_table.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/result.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 3117e7c70..45268bbe9 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -4,12 +4,10 @@
#pragma once
-#include <string>
#include "common/common_types.h"
-#include "common/swap.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/wait_object.h"
-#include "core/hle/result.h"
+#include "core/hle/kernel/object.h"
+
+union ResultCode;
namespace Kernel {
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
new file mode 100644
index 000000000..cdba272f5
--- /dev/null
+++ b/src/core/hle/kernel/object.cpp
@@ -0,0 +1,35 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "core/hle/kernel/object.h"
+
+namespace Kernel {
+
+Object::~Object() = default;
+
+bool Object::IsWaitable() const {
+ switch (GetHandleType()) {
+ case HandleType::Event:
+ case HandleType::Thread:
+ case HandleType::Timer:
+ case HandleType::ServerPort:
+ case HandleType::ServerSession:
+ return true;
+
+ case HandleType::Unknown:
+ case HandleType::SharedMemory:
+ case HandleType::Process:
+ case HandleType::AddressArbiter:
+ case HandleType::ResourceLimit:
+ case HandleType::CodeSet:
+ case HandleType::ClientPort:
+ case HandleType::ClientSession:
+ return false;
+ }
+
+ UNREACHABLE();
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
new file mode 100644
index 000000000..526ac9cc3
--- /dev/null
+++ b/src/core/hle/kernel/object.h
@@ -0,0 +1,101 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+#include <string>
+#include <utility>
+
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+
+#include "common/common_types.h"
+
+namespace Kernel {
+
+using Handle = u32;
+
+enum class HandleType : u32 {
+ Unknown,
+ Event,
+ SharedMemory,
+ Thread,
+ Process,
+ AddressArbiter,
+ Timer,
+ ResourceLimit,
+ CodeSet,
+ ClientPort,
+ ServerPort,
+ ClientSession,
+ ServerSession,
+};
+
+enum class ResetType {
+ OneShot,
+ Sticky,
+ Pulse,
+};
+
+class Object : NonCopyable {
+public:
+ virtual ~Object();
+
+ /// Returns a unique identifier for the object. For debugging purposes only.
+ u32 GetObjectId() const {
+ return object_id.load(std::memory_order_relaxed);
+ }
+
+ virtual std::string GetTypeName() const {
+ return "[BAD KERNEL OBJECT TYPE]";
+ }
+ virtual std::string GetName() const {
+ return "[UNKNOWN KERNEL OBJECT]";
+ }
+ virtual HandleType GetHandleType() const = 0;
+
+ /**
+ * Check if a thread can wait on the object
+ * @return True if a thread can wait on the object, otherwise false
+ */
+ bool IsWaitable() const;
+
+public:
+ static std::atomic<u32> next_object_id;
+
+private:
+ friend void intrusive_ptr_add_ref(Object*);
+ friend void intrusive_ptr_release(Object*);
+
+ std::atomic<u32> ref_count{0};
+ std::atomic<u32> object_id{next_object_id++};
+};
+
+// Special functions used by boost::instrusive_ptr to do automatic ref-counting
+inline void intrusive_ptr_add_ref(Object* object) {
+ object->ref_count.fetch_add(1, std::memory_order_relaxed);
+}
+
+inline void intrusive_ptr_release(Object* object) {
+ if (object->ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
+ delete object;
+ }
+}
+
+template <typename T>
+using SharedPtr = boost::intrusive_ptr<T>;
+
+/**
+ * Attempts to downcast the given Object pointer to a pointer to T.
+ * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T.
+ */
+template <typename T>
+inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
+ if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
+ return boost::static_pointer_cast<T>(std::move(object));
+ }
+ return nullptr;
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/object_address_table.cpp b/src/core/hle/kernel/object_address_table.cpp
deleted file mode 100644
index ca8a833a1..000000000
--- a/src/core/hle/kernel/object_address_table.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <utility>
-
-#include "common/assert.h"
-#include "core/hle/kernel/object_address_table.h"
-
-namespace Kernel {
-
-ObjectAddressTable g_object_address_table;
-
-void ObjectAddressTable::Insert(VAddr addr, SharedPtr<Object> obj) {
- ASSERT_MSG(objects.find(addr) == objects.end(), "Object already exists with addr=0x{:X}", addr);
- objects[addr] = std::move(obj);
-}
-
-void ObjectAddressTable::Close(VAddr addr) {
- ASSERT_MSG(objects.find(addr) != objects.end(), "Object does not exist with addr=0x{:X}", addr);
- objects.erase(addr);
-}
-
-SharedPtr<Object> ObjectAddressTable::GetGeneric(VAddr addr) const {
- auto iter = objects.find(addr);
- if (iter != objects.end()) {
- return iter->second;
- }
- return {};
-}
-
-void ObjectAddressTable::Clear() {
- objects.clear();
-}
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/object_address_table.h b/src/core/hle/kernel/object_address_table.h
deleted file mode 100644
index a09004b32..000000000
--- a/src/core/hle/kernel/object_address_table.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <map>
-#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
-
-namespace Kernel {
-
-/**
- * This class is used to keep a table of Kernel objects and their respective addresses in emulated
- * memory. For certain Switch SVCs, Kernel objects are referenced by an address to an object the
- * guest application manages, so we use this table to look these kernel objects up. This is similiar
- * to the HandleTable class.
- */
-class ObjectAddressTable final : NonCopyable {
-public:
- ObjectAddressTable() = default;
-
- /**
- * Inserts an object and address pair into the table.
- */
- void Insert(VAddr addr, SharedPtr<Object> obj);
-
- /**
- * Closes an object by its address, removing it from the table and decreasing the object's
- * ref-count.
- * @return `RESULT_SUCCESS` or one of the following errors:
- * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
- */
- void Close(VAddr addr);
-
- /**
- * Looks up an object by its address.
- * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
- */
- SharedPtr<Object> GetGeneric(VAddr addr) const;
-
- /**
- * Looks up an object by its address while verifying its type.
- * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
- * type differs from the requested one.
- */
- template <class T>
- SharedPtr<T> Get(VAddr addr) const {
- return DynamicObjectCast<T>(GetGeneric(addr));
- }
-
- /// Closes all addresses held in this table.
- void Clear();
-
-private:
- /// Stores the Object referenced by the address
- std::map<VAddr, SharedPtr<Object>> objects;
-};
-
-extern ObjectAddressTable g_object_address_table;
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 0c0506085..edf34c5a3 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -8,7 +8,6 @@
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "core/hle/kernel/errors.h"
-#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/thread.h"
@@ -125,14 +124,6 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
MemoryState::Mapped)
.Unwrap();
- misc_memory_used += stack_size;
- memory_region->used += stack_size;
-
- // Map special address mappings
- MapSharedPages(vm_manager);
- for (const auto& mapping : address_mappings) {
- HandleSpecialMapping(vm_manager, mapping);
- }
vm_manager.LogLayout();
status = ProcessStatus::Running;
@@ -141,37 +132,19 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
}
void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
- memory_region = GetMemoryRegion(flags.memory_region);
-
- auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
- MemoryState memory_state) {
+ const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
+ MemoryState memory_state) {
auto vma = vm_manager
.MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset,
segment.size, memory_state)
.Unwrap();
vm_manager.Reprotect(vma, permissions);
- misc_memory_used += segment.size;
- memory_region->used += segment.size;
};
// Map CodeSet segments
- MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::CodeStatic);
- MapSegment(module_->rodata, VMAPermission::Read, MemoryState::CodeMutable);
- MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::CodeMutable);
-}
-
-VAddr Process::GetLinearHeapAreaAddress() const {
- // Starting from system version 8.0.0 a new linear heap layout is supported to allow usage of
- // the extra RAM in the n3DS.
- return kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR;
-}
-
-VAddr Process::GetLinearHeapBase() const {
- return GetLinearHeapAreaAddress() + memory_region->base;
-}
-
-VAddr Process::GetLinearHeapLimit() const {
- return GetLinearHeapBase() + memory_region->size;
+ MapSegment(module_->CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic);
+ MapSegment(module_->RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable);
+ MapSegment(module_->DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable);
}
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
@@ -206,7 +179,6 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
vm_manager.Reprotect(vma, perms);
heap_used = size;
- memory_region->used += size;
return MakeResult<VAddr>(heap_end - size);
}
@@ -226,52 +198,6 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
return result;
heap_used -= size;
- memory_region->used -= size;
-
- return RESULT_SUCCESS;
-}
-
-ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) {
- UNIMPLEMENTED();
- return {};
-}
-
-ResultCode Process::LinearFree(VAddr target, u32 size) {
- auto& linheap_memory = memory_region->linear_heap_memory;
-
- if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
- target + size < target) {
-
- return ERR_INVALID_ADDRESS;
- }
-
- if (size == 0) {
- return RESULT_SUCCESS;
- }
-
- VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size();
- if (target + size > heap_end) {
- return ERR_INVALID_ADDRESS_STATE;
- }
-
- ResultCode result = vm_manager.UnmapRange(target, size);
- if (result.IsError())
- return result;
-
- linear_heap_used -= size;
- memory_region->used -= size;
-
- if (target + size == heap_end) {
- // End of linear heap has been freed, so check what's the last allocated block in it and
- // reduce the size.
- auto vma = vm_manager.FindVMA(target);
- ASSERT(vma != vm_manager.vma_map.end());
- ASSERT(vma->second.type == VMAType::Free);
- VAddr new_end = vma->second.base;
- if (new_end >= GetLinearHeapBase()) {
- linheap_memory->resize(new_end - GetLinearHeapBase());
- }
- }
return RESULT_SUCCESS;
}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 68e77a4d1..992689186 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -4,6 +4,7 @@
#pragma once
+#include <array>
#include <bitset>
#include <cstddef>
#include <memory>
@@ -12,7 +13,7 @@
#include <boost/container/static_vector.hpp>
#include "common/bit_field.h"
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
@@ -53,9 +54,14 @@ union ProcessFlags {
enum class ProcessStatus { Created, Running, Exited };
class ResourceLimit;
-struct MemoryRegionInfo;
struct CodeSet final : public Object {
+ struct Segment {
+ size_t offset = 0;
+ VAddr addr = 0;
+ u32 size = 0;
+ };
+
static SharedPtr<CodeSet> Create(std::string name);
std::string GetTypeName() const override {
@@ -70,24 +76,38 @@ struct CodeSet final : public Object {
return HANDLE_TYPE;
}
- /// Name of the process
- std::string name;
+ Segment& CodeSegment() {
+ return segments[0];
+ }
- std::shared_ptr<std::vector<u8>> memory;
+ const Segment& CodeSegment() const {
+ return segments[0];
+ }
- struct Segment {
- size_t offset = 0;
- VAddr addr = 0;
- u32 size = 0;
- };
+ Segment& RODataSegment() {
+ return segments[1];
+ }
+
+ const Segment& RODataSegment() const {
+ return segments[1];
+ }
+
+ Segment& DataSegment() {
+ return segments[2];
+ }
+
+ const Segment& DataSegment() const {
+ return segments[2];
+ }
- Segment segments[3];
- Segment& code = segments[0];
- Segment& rodata = segments[1];
- Segment& data = segments[2];
+ std::shared_ptr<std::vector<u8>> memory;
+ std::array<Segment, 3> segments;
VAddr entrypoint;
+ /// Name of the process
+ std::string name;
+
private:
CodeSet();
~CodeSet() override;
@@ -163,12 +183,11 @@ public:
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
// in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
std::shared_ptr<std::vector<u8>> heap_memory;
- // The left/right bounds of the address space covered by heap_memory.
- VAddr heap_start = 0, heap_end = 0;
- u64 heap_used = 0, linear_heap_used = 0, misc_memory_used = 0;
-
- MemoryRegionInfo* memory_region = nullptr;
+ // The left/right bounds of the address space covered by heap_memory.
+ VAddr heap_start = 0;
+ VAddr heap_end = 0;
+ u64 heap_used = 0;
/// The Thread Local Storage area is allocated as processes create threads,
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
@@ -179,16 +198,9 @@ public:
std::string name;
- VAddr GetLinearHeapAreaAddress() const;
- VAddr GetLinearHeapBase() const;
- VAddr GetLinearHeapLimit() const;
-
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
ResultCode HeapFree(VAddr target, u32 size);
- ResultVal<VAddr> LinearAllocate(VAddr target, u32 size, VMAPermission perms);
- ResultCode LinearFree(VAddr target, u32 size);
-
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index cc689a27a..0fa141db3 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -5,7 +5,7 @@
#pragma once
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index e307eec98..e770b9103 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -2,8 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <utility>
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/process.h"
@@ -21,7 +25,7 @@ Scheduler::~Scheduler() {
}
}
-bool Scheduler::HaveReadyThreads() {
+bool Scheduler::HaveReadyThreads() const {
std::lock_guard<std::mutex> lock(scheduler_mutex);
return ready_queue.get_first() != nullptr;
}
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index a3b5fb8ca..6a61ef64e 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -8,9 +8,11 @@
#include <vector>
#include "common/common_types.h"
#include "common/thread_queue_list.h"
-#include "core/arm/arm_interface.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
+class ARM_Interface;
+
namespace Kernel {
class Scheduler final {
@@ -19,7 +21,7 @@ public:
~Scheduler();
/// Returns whether there are any threads that are ready to run.
- bool HaveReadyThreads();
+ bool HaveReadyThreads() const;
/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule();
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 0b7061403..7b6211fd8 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -6,7 +6,7 @@
#include "common/assert.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/errors.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/thread.h"
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 9ef4ecc35..7f6d6b3eb 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -7,8 +7,9 @@
#include <memory>
#include <string>
#include <tuple>
+#include <vector>
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 29b163528..51a1ec160 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -5,6 +5,8 @@
#include <tuple>
#include <utility>
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
@@ -25,7 +27,7 @@ ServerSession::~ServerSession() {
// Decrease the port's connection count.
if (parent->port)
- parent->port->active_sessions--;
+ parent->port->ConnectionClosed();
// TODO(Subv): Wake up all the ClientSession's waiting threads and set
// the SendSyncRequest result to 0xC920181A.
@@ -69,6 +71,14 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
const u32 object_id{context.GetDomainMessageHeader()->object_id};
switch (domain_message_header->command) {
case IPC::DomainMessageHeader::CommandType::SendMessage:
+ if (object_id > domain_request_handlers.size()) {
+ LOG_CRITICAL(IPC,
+ "object_id {} is too big! This probably means a recent service call "
+ "to {} needed to return a new interface!",
+ object_id, name);
+ UNREACHABLE();
+ return RESULT_SUCCESS; // Ignore error if asserts are off
+ }
return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
@@ -142,7 +152,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
// Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the
// end of the command such that only commands following this one are handled as domains
if (convert_to_domain) {
- ASSERT_MSG(domain_request_handlers.empty(), "already a domain");
+ ASSERT_MSG(IsSession(), "ServerSession is already a domain instance.");
domain_request_handlers = {hle_handler};
convert_to_domain = false;
}
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 2da807042..1a88e66b9 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -6,12 +6,12 @@
#include <memory>
#include <string>
-#include "common/assert.h"
+#include <vector>
+
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
-#include "core/memory.h"
namespace Kernel {
@@ -97,7 +97,12 @@ public:
/// Returns true if the session has been converted to a domain, otherwise False
bool IsDomain() const {
- return !domain_request_handlers.empty();
+ return !IsSession();
+ }
+
+ /// Returns true if this session has not been converted to a domain, otherwise false.
+ bool IsSession() const {
+ return domain_request_handlers.empty();
}
/// Converts the session to a domain at the end of the current command
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index e69b034a7..7a551f5e4 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -4,7 +4,7 @@
#pragma once
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 4bf11c7e2..21ddc2f7d 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -3,10 +3,11 @@
// Refer to the license.txt file included.
#include <utility>
+
+#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/errors.h"
-#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/memory.h"
@@ -28,35 +29,17 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
shared_memory->other_permissions = other_permissions;
if (address == 0) {
- // We need to allocate a block from the Linear Heap ourselves.
- // We'll manually allocate some memory from the linear heap in the specified region.
- MemoryRegionInfo* memory_region = GetMemoryRegion(region);
- auto& linheap_memory = memory_region->linear_heap_memory;
-
- ASSERT_MSG(linheap_memory->size() + size <= memory_region->size,
- "Not enough space in region to allocate shared memory!");
-
- shared_memory->backing_block = linheap_memory;
- shared_memory->backing_block_offset = linheap_memory->size();
- // Allocate some memory from the end of the linear heap for this region.
- linheap_memory->insert(linheap_memory->end(), size, 0);
- memory_region->used += size;
-
- shared_memory->linear_heap_phys_address =
- Memory::FCRAM_PADDR + memory_region->base +
- static_cast<PAddr>(shared_memory->backing_block_offset);
-
- // Increase the amount of used linear heap memory for the owner process.
- if (shared_memory->owner_process != nullptr) {
- shared_memory->owner_process->linear_heap_used += size;
- }
+ shared_memory->backing_block = std::make_shared<std::vector<u8>>(size);
+ shared_memory->backing_block_offset = 0;
// Refresh the address mappings for the current process.
if (Core::CurrentProcess() != nullptr) {
- Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
+ Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings(
+ shared_memory->backing_block.get());
}
} else {
auto& vm_manager = shared_memory->owner_process->vm_manager;
+
// The memory is already available and mapped in the owner process.
auto vma = vm_manager.FindVMA(address);
ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
@@ -72,6 +55,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
}
shared_memory->base_address = address;
+
return shared_memory;
}
@@ -122,11 +106,6 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
VAddr target_address = address;
- if (base_address == 0 && target_address == 0) {
- // Calculate the address at which to map the memory block.
- target_address = Memory::PhysicalToVirtualAddress(linear_heap_phys_address).value();
- }
-
// Map the memory block into the target process
auto result = target_process->vm_manager.MapMemoryBlock(
target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 86f818e90..c50fee615 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -4,9 +4,12 @@
#pragma once
+#include <memory>
#include <string>
+#include <vector>
+
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/result.h"
@@ -108,9 +111,6 @@ public:
SharedPtr<Process> owner_process;
/// Address of shared memory block in the owner process if specified.
VAddr base_address;
- /// Physical address of the shared memory block in the linear heap if no address was specified
- /// during creation.
- PAddr linear_heap_phys_address;
/// Backing memory for this shared memory block.
std::shared_ptr<std::vector<u8>> backing_block;
/// Offset into the backing block for this shared memory.
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 0b439401a..6be5c474e 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -5,7 +5,10 @@
#include <algorithm>
#include <cinttypes>
#include <iterator>
+#include <mutex>
+#include <vector>
+#include "common/assert.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/string_util.h"
@@ -17,7 +20,6 @@
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/mutex.h"
-#include "core/hle/kernel/object_address_table.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/shared_memory.h"
@@ -248,8 +250,11 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
}
/// Break program execution
-static void Break(u64 unk_0, u64 unk_1, u64 unk_2) {
- LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!");
+static void Break(u64 reason, u64 info1, u64 info2) {
+ LOG_CRITICAL(
+ Debug_Emulated,
+ "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
+ reason, info1, info2);
ASSERT(false);
}
@@ -265,7 +270,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
info_sub_id, handle);
- auto& vm_manager = Core::CurrentProcess()->vm_manager;
+ const auto& vm_manager = Core::CurrentProcess()->vm_manager;
switch (static_cast<GetInfoType>(info_id)) {
case GetInfoType::AllowedCpuIdBitmask:
@@ -530,7 +535,6 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread));
*out_handle = thread->guest_handle;
- Core::System::GetInstance().PrepareReschedule();
Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
LOG_TRACE(Kernel_SVC,
@@ -704,8 +708,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
auto owner = g_handle_table.Get<Thread>(owner_handle);
ASSERT(owner);
- ASSERT(thread->status != ThreadStatus::Running);
- thread->status = ThreadStatus::WaitMutex;
+ ASSERT(thread->status == ThreadStatus::WaitMutex);
thread->wakeup_callback = nullptr;
owner->AddMutexWaiter(thread);
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 94735c86e..cf4f94822 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -4,8 +4,11 @@
#include <algorithm>
#include <cinttypes>
-#include <list>
#include <vector>
+
+#include <boost/optional.hpp>
+#include <boost/range/algorithm_ext/erase.hpp>
+
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
@@ -17,11 +20,10 @@
#include "core/core_timing_util.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory.h"
-#include "core/hle/kernel/mutex.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/memory.h"
@@ -79,8 +81,8 @@ void Thread::Stop() {
wait_objects.clear();
// Mark the TLS slot in the thread's page as free.
- u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
- u64 tls_slot =
+ const u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
+ const u64 tls_slot =
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot);
}
@@ -103,6 +105,10 @@ void ExitCurrentThread() {
*/
static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
const auto proper_handle = static_cast<Handle>(thread_handle);
+
+ // Lock the global kernel mutex when we enter the kernel HLE.
+ std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
+
SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle);
if (thread == nullptr) {
LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
@@ -154,12 +160,14 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
if (nanoseconds == -1)
return;
- CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType,
- callback_handle);
+ // This function might be called from any thread so we have to be cautious and use the
+ // thread-safe version of ScheduleEvent.
+ CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType,
+ callback_handle);
}
void Thread::CancelWakeupTimer() {
- CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
+ CoreTiming::UnscheduleEventThreadsafe(ThreadWakeupEventType, callback_handle);
}
static boost::optional<s32> GetNextProcessorId(u64 mask) {
@@ -250,13 +258,14 @@ void Thread::ResumeFromWait() {
* slot: The index of the first free slot in the indicated page.
* alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
*/
-std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& tls_slots) {
+static std::tuple<std::size_t, std::size_t, bool> GetFreeThreadLocalSlot(
+ const std::vector<std::bitset<8>>& tls_slots) {
// Iterate over all the allocated pages, and try to find one where not all slots are used.
- for (unsigned page = 0; page < tls_slots.size(); ++page) {
+ for (std::size_t page = 0; page < tls_slots.size(); ++page) {
const auto& page_tls_slots = tls_slots[page];
if (!page_tls_slots.all()) {
// We found a page with at least one free slot, find which slot it is
- for (unsigned slot = 0; slot < page_tls_slots.size(); ++slot) {
+ for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
if (!page_tls_slots.test(slot)) {
return std::make_tuple(page, slot, false);
}
@@ -331,42 +340,22 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
// Find the next available TLS index, and mark it as used
auto& tls_slots = owner_process->tls_slots;
- bool needs_allocation = true;
- u32 available_page; // Which allocated page has free space
- u32 available_slot; // Which slot within the page is free
-
- std::tie(available_page, available_slot, needs_allocation) = GetFreeThreadLocalSlot(tls_slots);
+ auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
if (needs_allocation) {
- // There are no already-allocated pages with free slots, lets allocate a new one.
- // TLS pages are allocated from the BASE region in the linear heap.
- MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::BASE);
- auto& linheap_memory = memory_region->linear_heap_memory;
-
- if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) {
- LOG_ERROR(Kernel_SVC,
- "Not enough space in region to allocate a new TLS page for thread");
- return ERR_OUT_OF_MEMORY;
- }
-
- size_t offset = linheap_memory->size();
-
- // Allocate some memory from the end of the linear heap for this region.
- linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0);
- memory_region->used += Memory::PAGE_SIZE;
- owner_process->linear_heap_used += Memory::PAGE_SIZE;
-
tls_slots.emplace_back(0); // The page is completely available at the start
- available_page = static_cast<u32>(tls_slots.size() - 1);
+ available_page = tls_slots.size() - 1;
available_slot = 0; // Use the first slot in the new page
+ // Allocate some memory from the end of the linear heap for this region.
+ const size_t offset = thread->tls_memory->size();
+ thread->tls_memory->insert(thread->tls_memory->end(), Memory::PAGE_SIZE, 0);
+
auto& vm_manager = owner_process->vm_manager;
- vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
+ vm_manager.RefreshMemoryBlockMappings(thread->tls_memory.get());
- // Map the page to the current process' address space.
- // TODO(Subv): Find the correct MemoryState for this region.
vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
- linheap_memory, offset, Memory::PAGE_SIZE,
+ thread->tls_memory, 0, Memory::PAGE_SIZE,
MemoryState::ThreadLocal);
}
@@ -437,12 +426,33 @@ VAddr Thread::GetCommandBufferAddress() const {
}
void Thread::AddMutexWaiter(SharedPtr<Thread> thread) {
+ if (thread->lock_owner == this) {
+ // If the thread is already waiting for this thread to release the mutex, ensure that the
+ // waiters list is consistent and return without doing anything.
+ auto itr = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread);
+ ASSERT(itr != wait_mutex_threads.end());
+ return;
+ }
+
+ // A thread can't wait on two different mutexes at the same time.
+ ASSERT(thread->lock_owner == nullptr);
+
+ // Ensure that the thread is not already in the list of mutex waiters
+ auto itr = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread);
+ ASSERT(itr == wait_mutex_threads.end());
+
thread->lock_owner = this;
wait_mutex_threads.emplace_back(std::move(thread));
UpdatePriority();
}
void Thread::RemoveMutexWaiter(SharedPtr<Thread> thread) {
+ ASSERT(thread->lock_owner == this);
+
+ // Ensure that the thread is in the list of mutex waiters
+ auto itr = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread);
+ ASSERT(itr != wait_mutex_threads.end());
+
boost::remove_erase(wait_mutex_threads, thread);
thread->lock_owner = nullptr;
UpdatePriority();
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 6218960d2..adc804248 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -4,15 +4,14 @@
#pragma once
+#include <functional>
#include <memory>
#include <string>
-#include <unordered_map>
#include <vector>
-#include <boost/container/flat_map.hpp>
-#include <boost/container/flat_set.hpp>
+
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
@@ -266,6 +265,8 @@ public:
private:
Thread();
~Thread() override;
+
+ std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>();
};
/**
@@ -289,12 +290,6 @@ Thread* GetCurrentThread();
void WaitCurrentThread_Sleep();
/**
- * Waits the current thread from an ArbitrateAddress call
- * @param wait_address Arbitration address used to resume from wait
- */
-void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
-
-/**
* Stops the current thread and removes it from the thread_list
*/
void ExitCurrentThread();
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 904a3d0a5..282360745 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -8,7 +8,7 @@
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/hle/kernel/handle_table.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index 82d19cefc..4dddc67e0 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -5,7 +5,7 @@
#pragma once
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
namespace Kernel {
@@ -32,13 +32,17 @@ public:
return HANDLE_TYPE;
}
- ResetType reset_type; ///< The ResetType of this timer
+ ResetType GetResetType() const {
+ return reset_type;
+ }
- bool signaled; ///< Whether the timer has been signaled or not
- std::string name; ///< Name of timer (optional)
+ u64 GetInitialDelay() const {
+ return initial_delay;
+ }
- u64 initial_delay; ///< The delay until the timer fires for the first time
- u64 interval_delay; ///< The delay until the timer fires after the first time
+ u64 GetIntervalDelay() const {
+ return interval_delay;
+ }
bool ShouldWait(Thread* thread) const override;
void Acquire(Thread* thread) override;
@@ -67,6 +71,14 @@ private:
Timer();
~Timer() override;
+ ResetType reset_type; ///< The ResetType of this timer
+
+ u64 initial_delay; ///< The delay until the timer fires for the first time
+ u64 interval_delay; ///< The delay until the timer fires after the first time
+
+ bool signaled; ///< Whether the timer has been signaled or not
+ std::string name; ///< Name of timer (optional)
+
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
Handle callback_handle;
};
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 9d26fd781..479cacb62 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <iterator>
#include <utility>
#include "common/assert.h"
@@ -175,9 +176,9 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) {
ResultCode VMManager::UnmapRange(VAddr target, u64 size) {
CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size));
- VAddr target_end = target + size;
+ const VAddr target_end = target + size;
- VMAIter end = vma_map.end();
+ const VMAIter end = vma_map.end();
// The comparison against the end of the range must be done using addresses since VMAs can be
// merged during this process, causing invalidation of the iterators.
while (vma != end && vma->second.base < target_end) {
@@ -207,9 +208,9 @@ VMManager::VMAHandle VMManager::Reprotect(VMAHandle vma_handle, VMAPermission ne
ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_perms) {
CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size));
- VAddr target_end = target + size;
+ const VAddr target_end = target + size;
- VMAIter end = vma_map.end();
+ const VMAIter end = vma_map.end();
// The comparison against the end of the range must be done using addresses since VMAs can be
// merged during this process, causing invalidation of the iterators.
while (vma != end && vma->second.base < target_end) {
@@ -258,14 +259,14 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u64 size) {
return ERR_INVALID_ADDRESS;
}
- VirtualMemoryArea& vma = vma_handle->second;
+ const VirtualMemoryArea& vma = vma_handle->second;
if (vma.type != VMAType::Free) {
// Region is already allocated
return ERR_INVALID_ADDRESS_STATE;
}
- u64 start_in_vma = base - vma.base;
- u64 end_in_vma = start_in_vma + size;
+ const VAddr start_in_vma = base - vma.base;
+ const VAddr end_in_vma = start_in_vma + size;
if (end_in_vma > vma.size) {
// Requested allocation doesn't fit inside VMA
@@ -288,17 +289,16 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) {
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x{:016X}", size);
ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x{:016X}", target);
- VAddr target_end = target + size;
+ const VAddr target_end = target + size;
ASSERT(target_end >= target);
ASSERT(target_end <= MAX_ADDRESS);
ASSERT(size > 0);
VMAIter begin_vma = StripIterConstness(FindVMA(target));
- VMAIter i_end = vma_map.lower_bound(target_end);
- for (auto i = begin_vma; i != i_end; ++i) {
- if (i->second.type == VMAType::Free) {
- return ERR_INVALID_ADDRESS_STATE;
- }
+ const VMAIter i_end = vma_map.lower_bound(target_end);
+ if (std::any_of(begin_vma, i_end,
+ [](const auto& entry) { return entry.second.type == VMAType::Free; })) {
+ return ERR_INVALID_ADDRESS_STATE;
}
if (target != begin_vma->second.base) {
@@ -346,7 +346,7 @@ VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u64 offset_in_vma) {
}
VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
- VMAIter next_vma = std::next(iter);
+ const VMAIter next_vma = std::next(iter);
if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) {
iter->second.size += next_vma->second.size;
vma_map.erase(next_vma);
@@ -382,22 +382,22 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
}
}
-u64 VMManager::GetTotalMemoryUsage() {
+u64 VMManager::GetTotalMemoryUsage() const {
LOG_WARNING(Kernel, "(STUBBED) called");
return 0xF8000000;
}
-u64 VMManager::GetTotalHeapUsage() {
+u64 VMManager::GetTotalHeapUsage() const {
LOG_WARNING(Kernel, "(STUBBED) called");
return 0x0;
}
-VAddr VMManager::GetAddressSpaceBaseAddr() {
+VAddr VMManager::GetAddressSpaceBaseAddr() const {
LOG_WARNING(Kernel, "(STUBBED) called");
return 0x8000000;
}
-u64 VMManager::GetAddressSpaceSize() {
+u64 VMManager::GetAddressSpaceSize() const {
LOG_WARNING(Kernel, "(STUBBED) called");
return MAX_ADDRESS;
}
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 38e4ebcd3..98bd04bea 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -190,16 +190,16 @@ public:
void LogLayout() const;
/// Gets the total memory usage, used by svcGetInfo
- u64 GetTotalMemoryUsage();
+ u64 GetTotalMemoryUsage() const;
/// Gets the total heap usage, used by svcGetInfo
- u64 GetTotalHeapUsage();
+ u64 GetTotalHeapUsage() const;
/// Gets the total address space base address, used by svcGetInfo
- VAddr GetAddressSpaceBaseAddr();
+ VAddr GetAddressSpaceBaseAddr() const;
/// Gets the total address space address size, used by svcGetInfo
- u64 GetAddressSpaceSize();
+ u64 GetAddressSpaceSize() const;
/// Each VMManager has its own page table, which is set as the main one when the owning process
/// is scheduled.
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
index 23af346d0..7681cdee7 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -5,11 +5,8 @@
#include <algorithm>
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/hle/kernel/errors.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory.h"
+#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
index 78bfd8c6c..b5fbc647b 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/wait_object.h
@@ -7,7 +7,7 @@
#include <vector>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
namespace Kernel {
diff --git a/src/core/hle/romfs.cpp b/src/core/hle/romfs.cpp
deleted file mode 100644
index 3157df71d..000000000
--- a/src/core/hle/romfs.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2017 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <cstring>
-#include "common/swap.h"
-#include "core/hle/romfs.h"
-
-namespace RomFS {
-
-struct Header {
- u32_le header_length;
- u32_le dir_hash_table_offset;
- u32_le dir_hash_table_length;
- u32_le dir_table_offset;
- u32_le dir_table_length;
- u32_le file_hash_table_offset;
- u32_le file_hash_table_length;
- u32_le file_table_offset;
- u32_le file_table_length;
- u32_le data_offset;
-};
-
-static_assert(sizeof(Header) == 0x28, "Header has incorrect size");
-
-struct DirectoryMetadata {
- u32_le parent_dir_offset;
- u32_le next_dir_offset;
- u32_le first_child_dir_offset;
- u32_le first_file_offset;
- u32_le same_hash_next_dir_offset;
- u32_le name_length; // in bytes
- // followed by directory name
-};
-
-static_assert(sizeof(DirectoryMetadata) == 0x18, "DirectoryMetadata has incorrect size");
-
-struct FileMetadata {
- u32_le parent_dir_offset;
- u32_le next_file_offset;
- u64_le data_offset;
- u64_le data_length;
- u32_le same_hash_next_file_offset;
- u32_le name_length; // in bytes
- // followed by file name
-};
-
-static_assert(sizeof(FileMetadata) == 0x20, "FileMetadata has incorrect size");
-
-static bool MatchName(const u8* buffer, u32 name_length, const std::u16string& name) {
- std::vector<char16_t> name_buffer(name_length / sizeof(char16_t));
- std::memcpy(name_buffer.data(), buffer, name_length);
- return name == std::u16string(name_buffer.begin(), name_buffer.end());
-}
-
-const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path) {
- constexpr u32 INVALID_FIELD = 0xFFFFFFFF;
-
- // Split path into directory names and file name
- std::vector<std::u16string> dir_names = path;
- dir_names.pop_back();
- const std::u16string& file_name = path.back();
-
- Header header;
- std::memcpy(&header, romfs, sizeof(header));
-
- // Find directories of each level
- DirectoryMetadata dir;
- const u8* current_dir = romfs + header.dir_table_offset;
- std::memcpy(&dir, current_dir, sizeof(dir));
- for (const std::u16string& dir_name : dir_names) {
- u32 child_dir_offset;
- child_dir_offset = dir.first_child_dir_offset;
- while (true) {
- if (child_dir_offset == INVALID_FIELD) {
- return nullptr;
- }
- const u8* current_child_dir = romfs + header.dir_table_offset + child_dir_offset;
- std::memcpy(&dir, current_child_dir, sizeof(dir));
- if (MatchName(current_child_dir + sizeof(dir), dir.name_length, dir_name)) {
- current_dir = current_child_dir;
- break;
- }
- child_dir_offset = dir.next_dir_offset;
- }
- }
-
- // Find the file
- FileMetadata file;
- u32 file_offset = dir.first_file_offset;
- while (file_offset != INVALID_FIELD) {
- const u8* current_file = romfs + header.file_table_offset + file_offset;
- std::memcpy(&file, current_file, sizeof(file));
- if (MatchName(current_file + sizeof(file), file.name_length, file_name)) {
- return romfs + header.data_offset + file.data_offset;
- }
- file_offset = file.next_file_offset;
- }
- return nullptr;
-}
-
-} // namespace RomFS
diff --git a/src/core/hle/romfs.h b/src/core/hle/romfs.h
deleted file mode 100644
index ee9f29760..000000000
--- a/src/core/hle/romfs.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <string>
-#include <vector>
-#include "common/common_types.h"
-
-namespace RomFS {
-
-/**
- * Gets the pointer to a file in a RomFS image.
- * @param romfs The pointer to the RomFS image
- * @param path A vector containing the directory names and file name of the path to the file
- * @return the pointer to the file
- * @todo reimplement this with a full RomFS manager
- */
-const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path);
-
-} // namespace RomFS
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 0b158e015..f3c5b1b9c 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -10,6 +10,7 @@
#include "core/hle/service/acc/acc_su.h"
#include "core/hle/service/acc/acc_u0.h"
#include "core/hle/service/acc/acc_u1.h"
+#include "core/settings.h"
namespace Service::Account {
@@ -31,34 +32,78 @@ struct ProfileBase {
};
static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase structure has incorrect size");
+// TODO(ogniK): Generate a real user id based on username, md5(username) maybe?
static constexpr u128 DEFAULT_USER_ID{1ull, 0ull};
class IProfile final : public ServiceFramework<IProfile> {
public:
explicit IProfile(u128 user_id) : ServiceFramework("IProfile"), user_id(user_id) {
static const FunctionInfo functions[] = {
- {0, nullptr, "Get"},
+ {0, &IProfile::Get, "Get"},
{1, &IProfile::GetBase, "GetBase"},
{10, nullptr, "GetImageSize"},
- {11, nullptr, "LoadImage"},
+ {11, &IProfile::LoadImage, "LoadImage"},
};
RegisterHandlers(functions);
}
private:
+ void Get(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_ACC, "(STUBBED) called");
+ ProfileBase profile_base{};
+ profile_base.user_id = user_id;
+ if (Settings::values.username.size() > profile_base.username.size()) {
+ std::copy_n(Settings::values.username.begin(), profile_base.username.size(),
+ profile_base.username.begin());
+ } else {
+ std::copy(Settings::values.username.begin(), Settings::values.username.end(),
+ profile_base.username.begin());
+ }
+
+ IPC::ResponseBuilder rb{ctx, 16};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw(profile_base);
+ }
+
void GetBase(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
// TODO(Subv): Retrieve this information from somewhere.
ProfileBase profile_base{};
profile_base.user_id = user_id;
- profile_base.username = {'y', 'u', 'z', 'u'};
-
+ if (Settings::values.username.size() > profile_base.username.size()) {
+ std::copy_n(Settings::values.username.begin(), profile_base.username.size(),
+ profile_base.username.begin());
+ } else {
+ std::copy(Settings::values.username.begin(), Settings::values.username.end(),
+ profile_base.username.begin());
+ }
IPC::ResponseBuilder rb{ctx, 16};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(profile_base);
}
+ void LoadImage(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_ACC, "(STUBBED) called");
+ // smallest jpeg https://github.com/mathiasbynens/small/blob/master/jpeg.jpg
+ // TODO(mailwl): load actual profile image from disk, width 256px, max size 0x20000
+ const u32 jpeg_size = 107;
+ static const std::array<u8, jpeg_size> jpeg{
+ 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03,
+ 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x08, 0x06, 0x06, 0x05, 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a,
+ 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, 0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13, 0x12, 0x10, 0x13, 0x0f, 0x10, 0x10,
+ 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x11, 0x00,
+ 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01,
+ 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9,
+ };
+ ctx.WriteBuffer(jpeg.data(), jpeg_size);
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(jpeg_size);
+ }
+
u128 user_id; ///< The user id this profile refers to.
};
@@ -95,6 +140,13 @@ private:
}
};
+void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_ACC, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(1);
+}
+
void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index 0a01d954c..88cabaa01 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -14,6 +14,7 @@ public:
public:
explicit Interface(std::shared_ptr<Module> module, const char* name);
+ void GetUserCount(Kernel::HLERequestContext& ctx);
void GetUserExistence(Kernel::HLERequestContext& ctx);
void ListAllUsers(Kernel::HLERequestContext& ctx);
void ListOpenUsers(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index 9ffb40b22..8b2a71f37 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -8,7 +8,7 @@ namespace Service::Account {
ACC_SU::ACC_SU(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:su") {
static const FunctionInfo functions[] = {
- {0, nullptr, "GetUserCount"},
+ {0, &ACC_SU::GetUserCount, "GetUserCount"},
{1, &ACC_SU::GetUserExistence, "GetUserExistence"},
{2, &ACC_SU::ListAllUsers, "ListAllUsers"},
{3, &ACC_SU::ListOpenUsers, "ListOpenUsers"},
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 44e21ac09..d84c8b2e1 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -8,7 +8,7 @@ namespace Service::Account {
ACC_U0::ACC_U0(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u0") {
static const FunctionInfo functions[] = {
- {0, nullptr, "GetUserCount"},
+ {0, &ACC_U0::GetUserCount, "GetUserCount"},
{1, &ACC_U0::GetUserExistence, "GetUserExistence"},
{2, &ACC_U0::ListAllUsers, "ListAllUsers"},
{3, &ACC_U0::ListOpenUsers, "ListOpenUsers"},
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index d101d4e0d..0ceaf06b5 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -8,7 +8,7 @@ namespace Service::Account {
ACC_U1::ACC_U1(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u1") {
static const FunctionInfo functions[] = {
- {0, nullptr, "GetUserCount"},
+ {0, &ACC_U1::GetUserCount, "GetUserCount"},
{1, &ACC_U1::GetUserExistence, "GetUserExistence"},
{2, &ACC_U1::ListAllUsers, "ListAllUsers"},
{3, &ACC_U1::ListOpenUsers, "ListOpenUsers"},
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 97ef07bf9..c524e7a48 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -11,6 +11,9 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
+#include "core/hle/service/am/idle.h"
+#include "core/hle/service/am/omm.h"
+#include "core/hle/service/am/spsm.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -133,7 +136,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
{16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
{17, nullptr, "SetControllerFirmwareUpdateSection"},
{18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
- {19, nullptr, "SetScreenShotImageOrientation"},
+ {19, &ISelfController::SetScreenShotImageOrientation, "SetScreenShotImageOrientation"},
{20, nullptr, "SetDesirableKeyboardLayout"},
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
{41, nullptr, "IsSystemBufferSharingEnabled"},
@@ -142,8 +145,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
{51, nullptr, "ApproveToDisplay"},
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
{61, nullptr, "SetMediaPlaybackState"},
- {62, nullptr, "SetIdleTimeDetectionExtension"},
- {63, nullptr, "GetIdleTimeDetectionExtension"},
+ {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
+ {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
{64, nullptr, "SetInputDetectionSourceSet"},
{65, nullptr, "ReportUserIsActive"},
{66, nullptr, "GetCurrentIlluminance"},
@@ -251,6 +254,13 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext&
LOG_WARNING(Service_AM, "(STUBBED) called");
}
+void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+}
+
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
// TODO(Subv): Find out how AM determines the display to use, for now just create the layer
// in the Default display.
@@ -271,6 +281,23 @@ void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx)
LOG_WARNING(Service_AM, "(STUBBED) called");
}
+void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ idle_time_detection_extension = rp.Pop<u32>();
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+}
+
+void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(idle_time_detection_extension);
+
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+}
+
ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -296,7 +323,8 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
{52, nullptr, "SwitchLcdBacklight"},
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
{60, nullptr, "GetDefaultDisplayResolution"},
- {61, nullptr, "GetDefaultDisplayResolutionChangeEvent"},
+ {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent,
+ "GetDefaultDisplayResolutionChangeEvent"},
{62, nullptr, "GetHdcpAuthenticationState"},
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
};
@@ -331,6 +359,16 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
}
+void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
+ event->Signal();
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(event);
+
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+}
+
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
const bool use_docked_mode{Settings::values.use_docked_mode};
IPC::ResponseBuilder rb{ctx, 3};
@@ -649,7 +687,8 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
// TODO(bunnei): This should be configurable
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u64>(Service::Set::LanguageCode::EN_US));
+ rb.Push(
+ static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index)));
LOG_DEBUG(Service_AM, "called");
}
@@ -689,6 +728,9 @@ void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager);
std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);
+ std::make_shared<IdleSys>()->InstallAsService(service_manager);
+ std::make_shared<OMM>()->InstallAsService(service_manager);
+ std::make_shared<SPSM>()->InstallAsService(service_manager);
}
IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") {
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 8f4f98346..b763aff6f 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -83,12 +83,16 @@ private:
void LockExit(Kernel::HLERequestContext& ctx);
void UnlockExit(Kernel::HLERequestContext& ctx);
void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx);
+ void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx);
void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
void SetScreenShotPermission(Kernel::HLERequestContext& ctx);
void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
+ void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
+ void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
Kernel::SharedPtr<Kernel::Event> launchable_event;
+ u32 idle_time_detection_extension = 0;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
@@ -109,6 +113,7 @@ private:
void GetEventHandle(Kernel::HLERequestContext& ctx);
void ReceiveMessage(Kernel::HLERequestContext& ctx);
void GetCurrentFocusState(Kernel::HLERequestContext& ctx);
+ void GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx);
void GetOperationMode(Kernel::HLERequestContext& ctx);
void GetPerformanceMode(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp
new file mode 100644
index 000000000..af46e9494
--- /dev/null
+++ b/src/core/hle/service/am/idle.cpp
@@ -0,0 +1,24 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/am/idle.h"
+
+namespace Service::AM {
+
+IdleSys::IdleSys() : ServiceFramework{"idle:sys"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetAutoPowerDownEvent"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/idle.h b/src/core/hle/service/am/idle.h
new file mode 100644
index 000000000..1eb68d2c9
--- /dev/null
+++ b/src/core/hle/service/am/idle.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class IdleSys final : public ServiceFramework<IdleSys> {
+public:
+ explicit IdleSys();
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp
new file mode 100644
index 000000000..447fe8669
--- /dev/null
+++ b/src/core/hle/service/am/omm.cpp
@@ -0,0 +1,42 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/am/omm.h"
+
+namespace Service::AM {
+
+OMM::OMM() : ServiceFramework{"omm"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetOperationMode"},
+ {1, nullptr, "GetOperationModeChangeEvent"},
+ {2, nullptr, "EnableAudioVisual"},
+ {3, nullptr, "DisableAudioVisual"},
+ {4, nullptr, "EnterSleepAndWait"},
+ {5, nullptr, "GetCradleStatus"},
+ {6, nullptr, "FadeInDisplay"},
+ {7, nullptr, "FadeOutDisplay"},
+ {8, nullptr, "Unknown1"},
+ {9, nullptr, "Unknown2"},
+ {10, nullptr, "Unknown3"},
+ {11, nullptr, "Unknown4"},
+ {12, nullptr, "Unknown5"},
+ {13, nullptr, "Unknown6"},
+ {14, nullptr, "Unknown7"},
+ {15, nullptr, "Unknown8"},
+ {16, nullptr, "Unknown9"},
+ {17, nullptr, "Unknown10"},
+ {18, nullptr, "Unknown11"},
+ {19, nullptr, "Unknown12"},
+ {20, nullptr, "Unknown13"},
+ {21, nullptr, "Unknown14"},
+ {22, nullptr, "Unknown15"},
+ {23, nullptr, "Unknown16"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/omm.h b/src/core/hle/service/am/omm.h
new file mode 100644
index 000000000..49e5d331c
--- /dev/null
+++ b/src/core/hle/service/am/omm.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class OMM final : public ServiceFramework<OMM> {
+public:
+ explicit OMM();
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp
new file mode 100644
index 000000000..a05d433d0
--- /dev/null
+++ b/src/core/hle/service/am/spsm.cpp
@@ -0,0 +1,30 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/am/spsm.h"
+
+namespace Service::AM {
+
+SPSM::SPSM() : ServiceFramework{"spsm"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetState"},
+ {1, nullptr, "SleepSystemAndWaitAwake"},
+ {2, nullptr, "Unknown1"},
+ {3, nullptr, "Unknown2"},
+ {4, nullptr, "GetNotificationMessageEventHandle"},
+ {5, nullptr, "Unknown3"},
+ {6, nullptr, "Unknown4"},
+ {7, nullptr, "Unknown5"},
+ {8, nullptr, "AnalyzePerformanceLogForLastSleepWakeSequence"},
+ {9, nullptr, "ChangeHomeButtonLongPressingTime"},
+ {10, nullptr, "Unknown6"},
+ {11, nullptr, "Unknown7"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/spsm.h b/src/core/hle/service/am/spsm.h
new file mode 100644
index 000000000..57dde62e1
--- /dev/null
+++ b/src/core/hle/service/am/spsm.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::AM {
+
+class SPSM final : public ServiceFramework<SPSM> {
+public:
+ explicit SPSM();
+};
+
+} // namespace Service::AM
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp
index 7a185c6c8..4109cb7f7 100644
--- a/src/core/hle/service/apm/apm.cpp
+++ b/src/core/hle/service/apm/apm.cpp
@@ -13,6 +13,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
auto module_ = std::make_shared<Module>();
std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager);
std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager);
+ std::make_shared<APM_Sys>()->InstallAsService(service_manager);
}
} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index ce943d829..4cd8132f5 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -74,6 +74,31 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISession>();
+
+ LOG_DEBUG(Service_APM, "called");
+}
+
+APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RequestPerformanceMode"},
+ {1, &APM_Sys::GetPerformanceEvent, "GetPerformanceEvent"},
+ {2, nullptr, "GetThrottlingState"},
+ {3, nullptr, "GetLastThrottlingState"},
+ {4, nullptr, "ClearLastThrottlingState"},
+ {5, nullptr, "LoadAndApplySettings"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ISession>();
+
+ LOG_DEBUG(Service_APM, "called");
}
} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h
index fa68c7d93..d14264ad7 100644
--- a/src/core/hle/service/apm/interface.h
+++ b/src/core/hle/service/apm/interface.h
@@ -19,4 +19,12 @@ private:
std::shared_ptr<Module> apm;
};
+class APM_Sys final : public ServiceFramework<APM_Sys> {
+public:
+ explicit APM_Sys();
+
+private:
+ void GetPerformanceEvent(Kernel::HLERequestContext& ctx);
+};
+
} // namespace Service::APM
diff --git a/src/core/hle/service/arp/arp.cpp b/src/core/hle/service/arp/arp.cpp
new file mode 100644
index 000000000..358ef2576
--- /dev/null
+++ b/src/core/hle/service/arp/arp.cpp
@@ -0,0 +1,75 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/arp/arp.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::ARP {
+
+class ARP_R final : public ServiceFramework<ARP_R> {
+public:
+ explicit ARP_R() : ServiceFramework{"arp:r"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetApplicationLaunchProperty"},
+ {1, nullptr, "GetApplicationLaunchPropertyWithApplicationId"},
+ {2, nullptr, "GetApplicationControlProperty"},
+ {3, nullptr, "GetApplicationControlPropertyWithApplicationId"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IRegistrar final : public ServiceFramework<IRegistrar> {
+public:
+ explicit IRegistrar() : ServiceFramework{"IRegistrar"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Issue"},
+ {1, nullptr, "SetApplicationLaunchProperty"},
+ {2, nullptr, "SetApplicationControlProperty"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class ARP_W final : public ServiceFramework<ARP_W> {
+public:
+ explicit ARP_W() : ServiceFramework{"arp:w"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
+ {1, nullptr, "DeleteProperties"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void AcquireRegistrar(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IRegistrar>();
+
+ LOG_DEBUG(Service_ARP, "called");
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<ARP_R>()->InstallAsService(sm);
+ std::make_shared<ARP_W>()->InstallAsService(sm);
+}
+
+} // namespace Service::ARP
diff --git a/src/core/hle/service/arp/arp.h b/src/core/hle/service/arp/arp.h
new file mode 100644
index 000000000..9d100187c
--- /dev/null
+++ b/src/core/hle/service/arp/arp.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::ARP {
+
+/// Registers all ARP services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::ARP
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp
new file mode 100644
index 000000000..37c3fdcac
--- /dev/null
+++ b/src/core/hle/service/audio/audctl.cpp
@@ -0,0 +1,45 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/audio/audctl.h"
+
+namespace Service::Audio {
+
+AudCtl::AudCtl() : ServiceFramework{"audctl"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetTargetVolume"},
+ {1, nullptr, "SetTargetVolume"},
+ {2, nullptr, "GetTargetVolumeMin"},
+ {3, nullptr, "GetTargetVolumeMax"},
+ {4, nullptr, "IsTargetMute"},
+ {5, nullptr, "SetTargetMute"},
+ {6, nullptr, "IsTargetConnected"},
+ {7, nullptr, "SetDefaultTarget"},
+ {8, nullptr, "GetDefaultTarget"},
+ {9, nullptr, "GetAudioOutputMode"},
+ {10, nullptr, "SetAudioOutputMode"},
+ {11, nullptr, "SetForceMutePolicy"},
+ {12, nullptr, "GetForceMutePolicy"},
+ {13, nullptr, "GetOutputModeSetting"},
+ {14, nullptr, "SetOutputModeSetting"},
+ {15, nullptr, "SetOutputTarget"},
+ {16, nullptr, "SetInputTargetForceEnabled"},
+ {17, nullptr, "SetHeadphoneOutputLevelMode"},
+ {18, nullptr, "GetHeadphoneOutputLevelMode"},
+ {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
+ {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
+ {21, nullptr, "GetAudioOutputTargetForPlayReport"},
+ {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
+ {23, nullptr, "SetSystemOutputMasterVolume"},
+ {24, nullptr, "GetSystemOutputMasterVolume"},
+ {25, nullptr, "GetAudioVolumeDataForPlayReport"},
+ {26, nullptr, "UpdateHeadphoneSettings"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h
new file mode 100644
index 000000000..ed837bdf2
--- /dev/null
+++ b/src/core/hle/service/audio/audctl.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class AudCtl final : public ServiceFramework<AudCtl> {
+public:
+ explicit AudCtl();
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/auddbg.cpp b/src/core/hle/service/audio/auddbg.cpp
new file mode 100644
index 000000000..b08c21a20
--- /dev/null
+++ b/src/core/hle/service/audio/auddbg.cpp
@@ -0,0 +1,20 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/audio/auddbg.h"
+
+namespace Service::Audio {
+
+AudDbg::AudDbg(const char* name) : ServiceFramework{name} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RequestSuspendForDebug"},
+ {1, nullptr, "RequestResumeForDebug"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/auddbg.h b/src/core/hle/service/audio/auddbg.h
new file mode 100644
index 000000000..a2f540b75
--- /dev/null
+++ b/src/core/hle/service/audio/auddbg.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class AudDbg final : public ServiceFramework<AudDbg> {
+public:
+ explicit AudDbg(const char* name);
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp
new file mode 100644
index 000000000..a70d5bca4
--- /dev/null
+++ b/src/core/hle/service/audio/audin_a.cpp
@@ -0,0 +1,22 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/audio/audin_a.h"
+
+namespace Service::Audio {
+
+AudInA::AudInA() : ServiceFramework{"audin:a"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RequestSuspendAudioIns"},
+ {1, nullptr, "RequestResumeAudioIns"},
+ {2, nullptr, "GetAudioInsProcessMasterVolume"},
+ {3, nullptr, "SetAudioInsProcessMasterVolume"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_a.h b/src/core/hle/service/audio/audin_a.h
new file mode 100644
index 000000000..e4c75510f
--- /dev/null
+++ b/src/core/hle/service/audio/audin_a.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class AudInA final : public ServiceFramework<AudInA> {
+public:
+ explicit AudInA();
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index d231e91e1..6b5e15633 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -2,10 +2,16 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/service/audio/audctl.h"
+#include "core/hle/service/audio/auddbg.h"
+#include "core/hle/service/audio/audin_a.h"
#include "core/hle/service/audio/audin_u.h"
#include "core/hle/service/audio/audio.h"
+#include "core/hle/service/audio/audout_a.h"
#include "core/hle/service/audio/audout_u.h"
+#include "core/hle/service/audio/audrec_a.h"
#include "core/hle/service/audio/audrec_u.h"
+#include "core/hle/service/audio/audren_a.h"
#include "core/hle/service/audio/audren_u.h"
#include "core/hle/service/audio/codecctl.h"
#include "core/hle/service/audio/hwopus.h"
@@ -13,12 +19,22 @@
namespace Service::Audio {
void InstallInterfaces(SM::ServiceManager& service_manager) {
+ std::make_shared<AudCtl>()->InstallAsService(service_manager);
+ std::make_shared<AudOutA>()->InstallAsService(service_manager);
std::make_shared<AudOutU>()->InstallAsService(service_manager);
+ std::make_shared<AudInA>()->InstallAsService(service_manager);
std::make_shared<AudInU>()->InstallAsService(service_manager);
+ std::make_shared<AudRecA>()->InstallAsService(service_manager);
std::make_shared<AudRecU>()->InstallAsService(service_manager);
+ std::make_shared<AudRenA>()->InstallAsService(service_manager);
std::make_shared<AudRenU>()->InstallAsService(service_manager);
std::make_shared<CodecCtl>()->InstallAsService(service_manager);
std::make_shared<HwOpus>()->InstallAsService(service_manager);
+
+ std::make_shared<AudDbg>("audin:d")->InstallAsService(service_manager);
+ std::make_shared<AudDbg>("audout:d")->InstallAsService(service_manager);
+ std::make_shared<AudDbg>("audrec:d")->InstallAsService(service_manager);
+ std::make_shared<AudDbg>("audren:d")->InstallAsService(service_manager);
}
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp
new file mode 100644
index 000000000..bf8d40157
--- /dev/null
+++ b/src/core/hle/service/audio/audout_a.cpp
@@ -0,0 +1,24 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/audio/audout_a.h"
+
+namespace Service::Audio {
+
+AudOutA::AudOutA() : ServiceFramework{"audout:a"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RequestSuspendAudioOuts"},
+ {1, nullptr, "RequestResumeAudioOuts"},
+ {2, nullptr, "GetAudioOutsProcessMasterVolume"},
+ {3, nullptr, "SetAudioOutsProcessMasterVolume"},
+ {4, nullptr, "GetAudioOutsProcessRecordVolume"},
+ {5, nullptr, "SetAudioOutsProcessRecordVolume"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_a.h b/src/core/hle/service/audio/audout_a.h
new file mode 100644
index 000000000..91a069152
--- /dev/null
+++ b/src/core/hle/service/audio/audout_a.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class AudOutA final : public ServiceFramework<AudOutA> {
+public:
+ explicit AudOutA();
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 1dcd84d98..ce709ccf4 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -4,9 +4,10 @@
#include <array>
#include <vector>
+
+#include "audio_core/codec.h"
#include "common/logging/log.h"
-#include "core/core_timing.h"
-#include "core/core_timing_util.h"
+#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
@@ -14,17 +15,21 @@
namespace Service::Audio {
-/// Switch sample rate frequency
-constexpr u32 sample_rate{48000};
-/// TODO(st4rk): dynamic number of channels, as I think Switch has support
-/// to more audio channels (probably when Docked I guess)
-constexpr u32 audio_channels{2};
-/// TODO(st4rk): find a proper value for the audio_ticks
-constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 500)};
+namespace ErrCodes {
+enum {
+ ErrorUnknown = 2,
+ BufferCountExceeded = 8,
+};
+}
+
+constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}};
+constexpr int DefaultSampleRate{48000};
class IAudioOut final : public ServiceFramework<IAudioOut> {
public:
- IAudioOut() : ServiceFramework("IAudioOut"), audio_out_state(AudioState::Stopped) {
+ IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
+ : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) {
+
static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
{1, &IAudioOut::StartAudioOut, "StartAudioOut"},
@@ -32,66 +37,65 @@ public:
{3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"},
{4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
{5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"},
- {6, nullptr, "ContainsAudioOutBuffer"},
+ {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
{7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
{8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"},
- {9, nullptr, "GetAudioOutBufferCount"},
+ {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
{10, nullptr, "GetAudioOutPlayedSampleCount"},
{11, nullptr, "FlushAudioOutBuffers"},
};
RegisterHandlers(functions);
// This is the event handle used to check if the audio buffer was released
- buffer_event =
- Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent");
-
- // Register event callback to update the Audio Buffer
- audio_event = CoreTiming::RegisterEvent(
- "IAudioOut::UpdateAudioBuffersCallback", [this](u64 userdata, int cycles_late) {
- UpdateAudioBuffersCallback();
- CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
- });
-
- // Start the audio event
- CoreTiming::ScheduleEvent(audio_ticks, audio_event);
- }
+ buffer_event = Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
- ~IAudioOut() {
- CoreTiming::UnscheduleEvent(audio_event, 0);
+ stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
+ "IAudioOut", [=]() { buffer_event->Signal(); });
}
private:
+ struct AudioBuffer {
+ u64_le next;
+ u64_le buffer;
+ u64_le buffer_capacity;
+ u64_le buffer_size;
+ u64_le offset;
+ };
+ static_assert(sizeof(AudioBuffer) == 0x28, "AudioBuffer is an invalid size");
+
void GetAudioOutState(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u32>(audio_out_state));
+ rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped));
}
void StartAudioOut(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_DEBUG(Service_Audio, "called");
- // Start audio
- audio_out_state = AudioState::Started;
+ if (stream->IsPlaying()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::ErrorUnknown));
+ return;
+ }
+
+ audio_core.StartStream(stream);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void StopAudioOut(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
-
- // Stop audio
- audio_out_state = AudioState::Stopped;
+ LOG_DEBUG(Service_Audio, "called");
- queue_keys.clear();
+ audio_core.StopStream(stream);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_DEBUG(Service_Audio, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
@@ -99,101 +103,107 @@ private:
}
void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_DEBUG(Service_Audio, "(STUBBED) called {}", ctx.Description());
IPC::RequestParser rp{ctx};
- const u64 key{rp.Pop<u64>()};
- queue_keys.insert(queue_keys.begin(), key);
+ const auto& input_buffer{ctx.ReadBuffer()};
+ ASSERT_MSG(input_buffer.size() == sizeof(AudioBuffer),
+ "AudioBuffer input is an invalid size!");
+ AudioBuffer audio_buffer{};
+ std::memcpy(&audio_buffer, input_buffer.data(), sizeof(AudioBuffer));
+ const u64 tag{rp.Pop<u64>()};
+
+ std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16));
+ Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
+
+ if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::BufferCountExceeded));
+ }
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
-
- // TODO(st4rk): This is how libtransistor currently implements the
- // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address
- // is used to know which buffer should be filled with data and send again to the service
- // through AppendAudioOutBuffer. Check if this is the proper way to do it.
- u64 key{0};
-
- if (queue_keys.size()) {
- key = queue_keys.back();
- queue_keys.pop_back();
- }
+ LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
+ IPC::RequestParser rp{ctx};
+ const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
+ const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
- ctx.WriteBuffer(&key, sizeof(u64));
+ std::vector<u64> tags{released_buffers};
+ tags.resize(max_count);
+ ctx.WriteBuffer(tags);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- // TODO(st4rk): This might be the total of released buffers, needs to be verified on
- // hardware
- rb.Push<u32>(static_cast<u32>(queue_keys.size()));
+ rb.Push<u32>(static_cast<u32>(released_buffers.size()));
}
- void UpdateAudioBuffersCallback() {
- if (audio_out_state != AudioState::Started) {
- return;
- }
-
- if (queue_keys.empty()) {
- return;
- }
+ void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+ IPC::RequestParser rp{ctx};
+ const u64 tag{rp.Pop<u64>()};
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(stream->ContainsBuffer(tag));
+ }
- buffer_event->Signal();
+ void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(static_cast<u32>(stream->GetQueueSize()));
}
- enum class AudioState : u32 {
- Started,
- Stopped,
- };
+ AudioCore::AudioOut& audio_core;
+ AudioCore::StreamPtr stream;
- /// This is used to trigger the audio event callback that is going to read the samples from the
- /// audio_buffer list and enqueue the samples using the sink (audio_core).
- CoreTiming::EventType* audio_event;
+ AudoutParams audio_params{};
/// This is the evend handle used to check if the audio buffer was released
Kernel::SharedPtr<Kernel::Event> buffer_event;
-
- /// (st4rk): This is just a temporary workaround for the future implementation. Libtransistor
- /// uses the key as an address in the App, so we need to return when the
- /// GetReleasedAudioOutBuffer_1 is called, otherwise we'll run in problems, because
- /// libtransistor uses the key returned as an pointer.
- std::vector<u64> queue_keys;
-
- AudioState audio_out_state;
};
void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_DEBUG(Service_Audio, "called");
IPC::RequestParser rp{ctx};
- constexpr std::array<char, 15> audio_interface{{"AudioInterface"}};
- ctx.WriteBuffer(audio_interface);
+ ctx.WriteBuffer(DefaultDevice);
IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
rb.Push(RESULT_SUCCESS);
- // TODO(st4rk): We're currently returning only one audio interface (stringlist size). However,
- // it's highly possible to have more than one interface (despite that libtransistor requires
- // only one).
- rb.Push<u32>(1);
+ rb.Push<u32>(1); // Amount of audio devices
}
void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_DEBUG(Service_Audio, "called");
- if (!audio_out_interface) {
- audio_out_interface = std::make_shared<IAudioOut>();
+ ctx.WriteBuffer(DefaultDevice);
+ IPC::RequestParser rp{ctx};
+ auto params{rp.PopRaw<AudoutParams>()};
+ if (params.channel_count <= 2) {
+ // Mono does not exist for audout
+ params.channel_count = 2;
+ } else {
+ params.channel_count = 6;
}
+ if (!params.sample_rate) {
+ params.sample_rate = DefaultSampleRate;
+ }
+
+ // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl
+ // will likely need to be updated as well.
+ ASSERT_MSG(!audio_out_interface, "Unimplemented");
+ audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core);
IPC::ResponseBuilder rb{ctx, 6, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(sample_rate);
- rb.Push<u32>(audio_channels);
- rb.Push<u32>(static_cast<u32>(PcmFormat::Int16));
- rb.Push<u32>(0); // This field is unknown
+ rb.Push<u32>(DefaultSampleRate);
+ rb.Push<u32>(params.channel_count);
+ rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
+ rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
}
@@ -203,6 +213,7 @@ AudOutU::AudOutU() : ServiceFramework("audout:u") {
{2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"},
{3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}};
RegisterHandlers(functions);
+ audio_core = std::make_unique<AudioCore::AudioOut>();
}
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index 847d86aa6..fd491f65d 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -4,6 +4,7 @@
#pragma once
+#include "audio_core/audio_out.h"
#include "core/hle/service/service.h"
namespace Kernel {
@@ -12,6 +13,18 @@ class HLERequestContext;
namespace Service::Audio {
+struct AudoutParams {
+ s32_le sample_rate;
+ u16_le channel_count;
+ INSERT_PADDING_BYTES(2);
+};
+static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size");
+
+enum class AudioState : u32 {
+ Started,
+ Stopped,
+};
+
class IAudioOut;
class AudOutU final : public ServiceFramework<AudOutU> {
@@ -21,19 +34,10 @@ public:
private:
std::shared_ptr<IAudioOut> audio_out_interface;
+ std::unique_ptr<AudioCore::AudioOut> audio_core;
void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);
void OpenAudioOutImpl(Kernel::HLERequestContext& ctx);
-
- enum class PcmFormat : u32 {
- Invalid = 0,
- Int8 = 1,
- Int16 = 2,
- Int24 = 3,
- Int32 = 4,
- PcmFloat = 5,
- Adpcm = 6,
- };
};
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp
new file mode 100644
index 000000000..016eabf53
--- /dev/null
+++ b/src/core/hle/service/audio/audrec_a.cpp
@@ -0,0 +1,20 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/audio/audrec_a.h"
+
+namespace Service::Audio {
+
+AudRecA::AudRecA() : ServiceFramework{"audrec:a"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RequestSuspendFinalOutputRecorders"},
+ {1, nullptr, "RequestResumeFinalOutputRecorders"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/audrec_a.h
new file mode 100644
index 000000000..9685047f2
--- /dev/null
+++ b/src/core/hle/service/audio/audrec_a.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class AudRecA final : public ServiceFramework<AudRecA> {
+public:
+ explicit AudRecA();
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp
new file mode 100644
index 000000000..616ff3dc4
--- /dev/null
+++ b/src/core/hle/service/audio/audren_a.cpp
@@ -0,0 +1,26 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/audio/audren_a.h"
+
+namespace Service::Audio {
+
+AudRenA::AudRenA() : ServiceFramework{"audren:a"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RequestSuspendAudioRenderers"},
+ {1, nullptr, "RequestResumeAudioRenderers"},
+ {2, nullptr, "GetAudioRenderersProcessMasterVolume"},
+ {3, nullptr, "SetAudioRenderersProcessMasterVolume"},
+ {4, nullptr, "RegisterAppletResourceUserId"},
+ {5, nullptr, "UnregisterAppletResourceUserId"},
+ {6, nullptr, "GetAudioRenderersProcessRecordVolume"},
+ {7, nullptr, "SetAudioRenderersProcessRecordVolume"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_a.h b/src/core/hle/service/audio/audren_a.h
new file mode 100644
index 000000000..5ecf2e184
--- /dev/null
+++ b/src/core/hle/service/audio/audren_a.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class AudRenA final : public ServiceFramework<AudRenA> {
+public:
+ explicit AudRenA();
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 6aed9e2fa..9e75eb3a6 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -15,17 +15,14 @@
namespace Service::Audio {
-/// TODO(bunnei): Find a proper value for the audio_ticks
-constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
-
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
public:
- explicit IAudioRenderer(AudioRendererParameter audren_params)
- : ServiceFramework("IAudioRenderer"), worker_params(audren_params) {
+ explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params)
+ : ServiceFramework("IAudioRenderer") {
static const FunctionInfo functions[] = {
- {0, nullptr, "GetAudioRendererSampleRate"},
- {1, nullptr, "GetAudioRendererSampleCount"},
- {2, nullptr, "GetAudioRendererMixBufferCount"},
+ {0, &IAudioRenderer::GetAudioRendererSampleRate, "GetAudioRendererSampleRate"},
+ {1, &IAudioRenderer::GetAudioRendererSampleCount, "GetAudioRendererSampleCount"},
+ {2, &IAudioRenderer::GetAudioRendererMixBufferCount, "GetAudioRendererMixBufferCount"},
{3, nullptr, "GetAudioRendererState"},
{4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
{5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
@@ -39,21 +36,8 @@ public:
RegisterHandlers(functions);
system_event =
- Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioRenderer:SystemEvent");
-
- // Register event callback to update the Audio Buffer
- audio_event = CoreTiming::RegisterEvent(
- "IAudioRenderer::UpdateAudioCallback", [this](u64 userdata, int cycles_late) {
- UpdateAudioCallback();
- CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
- });
-
- // Start the audio event
- CoreTiming::ScheduleEvent(audio_ticks, audio_event);
- voice_status_list.resize(worker_params.voice_count);
- }
- ~IAudioRenderer() {
- CoreTiming::UnscheduleEvent(audio_event, 0);
+ Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
+ renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event);
}
private:
@@ -61,61 +45,31 @@ private:
system_event->Signal();
}
- void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
- UpdateDataHeader config{};
- auto buf = ctx.ReadBuffer();
- std::memcpy(&config, buf.data(), sizeof(UpdateDataHeader));
- u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
-
- std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
- std::memcpy(mem_pool_info.data(),
- buf.data() + sizeof(UpdateDataHeader) + config.behavior_size,
- memory_pool_count * sizeof(MemoryPoolInfo));
-
- std::vector<VoiceInfo> voice_info(worker_params.voice_count);
- std::memcpy(voice_info.data(),
- buf.data() + sizeof(UpdateDataHeader) + config.behavior_size +
- config.memory_pools_size + config.voice_resource_size,
- worker_params.voice_count * sizeof(VoiceInfo));
-
- UpdateDataHeader response_data{worker_params};
-
- ASSERT(ctx.GetWriteBufferSize() == response_data.total_size);
-
- std::vector<u8> output(response_data.total_size);
- std::memcpy(output.data(), &response_data, sizeof(UpdateDataHeader));
- std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
- for (unsigned i = 0; i < memory_pool.size(); i++) {
- if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestAttach)
- memory_pool[i].state = MemoryPoolStates::Attached;
- else if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestDetach)
- memory_pool[i].state = MemoryPoolStates::Detached;
- }
- std::memcpy(output.data() + sizeof(UpdateDataHeader), memory_pool.data(),
- response_data.memory_pools_size);
-
- for (unsigned i = 0; i < voice_info.size(); i++) {
- if (voice_info[i].is_new) {
- voice_status_list[i].played_sample_count = 0;
- voice_status_list[i].wave_buffer_consumed = 0;
- } else if (voice_info[i].play_state == (u8)PlayStates::Started) {
- for (u32 buff_idx = 0; buff_idx < voice_info[i].wave_buffer_count; buff_idx++) {
- voice_status_list[i].played_sample_count +=
- (voice_info[i].wave_buffer[buff_idx].end_sample_offset -
- voice_info[i].wave_buffer[buff_idx].start_sample_offset) /
- 2;
- voice_status_list[i].wave_buffer_consumed++;
- }
- }
- }
- std::memcpy(output.data() + sizeof(UpdateDataHeader) + response_data.memory_pools_size,
- voice_status_list.data(), response_data.voices_size);
+ void GetAudioRendererSampleRate(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(renderer->GetSampleRate());
+ LOG_DEBUG(Service_Audio, "called");
+ }
+
+ void GetAudioRendererSampleCount(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(renderer->GetSampleCount());
+ LOG_DEBUG(Service_Audio, "called");
+ }
- ctx.WriteBuffer(output);
+ void GetAudioRendererMixBufferCount(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(renderer->GetMixBufferCount());
+ LOG_DEBUG(Service_Audio, "called");
+ }
+ void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
+ ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
LOG_WARNING(Service_Audio, "(STUBBED) called");
}
@@ -136,8 +90,6 @@ private:
}
void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
- // system_event->Signal();
-
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(system_event);
@@ -145,131 +97,8 @@ private:
LOG_WARNING(Service_Audio, "(STUBBED) called");
}
- enum class MemoryPoolStates : u32 { // Should be LE
- Invalid = 0x0,
- Unknown = 0x1,
- RequestDetach = 0x2,
- Detached = 0x3,
- RequestAttach = 0x4,
- Attached = 0x5,
- Released = 0x6,
- };
-
- enum class PlayStates : u8 {
- Started = 0,
- Stopped = 1,
- };
-
- struct MemoryPoolEntry {
- MemoryPoolStates state;
- u32_le unknown_4;
- u32_le unknown_8;
- u32_le unknown_c;
- };
- static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
-
- struct MemoryPoolInfo {
- u64_le pool_address;
- u64_le pool_size;
- MemoryPoolStates pool_state;
- INSERT_PADDING_WORDS(3); // Unknown
- };
- static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
-
- struct UpdateDataHeader {
- UpdateDataHeader() {}
-
- explicit UpdateDataHeader(const AudioRendererParameter& config) {
- revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
- behavior_size = 0xb0;
- memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
- voices_size = config.voice_count * 0x10;
- voice_resource_size = 0x0;
- effects_size = config.effect_count * 0x10;
- mixes_size = 0x0;
- sinks_size = config.sink_count * 0x20;
- performance_manager_size = 0x10;
- total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size +
- voices_size + effects_size + sinks_size + performance_manager_size;
- }
-
- u32_le revision;
- u32_le behavior_size;
- u32_le memory_pools_size;
- u32_le voices_size;
- u32_le voice_resource_size;
- u32_le effects_size;
- u32_le mixes_size;
- u32_le sinks_size;
- u32_le performance_manager_size;
- INSERT_PADDING_WORDS(6);
- u32_le total_size;
- };
- static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");
-
- struct BiquadFilter {
- u8 enable;
- INSERT_PADDING_BYTES(1);
- s16_le numerator[3];
- s16_le denominator[2];
- };
- static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");
-
- struct WaveBuffer {
- u64_le buffer_addr;
- u64_le buffer_sz;
- s32_le start_sample_offset;
- s32_le end_sample_offset;
- u8 loop;
- u8 end_of_stream;
- u8 sent_to_server;
- INSERT_PADDING_BYTES(5);
- u64 context_addr;
- u64 context_sz;
- INSERT_PADDING_BYTES(8);
- };
- static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
-
- struct VoiceInfo {
- u32_le id;
- u32_le node_id;
- u8 is_new;
- u8 is_in_use;
- u8 play_state;
- u8 sample_format;
- u32_le sample_rate;
- u32_le priority;
- u32_le sorting_order;
- u32_le channel_count;
- float_le pitch;
- float_le volume;
- BiquadFilter biquad_filter[2];
- u32_le wave_buffer_count;
- u16_le wave_buffer_head;
- INSERT_PADDING_BYTES(6);
- u64_le additional_params_addr;
- u64_le additional_params_sz;
- u32_le mix_id;
- u32_le splitter_info_id;
- WaveBuffer wave_buffer[4];
- u32_le voice_channel_resource_ids[6];
- INSERT_PADDING_BYTES(24);
- };
- static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");
-
- struct VoiceOutStatus {
- u64_le played_sample_count;
- u32_le wave_buffer_consumed;
- INSERT_PADDING_WORDS(1);
- };
- static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
-
- /// This is used to trigger the audio event callback.
- CoreTiming::EventType* audio_event;
-
Kernel::SharedPtr<Kernel::Event> system_event;
- AudioRendererParameter worker_params;
- std::vector<VoiceOutStatus> voice_status_list;
+ std::unique_ptr<AudioCore::AudioRenderer> renderer;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -361,14 +190,15 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
{1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
{2, &AudRenU::GetAudioDevice, "GetAudioDevice"},
{3, nullptr, "OpenAudioRendererAuto"},
- {4, nullptr, "GetAudioDeviceServiceWithRevisionInfo"},
+ {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo,
+ "GetAudioDeviceServiceWithRevisionInfo"},
};
RegisterHandlers(functions);
}
void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto params = rp.PopRaw<AudioRendererParameter>();
+ auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -379,9 +209,9 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto params = rp.PopRaw<AudioRendererParameter>();
+ auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
- u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40);
+ u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40);
buffer_sz += params.unknown_c * 1024;
buffer_sz += 0x940 * (params.unknown_c + 1);
buffer_sz += 0x3F0 * params.voice_count;
@@ -389,7 +219,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10);
buffer_sz +=
Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) *
- (params.unknown_8 + 6),
+ (params.mix_buffer_count + 6),
0x40);
if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
@@ -445,6 +275,16 @@ void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
}
+void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<Audio::IAudioDevice>();
+
+ LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different
+ // based on the current revision
+}
+
bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap
switch (feature) {
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index b9b81db4f..8600ac6e4 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -4,6 +4,7 @@
#pragma once
+#include "audio_core/audio_renderer.h"
#include "core/hle/service/service.h"
namespace Kernel {
@@ -12,24 +13,6 @@ class HLERequestContext;
namespace Service::Audio {
-struct AudioRendererParameter {
- u32_le sample_rate;
- u32_le sample_count;
- u32_le unknown_8;
- u32_le unknown_c;
- u32_le voice_count;
- u32_le sink_count;
- u32_le effect_count;
- u32_le unknown_1c;
- u8 unknown_20;
- INSERT_PADDING_BYTES(3);
- u32_le splitter_count;
- u32_le unknown_2c;
- INSERT_PADDING_WORDS(1);
- u32_le revision;
-};
-static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size");
-
class AudRenU final : public ServiceFramework<AudRenU> {
public:
explicit AudRenU();
@@ -39,6 +22,7 @@ private:
void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
void GetAudioDevice(Kernel::HLERequestContext& ctx);
+ void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx);
enum class AudioFeatures : u32 {
Splitter,
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 844df382c..371cd4997 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+#include <opus.h>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
@@ -9,19 +11,142 @@
namespace Service::Audio {
+struct OpusDeleter {
+ void operator()(void* ptr) const {
+ operator delete(ptr);
+ }
+};
+
+class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
+public:
+ IHardwareOpusDecoderManager(std::unique_ptr<OpusDecoder, OpusDeleter> decoder, u32 sample_rate,
+ u32 channel_count)
+ : ServiceFramework("IHardwareOpusDecoderManager"), decoder(std::move(decoder)),
+ sample_rate(sample_rate), channel_count(channel_count) {
+ static const FunctionInfo functions[] = {
+ {0, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
+ {1, nullptr, "SetContext"},
+ {2, nullptr, "DecodeInterleavedForMultiStream"},
+ {3, nullptr, "SetContextForMultiStream"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ };
+ RegisterHandlers(functions);
+ }
+
+private:
+ void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
+ u32 consumed = 0;
+ u32 sample_count = 0;
+ std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
+ if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ // TODO(ogniK): Use correct error code
+ rb.Push(ResultCode(-1));
+ return;
+ }
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(consumed);
+ rb.Push<u32>(sample_count);
+ ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
+ }
+
+ bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input,
+ std::vector<opus_int16>& output) {
+ size_t raw_output_sz = output.size() * sizeof(opus_int16);
+ if (sizeof(OpusHeader) > input.size())
+ return false;
+ OpusHeader hdr{};
+ std::memcpy(&hdr, input.data(), sizeof(OpusHeader));
+ if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) {
+ return false;
+ }
+ auto frame = input.data() + sizeof(OpusHeader);
+ auto decoded_sample_count = opus_packet_get_nb_samples(
+ frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)),
+ static_cast<opus_int32>(sample_rate));
+ if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz)
+ return false;
+ auto out_sample_count =
+ opus_decode(decoder.get(), frame, hdr.sz, output.data(),
+ (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0);
+ if (out_sample_count < 0)
+ return false;
+ sample_count = out_sample_count;
+ consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz);
+ return true;
+ }
+
+ struct OpusHeader {
+ u32_be sz; // Needs to be BE for some odd reason
+ INSERT_PADDING_WORDS(1);
+ };
+ static_assert(sizeof(OpusHeader) == 0x8, "OpusHeader is an invalid size");
+
+ std::unique_ptr<OpusDecoder, OpusDeleter> decoder;
+ u32 sample_rate;
+ u32 channel_count;
+};
+
+static size_t WorkerBufferSize(u32 channel_count) {
+ ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
+ return opus_decoder_get_size(static_cast<int>(channel_count));
+}
+
void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ auto sample_rate = rp.Pop<u32>();
+ auto channel_count = rp.Pop<u32>();
+ ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
+ sample_rate == 12000 || sample_rate == 8000,
+ "Invalid sample rate");
+ ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
+ u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
+ LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz);
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0x4000);
+ rb.Push<u32>(worker_buffer_sz);
+}
+
+void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ auto sample_rate = rp.Pop<u32>();
+ auto channel_count = rp.Pop<u32>();
+ auto buffer_sz = rp.Pop<u32>();
+ LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate,
+ channel_count, buffer_sz);
+ ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
+ sample_rate == 12000 || sample_rate == 8000,
+ "Invalid sample rate");
+ ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
+
+ size_t worker_sz = WorkerBufferSize(channel_count);
+ ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large");
+ std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
+ static_cast<OpusDecoder*>(operator new(worker_sz))};
+ if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ // TODO(ogniK): Use correct error code
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IHardwareOpusDecoderManager>(std::move(decoder), sample_rate,
+ channel_count);
}
HwOpus::HwOpus() : ServiceFramework("hwopus") {
static const FunctionInfo functions[] = {
- {0, nullptr, "Initialize"},
+ {0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"},
{1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
- {2, nullptr, "InitializeMultiStream"},
- {3, nullptr, "GetWorkBufferSizeMultiStream"},
+ {2, nullptr, "OpenOpusDecoderForMultiStream"},
+ {3, nullptr, "GetWorkBufferSizeForMultiStream"},
};
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
index 090b8c825..5258d59f3 100644
--- a/src/core/hle/service/audio/hwopus.h
+++ b/src/core/hle/service/audio/hwopus.h
@@ -14,6 +14,7 @@ public:
~HwOpus() = default;
private:
+ void OpenOpusDecoder(Kernel::HLERequestContext& ctx);
void GetWorkBufferSize(Kernel::HLERequestContext& ctx);
};
diff --git a/src/core/hle/service/bpc/bpc.cpp b/src/core/hle/service/bpc/bpc.cpp
new file mode 100644
index 000000000..1c1ecdb60
--- /dev/null
+++ b/src/core/hle/service/bpc/bpc.cpp
@@ -0,0 +1,57 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/service/bpc/bpc.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::BPC {
+
+class BPC final : public ServiceFramework<BPC> {
+public:
+ explicit BPC() : ServiceFramework{"bpc"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "ShutdownSystem"},
+ {1, nullptr, "RebootSystem"},
+ {2, nullptr, "GetWakeupReason"},
+ {3, nullptr, "GetShutdownReason"},
+ {4, nullptr, "GetAcOk"},
+ {5, nullptr, "GetBoardPowerControlEvent"},
+ {6, nullptr, "GetSleepButtonState"},
+ {7, nullptr, "GetPowerEvent"},
+ {8, nullptr, "Unknown1"},
+ {9, nullptr, "Unknown2"},
+ {10, nullptr, "Unknown3"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class BPC_R final : public ServiceFramework<BPC_R> {
+public:
+ explicit BPC_R() : ServiceFramework{"bpc:r"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetExternalRtcValue"},
+ {1, nullptr, "SetExternalRtcValue"},
+ {2, nullptr, "ReadExternalRtcResetFlag"},
+ {3, nullptr, "ClearExternalRtcResetFlag"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<BPC>()->InstallAsService(sm);
+ std::make_shared<BPC_R>()->InstallAsService(sm);
+}
+
+} // namespace Service::BPC
diff --git a/src/core/hle/service/bpc/bpc.h b/src/core/hle/service/bpc/bpc.h
new file mode 100644
index 000000000..eaa37be8d
--- /dev/null
+++ b/src/core/hle/service/bpc/bpc.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::BPC {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::BPC
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
new file mode 100644
index 000000000..d0a15cc4c
--- /dev/null
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -0,0 +1,72 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/btdrv/btdrv.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::BtDrv {
+
+class BtDrv final : public ServiceFramework<BtDrv> {
+public:
+ explicit BtDrv() : ServiceFramework{"btdrv"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown"},
+ {1, nullptr, "Init"},
+ {2, nullptr, "Enable"},
+ {3, nullptr, "Disable"},
+ {4, nullptr, "CleanupAndShutdown"},
+ {5, nullptr, "GetAdapterProperties"},
+ {6, nullptr, "GetAdapterProperty"},
+ {7, nullptr, "SetAdapterProperty"},
+ {8, nullptr, "StartDiscovery"},
+ {9, nullptr, "CancelDiscovery"},
+ {10, nullptr, "CreateBond"},
+ {11, nullptr, "RemoveBond"},
+ {12, nullptr, "CancelBond"},
+ {13, nullptr, "PinReply"},
+ {14, nullptr, "SspReply"},
+ {15, nullptr, "Unknown2"},
+ {16, nullptr, "InitInterfaces"},
+ {17, nullptr, "HidHostInterface_Connect"},
+ {18, nullptr, "HidHostInterface_Disconnect"},
+ {19, nullptr, "HidHostInterface_SendData"},
+ {20, nullptr, "HidHostInterface_SendData2"},
+ {21, nullptr, "HidHostInterface_SetReport"},
+ {22, nullptr, "HidHostInterface_GetReport"},
+ {23, nullptr, "HidHostInterface_WakeController"},
+ {24, nullptr, "HidHostInterface_AddPairedDevice"},
+ {25, nullptr, "HidHostInterface_GetPairedDevice"},
+ {26, nullptr, "HidHostInterface_CleanupAndShutdown"},
+ {27, nullptr, "Unknown3"},
+ {28, nullptr, "ExtInterface_SetTSI"},
+ {29, nullptr, "ExtInterface_SetBurstMode"},
+ {30, nullptr, "ExtInterface_SetZeroRetran"},
+ {31, nullptr, "ExtInterface_SetMcMode"},
+ {32, nullptr, "ExtInterface_StartLlrMode"},
+ {33, nullptr, "ExtInterface_ExitLlrMode"},
+ {34, nullptr, "ExtInterface_SetRadio"},
+ {35, nullptr, "ExtInterface_SetVisibility"},
+ {36, nullptr, "Unknown4"},
+ {37, nullptr, "Unknown5"},
+ {38, nullptr, "HidHostInterface_GetLatestPlr"},
+ {39, nullptr, "ExtInterface_GetPendingConnections"},
+ {40, nullptr, "HidHostInterface_GetChannelMap"},
+ {41, nullptr, "SetIsBluetoothBoostEnabled"},
+ {42, nullptr, "GetIsBluetoothBoostEnabled"},
+ {43, nullptr, "SetIsBluetoothAfhEnabled"},
+ {44, nullptr, "GetIsBluetoothAfhEnabled"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<BtDrv>()->InstallAsService(sm);
+}
+
+} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btdrv/btdrv.h b/src/core/hle/service/btdrv/btdrv.h
new file mode 100644
index 000000000..164e56f43
--- /dev/null
+++ b/src/core/hle/service/btdrv/btdrv.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::BtDrv {
+
+/// Registers all BtDrv services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
new file mode 100644
index 000000000..b949bfabd
--- /dev/null
+++ b/src/core/hle/service/btm/btm.cpp
@@ -0,0 +1,121 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/btm/btm.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::BTM {
+
+class BTM final : public ServiceFramework<BTM> {
+public:
+ explicit BTM() : ServiceFramework{"btm"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "RegisterSystemEventForConnectedDeviceConditionImpl"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "RegisterSystemEventForRegisteredDeviceInfoImpl"},
+ {9, nullptr, "Unknown8"},
+ {10, nullptr, "Unknown9"},
+ {11, nullptr, "Unknown10"},
+ {12, nullptr, "Unknown11"},
+ {13, nullptr, "Unknown12"},
+ {14, nullptr, "EnableRadioImpl"},
+ {15, nullptr, "DisableRadioImpl"},
+ {16, nullptr, "Unknown13"},
+ {17, nullptr, "Unknown14"},
+ {18, nullptr, "Unknown15"},
+ {19, nullptr, "Unknown16"},
+ {20, nullptr, "Unknown17"},
+ {21, nullptr, "Unknown18"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class BTM_DBG final : public ServiceFramework<BTM_DBG> {
+public:
+ explicit BTM_DBG() : ServiceFramework{"btm:dbg"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RegisterSystemEventForDiscoveryImpl"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "Unknown8"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
+public:
+ explicit IBtmSystemCore() : ServiceFramework{"IBtmSystemCore"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "StartGamepadPairingImpl"},
+ {1, nullptr, "CancelGamepadPairingImpl"},
+ {2, nullptr, "ClearGamepadPairingDatabaseImpl"},
+ {3, nullptr, "GetPairedGamepadCountImpl"},
+ {4, nullptr, "EnableRadioImpl"},
+ {5, nullptr, "DisableRadioImpl"},
+ {6, nullptr, "GetRadioOnOffImpl"},
+ {7, nullptr, "AcquireRadioEventImpl"},
+ {8, nullptr, "AcquireGamepadPairingEventImpl"},
+ {9, nullptr, "IsGamepadPairingStartedImpl"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class BTM_SYS final : public ServiceFramework<BTM_SYS> {
+public:
+ explicit BTM_SYS() : ServiceFramework{"btm:sys"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &BTM_SYS::GetCoreImpl, "GetCoreImpl"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void GetCoreImpl(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IBtmSystemCore>();
+
+ LOG_DEBUG(Service_BTM, "called");
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<BTM>()->InstallAsService(sm);
+ std::make_shared<BTM_DBG>()->InstallAsService(sm);
+ std::make_shared<BTM_SYS>()->InstallAsService(sm);
+}
+
+} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h
new file mode 100644
index 000000000..e6425a7e3
--- /dev/null
+++ b/src/core/hle/service/btm/btm.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::BTM {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::BTM
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp
new file mode 100644
index 000000000..ae7b0720b
--- /dev/null
+++ b/src/core/hle/service/caps/caps.cpp
@@ -0,0 +1,152 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/service/caps/caps.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::Capture {
+
+class CAPS_A final : public ServiceFramework<CAPS_A> {
+public:
+ explicit CAPS_A() : ServiceFramework{"caps:a"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "Unknown3"},
+ {3, nullptr, "Unknown4"},
+ {4, nullptr, "Unknown5"},
+ {5, nullptr, "Unknown6"},
+ {6, nullptr, "Unknown7"},
+ {7, nullptr, "Unknown8"},
+ {8, nullptr, "Unknown9"},
+ {9, nullptr, "Unknown10"},
+ {10, nullptr, "Unknown11"},
+ {11, nullptr, "Unknown12"},
+ {12, nullptr, "Unknown13"},
+ {13, nullptr, "Unknown14"},
+ {14, nullptr, "Unknown15"},
+ {301, nullptr, "Unknown16"},
+ {401, nullptr, "Unknown17"},
+ {501, nullptr, "Unknown18"},
+ {1001, nullptr, "Unknown19"},
+ {1002, nullptr, "Unknown20"},
+ {8001, nullptr, "Unknown21"},
+ {8002, nullptr, "Unknown22"},
+ {8011, nullptr, "Unknown23"},
+ {8012, nullptr, "Unknown24"},
+ {8021, nullptr, "Unknown25"},
+ {10011, nullptr, "Unknown26"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class CAPS_C final : public ServiceFramework<CAPS_C> {
+public:
+ explicit CAPS_C() : ServiceFramework{"caps:c"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {2001, nullptr, "Unknown1"},
+ {2002, nullptr, "Unknown2"},
+ {2011, nullptr, "Unknown3"},
+ {2012, nullptr, "Unknown4"},
+ {2013, nullptr, "Unknown5"},
+ {2014, nullptr, "Unknown6"},
+ {2101, nullptr, "Unknown7"},
+ {2102, nullptr, "Unknown8"},
+ {2201, nullptr, "Unknown9"},
+ {2301, nullptr, "Unknown10"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class CAPS_SC final : public ServiceFramework<CAPS_SC> {
+public:
+ explicit CAPS_SC() : ServiceFramework{"caps:sc"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {1001, nullptr, "Unknown3"},
+ {1002, nullptr, "Unknown4"},
+ {1003, nullptr, "Unknown5"},
+ {1011, nullptr, "Unknown6"},
+ {1012, nullptr, "Unknown7"},
+ {1201, nullptr, "Unknown8"},
+ {1202, nullptr, "Unknown9"},
+ {1203, nullptr, "Unknown10"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class CAPS_SS final : public ServiceFramework<CAPS_SS> {
+public:
+ explicit CAPS_SS() : ServiceFramework{"caps:ss"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {201, nullptr, "Unknown1"},
+ {202, nullptr, "Unknown2"},
+ {203, nullptr, "Unknown3"},
+ {204, nullptr, "Unknown4"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class CAPS_SU final : public ServiceFramework<CAPS_SU> {
+public:
+ explicit CAPS_SU() : ServiceFramework{"caps:su"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {201, nullptr, "SaveScreenShot"},
+ {203, nullptr, "SaveScreenShotEx0"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class CAPS_U final : public ServiceFramework<CAPS_U> {
+public:
+ explicit CAPS_U() : ServiceFramework{"caps:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {102, nullptr, "GetAlbumFileListByAruid"},
+ {103, nullptr, "DeleteAlbumFileByAruid"},
+ {104, nullptr, "GetAlbumFileSizeByAruid"},
+ {110, nullptr, "LoadAlbumScreenShotImageByAruid"},
+ {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"},
+ {60002, nullptr, "OpenAccessorSessionForApplication"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<CAPS_A>()->InstallAsService(sm);
+ std::make_shared<CAPS_C>()->InstallAsService(sm);
+ std::make_shared<CAPS_SC>()->InstallAsService(sm);
+ std::make_shared<CAPS_SS>()->InstallAsService(sm);
+ std::make_shared<CAPS_SU>()->InstallAsService(sm);
+ std::make_shared<CAPS_U>()->InstallAsService(sm);
+}
+
+} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h
new file mode 100644
index 000000000..471185dfa
--- /dev/null
+++ b/src/core/hle/service/caps/caps.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::Capture {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::Capture
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp
new file mode 100644
index 000000000..566fbf924
--- /dev/null
+++ b/src/core/hle/service/fgm/fgm.cpp
@@ -0,0 +1,75 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/fgm/fgm.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::FGM {
+
+class IRequest final : public ServiceFramework<IRequest> {
+public:
+ explicit IRequest() : ServiceFramework{"IRequest"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "Set"},
+ {2, nullptr, "Get"},
+ {3, nullptr, "Cancel"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class FGM final : public ServiceFramework<FGM> {
+public:
+ explicit FGM(const char* name) : ServiceFramework{name} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &FGM::Initialize, "Initialize"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void Initialize(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IRequest>();
+
+ LOG_DEBUG(Service_FGM, "called");
+ }
+};
+
+class FGM_DBG final : public ServiceFramework<FGM_DBG> {
+public:
+ explicit FGM_DBG() : ServiceFramework{"fgm:dbg"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "Read"},
+ {2, nullptr, "Cancel"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<FGM>("fgm")->InstallAsService(sm);
+ std::make_shared<FGM>("fgm:0")->InstallAsService(sm);
+ std::make_shared<FGM>("fgm:9")->InstallAsService(sm);
+ std::make_shared<FGM_DBG>()->InstallAsService(sm);
+}
+
+} // namespace Service::FGM
diff --git a/src/core/hle/service/fgm/fgm.h b/src/core/hle/service/fgm/fgm.h
new file mode 100644
index 000000000..e59691264
--- /dev/null
+++ b/src/core/hle/service/fgm/fgm.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::FGM {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::FGM
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index fdd2fda18..da658cbe6 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -14,6 +14,8 @@
#include "core/file_sys/vfs_offset.h"
#include "core/file_sys/vfs_real.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/filesystem/fsp_ldr.h"
+#include "core/hle/service/filesystem/fsp_pr.h"
#include "core/hle/service/filesystem/fsp_srv.h"
namespace Service::FileSystem {
@@ -57,7 +59,7 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64
ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
std::string path(FileUtil::SanitizePath(path_));
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
- if (path == "/" || path == "\\") {
+ if (path.empty()) {
// TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
return RESULT_SUCCESS;
}
@@ -224,6 +226,7 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
static std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
static std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
static std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
+static std::unique_ptr<FileSys::BISFactory> bis_factory;
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second RomFS");
@@ -246,6 +249,13 @@ ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
return RESULT_SUCCESS;
}
+ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
+ ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS");
+ bis_factory = std::move(factory);
+ LOG_DEBUG(Service_FS, "Registred BIS");
+ return RESULT_SUCCESS;
+}
+
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id) {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}", title_id);
@@ -279,15 +289,26 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
return sdmc_factory->Open();
}
-void RegisterFileSystems() {
+std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents() {
+ return bis_factory->GetSystemNANDContents();
+}
+
+std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents() {
+ return bis_factory->GetUserNANDContents();
+}
+
+void RegisterFileSystems(const FileSys::VirtualFilesystem& vfs) {
romfs_factory = nullptr;
save_data_factory = nullptr;
sdmc_factory = nullptr;
- auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>(
- FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite);
- auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>(
- FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::ReadWrite);
+ auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
+ FileSys::Mode::ReadWrite);
+ auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir),
+ FileSys::Mode::ReadWrite);
+
+ if (bis_factory == nullptr)
+ bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory);
auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
save_data_factory = std::move(savedata);
@@ -296,8 +317,10 @@ void RegisterFileSystems() {
sdmc_factory = std::move(sdcard);
}
-void InstallInterfaces(SM::ServiceManager& service_manager) {
- RegisterFileSystems();
+void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) {
+ RegisterFileSystems(vfs);
+ std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
+ std::make_shared<FSP_PR>()->InstallAsService(service_manager);
std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
}
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index d4483daa5..1d6f922dd 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -6,6 +6,7 @@
#include <memory>
#include "common/common_types.h"
+#include "core/file_sys/bis_factory.h"
#include "core/file_sys/directory.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/romfs_factory.h"
@@ -24,19 +25,18 @@ namespace FileSystem {
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
+ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
-// TODO(DarkLordZach): BIS Filesystem
-// ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id);
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
FileSys::SaveDataDescriptor save_struct);
ResultVal<FileSys::VirtualDir> OpenSDMC();
-// TODO(DarkLordZach): BIS Filesystem
-// ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS();
+std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents();
+std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents();
/// Registers all Filesystem services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs);
// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp
new file mode 100644
index 000000000..0ab9c2606
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_ldr.cpp
@@ -0,0 +1,22 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/filesystem/fsp_ldr.h"
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+FSP_LDR::FSP_LDR() : ServiceFramework{"fsp:ldr"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "OpenCodeFileSystem"},
+ {1, nullptr, "IsArchivedProgram"},
+ {2, nullptr, "SetCurrentProcess"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp_ldr.h
new file mode 100644
index 000000000..fa8e11b4c
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_ldr.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class FSP_LDR final : public ServiceFramework<FSP_LDR> {
+public:
+ explicit FSP_LDR();
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp
new file mode 100644
index 000000000..32b0ae454
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_pr.cpp
@@ -0,0 +1,23 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/filesystem/fsp_pr.h"
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+FSP_PR::FSP_PR() : ServiceFramework{"fsp:pr"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RegisterProgram"},
+ {1, nullptr, "UnregisterProgram"},
+ {2, nullptr, "SetCurrentProcess"},
+ {256, nullptr, "SetEnabledProgramVerification"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp_pr.h
new file mode 100644
index 000000000..62edcd08a
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_pr.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class FSP_PR final : public ServiceFramework<FSP_PR> {
+public:
+ explicit FSP_PR();
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index e7ffb6bd1..1470f9017 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -193,13 +193,10 @@ private:
template <typename T>
static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data,
FileSys::EntryType type) {
+ entries.reserve(entries.size() + new_data.size());
+
for (const auto& new_entry : new_data) {
- FileSys::Entry entry;
- entry.filename[0] = '\0';
- std::strncat(entry.filename, new_entry->GetName().c_str(), FileSys::FILENAME_LENGTH - 1);
- entry.type = type;
- entry.file_size = new_entry->GetSize();
- entries.emplace_back(std::move(entry));
+ entries.emplace_back(new_entry->GetName(), type, new_entry->GetSize());
}
}
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index fb4d89068..f2b0e509a 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -9,10 +9,110 @@
namespace Service::Friend {
+class IFriendService final : public ServiceFramework<IFriendService> {
+public:
+ IFriendService() : ServiceFramework("IFriendService") {
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetCompletionEvent"},
+ {1, nullptr, "Cancel"},
+ {10100, nullptr, "GetFriendListIds"},
+ {10101, nullptr, "GetFriendList"},
+ {10102, nullptr, "UpdateFriendInfo"},
+ {10110, nullptr, "GetFriendProfileImage"},
+ {10200, nullptr, "SendFriendRequestForApplication"},
+ {10211, nullptr, "AddFacedFriendRequestForApplication"},
+ {10400, nullptr, "GetBlockedUserListIds"},
+ {10500, nullptr, "GetProfileList"},
+ {10600, nullptr, "DeclareOpenOnlinePlaySession"},
+ {10601, &IFriendService::DeclareCloseOnlinePlaySession,
+ "DeclareCloseOnlinePlaySession"},
+ {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
+ {10700, nullptr, "GetPlayHistoryRegistrationKey"},
+ {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
+ {10702, nullptr, "AddPlayHistory"},
+ {11000, nullptr, "GetProfileImageUrl"},
+ {20100, nullptr, "GetFriendCount"},
+ {20101, nullptr, "GetNewlyFriendCount"},
+ {20102, nullptr, "GetFriendDetailedInfo"},
+ {20103, nullptr, "SyncFriendList"},
+ {20104, nullptr, "RequestSyncFriendList"},
+ {20110, nullptr, "LoadFriendSetting"},
+ {20200, nullptr, "GetReceivedFriendRequestCount"},
+ {20201, nullptr, "GetFriendRequestList"},
+ {20300, nullptr, "GetFriendCandidateList"},
+ {20301, nullptr, "GetNintendoNetworkIdInfo"},
+ {20302, nullptr, "GetSnsAccountLinkage"},
+ {20303, nullptr, "GetSnsAccountProfile"},
+ {20304, nullptr, "GetSnsAccountFriendList"},
+ {20400, nullptr, "GetBlockedUserList"},
+ {20401, nullptr, "SyncBlockedUserList"},
+ {20500, nullptr, "GetProfileExtraList"},
+ {20501, nullptr, "GetRelationship"},
+ {20600, nullptr, "GetUserPresenceView"},
+ {20700, nullptr, "GetPlayHistoryList"},
+ {20701, nullptr, "GetPlayHistoryStatistics"},
+ {20800, nullptr, "LoadUserSetting"},
+ {20801, nullptr, "SyncUserSetting"},
+ {20900, nullptr, "RequestListSummaryOverlayNotification"},
+ {21000, nullptr, "GetExternalApplicationCatalog"},
+ {30100, nullptr, "DropFriendNewlyFlags"},
+ {30101, nullptr, "DeleteFriend"},
+ {30110, nullptr, "DropFriendNewlyFlag"},
+ {30120, nullptr, "ChangeFriendFavoriteFlag"},
+ {30121, nullptr, "ChangeFriendOnlineNotificationFlag"},
+ {30200, nullptr, "SendFriendRequest"},
+ {30201, nullptr, "SendFriendRequestWithApplicationInfo"},
+ {30202, nullptr, "CancelFriendRequest"},
+ {30203, nullptr, "AcceptFriendRequest"},
+ {30204, nullptr, "RejectFriendRequest"},
+ {30205, nullptr, "ReadFriendRequest"},
+ {30210, nullptr, "GetFacedFriendRequestRegistrationKey"},
+ {30211, nullptr, "AddFacedFriendRequest"},
+ {30212, nullptr, "CancelFacedFriendRequest"},
+ {30213, nullptr, "GetFacedFriendRequestProfileImage"},
+ {30214, nullptr, "GetFacedFriendRequestProfileImageFromPath"},
+ {30215, nullptr, "SendFriendRequestWithExternalApplicationCatalogId"},
+ {30216, nullptr, "ResendFacedFriendRequest"},
+ {30217, nullptr, "SendFriendRequestWithNintendoNetworkIdInfo"},
+ {30300, nullptr, "GetSnsAccountLinkPageUrl"},
+ {30301, nullptr, "UnlinkSnsAccount"},
+ {30400, nullptr, "BlockUser"},
+ {30401, nullptr, "BlockUserWithApplicationInfo"},
+ {30402, nullptr, "UnblockUser"},
+ {30500, nullptr, "GetProfileExtraFromFriendCode"},
+ {30700, nullptr, "DeletePlayHistory"},
+ {30810, nullptr, "ChangePresencePermission"},
+ {30811, nullptr, "ChangeFriendRequestReception"},
+ {30812, nullptr, "ChangePlayLogPermission"},
+ {30820, nullptr, "IssueFriendCode"},
+ {30830, nullptr, "ClearPlayLog"},
+ {49900, nullptr, "DeleteNetworkServiceAccountCache"},
+ };
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
+ // Stub used by Splatoon 2
+ LOG_WARNING(Service_ACC, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
+ // Stub used by Retro City Rampage
+ LOG_WARNING(Service_ACC, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+};
+
void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_Friend, "(STUBBED) called");
+ rb.PushIpcInterface<IFriendService>();
+ LOG_DEBUG(Service_ACC, "called");
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
diff --git a/src/core/hle/service/grc/grc.cpp b/src/core/hle/service/grc/grc.cpp
new file mode 100644
index 000000000..24910ac6c
--- /dev/null
+++ b/src/core/hle/service/grc/grc.cpp
@@ -0,0 +1,31 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/service/grc/grc.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::GRC {
+
+class GRC final : public ServiceFramework<GRC> {
+public:
+ explicit GRC() : ServiceFramework{"grc:c"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1, nullptr, "OpenContinuousRecorder"},
+ {2, nullptr, "OpenGameMovieTrimmer"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<GRC>()->InstallAsService(sm);
+}
+
+} // namespace Service::GRC
diff --git a/src/core/hle/service/grc/grc.h b/src/core/hle/service/grc/grc.h
new file mode 100644
index 000000000..e0d29e70d
--- /dev/null
+++ b/src/core/hle/service/grc/grc.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::GRC {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::GRC
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 9a02ba686..970942d3f 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -14,6 +14,8 @@
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/hid/irs.h"
+#include "core/hle/service/hid/xcd.h"
#include "core/hle/service/service.h"
namespace Service::HID {
@@ -289,6 +291,7 @@ private:
class Hid final : public ServiceFramework<Hid> {
public:
Hid() : ServiceFramework("hid") {
+ // clang-format off
static const FunctionInfo functions[] = {
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
{1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
@@ -324,24 +327,23 @@ public:
{79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
{80, nullptr, "GetGyroscopeZeroDriftMode"},
{81, nullptr, "ResetGyroscopeZeroDriftMode"},
- {82, nullptr, "IsSixAxisSensorAtRest"},
+ {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
{91, nullptr, "ActivateGesture"},
{100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
{101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
{102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
{103, &Hid::ActivateNpad, "ActivateNpad"},
{104, nullptr, "DeactivateNpad"},
- {106, &Hid::AcquireNpadStyleSetUpdateEventHandle,
- "AcquireNpadStyleSetUpdateEventHandle"},
- {107, nullptr, "DisconnectNpad"},
+ {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
+ {107, &Hid::DisconnectNpad, "DisconnectNpad"},
{108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
+ {109, nullptr, "ActivateNpadWithRevision"},
{120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
{121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
- {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault,
- "SetNpadJoyAssignmentModeSingleByDefault"},
+ {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
{123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
{124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
- {125, nullptr, "MergeSingleJoyAsDualJoy"},
+ {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
{126, nullptr, "StartLrAssignmentMode"},
{127, nullptr, "StopLrAssignmentMode"},
{128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
@@ -395,6 +397,8 @@ public:
{1000, nullptr, "SetNpadCommunicationMode"},
{1001, nullptr, "GetNpadCommunicationMode"},
};
+ // clang-format on
+
RegisterHandlers(functions);
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle");
@@ -453,6 +457,14 @@ private:
LOG_WARNING(Service_HID, "(STUBBED) called");
}
+ void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ // TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
+ rb.Push(true);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -485,6 +497,12 @@ private:
LOG_WARNING(Service_HID, "(STUBBED) called");
}
+ void DisconnectNpad(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -528,6 +546,12 @@ private:
LOG_WARNING(Service_HID, "(STUBBED) called");
}
+ void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -555,10 +579,233 @@ private:
}
};
+class HidDbg final : public ServiceFramework<HidDbg> {
+public:
+ explicit HidDbg() : ServiceFramework{"hid:dbg"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "DeactivateDebugPad"},
+ {1, nullptr, "SetDebugPadAutoPilotState"},
+ {2, nullptr, "UnsetDebugPadAutoPilotState"},
+ {10, nullptr, "DeactivateTouchScreen"},
+ {11, nullptr, "SetTouchScreenAutoPilotState"},
+ {12, nullptr, "UnsetTouchScreenAutoPilotState"},
+ {20, nullptr, "DeactivateMouse"},
+ {21, nullptr, "SetMouseAutoPilotState"},
+ {22, nullptr, "UnsetMouseAutoPilotState"},
+ {30, nullptr, "DeactivateKeyboard"},
+ {31, nullptr, "SetKeyboardAutoPilotState"},
+ {32, nullptr, "UnsetKeyboardAutoPilotState"},
+ {50, nullptr, "DeactivateXpad"},
+ {51, nullptr, "SetXpadAutoPilotState"},
+ {52, nullptr, "UnsetXpadAutoPilotState"},
+ {60, nullptr, "DeactivateJoyXpad"},
+ {91, nullptr, "DeactivateGesture"},
+ {110, nullptr, "DeactivateHomeButton"},
+ {111, nullptr, "SetHomeButtonAutoPilotState"},
+ {112, nullptr, "UnsetHomeButtonAutoPilotState"},
+ {120, nullptr, "DeactivateSleepButton"},
+ {121, nullptr, "SetSleepButtonAutoPilotState"},
+ {122, nullptr, "UnsetSleepButtonAutoPilotState"},
+ {123, nullptr, "DeactivateInputDetector"},
+ {130, nullptr, "DeactivateCaptureButton"},
+ {131, nullptr, "SetCaptureButtonAutoPilotState"},
+ {132, nullptr, "UnsetCaptureButtonAutoPilotState"},
+ {133, nullptr, "SetShiftAccelerometerCalibrationValue"},
+ {134, nullptr, "GetShiftAccelerometerCalibrationValue"},
+ {135, nullptr, "SetShiftGyroscopeCalibrationValue"},
+ {136, nullptr, "GetShiftGyroscopeCalibrationValue"},
+ {140, nullptr, "DeactivateConsoleSixAxisSensor"},
+ {141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
+ {142, nullptr, "DeactivateSevenSixAxisSensor"},
+ {201, nullptr, "ActivateFirmwareUpdate"},
+ {202, nullptr, "DeactivateFirmwareUpdate"},
+ {203, nullptr, "StartFirmwareUpdate"},
+ {204, nullptr, "GetFirmwareUpdateStage"},
+ {205, nullptr, "GetFirmwareVersion"},
+ {206, nullptr, "GetDestinationFirmwareVersion"},
+ {207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
+ {208, nullptr, "StartFirmwareUpdateForRevert"},
+ {209, nullptr, "GetAvailableFirmwareVersionForRevert"},
+ {210, nullptr, "IsFirmwareUpdatingDevice"},
+ {221, nullptr, "UpdateControllerColor"},
+ {222, nullptr, "ConnectUsbPadsAsync"},
+ {223, nullptr, "DisconnectUsbPadsAsync"},
+ {224, nullptr, "UpdateDesignInfo"},
+ {225, nullptr, "GetUniquePadDriverState"},
+ {226, nullptr, "GetSixAxisSensorDriverStates"},
+ {301, nullptr, "GetAbstractedPadHandles"},
+ {302, nullptr, "GetAbstractedPadState"},
+ {303, nullptr, "GetAbstractedPadsState"},
+ {321, nullptr, "SetAutoPilotVirtualPadState"},
+ {322, nullptr, "UnsetAutoPilotVirtualPadState"},
+ {323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
+ {350, nullptr, "AddRegisteredDevice"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class HidSys final : public ServiceFramework<HidSys> {
+public:
+ explicit HidSys() : ServiceFramework{"hid:sys"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {31, nullptr, "SendKeyboardLockKeyEvent"},
+ {101, nullptr, "AcquireHomeButtonEventHandle"},
+ {111, nullptr, "ActivateHomeButton"},
+ {121, nullptr, "AcquireSleepButtonEventHandle"},
+ {131, nullptr, "ActivateSleepButton"},
+ {141, nullptr, "AcquireCaptureButtonEventHandle"},
+ {151, nullptr, "ActivateCaptureButton"},
+ {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
+ {211, nullptr, "GetNpadsWithNfc"},
+ {212, nullptr, "AcquireNfcActivateEventHandle"},
+ {213, nullptr, "ActivateNfc"},
+ {214, nullptr, "GetXcdHandleForNpadWithNfc"},
+ {215, nullptr, "IsNfcActivated"},
+ {230, nullptr, "AcquireIrSensorEventHandle"},
+ {231, nullptr, "ActivateIrSensor"},
+ {301, nullptr, "ActivateNpadSystem"},
+ {303, nullptr, "ApplyNpadSystemCommonPolicy"},
+ {304, nullptr, "EnableAssigningSingleOnSlSrPress"},
+ {305, nullptr, "DisableAssigningSingleOnSlSrPress"},
+ {306, nullptr, "GetLastActiveNpad"},
+ {307, nullptr, "GetNpadSystemExtStyle"},
+ {308, nullptr, "ApplyNpadSystemCommonPolicyFull"},
+ {309, nullptr, "GetNpadFullKeyGripColor"},
+ {311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
+ {321, nullptr, "GetUniquePadsFromNpad"},
+ {322, nullptr, "GetIrSensorState"},
+ {323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
+ {500, nullptr, "SetAppletResourceUserId"},
+ {501, nullptr, "RegisterAppletResourceUserId"},
+ {502, nullptr, "UnregisterAppletResourceUserId"},
+ {503, nullptr, "EnableAppletToGetInput"},
+ {504, nullptr, "SetAruidValidForVibration"},
+ {505, nullptr, "EnableAppletToGetSixAxisSensor"},
+ {510, nullptr, "SetVibrationMasterVolume"},
+ {511, nullptr, "GetVibrationMasterVolume"},
+ {512, nullptr, "BeginPermitVibrationSession"},
+ {513, nullptr, "EndPermitVibrationSession"},
+ {520, nullptr, "EnableHandheldHids"},
+ {521, nullptr, "DisableHandheldHids"},
+ {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
+ {541, nullptr, "GetPlayReportControllerUsages"},
+ {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
+ {543, nullptr, "GetRegisteredDevicesOld"},
+ {544, nullptr, "AcquireConnectionTriggerTimeoutEvent"},
+ {545, nullptr, "SendConnectionTrigger"},
+ {546, nullptr, "AcquireDeviceRegisteredEventForControllerSupport"},
+ {547, nullptr, "GetAllowedBluetoothLinksCount"},
+ {548, nullptr, "GetRegisteredDevices"},
+ {700, nullptr, "ActivateUniquePad"},
+ {702, nullptr, "AcquireUniquePadConnectionEventHandle"},
+ {703, nullptr, "GetUniquePadIds"},
+ {751, nullptr, "AcquireJoyDetachOnBluetoothOffEventHandle"},
+ {800, nullptr, "ListSixAxisSensorHandles"},
+ {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
+ {802, nullptr, "ResetSixAxisSensorCalibrationValues"},
+ {803, nullptr, "StartSixAxisSensorUserCalibration"},
+ {804, nullptr, "CancelSixAxisSensorUserCalibration"},
+ {805, nullptr, "GetUniquePadBluetoothAddress"},
+ {806, nullptr, "DisconnectUniquePad"},
+ {807, nullptr, "GetUniquePadType"},
+ {808, nullptr, "GetUniquePadInterface"},
+ {809, nullptr, "GetUniquePadSerialNumber"},
+ {810, nullptr, "GetUniquePadControllerNumber"},
+ {811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
+ {821, nullptr, "StartAnalogStickManualCalibration"},
+ {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
+ {823, nullptr, "CancelAnalogStickManualCalibration"},
+ {824, nullptr, "ResetAnalogStickManualCalibration"},
+ {825, nullptr, "GetAnalogStickState"},
+ {826, nullptr, "GetAnalogStickManualCalibrationStage"},
+ {827, nullptr, "IsAnalogStickButtonPressed"},
+ {828, nullptr, "IsAnalogStickInReleasePosition"},
+ {829, nullptr, "IsAnalogStickInCircumference"},
+ {850, nullptr, "IsUsbFullKeyControllerEnabled"},
+ {851, nullptr, "EnableUsbFullKeyController"},
+ {852, nullptr, "IsUsbConnected"},
+ {900, nullptr, "ActivateInputDetector"},
+ {901, nullptr, "NotifyInputDetector"},
+ {1000, nullptr, "InitializeFirmwareUpdate"},
+ {1001, nullptr, "GetFirmwareVersion"},
+ {1002, nullptr, "GetAvailableFirmwareVersion"},
+ {1003, nullptr, "IsFirmwareUpdateAvailable"},
+ {1004, nullptr, "CheckFirmwareUpdateRequired"},
+ {1005, nullptr, "StartFirmwareUpdate"},
+ {1006, nullptr, "AbortFirmwareUpdate"},
+ {1007, nullptr, "GetFirmwareUpdateState"},
+ {1008, nullptr, "ActivateAudioControl"},
+ {1009, nullptr, "AcquireAudioControlEventHandle"},
+ {1010, nullptr, "GetAudioControlStates"},
+ {1011, nullptr, "DeactivateAudioControl"},
+ {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
+ {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
+ {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
+ {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
+ {1100, nullptr, "GetHidbusSystemServiceObject"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class HidTmp final : public ServiceFramework<HidTmp> {
+public:
+ explicit HidTmp() : ServiceFramework{"hid:tmp"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetConsoleSixAxisSensorCalibrationValues"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class HidBus final : public ServiceFramework<HidBus> {
+public:
+ explicit HidBus() : ServiceFramework{"hidbus"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1, nullptr, "GetBusHandle"},
+ {2, nullptr, "IsExternalDeviceConnected"},
+ {3, nullptr, "Initialize"},
+ {4, nullptr, "Finalize"},
+ {5, nullptr, "EnableExternalDevice"},
+ {6, nullptr, "GetExternalDeviceId"},
+ {7, nullptr, "SendCommandAsync"},
+ {8, nullptr, "GetSendCommandAsynceResult"},
+ {9, nullptr, "SetEventForSendCommandAsycResult"},
+ {10, nullptr, "GetSharedMemoryHandle"},
+ {11, nullptr, "EnableJoyPollingReceiveMode"},
+ {12, nullptr, "DisableJoyPollingReceiveMode"},
+ {13, nullptr, "GetPollingData"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
void ReloadInputDevices() {}
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<Hid>()->InstallAsService(service_manager);
+ std::make_shared<HidBus>()->InstallAsService(service_manager);
+ std::make_shared<HidDbg>()->InstallAsService(service_manager);
+ std::make_shared<HidSys>()->InstallAsService(service_manager);
+ std::make_shared<HidTmp>()->InstallAsService(service_manager);
+
+ std::make_shared<IRS>()->InstallAsService(service_manager);
+ std::make_shared<IRS_SYS>()->InstallAsService(service_manager);
+
+ std::make_shared<XCD_SYS>()->InstallAsService(service_manager);
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
new file mode 100644
index 000000000..aaf311912
--- /dev/null
+++ b/src/core/hle/service/hid/irs.cpp
@@ -0,0 +1,49 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/hid/irs.h"
+
+namespace Service::HID {
+
+IRS::IRS() : ServiceFramework{"irs"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {302, nullptr, "ActivateIrsensor"},
+ {303, nullptr, "DeactivateIrsensor"},
+ {304, nullptr, "GetIrsensorSharedMemoryHandle"},
+ {305, nullptr, "StopImageProcessor"},
+ {306, nullptr, "RunMomentProcessor"},
+ {307, nullptr, "RunClusteringProcessor"},
+ {308, nullptr, "RunImageTransferProcessor"},
+ {309, nullptr, "GetImageTransferProcessorState"},
+ {310, nullptr, "RunTeraPluginProcessor"},
+ {311, nullptr, "GetNpadIrCameraHandle"},
+ {312, nullptr, "RunPointingProcessor"},
+ {313, nullptr, "SuspendImageProcessor"},
+ {314, nullptr, "CheckFirmwareVersion"},
+ {315, nullptr, "SetFunctionLevel"},
+ {316, nullptr, "RunImageTransferExProcessor"},
+ {317, nullptr, "RunIrLedProcessor"},
+ {318, nullptr, "StopImageProcessorAsync"},
+ {319, nullptr, "ActivateIrsensorWithFunctionLevel"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {500, nullptr, "SetAppletResourceUserId"},
+ {501, nullptr, "RegisterAppletResourceUserId"},
+ {502, nullptr, "UnregisterAppletResourceUserId"},
+ {503, nullptr, "EnableAppletToGetInput"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
new file mode 100644
index 000000000..a8be701c7
--- /dev/null
+++ b/src/core/hle/service/hid/irs.h
@@ -0,0 +1,21 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::HID {
+
+class IRS final : public ServiceFramework<IRS> {
+public:
+ explicit IRS();
+};
+
+class IRS_SYS final : public ServiceFramework<IRS_SYS> {
+public:
+ explicit IRS_SYS();
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp
new file mode 100644
index 000000000..49f733f60
--- /dev/null
+++ b/src/core/hle/service/hid/xcd.cpp
@@ -0,0 +1,37 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/hid/xcd.h"
+
+namespace Service::HID {
+
+XCD_SYS::XCD_SYS() : ServiceFramework{"xcd:sys"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetDataFormat"},
+ {1, nullptr, "SetDataFormat"},
+ {2, nullptr, "GetMcuState"},
+ {3, nullptr, "SetMcuState"},
+ {4, nullptr, "GetMcuVersionForNfc"},
+ {5, nullptr, "CheckNfcDevicePower"},
+ {10, nullptr, "SetNfcEvent"},
+ {11, nullptr, "GetNfcInfo"},
+ {12, nullptr, "StartNfcDiscovery"},
+ {13, nullptr, "StopNfcDiscovery"},
+ {14, nullptr, "StartNtagRead"},
+ {15, nullptr, "StartNtagWrite"},
+ {16, nullptr, "SendNfcRawData"},
+ {17, nullptr, "RegisterMifareKey"},
+ {18, nullptr, "ClearMifareKey"},
+ {19, nullptr, "StartMifareRead"},
+ {20, nullptr, "StartMifareWrite"},
+ {101, nullptr, "GetAwakeTriggerReasonForLeftRail"},
+ {102, nullptr, "GetAwakeTriggerReasonForRightRail"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/xcd.h b/src/core/hle/service/hid/xcd.h
new file mode 100644
index 000000000..232a044df
--- /dev/null
+++ b/src/core/hle/service/hid/xcd.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::HID {
+
+class XCD_SYS final : public ServiceFramework<XCD_SYS> {
+public:
+ explicit XCD_SYS();
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
new file mode 100644
index 000000000..8fc8b1057
--- /dev/null
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -0,0 +1,90 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/lbl/lbl.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::LBL {
+
+class LBL final : public ServiceFramework<LBL> {
+public:
+ explicit LBL() : ServiceFramework{"lbl"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "Unknown3"},
+ {3, nullptr, "Unknown4"},
+ {4, nullptr, "Unknown5"},
+ {5, nullptr, "Unknown6"},
+ {6, nullptr, "TurnOffBacklight"},
+ {7, nullptr, "TurnOnBacklight"},
+ {8, nullptr, "GetBacklightStatus"},
+ {9, nullptr, "Unknown7"},
+ {10, nullptr, "Unknown8"},
+ {11, nullptr, "Unknown9"},
+ {12, nullptr, "Unknown10"},
+ {13, nullptr, "Unknown11"},
+ {14, nullptr, "Unknown12"},
+ {15, nullptr, "Unknown13"},
+ {16, nullptr, "ReadRawLightSensor"},
+ {17, nullptr, "Unknown14"},
+ {18, nullptr, "Unknown15"},
+ {19, nullptr, "Unknown16"},
+ {20, nullptr, "Unknown17"},
+ {21, nullptr, "Unknown18"},
+ {22, nullptr, "Unknown19"},
+ {23, nullptr, "Unknown20"},
+ {24, nullptr, "Unknown21"},
+ {25, nullptr, "Unknown22"},
+ {26, &LBL::EnableVrMode, "EnableVrMode"},
+ {27, &LBL::DisableVrMode, "DisableVrMode"},
+ {28, &LBL::GetVrMode, "GetVrMode"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void EnableVrMode(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+
+ vr_mode_enabled = true;
+
+ LOG_DEBUG(Service_LBL, "called");
+ }
+
+ void DisableVrMode(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+
+ vr_mode_enabled = false;
+
+ LOG_DEBUG(Service_LBL, "called");
+ }
+
+ void GetVrMode(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(vr_mode_enabled);
+
+ LOG_DEBUG(Service_LBL, "called");
+ }
+
+ bool vr_mode_enabled = false;
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<LBL>()->InstallAsService(sm);
+}
+
+} // namespace Service::LBL
diff --git a/src/core/hle/service/lbl/lbl.h b/src/core/hle/service/lbl/lbl.h
new file mode 100644
index 000000000..bf6f400f8
--- /dev/null
+++ b/src/core/hle/service/lbl/lbl.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::LBL {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::LBL
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
new file mode 100644
index 000000000..167f2c66a
--- /dev/null
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -0,0 +1,142 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/result.h"
+#include "core/hle/service/ldn/ldn.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::LDN {
+
+class IMonitorService final : public ServiceFramework<IMonitorService> {
+public:
+ explicit IMonitorService() : ServiceFramework{"IMonitorService"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetStateForMonitor"},
+ {1, nullptr, "GetNetworkInfoForMonitor"},
+ {2, nullptr, "GetIpv4AddressForMonitor"},
+ {3, nullptr, "GetDisconnectReasonForMonitor"},
+ {4, nullptr, "GetSecurityParameterForMonitor"},
+ {5, nullptr, "GetNetworkConfigForMonitor"},
+ {100, nullptr, "InitializeMonitor"},
+ {101, nullptr, "FinalizeMonitor"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class LDNM final : public ServiceFramework<LDNM> {
+public:
+ explicit LDNM() : ServiceFramework{"ldn:m"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &LDNM::CreateMonitorService, "CreateMonitorService"}
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+ void CreateMonitorService(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IMonitorService>();
+
+ LOG_DEBUG(Service_LDN, "called");
+ }
+};
+
+class ILocalCommunicationService final : public ServiceFramework<ILocalCommunicationService> {
+public:
+ explicit ILocalCommunicationService(const char* name) : ServiceFramework{name} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetState"},
+ {1, nullptr, "GetNetworkInfo"},
+ {2, nullptr, "GetIpv4Address"},
+ {3, nullptr, "GetDisconnectReason"},
+ {4, nullptr, "GetSecurityParameter"},
+ {5, nullptr, "GetNetworkConfig"},
+ {100, nullptr, "AttachStateChangeEvent"},
+ {101, nullptr, "GetNetworkInfoLatestUpdate"},
+ {102, nullptr, "Scan"},
+ {103, nullptr, "ScanPrivate"},
+ {200, nullptr, "OpenAccessPoint"},
+ {201, nullptr, "CloseAccessPoint"},
+ {202, nullptr, "CreateNetwork"},
+ {203, nullptr, "CreateNetworkPrivate"},
+ {204, nullptr, "DestroyNetwork"},
+ {205, nullptr, "Reject"},
+ {206, nullptr, "SetAdvertiseData"},
+ {207, nullptr, "SetStationAcceptPolicy"},
+ {208, nullptr, "AddAcceptFilterEntry"},
+ {209, nullptr, "ClearAcceptFilter"},
+ {300, nullptr, "OpenStation"},
+ {301, nullptr, "CloseStation"},
+ {302, nullptr, "Connect"},
+ {303, nullptr, "ConnectPrivate"},
+ {304, nullptr, "Disconnect"},
+ {400, nullptr, "InitializeSystem"},
+ {401, nullptr, "FinalizeSystem"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class LDNS final : public ServiceFramework<LDNS> {
+public:
+ explicit LDNS() : ServiceFramework{"ldn:s"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+ void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService");
+
+ LOG_DEBUG(Service_LDN, "called");
+ }
+};
+
+class LDNU final : public ServiceFramework<LDNU> {
+public:
+ explicit LDNU() : ServiceFramework{"ldn:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+ void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService");
+
+ LOG_DEBUG(Service_LDN, "called");
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<LDNM>()->InstallAsService(sm);
+ std::make_shared<LDNS>()->InstallAsService(sm);
+ std::make_shared<LDNU>()->InstallAsService(sm);
+}
+
+} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h
new file mode 100644
index 000000000..6b2a3c2b2
--- /dev/null
+++ b/src/core/hle/service/ldn/ldn.h
@@ -0,0 +1,16 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::LDN {
+
+/// Registers all LDN services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::LDN
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index b497376d7..098da2a41 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -13,11 +13,11 @@
namespace Service::LM {
-class Logger final : public ServiceFramework<Logger> {
+class ILogger final : public ServiceFramework<ILogger> {
public:
- Logger() : ServiceFramework("Logger") {
+ ILogger() : ServiceFramework("ILogger") {
static const FunctionInfo functions[] = {
- {0x00000000, &Logger::Initialize, "Initialize"},
+ {0x00000000, &ILogger::Initialize, "Initialize"},
{0x00000001, nullptr, "SetDestination"},
};
RegisterHandlers(functions);
@@ -92,7 +92,11 @@ private:
// Parse out log metadata
u32 line{};
- std::string message, filename, function;
+ std::string module;
+ std::string message;
+ std::string filename;
+ std::string function;
+ std::string thread;
while (addr < end_addr) {
const Field field{static_cast<Field>(Memory::Read8(addr++))};
const size_t length{Memory::Read8(addr++)};
@@ -102,6 +106,8 @@ private:
}
switch (field) {
+ case Field::Skip:
+ break;
case Field::Message:
message = Memory::ReadCString(addr, length);
break;
@@ -114,6 +120,12 @@ private:
case Field::Function:
function = Memory::ReadCString(addr, length);
break;
+ case Field::Module:
+ module = Memory::ReadCString(addr, length);
+ break;
+ case Field::Thread:
+ thread = Memory::ReadCString(addr, length);
+ break;
}
addr += length;
@@ -128,12 +140,18 @@ private:
if (!filename.empty()) {
log_stream << filename << ':';
}
+ if (!module.empty()) {
+ log_stream << module << ':';
+ }
if (!function.empty()) {
log_stream << function << ':';
}
if (line) {
log_stream << std::to_string(line) << ':';
}
+ if (!thread.empty()) {
+ log_stream << thread << ':';
+ }
if (log_stream.str().length() > 0 && log_stream.str().back() == ':') {
log_stream << ' ';
}
@@ -142,7 +160,7 @@ private:
if (header.IsTailLog()) {
switch (header.severity) {
case MessageHeader::Severity::Trace:
- LOG_TRACE(Debug_Emulated, "{}", log_stream.str());
+ LOG_DEBUG(Debug_Emulated, "{}", log_stream.str());
break;
case MessageHeader::Severity::Info:
LOG_INFO(Debug_Emulated, "{}", log_stream.str());
@@ -182,7 +200,7 @@ public:
void OpenLogger(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<Logger>();
+ rb.PushIpcInterface<ILogger>();
LOG_DEBUG(Service_LM, "called");
}
diff --git a/src/core/hle/service/mig/mig.cpp b/src/core/hle/service/mig/mig.cpp
new file mode 100644
index 000000000..d16367f2c
--- /dev/null
+++ b/src/core/hle/service/mig/mig.cpp
@@ -0,0 +1,34 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/service/mig/mig.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::Migration {
+
+class MIG_USR final : public ServiceFramework<MIG_USR> {
+public:
+ explicit MIG_USR() : ServiceFramework{"mig:usr"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {10, nullptr, "TryGetLastMigrationInfo"},
+ {100, nullptr, "CreateServer"},
+ {101, nullptr, "ResumeServer"},
+ {200, nullptr, "CreateClient"},
+ {201, nullptr, "ResumeClient"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<MIG_USR>()->InstallAsService(sm);
+}
+
+} // namespace Service::Migration
diff --git a/src/core/hle/service/mig/mig.h b/src/core/hle/service/mig/mig.h
new file mode 100644
index 000000000..288c1c1b3
--- /dev/null
+++ b/src/core/hle/service/mig/mig.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::Migration {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::Migration
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
new file mode 100644
index 000000000..a6197124a
--- /dev/null
+++ b/src/core/hle/service/mii/mii.cpp
@@ -0,0 +1,107 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/mii/mii.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::Mii {
+
+class IDatabaseService final : public ServiceFramework<IDatabaseService> {
+public:
+ explicit IDatabaseService() : ServiceFramework{"IDatabaseService"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "IsUpdated"},
+ {1, nullptr, "IsFullDatabase"},
+ {2, nullptr, "GetCount"},
+ {3, nullptr, "Get"},
+ {4, nullptr, "Get1"},
+ {5, nullptr, "UpdateLatest"},
+ {6, nullptr, "BuildRandom"},
+ {7, nullptr, "BuildDefault"},
+ {8, nullptr, "Get2"},
+ {9, nullptr, "Get3"},
+ {10, nullptr, "UpdateLatest1"},
+ {11, nullptr, "FindIndex"},
+ {12, nullptr, "Move"},
+ {13, nullptr, "AddOrReplace"},
+ {14, nullptr, "Delete"},
+ {15, nullptr, "DestroyFile"},
+ {16, nullptr, "DeleteFile"},
+ {17, nullptr, "Format"},
+ {18, nullptr, "Import"},
+ {19, nullptr, "Export"},
+ {20, nullptr, "IsBrokenDatabaseWithClearFlag"},
+ {21, nullptr, "GetIndex"},
+ {22, nullptr, "SetInterfaceVersion"},
+ {23, nullptr, "Convert"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class MiiDBModule final : public ServiceFramework<MiiDBModule> {
+public:
+ explicit MiiDBModule(const char* name) : ServiceFramework{name} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void GetDatabaseService(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IDatabaseService>();
+
+ LOG_DEBUG(Service_Mii, "called");
+ }
+};
+
+class MiiImg final : public ServiceFramework<MiiImg> {
+public:
+ explicit MiiImg() : ServiceFramework{"miiimg"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {10, nullptr, "Reload"},
+ {11, nullptr, "GetCount"},
+ {12, nullptr, "IsEmpty"},
+ {13, nullptr, "IsFull"},
+ {14, nullptr, "GetAttribute"},
+ {15, nullptr, "LoadImage"},
+ {16, nullptr, "AddOrUpdateImage"},
+ {17, nullptr, "DeleteImages"},
+ {100, nullptr, "DeleteFile"},
+ {101, nullptr, "DestroyFile"},
+ {102, nullptr, "ImportFile"},
+ {103, nullptr, "ExportFile"},
+ {104, nullptr, "ForceInitialize"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<MiiDBModule>("mii:e")->InstallAsService(sm);
+ std::make_shared<MiiDBModule>("mii:u")->InstallAsService(sm);
+
+ std::make_shared<MiiImg>()->InstallAsService(sm);
+}
+
+} // namespace Service::Mii
diff --git a/src/core/hle/service/mii/mii.h b/src/core/hle/service/mii/mii.h
new file mode 100644
index 000000000..7ce9be50e
--- /dev/null
+++ b/src/core/hle/service/mii/mii.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::Mii {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::Mii
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index 08f45b78a..7b91bb258 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -9,42 +9,63 @@
namespace Service::MM {
-void InstallInterfaces(SM::ServiceManager& service_manager) {
- std::make_shared<MM_U>()->InstallAsService(service_manager);
-}
+class MM_U final : public ServiceFramework<MM_U> {
+public:
+ explicit MM_U() : ServiceFramework{"mm:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &MM_U::Initialize, "InitializeOld"},
+ {1, &MM_U::Finalize, "FinalizeOld"},
+ {2, &MM_U::SetAndWait, "SetAndWaitOld"},
+ {3, &MM_U::Get, "GetOld"},
+ {4, &MM_U::Initialize, "Initialize"},
+ {5, &MM_U::Finalize, "Finalize"},
+ {6, &MM_U::SetAndWait, "SetAndWait"},
+ {7, &MM_U::Get, "Get"},
+ };
+ // clang-format on
-void MM_U::Initialize(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_MM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
-}
+ RegisterHandlers(functions);
+ }
-void MM_U::SetAndWait(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- min = rp.Pop<u32>();
- max = rp.Pop<u32>();
- current = min;
+private:
+ void Initialize(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_MM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
- LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
-}
+ void Finalize(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_MM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
-void MM_U::Get(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_MM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(RESULT_SUCCESS);
- rb.Push(current);
-}
+ void SetAndWait(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ min = rp.Pop<u32>();
+ max = rp.Pop<u32>();
+ current = min;
-MM_U::MM_U() : ServiceFramework("mm:u") {
- static const FunctionInfo functions[] = {
- {0, nullptr, "InitializeOld"}, {1, nullptr, "FinalizeOld"},
- {2, nullptr, "SetAndWaitOld"}, {3, nullptr, "GetOld"},
- {4, &MM_U::Initialize, "Initialize"}, {5, nullptr, "Finalize"},
- {6, &MM_U::SetAndWait, "SetAndWait"}, {7, &MM_U::Get, "Get"},
- };
- RegisterHandlers(functions);
+ LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void Get(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_MM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(current);
+ }
+
+ u32 min{0};
+ u32 max{0};
+ u32 current{0};
+};
+
+void InstallInterfaces(SM::ServiceManager& service_manager) {
+ std::make_shared<MM_U>()->InstallAsService(service_manager);
}
} // namespace Service::MM
diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h
index 79eeedf9c..5439fa653 100644
--- a/src/core/hle/service/mm/mm_u.h
+++ b/src/core/hle/service/mm/mm_u.h
@@ -8,21 +8,6 @@
namespace Service::MM {
-class MM_U final : public ServiceFramework<MM_U> {
-public:
- MM_U();
- ~MM_U() = default;
-
-private:
- void Initialize(Kernel::HLERequestContext& ctx);
- void SetAndWait(Kernel::HLERequestContext& ctx);
- void Get(Kernel::HLERequestContext& ctx);
-
- u32 min{0};
- u32 max{0};
- u32 current{0};
-};
-
/// Registers all MM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
diff --git a/src/core/hle/service/ncm/ncm.cpp b/src/core/hle/service/ncm/ncm.cpp
new file mode 100644
index 000000000..0297edca0
--- /dev/null
+++ b/src/core/hle/service/ncm/ncm.cpp
@@ -0,0 +1,59 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/service/ncm/ncm.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::NCM {
+
+class LocationResolver final : public ServiceFramework<LocationResolver> {
+public:
+ explicit LocationResolver() : ServiceFramework{"lr"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "OpenLocationResolver"},
+ {1, nullptr, "OpenRegisteredLocationResolver"},
+ {2, nullptr, "RefreshLocationResolver"},
+ {3, nullptr, "OpenAddOnContentLocationResolver"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class NCM final : public ServiceFramework<NCM> {
+public:
+ explicit NCM() : ServiceFramework{"ncm"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "CreateContentStorage"},
+ {1, nullptr, "CreateContentMetaDatabase"},
+ {2, nullptr, "VerifyContentStorage"},
+ {3, nullptr, "VerifyContentMetaDatabase"},
+ {4, nullptr, "OpenContentStorage"},
+ {5, nullptr, "OpenContentMetaDatabase"},
+ {6, nullptr, "CloseContentStorageForcibly"},
+ {7, nullptr, "CloseContentMetaDatabaseForcibly"},
+ {8, nullptr, "CleanupContentMetaDatabase"},
+ {9, nullptr, "OpenContentStorage2"},
+ {10, nullptr, "CloseContentStorage"},
+ {11, nullptr, "OpenContentMetaDatabase2"},
+ {12, nullptr, "CloseContentMetaDatabase"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<LocationResolver>()->InstallAsService(sm);
+ std::make_shared<NCM>()->InstallAsService(sm);
+}
+
+} // namespace Service::NCM
diff --git a/src/core/hle/service/ncm/ncm.h b/src/core/hle/service/ncm/ncm.h
new file mode 100644
index 000000000..7bc8518a6
--- /dev/null
+++ b/src/core/hle/service/ncm/ncm.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::NCM {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::NCM
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
new file mode 100644
index 000000000..8fec97db8
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -0,0 +1,222 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/nfc/nfc.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::NFC {
+
+class IAm final : public ServiceFramework<IAm> {
+public:
+ explicit IAm() : ServiceFramework{"IAm"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "Finalize"},
+ {2, nullptr, "NotifyForegroundApplet"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class NFC_AM final : public ServiceFramework<NFC_AM> {
+public:
+ explicit NFC_AM() : ServiceFramework{"nfc:am"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void CreateAmInterface(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IAm>();
+
+ LOG_DEBUG(Service_NFC, "called");
+ }
+};
+
+class MFIUser final : public ServiceFramework<MFIUser> {
+public:
+ explicit MFIUser() : ServiceFramework{"IUser"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "Finalize"},
+ {2, nullptr, "ListDevices"},
+ {3, nullptr, "StartDetection"},
+ {4, nullptr, "StopDetection"},
+ {5, nullptr, "Read"},
+ {6, nullptr, "Write"},
+ {7, nullptr, "GetTagInfo"},
+ {8, nullptr, "GetActivateEventHandle"},
+ {9, nullptr, "GetDeactivateEventHandle"},
+ {10, nullptr, "GetState"},
+ {11, nullptr, "GetDeviceState"},
+ {12, nullptr, "GetNpadId"},
+ {13, nullptr, "GetAvailabilityChangeEventHandle"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class NFC_MF_U final : public ServiceFramework<NFC_MF_U> {
+public:
+ explicit NFC_MF_U() : ServiceFramework{"nfc:mf:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void CreateUserInterface(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<MFIUser>();
+
+ LOG_DEBUG(Service_NFC, "called");
+ }
+};
+
+class IUser final : public ServiceFramework<IUser> {
+public:
+ explicit IUser() : ServiceFramework{"IUser"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "Finalize"},
+ {2, nullptr, "GetState"},
+ {3, nullptr, "IsNfcEnabled"},
+ {400, nullptr, "Initialize"},
+ {401, nullptr, "Finalize"},
+ {402, nullptr, "GetState"},
+ {403, nullptr, "IsNfcEnabled"},
+ {404, nullptr, "ListDevices"},
+ {405, nullptr, "GetDeviceState"},
+ {406, nullptr, "GetNpadId"},
+ {407, nullptr, "AttachAvailabilityChangeEvent"},
+ {408, nullptr, "StartDetection"},
+ {409, nullptr, "StopDetection"},
+ {410, nullptr, "GetTagInfo"},
+ {411, nullptr, "AttachActivateEvent"},
+ {412, nullptr, "AttachDeactivateEvent"},
+ {1000, nullptr, "ReadMifare"},
+ {1001, nullptr, "WriteMifare"},
+ {1300, nullptr, "SendCommandByPassThrough"},
+ {1301, nullptr, "KeepPassThroughSession"},
+ {1302, nullptr, "ReleasePassThroughSession"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class NFC_U final : public ServiceFramework<NFC_U> {
+public:
+ explicit NFC_U() : ServiceFramework{"nfc:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &NFC_U::CreateUserInterface, "CreateUserInterface"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void CreateUserInterface(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IUser>();
+
+ LOG_DEBUG(Service_NFC, "called");
+ }
+};
+
+class ISystem final : public ServiceFramework<ISystem> {
+public:
+ explicit ISystem() : ServiceFramework{"ISystem"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "Finalize"},
+ {2, nullptr, "GetState"},
+ {3, nullptr, "IsNfcEnabled"},
+ {100, nullptr, "SetNfcEnabled"},
+ {400, nullptr, "InitializeSystem"},
+ {401, nullptr, "FinalizeSystem"},
+ {402, nullptr, "GetState"},
+ {403, nullptr, "IsNfcEnabled"},
+ {404, nullptr, "ListDevices"},
+ {405, nullptr, "GetDeviceState"},
+ {406, nullptr, "GetNpadId"},
+ {407, nullptr, "AttachAvailabilityChangeEvent"},
+ {408, nullptr, "StartDetection"},
+ {409, nullptr, "StopDetection"},
+ {410, nullptr, "GetTagInfo"},
+ {411, nullptr, "AttachActivateEvent"},
+ {412, nullptr, "AttachDeactivateEvent"},
+ {500, nullptr, "SetNfcEnabled"},
+ {1000, nullptr, "ReadMifare"},
+ {1001, nullptr, "WriteMifare"},
+ {1300, nullptr, "SendCommandByPassThrough"},
+ {1301, nullptr, "KeepPassThroughSession"},
+ {1302, nullptr, "ReleasePassThroughSession"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class NFC_SYS final : public ServiceFramework<NFC_SYS> {
+public:
+ explicit NFC_SYS() : ServiceFramework{"nfc:sys"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void CreateSystemInterface(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ISystem>();
+
+ LOG_DEBUG(Service_NFC, "called");
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<NFC_AM>()->InstallAsService(sm);
+ std::make_shared<NFC_MF_U>()->InstallAsService(sm);
+ std::make_shared<NFC_U>()->InstallAsService(sm);
+ std::make_shared<NFC_SYS>()->InstallAsService(sm);
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h
new file mode 100644
index 000000000..4d2d815f9
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::NFC {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
new file mode 100644
index 000000000..bd05b0a70
--- /dev/null
+++ b/src/core/hle/service/nim/nim.cpp
@@ -0,0 +1,124 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nim/nim.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::NIM {
+
+class NIM final : public ServiceFramework<NIM> {
+public:
+ explicit NIM() : ServiceFramework{"nim"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "CreateSystemUpdateTask"},
+ {1, nullptr, "DestroySystemUpdateTask"},
+ {2, nullptr, "ListSystemUpdateTask"},
+ {3, nullptr, "RequestSystemUpdateTaskRun"},
+ {4, nullptr, "GetSystemUpdateTaskInfo"},
+ {5, nullptr, "CommitSystemUpdateTask"},
+ {6, nullptr, "CreateNetworkInstallTask"},
+ {7, nullptr, "DestroyNetworkInstallTask"},
+ {8, nullptr, "ListNetworkInstallTask"},
+ {9, nullptr, "RequestNetworkInstallTaskRun"},
+ {10, nullptr, "GetNetworkInstallTaskInfo"},
+ {11, nullptr, "CommitNetworkInstallTask"},
+ {12, nullptr, "RequestLatestSystemUpdateMeta"},
+ {14, nullptr, "ListApplicationNetworkInstallTask"},
+ {15, nullptr, "ListNetworkInstallTaskContentMeta"},
+ {16, nullptr, "RequestLatestVersion"},
+ {17, nullptr, "SetNetworkInstallTaskAttribute"},
+ {18, nullptr, "AddNetworkInstallTaskContentMeta"},
+ {19, nullptr, "GetDownloadedSystemDataPath"},
+ {20, nullptr, "CalculateNetworkInstallTaskRequiredSize"},
+ {21, nullptr, "IsExFatDriverIncluded"},
+ {22, nullptr, "GetBackgroundDownloadStressTaskInfo"},
+ {23, nullptr, "RequestDeviceAuthenticationToken"},
+ {24, nullptr, "RequestGameCardRegistrationStatus"},
+ {25, nullptr, "RequestRegisterGameCard"},
+ {26, nullptr, "RequestRegisterNotificationToken"},
+ {27, nullptr, "RequestDownloadTaskList"},
+ {28, nullptr, "RequestApplicationControl"},
+ {29, nullptr, "RequestLatestApplicationControl"},
+ {30, nullptr, "RequestVersionList"},
+ {31, nullptr, "CreateApplyDeltaTask"},
+ {32, nullptr, "DestroyApplyDeltaTask"},
+ {33, nullptr, "ListApplicationApplyDeltaTask"},
+ {34, nullptr, "RequestApplyDeltaTaskRun"},
+ {35, nullptr, "GetApplyDeltaTaskInfo"},
+ {36, nullptr, "ListApplyDeltaTask"},
+ {37, nullptr, "CommitApplyDeltaTask"},
+ {38, nullptr, "CalculateApplyDeltaTaskRequiredSize"},
+ {39, nullptr, "PrepareShutdown"},
+ {40, nullptr, "ListApplyDeltaTask"},
+ {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"},
+ {42, nullptr, "Unknown1"},
+ {43, nullptr, "Unknown2"},
+ {44, nullptr, "Unknown3"},
+ {45, nullptr, "Unknown4"},
+ {46, nullptr, "Unknown5"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class NIM_SHP final : public ServiceFramework<NIM_SHP> {
+public:
+ explicit NIM_SHP() : ServiceFramework{"nim:shp"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RequestDeviceAuthenticationToken"},
+ {1, nullptr, "RequestCachedDeviceAuthenticationToken"},
+ {100, nullptr, "RequestRegisterDeviceAccount"},
+ {101, nullptr, "RequestUnregisterDeviceAccount"},
+ {102, nullptr, "RequestDeviceAccountStatus"},
+ {103, nullptr, "GetDeviceAccountInfo"},
+ {104, nullptr, "RequestDeviceRegistrationInfo"},
+ {105, nullptr, "RequestTransferDeviceAccount"},
+ {106, nullptr, "RequestSyncRegistration"},
+ {107, nullptr, "IsOwnDeviceId"},
+ {200, nullptr, "RequestRegisterNotificationToken"},
+ {300, nullptr, "RequestUnlinkDevice"},
+ {301, nullptr, "RequestUnlinkDeviceIntegrated"},
+ {302, nullptr, "RequestLinkDevice"},
+ {303, nullptr, "HasDeviceLink"},
+ {304, nullptr, "RequestUnlinkDeviceAll"},
+ {305, nullptr, "RequestCreateVirtualAccount"},
+ {306, nullptr, "RequestDeviceLinkStatus"},
+ {400, nullptr, "GetAccountByVirtualAccount"},
+ {500, nullptr, "RequestSyncTicket"},
+ {501, nullptr, "RequestDownloadTicket"},
+ {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class NTC final : public ServiceFramework<NTC> {
+public:
+ explicit NTC() : ServiceFramework{"ntc"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "OpenEnsureNetworkClockAvailabilityService"},
+ {100, nullptr, "SuspendAutonomicTimeCorrection"},
+ {101, nullptr, "ResumeAutonomicTimeCorrection"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<NIM>()->InstallAsService(sm);
+ std::make_shared<NIM_SHP>()->InstallAsService(sm);
+ std::make_shared<NTC>()->InstallAsService(sm);
+}
+
+} // namespace Service::NIM
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h
new file mode 100644
index 000000000..2a2a92df0
--- /dev/null
+++ b/src/core/hle/service/nim/nim.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::NIM {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::NIM
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 89c703310..98017267c 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -2,12 +2,459 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/pl_u.h"
namespace Service::NS {
+class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
+public:
+ explicit IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "CreateUserAccount"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
+public:
+ explicit IApplicationManagerInterface() : ServiceFramework{"IApplicationManagerInterface"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "ListApplicationRecord"},
+ {1, nullptr, "GenerateApplicationRecordCount"},
+ {2, nullptr, "GetApplicationRecordUpdateSystemEvent"},
+ {3, nullptr, "GetApplicationViewDeprecated"},
+ {4, nullptr, "DeleteApplicationEntity"},
+ {5, nullptr, "DeleteApplicationCompletely"},
+ {6, nullptr, "IsAnyApplicationEntityRedundant"},
+ {7, nullptr, "DeleteRedundantApplicationEntity"},
+ {8, nullptr, "IsApplicationEntityMovable"},
+ {9, nullptr, "MoveApplicationEntity"},
+ {11, nullptr, "CalculateApplicationOccupiedSize"},
+ {16, nullptr, "PushApplicationRecord"},
+ {17, nullptr, "ListApplicationRecordContentMeta"},
+ {19, nullptr, "LaunchApplication"},
+ {21, nullptr, "GetApplicationContentPath"},
+ {22, nullptr, "TerminateApplication"},
+ {23, nullptr, "ResolveApplicationContentPath"},
+ {26, nullptr, "BeginInstallApplication"},
+ {27, nullptr, "DeleteApplicationRecord"},
+ {30, nullptr, "RequestApplicationUpdateInfo"},
+ {32, nullptr, "CancelApplicationDownload"},
+ {33, nullptr, "ResumeApplicationDownload"},
+ {35, nullptr, "UpdateVersionList"},
+ {36, nullptr, "PushLaunchVersion"},
+ {37, nullptr, "ListRequiredVersion"},
+ {38, nullptr, "CheckApplicationLaunchVersion"},
+ {39, nullptr, "CheckApplicationLaunchRights"},
+ {40, nullptr, "GetApplicationLogoData"},
+ {41, nullptr, "CalculateApplicationDownloadRequiredSize"},
+ {42, nullptr, "CleanupSdCard"},
+ {43, nullptr, "CheckSdCardMountStatus"},
+ {44, nullptr, "GetSdCardMountStatusChangedEvent"},
+ {45, nullptr, "GetGameCardAttachmentEvent"},
+ {46, nullptr, "GetGameCardAttachmentInfo"},
+ {47, nullptr, "GetTotalSpaceSize"},
+ {48, nullptr, "GetFreeSpaceSize"},
+ {49, nullptr, "GetSdCardRemovedEvent"},
+ {52, nullptr, "GetGameCardUpdateDetectionEvent"},
+ {53, nullptr, "DisableApplicationAutoDelete"},
+ {54, nullptr, "EnableApplicationAutoDelete"},
+ {55, nullptr, "GetApplicationDesiredLanguage"},
+ {56, nullptr, "SetApplicationTerminateResult"},
+ {57, nullptr, "ClearApplicationTerminateResult"},
+ {58, nullptr, "GetLastSdCardMountUnexpectedResult"},
+ {59, nullptr, "ConvertApplicationLanguageToLanguageCode"},
+ {60, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
+ {61, nullptr, "GetBackgroundDownloadStressTaskInfo"},
+ {62, nullptr, "GetGameCardStopper"},
+ {63, nullptr, "IsSystemProgramInstalled"},
+ {64, nullptr, "StartApplyDeltaTask"},
+ {65, nullptr, "GetRequestServerStopper"},
+ {66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
+ {67, nullptr, "CancelApplicationApplyDelta"},
+ {68, nullptr, "ResumeApplicationApplyDelta"},
+ {69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"},
+ {70, nullptr, "ResumeAll"},
+ {71, nullptr, "GetStorageSize"},
+ {80, nullptr, "RequestDownloadApplication"},
+ {81, nullptr, "RequestDownloadAddOnContent"},
+ {82, nullptr, "DownloadApplication"},
+ {83, nullptr, "CheckApplicationResumeRights"},
+ {84, nullptr, "GetDynamicCommitEvent"},
+ {85, nullptr, "RequestUpdateApplication2"},
+ {86, nullptr, "EnableApplicationCrashReport"},
+ {87, nullptr, "IsApplicationCrashReportEnabled"},
+ {90, nullptr, "BoostSystemMemoryResourceLimit"},
+ {100, nullptr, "ResetToFactorySettings"},
+ {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
+ {102, nullptr, "ResetToFactorySettingsForRefurbishment"},
+ {200, nullptr, "CalculateUserSaveDataStatistics"},
+ {201, nullptr, "DeleteUserSaveDataAll"},
+ {210, nullptr, "DeleteUserSystemSaveData"},
+ {220, nullptr, "UnregisterNetworkServiceAccount"},
+ {300, nullptr, "GetApplicationShellEvent"},
+ {301, nullptr, "PopApplicationShellEventInfo"},
+ {302, nullptr, "LaunchLibraryApplet"},
+ {303, nullptr, "TerminateLibraryApplet"},
+ {304, nullptr, "LaunchSystemApplet"},
+ {305, nullptr, "TerminateSystemApplet"},
+ {306, nullptr, "LaunchOverlayApplet"},
+ {307, nullptr, "TerminateOverlayApplet"},
+ {400, nullptr, "GetApplicationControlData"},
+ {401, nullptr, "InvalidateAllApplicationControlCache"},
+ {402, nullptr, "RequestDownloadApplicationControlData"},
+ {403, nullptr, "GetMaxApplicationControlCacheCount"},
+ {404, nullptr, "InvalidateApplicationControlCache"},
+ {405, nullptr, "ListApplicationControlCacheEntryInfo"},
+ {502, nullptr, "RequestCheckGameCardRegistration"},
+ {503, nullptr, "RequestGameCardRegistrationGoldPoint"},
+ {504, nullptr, "RequestRegisterGameCard"},
+ {505, nullptr, "GetGameCardMountFailureEvent"},
+ {506, nullptr, "IsGameCardInserted"},
+ {507, nullptr, "EnsureGameCardAccess"},
+ {508, nullptr, "GetLastGameCardMountFailureResult"},
+ {509, nullptr, "ListApplicationIdOnGameCard"},
+ {600, nullptr, "CountApplicationContentMeta"},
+ {601, nullptr, "ListApplicationContentMetaStatus"},
+ {602, nullptr, "ListAvailableAddOnContent"},
+ {603, nullptr, "GetOwnedApplicationContentMetaStatus"},
+ {604, nullptr, "RegisterContentsExternalKey"},
+ {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
+ {606, nullptr, "GetContentMetaStorage"},
+ {700, nullptr, "PushDownloadTaskList"},
+ {701, nullptr, "ClearTaskStatusList"},
+ {702, nullptr, "RequestDownloadTaskList"},
+ {703, nullptr, "RequestEnsureDownloadTask"},
+ {704, nullptr, "ListDownloadTaskStatus"},
+ {705, nullptr, "RequestDownloadTaskListData"},
+ {800, nullptr, "RequestVersionList"},
+ {801, nullptr, "ListVersionList"},
+ {802, nullptr, "RequestVersionListData"},
+ {900, nullptr, "GetApplicationRecord"},
+ {901, nullptr, "GetApplicationRecordProperty"},
+ {902, nullptr, "EnableApplicationAutoUpdate"},
+ {903, nullptr, "DisableApplicationAutoUpdate"},
+ {904, nullptr, "TouchApplication"},
+ {905, nullptr, "RequestApplicationUpdate"},
+ {906, nullptr, "IsApplicationUpdateRequested"},
+ {907, nullptr, "WithdrawApplicationUpdateRequest"},
+ {908, nullptr, "ListApplicationRecordInstalledContentMeta"},
+ {909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
+ {1000, nullptr, "RequestVerifyApplicationDeprecated"},
+ {1001, nullptr, "CorruptApplicationForDebug"},
+ {1002, nullptr, "RequestVerifyAddOnContentsRights"},
+ {1003, nullptr, "RequestVerifyApplication"},
+ {1004, nullptr, "CorruptContentForDebug"},
+ {1200, nullptr, "NeedsUpdateVulnerability"},
+ {1300, nullptr, "IsAnyApplicationEntityInstalled"},
+ {1301, nullptr, "DeleteApplicationContentEntities"},
+ {1302, nullptr, "CleanupUnrecordedApplicationEntity"},
+ {1303, nullptr, "CleanupAddOnContentsWithNoRights"},
+ {1304, nullptr, "DeleteApplicationContentEntity"},
+ {1305, nullptr, "TryDeleteRunningApplicationEntity"},
+ {1306, nullptr, "TryDeleteRunningApplicationCompletely"},
+ {1307, nullptr, "TryDeleteRunningApplicationContentEntities"},
+ {1400, nullptr, "PrepareShutdown"},
+ {1500, nullptr, "FormatSdCard"},
+ {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
+ {1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
+ {1504, nullptr, "InsertSdCard"},
+ {1505, nullptr, "RemoveSdCard"},
+ {1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
+ {1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
+ {1700, nullptr, "ListApplicationDownloadingContentMeta"},
+ {1701, nullptr, "GetApplicationView"},
+ {1702, nullptr, "GetApplicationDownloadTaskStatus"},
+ {1703, nullptr, "GetApplicationViewDownloadErrorContext"},
+ {1800, nullptr, "IsNotificationSetupCompleted"},
+ {1801, nullptr, "GetLastNotificationInfoCount"},
+ {1802, nullptr, "ListLastNotificationInfo"},
+ {1803, nullptr, "ListNotificationTask"},
+ {1900, nullptr, "IsActiveAccount"},
+ {1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
+ {1902, nullptr, "GetApplicationTicketInfo"},
+ {2000, nullptr, "GetSystemDeliveryInfo"},
+ {2001, nullptr, "SelectLatestSystemDeliveryInfo"},
+ {2002, nullptr, "VerifyDeliveryProtocolVersion"},
+ {2003, nullptr, "GetApplicationDeliveryInfo"},
+ {2004, nullptr, "HasAllContentsToDeliver"},
+ {2005, nullptr, "CompareApplicationDeliveryInfo"},
+ {2006, nullptr, "CanDeliverApplication"},
+ {2007, nullptr, "ListContentMetaKeyToDeliverApplication"},
+ {2008, nullptr, "NeedsSystemUpdateToDeliverApplication"},
+ {2009, nullptr, "EstimateRequiredSize"},
+ {2010, nullptr, "RequestReceiveApplication"},
+ {2011, nullptr, "CommitReceiveApplication"},
+ {2012, nullptr, "GetReceiveApplicationProgress"},
+ {2013, nullptr, "RequestSendApplication"},
+ {2014, nullptr, "GetSendApplicationProgress"},
+ {2015, nullptr, "CompareSystemDeliveryInfo"},
+ {2016, nullptr, "ListNotCommittedContentMeta"},
+ {2017, nullptr, "CreateDownloadTask"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
+public:
+ explicit IApplicationVersionInterface() : ServiceFramework{"IApplicationVersionInterface"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetLaunchRequiredVersion"},
+ {1, nullptr, "UpgradeLaunchRequiredVersion"},
+ {35, nullptr, "UpdateVersionList"},
+ {36, nullptr, "PushLaunchVersion"},
+ {37, nullptr, "ListRequiredVersion"},
+ {800, nullptr, "RequestVersionList"},
+ {801, nullptr, "ListVersionList"},
+ {802, nullptr, "RequestVersionListData"},
+ {1000, nullptr, "PerformAutoUpdate"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> {
+public:
+ explicit IContentManagerInterface() : ServiceFramework{"IContentManagerInterface"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {11, nullptr, "CalculateApplicationOccupiedSize"},
+ {43, nullptr, "CheckSdCardMountStatus"},
+ {47, nullptr, "GetTotalSpaceSize"},
+ {48, nullptr, "GetFreeSpaceSize"},
+ {600, nullptr, "CountApplicationContentMeta"},
+ {601, nullptr, "ListApplicationContentMetaStatus"},
+ {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
+ {607, nullptr, "IsAnyApplicationRunning"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
+public:
+ explicit IDocumentInterface() : ServiceFramework{"IDocumentInterface"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {21, nullptr, "GetApplicationContentPath"},
+ {23, nullptr, "ResolveApplicationContentPath"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
+public:
+ explicit IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {701, nullptr, "ClearTaskStatusList"},
+ {702, nullptr, "RequestDownloadTaskList"},
+ {703, nullptr, "RequestEnsureDownloadTask"},
+ {704, nullptr, "ListDownloadTaskStatus"},
+ {705, nullptr, "RequestDownloadTaskListData"},
+ {706, nullptr, "TryCommitCurrentApplicationDownloadTask"},
+ {707, nullptr, "EnableAutoCommit"},
+ {708, nullptr, "DisableAutoCommit"},
+ {709, nullptr, "TriggerDynamicCommitEvent"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IECommerceInterface final : public ServiceFramework<IECommerceInterface> {
+public:
+ explicit IECommerceInterface() : ServiceFramework{"IECommerceInterface"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RequestLinkDevice"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> {
+public:
+ explicit IFactoryResetInterface() : ServiceFramework{"IFactoryResetInterface"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {100, nullptr, "ResetToFactorySettings"},
+ {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
+ {102, nullptr, "ResetToFactorySettingsForRefurbishment "},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class NS final : public ServiceFramework<NS> {
+public:
+ explicit NS(const char* name) : ServiceFramework{name} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
+ {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
+ {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
+ {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
+ {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
+ {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
+ {7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"},
+ {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ template <typename T>
+ void PushInterface(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<T>();
+
+ LOG_DEBUG(Service_NS, "called");
+ }
+};
+
+class NS_DEV final : public ServiceFramework<NS_DEV> {
+public:
+ explicit NS_DEV() : ServiceFramework{"ns:dev"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "LaunchProgram"},
+ {1, nullptr, "TerminateProcess"},
+ {2, nullptr, "TerminateProgram"},
+ {3, nullptr, "GetShellEventHandle"},
+ {4, nullptr, "GetShellEventInfo"},
+ {5, nullptr, "TerminateApplication"},
+ {6, nullptr, "PrepareLaunchProgramFromHost"},
+ {7, nullptr, "LaunchApplication"},
+ {8, nullptr, "LaunchApplicationWithStorageId"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> {
+public:
+ explicit ISystemUpdateControl() : ServiceFramework{"ISystemUpdateControl"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "HasDownloaded"},
+ {1, nullptr, "RequestCheckLatestUpdate"},
+ {2, nullptr, "RequestDownloadLatestUpdate"},
+ {3, nullptr, "GetDownloadProgress"},
+ {4, nullptr, "ApplyDownloadedUpdate"},
+ {5, nullptr, "RequestPrepareCardUpdate"},
+ {6, nullptr, "GetPrepareCardUpdateProgress"},
+ {7, nullptr, "HasPreparedCardUpdate"},
+ {8, nullptr, "ApplyCardUpdate"},
+ {9, nullptr, "GetDownloadedEulaDataSize"},
+ {10, nullptr, "GetDownloadedEulaData"},
+ {11, nullptr, "SetupCardUpdate"},
+ {12, nullptr, "GetPreparedCardUpdateEulaDataSize"},
+ {13, nullptr, "GetPreparedCardUpdateEulaData"},
+ {14, nullptr, "SetupCardUpdateViaSystemUpdater"},
+ {15, nullptr, "HasReceived"},
+ {16, nullptr, "RequestReceiveSystemUpdate"},
+ {17, nullptr, "GetReceiveProgress"},
+ {18, nullptr, "ApplyReceivedUpdate"},
+ {19, nullptr, "GetReceivedEulaDataSize"},
+ {20, nullptr, "GetReceivedEulaData"},
+ {21, nullptr, "SetupToReceiveSystemUpdate"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class NS_SU final : public ServiceFramework<NS_SU> {
+public:
+ explicit NS_SU() : ServiceFramework{"ns:su"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetBackgroundNetworkUpdateState"},
+ {1, &NS_SU::OpenSystemUpdateControl, "OpenSystemUpdateControl"},
+ {2, nullptr, "NotifyExFatDriverRequired"},
+ {3, nullptr, "ClearExFatDriverStatusForDebug"},
+ {4, nullptr, "RequestBackgroundNetworkUpdate"},
+ {5, nullptr, "NotifyBackgroundNetworkUpdate"},
+ {6, nullptr, "NotifyExFatDriverDownloadedForDebug"},
+ {9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"},
+ {10, nullptr, "NotifySystemUpdateForContentDelivery"},
+ {11, nullptr, "PrepareShutdown"},
+ {16, nullptr, "DestroySystemUpdateTask"},
+ {17, nullptr, "RequestSendSystemUpdate"},
+ {18, nullptr, "GetSendSystemUpdateProgress"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ISystemUpdateControl>();
+
+ LOG_DEBUG(Service_NS, "called");
+ }
+};
+
+class NS_VM final : public ServiceFramework<NS_VM> {
+public:
+ explicit NS_VM() : ServiceFramework{"ns:vm"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1200, nullptr, "NeedsUpdateVulnerability"},
+ {1201, nullptr, "UpdateSafeSystemVersionForDebug"},
+ {1202, nullptr, "GetSafeSystemVersion"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
void InstallInterfaces(SM::ServiceManager& service_manager) {
+ std::make_shared<NS>("ns:am2")->InstallAsService(service_manager);
+ std::make_shared<NS>("ns:ec")->InstallAsService(service_manager);
+ std::make_shared<NS>("ns:rid")->InstallAsService(service_manager);
+ std::make_shared<NS>("ns:rt")->InstallAsService(service_manager);
+ std::make_shared<NS>("ns:web")->InstallAsService(service_manager);
+
+ std::make_shared<NS_DEV>()->InstallAsService(service_manager);
+ std::make_shared<NS_SU>()->InstallAsService(service_manager);
+ std::make_shared<NS_VM>()->InstallAsService(service_manager);
+
std::make_shared<PL_U>()->InstallAsService(service_manager);
}
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index ed69a4325..8bc49935a 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -7,8 +7,8 @@
#include "core/core.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
+#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
-#include "video_core/video_core.h"
namespace Service::Nvidia::Devices {
@@ -30,9 +30,9 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
addr, offset, width, height, stride, static_cast<PixelFormat>(format),
transform, crop_rect};
- Core::System::GetInstance().perf_stats.EndGameFrame();
-
- VideoCore::g_renderer->SwapBuffers(framebuffer);
+ auto& instance = Core::System::GetInstance();
+ instance.perf_stats.EndGameFrame();
+ instance.Renderer().SwapBuffers(framebuffer);
}
} // namespace Service::Nvidia::Devices
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 57b128b40..be2b79256 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -2,14 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <cinttypes>
+#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
+#include "video_core/memory_manager.h"
+#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
-#include "video_core/video_core.h"
namespace Service::Nvidia::Devices {
@@ -150,15 +151,16 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
- auto& gpu = Core::System::GetInstance().GPU();
-
- auto itr = buffer_mappings.find(params.offset);
-
+ const auto itr = buffer_mappings.find(params.offset);
ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping");
+ auto& system_instance = Core::System::GetInstance();
+
// Remove this memory region from the rasterizer cache.
- VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(params.offset, itr->second.size);
+ system_instance.Renderer().Rasterizer().FlushAndInvalidateRegion(params.offset,
+ itr->second.size);
+ auto& gpu = system_instance.GPU();
params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size);
buffer_mappings.erase(itr->second.offset);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 671b092e1..5685eb2be 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstdlib>
+#include <cstring>
+
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 090261a60..6b496e9fe 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -5,8 +5,6 @@
#pragma once
#include <array>
-#include <cstdlib>
-#include <cstring>
#include <vector>
#include "common/common_types.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
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 44e062f50..ae421247d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <cinttypes>
+#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
@@ -97,7 +97,9 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>&
u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlActiveSlotMask params{};
- std::memcpy(&params, input.data(), input.size());
+ if (input.size() > 0) {
+ std::memcpy(&params, input.data(), input.size());
+ }
params.slot = 0x07;
params.mask = 0x01;
std::memcpy(output.data(), &params, output.size());
@@ -107,7 +109,9 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlZcullGetCtxSize params{};
- std::memcpy(&params, input.data(), input.size());
+ if (input.size() > 0) {
+ std::memcpy(&params, input.data(), input.size());
+ }
params.size = 0x1;
std::memcpy(output.data(), &params, output.size());
return 0;
@@ -116,7 +120,11 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlNvgpuGpuZcullGetInfoArgs params{};
- std::memcpy(&params, input.data(), input.size());
+
+ if (input.size() > 0) {
+ std::memcpy(&params, input.data(), input.size());
+ }
+
params.width_align_pixels = 0x20;
params.height_align_pixels = 0x20;
params.pixel_squares_by_aliquots = 0x400;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 126782573..4cdf7f613 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -2,12 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <cinttypes>
-#include <map>
+#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
+#include "core/memory.h"
+#include "video_core/gpu.h"
+#include "video_core/memory_manager.h"
namespace Service::Nvidia::Devices {
@@ -132,9 +134,12 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
params.address, params.num_entries, params.flags);
- auto entries = std::vector<IoctlGpfifoEntry>();
- entries.resize(params.num_entries);
- std::memcpy(&entries[0], &input.data()[sizeof(IoctlSubmitGpfifo)],
+ ASSERT_MSG(input.size() ==
+ sizeof(IoctlSubmitGpfifo) + params.num_entries * sizeof(IoctlGpfifoEntry),
+ "Incorrect input size");
+
+ std::vector<IoctlGpfifoEntry> entries(params.num_entries);
+ std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],
params.num_entries * sizeof(IoctlGpfifoEntry));
for (auto entry : entries) {
Tegra::GPUVAddr va_addr = entry.Address();
@@ -142,7 +147,7 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
}
params.fence_out.id = 0;
params.fence_out.value = 0;
- std::memcpy(output.data(), &params, output.size());
+ std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index aa8df2e6e..650ed8fbc 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -6,6 +6,7 @@
#include <memory>
#include <vector>
+#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index b51c73ee8..364619e67 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 0192aecdd..6ad74421b 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -4,11 +4,9 @@
#pragma once
-#include <array>
-#include <cstdlib>
-#include <cstring>
#include <vector>
#include "common/common_types.h"
+#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
namespace Service::Nvidia::Devices {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
new file mode 100644
index 000000000..51f01077b
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -0,0 +1,34 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cstring>
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
+
+namespace Service::Nvidia::Devices {
+
+u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+ LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
+ command.raw, input.size(), output.size());
+
+ switch (static_cast<IoctlCommand>(command.raw)) {
+ case IoctlCommand::IocSetNVMAPfdCommand:
+ return SetNVMAPfd(input, output);
+ }
+
+ UNIMPLEMENTED_MSG("Unimplemented ioctl");
+ return 0;
+}
+
+u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlSetNvmapFD params{};
+ std::memcpy(&params, input.data(), input.size());
+ LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
+ nvmap_fd = params.nvmap_fd;
+ return 0;
+}
+
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
new file mode 100644
index 000000000..2b0eb43ee
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -0,0 +1,36 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/hle/service/nvdrv/devices/nvdevice.h"
+
+namespace Service::Nvidia::Devices {
+
+class nvhost_nvjpg final : public nvdevice {
+public:
+ nvhost_nvjpg() = default;
+ ~nvhost_nvjpg() override = default;
+
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+
+private:
+ enum class IoctlCommand : u32_le {
+ IocSetNVMAPfdCommand = 0x40044801,
+ };
+
+ struct IoctlSetNvmapFD {
+ u32_le nvmap_fd;
+ };
+ static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
+
+ u32_le nvmap_fd{};
+
+ u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
+};
+
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
new file mode 100644
index 000000000..fcb488d50
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -0,0 +1,34 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cstring>
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
+
+namespace Service::Nvidia::Devices {
+
+u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+ LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
+ command.raw, input.size(), output.size());
+
+ switch (static_cast<IoctlCommand>(command.raw)) {
+ case IoctlCommand::IocSetNVMAPfdCommand:
+ return SetNVMAPfd(input, output);
+ }
+
+ UNIMPLEMENTED_MSG("Unimplemented ioctl");
+ return 0;
+}
+
+u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlSetNvmapFD params{};
+ std::memcpy(&params, input.data(), input.size());
+ LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
+ nvmap_fd = params.nvmap_fd;
+ return 0;
+}
+
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
new file mode 100644
index 000000000..c7d681e52
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -0,0 +1,36 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/hle/service/nvdrv/devices/nvdevice.h"
+
+namespace Service::Nvidia::Devices {
+
+class nvhost_vic final : public nvdevice {
+public:
+ nvhost_vic() = default;
+ ~nvhost_vic() override = default;
+
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+
+private:
+ enum class IoctlCommand : u32_le {
+ IocSetNVMAPfdCommand = 0x40044801,
+ };
+
+ struct IoctlSetNvmapFD {
+ u32_le nvmap_fd;
+ };
+ static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
+
+ u32_le nvmap_fd{};
+
+ u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
+};
+
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 724eeb139..e9305bfb3 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <cinttypes>
+#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 959b5ba29..1c3529bb6 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -5,7 +5,6 @@
#pragma once
#include <memory>
-#include <string>
#include "core/hle/kernel/event.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/service.h"
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 1555ea806..2de39822f 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -12,23 +12,24 @@
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
+#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
+#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
#include "core/hle/service/nvdrv/interface.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvdrv/nvmemp.h"
+#include "core/hle/service/nvflinger/nvflinger.h"
namespace Service::Nvidia {
-std::weak_ptr<Module> nvdrv;
-
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger) {
auto module_ = std::make_shared<Module>();
std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager);
std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager);
std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager);
std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager);
std::make_shared<NVMEMP>()->InstallAsService(service_manager);
- nvdrv = module_;
+ nvflinger.SetNVDrvInstance(module_);
}
Module::Module() {
@@ -40,6 +41,8 @@ Module::Module() {
devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);
devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>();
devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>();
+ devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>();
+ devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>();
}
u32 Module::Open(const std::string& device_name) {
@@ -54,7 +57,7 @@ u32 Module::Open(const std::string& device_name) {
return fd;
}
-u32 Module::Ioctl(u32 fd, u32_le command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
auto itr = open_files.find(fd);
ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device");
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index 184f3c9fc..99eb1128a 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -10,6 +10,10 @@
#include "common/common_types.h"
#include "core/hle/service/service.h"
+namespace Service::NVFlinger {
+class NVFlinger;
+}
+
namespace Service::Nvidia {
namespace Devices {
@@ -56,8 +60,6 @@ private:
};
/// Registers all NVDRV services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
-
-extern std::weak_ptr<Module> nvdrv;
+void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger);
} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp
index 9ca6e5512..0e8e21bad 100644
--- a/src/core/hle/service/nvdrv/nvmemp.cpp
+++ b/src/core/hle/service/nvdrv/nvmemp.cpp
@@ -4,8 +4,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvdrv/nvmemp.h"
namespace Service::Nvidia {
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 7132b18ad..ef5713a71 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -4,9 +4,8 @@
#include <algorithm>
-#include "common/alignment.h"
-#include "common/scope_exit.h"
-#include "core/core_timing.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
namespace Service {
@@ -17,7 +16,7 @@ BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
Kernel::Event::Create(Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
}
-void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) {
+void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
Buffer buffer{};
buffer.slot = slot;
buffer.igbp_buffer = igbp_buffer;
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 004170538..db2e17c0c 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -6,6 +6,7 @@
#include <vector>
#include <boost/optional.hpp>
+#include "common/common_funcs.h"
#include "common/math_util.h"
#include "common/swap.h"
#include "core/hle/kernel/event.h"
@@ -72,7 +73,7 @@ public:
MathUtil::Rectangle<int> crop_rect;
};
- void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer);
+ void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer);
boost::optional<u32> DequeueBuffer(u32 width, u32 height);
const IGBPBuffer& RequestBuffer(u32 slot) const;
void QueueBuffer(u32 slot, BufferTransformFlags transform,
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 5344441e1..a26a5f812 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -3,8 +3,11 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <boost/optional.hpp>
#include "common/alignment.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
#include "core/core.h"
@@ -31,7 +34,7 @@ NVFlinger::NVFlinger() {
// Schedule the screen composition events
composition_event =
- CoreTiming::RegisterEvent("ScreenCompositioin", [this](u64 userdata, int cycles_late) {
+ CoreTiming::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) {
Compose();
CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event);
});
@@ -43,7 +46,11 @@ NVFlinger::~NVFlinger() {
CoreTiming::UnscheduleEvent(composition_event, 0);
}
-u64 NVFlinger::OpenDisplay(const std::string& name) {
+void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
+ nvdrv = std::move(instance);
+}
+
+u64 NVFlinger::OpenDisplay(std::string_view name) {
LOG_WARNING(Service, "Opening display {}", name);
// TODO(Subv): Currently we only support the Default display.
@@ -127,18 +134,17 @@ void NVFlinger::Compose() {
MicroProfileFlip();
if (buffer == boost::none) {
+ auto& system_instance = Core::System::GetInstance();
+
// There was no queued buffer to draw, render previous frame
- Core::System::GetInstance().perf_stats.EndGameFrame();
- VideoCore::g_renderer->SwapBuffers({});
+ system_instance.perf_stats.EndGameFrame();
+ system_instance.Renderer().SwapBuffers({});
continue;
}
auto& igbp_buffer = buffer->igbp_buffer;
// Now send the buffer to the GPU for drawing.
- auto nvdrv = Nvidia::nvdrv.lock();
- ASSERT(nvdrv);
-
// TODO(Subv): Support more than just disp0. The display device selection is probably based
// on which display we're drawing (Default, Internal, External, etc)
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 2c908297b..f7112949f 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -5,13 +5,21 @@
#pragma once
#include <memory>
-#include <boost/optional.hpp>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include "common/common_types.h"
#include "core/hle/kernel/event.h"
namespace CoreTiming {
struct EventType;
}
+namespace Service::Nvidia {
+class Module;
+}
+
namespace Service::NVFlinger {
class BufferQueue;
@@ -40,8 +48,11 @@ public:
NVFlinger();
~NVFlinger();
+ /// Sets the NVDrv module instance to use to send buffers to the GPU.
+ void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance);
+
/// Opens the specified display and returns the id.
- u64 OpenDisplay(const std::string& name);
+ u64 OpenDisplay(std::string_view name);
/// Creates a layer on the specified display and returns the layer id.
u64 CreateLayer(u64 display_id);
@@ -66,6 +77,8 @@ private:
/// Returns the layer identified by the specified id in the desired display.
Layer& GetLayer(u64 display_id, u64 layer_id);
+ std::shared_ptr<Nvidia::Module> nvdrv;
+
std::vector<Display> displays;
std::vector<std::shared_ptr<BufferQueue>> buffer_queues;
diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp
new file mode 100644
index 000000000..39cf05eba
--- /dev/null
+++ b/src/core/hle/service/pcie/pcie.cpp
@@ -0,0 +1,64 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/service/pcie/pcie.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::PCIe {
+
+class ISession final : public ServiceFramework<ISession> {
+public:
+ explicit ISession() : ServiceFramework{"ISession"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "QueryFunctions"},
+ {1, nullptr, "AcquireFunction"},
+ {2, nullptr, "ReleaseFunction"},
+ {3, nullptr, "GetFunctionState"},
+ {4, nullptr, "GetBarProfile"},
+ {5, nullptr, "ReadConfig"},
+ {6, nullptr, "WriteConfig"},
+ {7, nullptr, "ReadBarRegion"},
+ {8, nullptr, "WriteBarRegion"},
+ {9, nullptr, "FindCapability"},
+ {10, nullptr, "FindExtendedCapability"},
+ {11, nullptr, "MapDma"},
+ {12, nullptr, "UnmapDma"},
+ {13, nullptr, "UnmapDmaBusAddress"},
+ {14, nullptr, "GetDmaBusAddress"},
+ {15, nullptr, "GetDmaBusAddressRange"},
+ {16, nullptr, "SetDmaEnable"},
+ {17, nullptr, "AcquireIrq"},
+ {18, nullptr, "ReleaseIrq"},
+ {19, nullptr, "SetIrqEnable"},
+ {20, nullptr, "SetAspmEnable"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class PCIe final : public ServiceFramework<PCIe> {
+public:
+ explicit PCIe() : ServiceFramework{"pcie"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RegisterClassDriver"},
+ {1, nullptr, "QueryFunctionsUnregistered"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<PCIe>()->InstallAsService(sm);
+}
+
+} // namespace Service::PCIe
diff --git a/src/core/hle/service/pcie/pcie.h b/src/core/hle/service/pcie/pcie.h
new file mode 100644
index 000000000..59c22ca45
--- /dev/null
+++ b/src/core/hle/service/pcie/pcie.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::PCIe {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::PCIe
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp
new file mode 100644
index 000000000..d6891a659
--- /dev/null
+++ b/src/core/hle/service/pcv/pcv.cpp
@@ -0,0 +1,84 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/service/pcv/pcv.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::PCV {
+
+class PCV final : public ServiceFramework<PCV> {
+public:
+ explicit PCV() : ServiceFramework{"pcv"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "SetPowerEnabled"},
+ {1, nullptr, "SetClockEnabled"},
+ {2, nullptr, "SetClockRate"},
+ {3, nullptr, "GetClockRate"},
+ {4, nullptr, "GetState"},
+ {5, nullptr, "GetPossibleClockRates"},
+ {6, nullptr, "SetMinVClockRate"},
+ {7, nullptr, "SetReset"},
+ {8, nullptr, "SetVoltageEnabled"},
+ {9, nullptr, "GetVoltageEnabled"},
+ {10, nullptr, "GetVoltageRange"},
+ {11, nullptr, "SetVoltageValue"},
+ {12, nullptr, "GetVoltageValue"},
+ {13, nullptr, "GetTemperatureThresholds"},
+ {14, nullptr, "SetTemperature"},
+ {15, nullptr, "Initialize"},
+ {16, nullptr, "IsInitialized"},
+ {17, nullptr, "Finalize"},
+ {18, nullptr, "PowerOn"},
+ {19, nullptr, "PowerOff"},
+ {20, nullptr, "ChangeVoltage"},
+ {21, nullptr, "GetPowerClockInfoEvent"},
+ {22, nullptr, "GetOscillatorClock"},
+ {23, nullptr, "GetDvfsTable"},
+ {24, nullptr, "GetModuleStateTable"},
+ {25, nullptr, "GetPowerDomainStateTable"},
+ {26, nullptr, "GetFuseInfo"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class PCV_ARB final : public ServiceFramework<PCV_ARB> {
+public:
+ explicit PCV_ARB() : ServiceFramework{"pcv:arb"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "ReleaseControl"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class PCV_IMM final : public ServiceFramework<PCV_IMM> {
+public:
+ explicit PCV_IMM() : ServiceFramework{"pcv:imm"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "SetClockRate"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<PCV>()->InstallAsService(sm);
+ std::make_shared<PCV_ARB>()->InstallAsService(sm);
+ std::make_shared<PCV_IMM>()->InstallAsService(sm);
+}
+
+} // namespace Service::PCV
diff --git a/src/core/hle/service/pcv/pcv.h b/src/core/hle/service/pcv/pcv.h
new file mode 100644
index 000000000..219a893c3
--- /dev/null
+++ b/src/core/hle/service/pcv/pcv.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::PCV {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::PCV
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
new file mode 100644
index 000000000..bbad870a2
--- /dev/null
+++ b/src/core/hle/service/psc/psc.cpp
@@ -0,0 +1,77 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/psc/psc.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::PSC {
+
+class PSC_C final : public ServiceFramework<PSC_C> {
+public:
+ explicit PSC_C() : ServiceFramework{"psc:c"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "Unknown3"},
+ {3, nullptr, "Unknown4"},
+ {4, nullptr, "Unknown5"},
+ {5, nullptr, "Unknown6"},
+ {6, nullptr, "Unknown7"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IPmModule final : public ServiceFramework<IPmModule> {
+public:
+ explicit IPmModule() : ServiceFramework{"IPmModule"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "GetRequest"},
+ {2, nullptr, "Acknowledge"},
+ {3, nullptr, "Unknown1"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class PSC_M final : public ServiceFramework<PSC_M> {
+public:
+ explicit PSC_M() : ServiceFramework{"psc:m"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &PSC_M::GetPmModule, "GetPmModule"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void GetPmModule(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IPmModule>();
+
+ LOG_DEBUG(Service_PSC, "called");
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<PSC_C>()->InstallAsService(sm);
+ std::make_shared<PSC_M>()->InstallAsService(sm);
+}
+
+} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/psc.h b/src/core/hle/service/psc/psc.h
new file mode 100644
index 000000000..5052eb02c
--- /dev/null
+++ b/src/core/hle/service/psc/psc.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::PSC {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::PSC
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 482989ea7..11951adaf 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -19,25 +19,42 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/aoc/aoc_u.h"
#include "core/hle/service/apm/apm.h"
+#include "core/hle/service/arp/arp.h"
#include "core/hle/service/audio/audio.h"
#include "core/hle/service/bcat/bcat.h"
+#include "core/hle/service/bpc/bpc.h"
+#include "core/hle/service/btdrv/btdrv.h"
+#include "core/hle/service/btm/btm.h"
+#include "core/hle/service/caps/caps.h"
#include "core/hle/service/erpt/erpt.h"
#include "core/hle/service/es/es.h"
#include "core/hle/service/eupld/eupld.h"
#include "core/hle/service/fatal/fatal.h"
+#include "core/hle/service/fgm/fgm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/friend/friend.h"
+#include "core/hle/service/grc/grc.h"
#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/lbl/lbl.h"
+#include "core/hle/service/ldn/ldn.h"
#include "core/hle/service/ldr/ldr.h"
#include "core/hle/service/lm/lm.h"
+#include "core/hle/service/mig/mig.h"
+#include "core/hle/service/mii/mii.h"
#include "core/hle/service/mm/mm_u.h"
+#include "core/hle/service/ncm/ncm.h"
+#include "core/hle/service/nfc/nfc.h"
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nifm/nifm.h"
+#include "core/hle/service/nim/nim.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/pcie/pcie.h"
#include "core/hle/service/pctl/pctl.h"
+#include "core/hle/service/pcv/pcv.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/prepo/prepo.h"
+#include "core/hle/service/psc/psc.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/settings.h"
#include "core/hle/service/sm/controller.h"
@@ -46,7 +63,9 @@
#include "core/hle/service/spl/module.h"
#include "core/hle/service/ssl/ssl.h"
#include "core/hle/service/time/time.h"
+#include "core/hle/service/usb/usb.h"
#include "core/hle/service/vi/vi.h"
+#include "core/hle/service/wlan/wlan.h"
using Kernel::ClientPort;
using Kernel::ServerPort;
@@ -179,7 +198,7 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
}
/// Initialize ServiceManager
-void Init(std::shared_ptr<SM::ServiceManager>& sm) {
+void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesystem& rfs) {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
// here and pass it into the respective InstallInterfaces functions.
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
@@ -190,31 +209,50 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
AM::InstallInterfaces(*sm, nv_flinger);
AOC::InstallInterfaces(*sm);
APM::InstallInterfaces(*sm);
- BCAT::InstallInterfaces(*sm);
+ ARP::InstallInterfaces(*sm);
Audio::InstallInterfaces(*sm);
+ BCAT::InstallInterfaces(*sm);
+ BPC::InstallInterfaces(*sm);
+ BtDrv::InstallInterfaces(*sm);
+ BTM::InstallInterfaces(*sm);
+ Capture::InstallInterfaces(*sm);
ERPT::InstallInterfaces(*sm);
ES::InstallInterfaces(*sm);
EUPLD::InstallInterfaces(*sm);
Fatal::InstallInterfaces(*sm);
- FileSystem::InstallInterfaces(*sm);
+ FGM::InstallInterfaces(*sm);
+ FileSystem::InstallInterfaces(*sm, rfs);
Friend::InstallInterfaces(*sm);
+ GRC::InstallInterfaces(*sm);
HID::InstallInterfaces(*sm);
+ LBL::InstallInterfaces(*sm);
+ LDN::InstallInterfaces(*sm);
LDR::InstallInterfaces(*sm);
LM::InstallInterfaces(*sm);
+ Migration::InstallInterfaces(*sm);
+ Mii::InstallInterfaces(*sm);
MM::InstallInterfaces(*sm);
+ NCM::InstallInterfaces(*sm);
+ NFC::InstallInterfaces(*sm);
NFP::InstallInterfaces(*sm);
NIFM::InstallInterfaces(*sm);
+ NIM::InstallInterfaces(*sm);
NS::InstallInterfaces(*sm);
- Nvidia::InstallInterfaces(*sm);
+ Nvidia::InstallInterfaces(*sm, *nv_flinger);
+ PCIe::InstallInterfaces(*sm);
PCTL::InstallInterfaces(*sm);
+ PCV::InstallInterfaces(*sm);
PlayReport::InstallInterfaces(*sm);
PM::InstallInterfaces(*sm);
+ PSC::InstallInterfaces(*sm);
+ Set::InstallInterfaces(*sm);
Sockets::InstallInterfaces(*sm);
SPL::InstallInterfaces(*sm);
SSL::InstallInterfaces(*sm);
Time::InstallInterfaces(*sm);
+ USB::InstallInterfaces(*sm);
VI::InstallInterfaces(*sm, nv_flinger);
- Set::InstallInterfaces(*sm);
+ WLAN::InstallInterfaces(*sm);
LOG_DEBUG(Service, "initialized OK");
}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 180f22703..cd9c74f3d 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -8,10 +8,9 @@
#include <string>
#include <unordered_map>
#include <boost/container/flat_map.hpp>
-#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
@@ -23,6 +22,10 @@ class ServerSession;
class HLERequestContext;
} // namespace Kernel
+namespace FileSys {
+class VfsFilesystem;
+}
+
namespace Service {
namespace SM {
@@ -178,7 +181,8 @@ private:
};
/// Initialize ServiceManager
-void Init(std::shared_ptr<SM::ServiceManager>& sm);
+void Init(std::shared_ptr<SM::ServiceManager>& sm,
+ const std::shared_ptr<FileSys::VfsFilesystem>& vfs);
/// Shutdown ServiceManager
void Shutdown();
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 1651f6122..a461e72ec 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -8,6 +8,7 @@
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/service/set/set.h"
+#include "core/settings.h"
namespace Service::Set {
@@ -31,6 +32,10 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
LanguageCode::ZH_HANT,
}};
+LanguageCode GetLanguageCodeFromIndex(size_t index) {
+ return available_language_codes.at(index);
+}
+
void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
ctx.WriteBuffer(available_language_codes);
@@ -49,9 +54,17 @@ void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
}
+void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index]));
+
+ LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
+}
+
SET::SET() : ServiceFramework("set") {
static const FunctionInfo functions[] = {
- {0, nullptr, "GetLanguageCode"},
+ {0, &SET::GetLanguageCode, "GetLanguageCode"},
{1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"},
{2, nullptr, "MakeLanguageCode"},
{3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"},
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index a2472ec4c..4232b6162 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -28,6 +28,7 @@ enum class LanguageCode : u64 {
ZH_HANS = 0x00736E61482D687A,
ZH_HANT = 0x00746E61482D687A,
};
+LanguageCode GetLanguageCodeFromIndex(size_t idx);
class SET final : public ServiceFramework<SET> {
public:
@@ -35,6 +36,7 @@ public:
~SET() = default;
private:
+ void GetLanguageCode(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
};
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 518a0cc46..1cef73216 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -10,7 +10,7 @@
namespace Service::SM {
void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
- ASSERT_MSG(!ctx.Session()->IsDomain(), "session is alread a domain");
+ ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
ctx.Session()->ConvertToDomain();
IPC::ResponseBuilder rb{ctx, 3};
@@ -41,7 +41,7 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0x500);
+ rb.Push<u16>(0x500);
LOG_WARNING(Service, "(STUBBED) called");
}
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index e2a00e4f6..e8ea62f08 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -4,9 +4,11 @@
#pragma once
+#include <memory>
#include <string>
#include <unordered_map>
-#include "core/hle/kernel/kernel.h"
+
+#include "core/hle/kernel/object.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
@@ -19,6 +21,8 @@ class SessionRequestHandler;
namespace Service::SM {
+class Controller;
+
/// Interface to "sm:" service
class SM final : public ServiceFramework<SM> {
public:
@@ -32,8 +36,6 @@ private:
std::shared_ptr<ServiceManager> service_manager;
};
-class Controller;
-
constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(-1);
constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1);
constexpr ResultCode ERR_INVALID_NAME_SIZE(-1);
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 6aa1e2511..3211a8346 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -109,4 +109,26 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
RegisterHandlers(functions);
}
+BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "SetIfUp"},
+ {1, nullptr, "SetIfUpWithEvent"},
+ {2, nullptr, "CancelIf"},
+ {3, nullptr, "SetIfDown"},
+ {4, nullptr, "GetIfState"},
+ {5, nullptr, "DhcpRenew"},
+ {6, nullptr, "AddStaticArpEntry"},
+ {7, nullptr, "RemoveArpEntry"},
+ {8, nullptr, "LookupArpEntry"},
+ {9, nullptr, "LookupArpEntry2"},
+ {10, nullptr, "ClearArpEntries"},
+ {11, nullptr, "ClearArpEntries2"},
+ {12, nullptr, "PrintArpEntries"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index a6b1ca7d0..c1da59b24 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -26,4 +26,9 @@ private:
u32 next_fd = 1;
};
+class BSDCFG final : public ServiceFramework<BSDCFG> {
+public:
+ explicit BSDCFG();
+};
+
} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp
new file mode 100644
index 000000000..d53c25eec
--- /dev/null
+++ b/src/core/hle/service/sockets/ethc.cpp
@@ -0,0 +1,38 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/sockets/ethc.h"
+
+namespace Service::Sockets {
+
+ETHC_C::ETHC_C() : ServiceFramework{"ethc:c"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "Cancel"},
+ {2, nullptr, "GetResult"},
+ {3, nullptr, "GetMediaList"},
+ {4, nullptr, "SetMediaType"},
+ {5, nullptr, "GetMediaType"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetReadableHandle"},
+ {1, nullptr, "Cancel"},
+ {2, nullptr, "GetResult"},
+ {3, nullptr, "GetInterfaceList"},
+ {4, nullptr, "GetInterfaceCount"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/ethc.h b/src/core/hle/service/sockets/ethc.h
new file mode 100644
index 000000000..9a3c88100
--- /dev/null
+++ b/src/core/hle/service/sockets/ethc.h
@@ -0,0 +1,21 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::Sockets {
+
+class ETHC_C final : public ServiceFramework<ETHC_C> {
+public:
+ explicit ETHC_C();
+};
+
+class ETHC_I final : public ServiceFramework<ETHC_I> {
+public:
+ explicit ETHC_I();
+};
+
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp
index 05bd10d35..08d2d306a 100644
--- a/src/core/hle/service/sockets/sockets.cpp
+++ b/src/core/hle/service/sockets/sockets.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "core/hle/service/sockets/bsd.h"
+#include "core/hle/service/sockets/ethc.h"
#include "core/hle/service/sockets/nsd.h"
#include "core/hle/service/sockets/sfdnsres.h"
#include "core/hle/service/sockets/sockets.h"
@@ -12,8 +13,14 @@ namespace Service::Sockets {
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<BSD>("bsd:s")->InstallAsService(service_manager);
std::make_shared<BSD>("bsd:u")->InstallAsService(service_manager);
+ std::make_shared<BSDCFG>()->InstallAsService(service_manager);
+
+ std::make_shared<ETHC_C>()->InstallAsService(service_manager);
+ std::make_shared<ETHC_I>()->InstallAsService(service_manager);
+
std::make_shared<NSD>("nsd:a")->InstallAsService(service_manager);
std::make_shared<NSD>("nsd:u")->InstallAsService(service_manager);
+
std::make_shared<SFDNSRES>()->InstallAsService(service_manager);
}
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 37b58bb77..2172c681b 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -80,8 +80,8 @@ public:
{5, nullptr, "GetTimeZoneRuleVersion"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
- {200, nullptr, "ToPosixTime"},
- {201, nullptr, "ToPosixTimeWithMyRule"},
+ {201, nullptr, "ToPosixTime"},
+ {202, nullptr, "ToPosixTimeWithMyRule"},
};
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
new file mode 100644
index 000000000..e7fb5a419
--- /dev/null
+++ b/src/core/hle/service/usb/usb.cpp
@@ -0,0 +1,238 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+#include "core/hle/service/usb/usb.h"
+
+namespace Service::USB {
+
+class IDsInterface final : public ServiceFramework<IDsInterface> {
+public:
+ explicit IDsInterface() : ServiceFramework{"IDsInterface"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetDsEndpoint"},
+ {1, nullptr, "GetSetupEvent"},
+ {2, nullptr, "Unknown"},
+ {3, nullptr, "EnableInterface"},
+ {4, nullptr, "DisableInterface"},
+ {5, nullptr, "CtrlInPostBufferAsync"},
+ {6, nullptr, "CtrlOutPostBufferAsync"},
+ {7, nullptr, "GetCtrlInCompletionEvent"},
+ {8, nullptr, "GetCtrlInReportData"},
+ {9, nullptr, "GetCtrlOutCompletionEvent"},
+ {10, nullptr, "GetCtrlOutReportData"},
+ {11, nullptr, "StallCtrl"},
+ {12, nullptr, "AppendConfigurationData"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class USB_DS final : public ServiceFramework<USB_DS> {
+public:
+ explicit USB_DS() : ServiceFramework{"usb:ds"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "BindDevice"},
+ {1, nullptr, "BindClientProcess"},
+ {2, nullptr, "GetDsInterface"},
+ {3, nullptr, "GetStateChangeEvent"},
+ {4, nullptr, "GetState"},
+ {5, nullptr, "ClearDeviceData"},
+ {6, nullptr, "AddUsbStringDescriptor"},
+ {7, nullptr, "DeleteUsbStringDescriptor"},
+ {8, nullptr, "SetUsbDeviceDescriptor"},
+ {9, nullptr, "SetBinaryObjectStore"},
+ {10, nullptr, "Enable"},
+ {11, nullptr, "Disable"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IClientEpSession final : public ServiceFramework<IClientEpSession> {
+public:
+ explicit IClientEpSession() : ServiceFramework{"IClientEpSession"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "Unknown3"},
+ {3, nullptr, "Unknown4"},
+ {4, nullptr, "PostBufferAsync"},
+ {5, nullptr, "Unknown5"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "Unknown8"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IClientIfSession final : public ServiceFramework<IClientIfSession> {
+public:
+ explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "Unknown3"},
+ {3, nullptr, "Unknown4"},
+ {4, nullptr, "Unknown5"},
+ {5, nullptr, "CtrlXferAsync"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "GetCtrlXferReport"},
+ {8, nullptr, "Unknown7"},
+ {9, nullptr, "GetClientEpSession"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class USB_HS final : public ServiceFramework<USB_HS> {
+public:
+ explicit USB_HS() : ServiceFramework{"usb:hs"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "BindClientProcess"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
+ {6, nullptr, "GetInterfaceStateChangeEvent"},
+ {7, nullptr, "GetClientIfSession"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IPdSession final : public ServiceFramework<IPdSession> {
+public:
+ explicit IPdSession() : ServiceFramework{"IPdSession"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "BindNoticeEvent"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "GetStatus"},
+ {3, nullptr, "GetNotice"},
+ {4, nullptr, "Unknown2"},
+ {5, nullptr, "Unknown3"},
+ {6, nullptr, "ReplyPowerRequest"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class USB_PD final : public ServiceFramework<USB_PD> {
+public:
+ explicit USB_PD() : ServiceFramework{"usb:pd"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &USB_PD::GetPdSession, "GetPdSession"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void GetPdSession(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IPdSession>();
+
+ LOG_DEBUG(Service_USB, "called");
+ }
+};
+
+class IPdCradleSession final : public ServiceFramework<IPdCradleSession> {
+public:
+ explicit IPdCradleSession() : ServiceFramework{"IPdCradleSession"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "VdmUserWrite"},
+ {1, nullptr, "VdmUserRead"},
+ {2, nullptr, "Vdm20Init"},
+ {3, nullptr, "GetFwType"},
+ {4, nullptr, "GetFwRevision"},
+ {5, nullptr, "GetManufacturerId"},
+ {6, nullptr, "GetDeviceId"},
+ {7, nullptr, "Unknown1"},
+ {8, nullptr, "Unknown2"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class USB_PD_C final : public ServiceFramework<USB_PD_C> {
+public:
+ explicit USB_PD_C() : ServiceFramework{"usb:pd:c"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &USB_PD_C::GetPdCradleSession, "GetPdCradleSession"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void GetPdCradleSession(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IPdCradleSession>();
+
+ LOG_DEBUG(Service_USB, "called");
+ }
+};
+
+class USB_PM final : public ServiceFramework<USB_PM> {
+public:
+ explicit USB_PM() : ServiceFramework{"usb:pm"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "Unknown3"},
+ {3, nullptr, "Unknown4"},
+ {4, nullptr, "Unknown5"},
+ {5, nullptr, "Unknown6"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<USB_DS>()->InstallAsService(sm);
+ std::make_shared<USB_HS>()->InstallAsService(sm);
+ std::make_shared<USB_PD>()->InstallAsService(sm);
+ std::make_shared<USB_PD_C>()->InstallAsService(sm);
+ std::make_shared<USB_PM>()->InstallAsService(sm);
+}
+
+} // namespace Service::USB
diff --git a/src/core/hle/service/usb/usb.h b/src/core/hle/service/usb/usb.h
new file mode 100644
index 000000000..970a11fe8
--- /dev/null
+++ b/src/core/hle/service/usb/usb.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::USB {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::USB
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp
new file mode 100644
index 000000000..2654594c1
--- /dev/null
+++ b/src/core/hle/service/wlan/wlan.cpp
@@ -0,0 +1,172 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/sm/sm.h"
+#include "core/hle/service/wlan/wlan.h"
+
+namespace Service::WLAN {
+
+class WLANInfra final : public ServiceFramework<WLANInfra> {
+public:
+ explicit WLANInfra() : ServiceFramework{"wlan:inf"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "GetMacAddress"},
+ {3, nullptr, "StartScan"},
+ {4, nullptr, "StopScan"},
+ {5, nullptr, "Connect"},
+ {6, nullptr, "CancelConnect"},
+ {7, nullptr, "Disconnect"},
+ {8, nullptr, "Unknown3"},
+ {9, nullptr, "Unknown4"},
+ {10, nullptr, "GetState"},
+ {11, nullptr, "GetScanResult"},
+ {12, nullptr, "GetRssi"},
+ {13, nullptr, "ChangeRxAntenna"},
+ {14, nullptr, "Unknown5"},
+ {15, nullptr, "Unknown6"},
+ {16, nullptr, "RequestWakeUp"},
+ {17, nullptr, "RequestIfUpDown"},
+ {18, nullptr, "Unknown7"},
+ {19, nullptr, "Unknown8"},
+ {20, nullptr, "Unknown9"},
+ {21, nullptr, "Unknown10"},
+ {22, nullptr, "Unknown11"},
+ {23, nullptr, "Unknown12"},
+ {24, nullptr, "Unknown13"},
+ {25, nullptr, "Unknown14"},
+ {26, nullptr, "Unknown15"},
+ {27, nullptr, "Unknown16"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class WLANLocal final : public ServiceFramework<WLANLocal> {
+public:
+ explicit WLANLocal() : ServiceFramework{"wlan:lcl"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "Unknown3"},
+ {3, nullptr, "Unknown4"},
+ {4, nullptr, "Unknown5"},
+ {5, nullptr, "Unknown6"},
+ {6, nullptr, "GetMacAddress"},
+ {7, nullptr, "CreateBss"},
+ {8, nullptr, "DestroyBss"},
+ {9, nullptr, "StartScan"},
+ {10, nullptr, "StopScan"},
+ {11, nullptr, "Connect"},
+ {12, nullptr, "CancelConnect"},
+ {13, nullptr, "Join"},
+ {14, nullptr, "CancelJoin"},
+ {15, nullptr, "Disconnect"},
+ {16, nullptr, "SetBeaconLostCount"},
+ {17, nullptr, "Unknown7"},
+ {18, nullptr, "Unknown8"},
+ {19, nullptr, "Unknown9"},
+ {20, nullptr, "GetBssIndicationEvent"},
+ {21, nullptr, "GetBssIndicationInfo"},
+ {22, nullptr, "GetState"},
+ {23, nullptr, "GetAllowedChannels"},
+ {24, nullptr, "AddIe"},
+ {25, nullptr, "DeleteIe"},
+ {26, nullptr, "Unknown10"},
+ {27, nullptr, "Unknown11"},
+ {28, nullptr, "CreateRxEntry"},
+ {29, nullptr, "DeleteRxEntry"},
+ {30, nullptr, "Unknown12"},
+ {31, nullptr, "Unknown13"},
+ {32, nullptr, "AddMatchingDataToRxEntry"},
+ {33, nullptr, "RemoveMatchingDataFromRxEntry"},
+ {34, nullptr, "GetScanResult"},
+ {35, nullptr, "Unknown14"},
+ {36, nullptr, "SetActionFrameWithBeacon"},
+ {37, nullptr, "CancelActionFrameWithBeacon"},
+ {38, nullptr, "CreateRxEntryForActionFrame"},
+ {39, nullptr, "DeleteRxEntryForActionFrame"},
+ {40, nullptr, "Unknown15"},
+ {41, nullptr, "Unknown16"},
+ {42, nullptr, "CancelGetActionFrame"},
+ {43, nullptr, "GetRssi"},
+ {44, nullptr, "Unknown17"},
+ {45, nullptr, "Unknown18"},
+ {46, nullptr, "Unknown19"},
+ {47, nullptr, "Unknown20"},
+ {48, nullptr, "Unknown21"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> {
+public:
+ explicit WLANLocalGetFrame() : ServiceFramework{"wlan:lg"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> {
+public:
+ explicit WLANSocketGetFrame() : ServiceFramework{"wlan:sg"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class WLANSocketManager final : public ServiceFramework<WLANSocketManager> {
+public:
+ explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown1"},
+ {1, nullptr, "Unknown2"},
+ {2, nullptr, "Unknown3"},
+ {3, nullptr, "Unknown4"},
+ {4, nullptr, "Unknown5"},
+ {5, nullptr, "Unknown6"},
+ {6, nullptr, "GetMacAddress"},
+ {7, nullptr, "SwitchTsfTimerFunction"},
+ {8, nullptr, "Unknown7"},
+ {9, nullptr, "Unknown8"},
+ {10, nullptr, "Unknown9"},
+ {11, nullptr, "Unknown10"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& sm) {
+ std::make_shared<WLANInfra>()->InstallAsService(sm);
+ std::make_shared<WLANLocal>()->InstallAsService(sm);
+ std::make_shared<WLANLocalGetFrame>()->InstallAsService(sm);
+ std::make_shared<WLANSocketGetFrame>()->InstallAsService(sm);
+ std::make_shared<WLANSocketManager>()->InstallAsService(sm);
+}
+
+} // namespace Service::WLAN
diff --git a/src/core/hle/service/wlan/wlan.h b/src/core/hle/service/wlan/wlan.h
new file mode 100644
index 000000000..054ea928a
--- /dev/null
+++ b/src/core/hle/service/wlan/wlan.h
@@ -0,0 +1,15 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::WLAN {
+
+void InstallInterfaces(SM::ServiceManager& sm);
+
+} // namespace Service::WLAN
diff --git a/src/core/hw/aes/ccm.cpp b/src/core/hw/aes/ccm.cpp
deleted file mode 100644
index 1ee37aaa4..000000000
--- a/src/core/hw/aes/ccm.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <algorithm>
-#include "common/alignment.h"
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "core/hw/aes/ccm.h"
-#include "core/hw/aes/key.h"
-
-namespace HW {
-namespace AES {
-
-std::vector<u8> EncryptSignCCM(const std::vector<u8>& pdata, const CCMNonce& nonce,
- size_t slot_id) {
- UNIMPLEMENTED();
- return {};
-}
-
-std::vector<u8> DecryptVerifyCCM(const std::vector<u8>& cipher, const CCMNonce& nonce,
- size_t slot_id) {
- UNIMPLEMENTED();
- return {};
-}
-
-} // namespace AES
-} // namespace HW
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
deleted file mode 100644
index 2f48068c1..000000000
--- a/src/core/hw/hw.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/common_types.h"
-#include "common/logging/log.h"
-#include "core/hw/hw.h"
-#include "core/hw/lcd.h"
-
-namespace HW {
-
-template <typename T>
-inline void Read(T& var, const u32 addr) {
- switch (addr & 0xFFFFF000) {
- case VADDR_GPU:
- case VADDR_GPU + 0x1000:
- case VADDR_GPU + 0x2000:
- case VADDR_GPU + 0x3000:
- case VADDR_GPU + 0x4000:
- case VADDR_GPU + 0x5000:
- case VADDR_GPU + 0x6000:
- case VADDR_GPU + 0x7000:
- case VADDR_GPU + 0x8000:
- case VADDR_GPU + 0x9000:
- case VADDR_GPU + 0xA000:
- case VADDR_GPU + 0xB000:
- case VADDR_GPU + 0xC000:
- case VADDR_GPU + 0xD000:
- case VADDR_GPU + 0xE000:
- case VADDR_GPU + 0xF000:
- break;
- case VADDR_LCD:
- LCD::Read(var, addr);
- break;
- default:
- LOG_ERROR(HW_Memory, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr);
- break;
- }
-}
-
-template <typename T>
-inline void Write(u32 addr, const T data) {
- switch (addr & 0xFFFFF000) {
- case VADDR_GPU:
- case VADDR_GPU + 0x1000:
- case VADDR_GPU + 0x2000:
- case VADDR_GPU + 0x3000:
- case VADDR_GPU + 0x4000:
- case VADDR_GPU + 0x5000:
- case VADDR_GPU + 0x6000:
- case VADDR_GPU + 0x7000:
- case VADDR_GPU + 0x8000:
- case VADDR_GPU + 0x9000:
- case VADDR_GPU + 0xA000:
- case VADDR_GPU + 0xB000:
- case VADDR_GPU + 0xC000:
- case VADDR_GPU + 0xD000:
- case VADDR_GPU + 0xE000:
- case VADDR_GPU + 0xF000:
- break;
- case VADDR_LCD:
- LCD::Write(addr, data);
- break;
- default:
- LOG_ERROR(HW_Memory, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr);
- break;
- }
-}
-
-// Explicitly instantiate template functions because we aren't defining this in the header:
-
-template void Read<u64>(u64& var, const u32 addr);
-template void Read<u32>(u32& var, const u32 addr);
-template void Read<u16>(u16& var, const u32 addr);
-template void Read<u8>(u8& var, const u32 addr);
-
-template void Write<u64>(u32 addr, const u64 data);
-template void Write<u32>(u32 addr, const u32 data);
-template void Write<u16>(u32 addr, const u16 data);
-template void Write<u8>(u32 addr, const u8 data);
-
-/// Update hardware
-void Update() {}
-
-/// Initialize hardware
-void Init() {
- LCD::Init();
- LOG_DEBUG(HW, "Initialized OK");
-}
-
-/// Shutdown hardware
-void Shutdown() {
- LCD::Shutdown();
- LOG_DEBUG(HW, "Shutdown OK");
-}
-} // namespace HW
diff --git a/src/core/hw/hw.h b/src/core/hw/hw.h
deleted file mode 100644
index 5890d2b5c..000000000
--- a/src/core/hw/hw.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-
-namespace HW {
-
-/// Beginnings of IO register regions, in the user VA space.
-enum : u32 {
- VADDR_HASH = 0x1EC01000,
- VADDR_CSND = 0x1EC03000,
- VADDR_DSP = 0x1EC40000,
- VADDR_PDN = 0x1EC41000,
- VADDR_CODEC = 0x1EC41000,
- VADDR_SPI = 0x1EC42000,
- VADDR_SPI_2 = 0x1EC43000, // Only used under TWL_FIRM?
- VADDR_I2C = 0x1EC44000,
- VADDR_CODEC_2 = 0x1EC45000,
- VADDR_HID = 0x1EC46000,
- VADDR_GPIO = 0x1EC47000,
- VADDR_I2C_2 = 0x1EC48000,
- VADDR_SPI_3 = 0x1EC60000,
- VADDR_I2C_3 = 0x1EC61000,
- VADDR_MIC = 0x1EC62000,
- VADDR_PXI = 0x1EC63000,
- VADDR_LCD = 0x1ED02000,
- VADDR_DSP_2 = 0x1ED03000,
- VADDR_HASH_2 = 0x1EE01000,
- VADDR_GPU = 0x1EF00000,
-};
-
-template <typename T>
-void Read(T& var, const u32 addr);
-
-template <typename T>
-void Write(u32 addr, const T data);
-
-/// Update hardware
-void Update();
-
-/// Initialize hardware
-void Init();
-
-/// Shutdown hardware
-void Shutdown();
-
-} // namespace HW
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
deleted file mode 100644
index 0b62174d5..000000000
--- a/src/core/hw/lcd.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <cstring>
-#include "common/common_types.h"
-#include "common/logging/log.h"
-#include "core/hw/hw.h"
-#include "core/hw/lcd.h"
-#include "core/tracer/recorder.h"
-
-namespace LCD {
-
-Regs g_regs;
-
-template <typename T>
-inline void Read(T& var, const u32 raw_addr) {
- u32 addr = raw_addr - HW::VADDR_LCD;
- u32 index = addr / 4;
-
- // Reads other than u32 are untested, so I'd rather have them abort than silently fail
- if (index >= 0x400 || !std::is_same<T, u32>::value) {
- LOG_ERROR(HW_LCD, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr);
- return;
- }
-
- var = g_regs[index];
-}
-
-template <typename T>
-inline void Write(u32 addr, const T data) {
- addr -= HW::VADDR_LCD;
- u32 index = addr / 4;
-
- // Writes other than u32 are untested, so I'd rather have them abort than silently fail
- if (index >= 0x400 || !std::is_same<T, u32>::value) {
- LOG_ERROR(HW_LCD, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr);
- return;
- }
-
- g_regs[index] = static_cast<u32>(data);
-}
-
-// Explicitly instantiate template functions because we aren't defining this in the header:
-
-template void Read<u64>(u64& var, const u32 addr);
-template void Read<u32>(u32& var, const u32 addr);
-template void Read<u16>(u16& var, const u32 addr);
-template void Read<u8>(u8& var, const u32 addr);
-
-template void Write<u64>(u32 addr, const u64 data);
-template void Write<u32>(u32 addr, const u32 data);
-template void Write<u16>(u32 addr, const u16 data);
-template void Write<u8>(u32 addr, const u8 data);
-
-/// Initialize hardware
-void Init() {
- memset(&g_regs, 0, sizeof(g_regs));
- LOG_DEBUG(HW_LCD, "Initialized OK");
-}
-
-/// Shutdown hardware
-void Shutdown() {
- LOG_DEBUG(HW_LCD, "Shutdown OK");
-}
-
-} // namespace LCD
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
deleted file mode 100644
index d2db9700f..000000000
--- a/src/core/hw/lcd.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <cstddef>
-#include <type_traits>
-#include "common/bit_field.h"
-#include "common/common_funcs.h"
-#include "common/common_types.h"
-
-#define LCD_REG_INDEX(field_name) (offsetof(LCD::Regs, field_name) / sizeof(u32))
-
-namespace LCD {
-
-struct Regs {
-
- union ColorFill {
- u32 raw;
-
- BitField<0, 8, u32> color_r;
- BitField<8, 8, u32> color_g;
- BitField<16, 8, u32> color_b;
- BitField<24, 1, u32> is_enabled;
- };
-
- INSERT_PADDING_WORDS(0x81);
- ColorFill color_fill_top;
- INSERT_PADDING_WORDS(0xE);
- u32 backlight_top;
-
- INSERT_PADDING_WORDS(0x1F0);
-
- ColorFill color_fill_bottom;
- INSERT_PADDING_WORDS(0xE);
- u32 backlight_bottom;
- INSERT_PADDING_WORDS(0x16F);
-
- static constexpr size_t NumIds() {
- return sizeof(Regs) / sizeof(u32);
- }
-
- const u32& operator[](int index) const {
- const u32* content = reinterpret_cast<const u32*>(this);
- return content[index];
- }
-
- u32& operator[](int index) {
- u32* content = reinterpret_cast<u32*>(this);
- return content[index];
- }
-};
-static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
-
-// TODO: MSVC does not support using offsetof() on non-static data members even though this
-// is technically allowed since C++11. This macro should be enabled once MSVC adds
-// support for that.
-#ifndef _MSC_VER
-#define ASSERT_REG_POSITION(field_name, position) \
- static_assert(offsetof(Regs, field_name) == position * 4, \
- "Field " #field_name " has invalid position")
-
-ASSERT_REG_POSITION(color_fill_top, 0x81);
-ASSERT_REG_POSITION(backlight_top, 0x90);
-ASSERT_REG_POSITION(color_fill_bottom, 0x281);
-ASSERT_REG_POSITION(backlight_bottom, 0x290);
-
-#undef ASSERT_REG_POSITION
-#endif // !defined(_MSC_VER)
-
-extern Regs g_regs;
-
-template <typename T>
-void Read(T& var, const u32 addr);
-
-template <typename T>
-void Write(u32 addr, const T data);
-
-/// Initialize hardware
-void Init();
-
-/// Shutdown hardware
-void Shutdown();
-
-} // namespace LCD
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index b0277a875..d575a9bea 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -7,6 +7,7 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/file_sys/content_archive.h"
+#include "core/file_sys/control_metadata.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
@@ -17,8 +18,54 @@
namespace Loader {
-AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file)
- : AppLoader(std::move(file)) {}
+AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_)
+ : AppLoader(std::move(file_)) {
+ const auto dir = file->GetContainingDirectory();
+
+ // Icon
+ FileSys::VirtualFile icon_file = nullptr;
+ for (const auto& language : FileSys::LANGUAGE_NAMES) {
+ icon_file = dir->GetFile("icon_" + std::string(language) + ".dat");
+ if (icon_file != nullptr) {
+ icon_data = icon_file->ReadAllBytes();
+ break;
+ }
+ }
+
+ if (icon_data.empty()) {
+ // Any png, jpeg, or bmp file
+ const auto& files = dir->GetFiles();
+ const auto icon_iter =
+ std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
+ return file->GetExtension() == "png" || file->GetExtension() == "jpg" ||
+ file->GetExtension() == "bmp" || file->GetExtension() == "jpeg";
+ });
+ if (icon_iter != files.end())
+ icon_data = (*icon_iter)->ReadAllBytes();
+ }
+
+ // Metadata
+ FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp");
+ if (nacp_file == nullptr) {
+ const auto& files = dir->GetFiles();
+ const auto nacp_iter =
+ std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
+ return file->GetExtension() == "nacp";
+ });
+ if (nacp_iter != files.end())
+ nacp_file = *nacp_iter;
+ }
+
+ if (nacp_file != nullptr) {
+ FileSys::NACP nacp(nacp_file);
+ title_id = nacp.GetTitleId();
+ name = nacp.GetApplicationName();
+ }
+}
+
+AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
+ FileSys::VirtualDir directory)
+ : AppLoader(directory->GetFile("main")), dir(std::move(directory)) {}
FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& file) {
if (FileSys::IsDirectoryExeFS(file->GetContainingDirectory())) {
@@ -34,10 +81,15 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
return ResultStatus::ErrorAlreadyLoaded;
}
- const FileSys::VirtualDir dir = file->GetContainingDirectory();
+ if (dir == nullptr) {
+ if (file == nullptr)
+ return ResultStatus::ErrorNullFile;
+ dir = file->GetContainingDirectory();
+ }
+
const FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
if (npdm == nullptr)
- return ResultStatus::ErrorInvalidFormat;
+ return ResultStatus::ErrorMissingNPDM;
ResultStatus result = metadata.Load(npdm);
if (result != ResultStatus::Success) {
@@ -47,7 +99,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
- return ResultStatus::ErrorUnsupportedArch;
+ return ResultStatus::Error32BitISA;
}
// Load NSO modules
@@ -66,7 +118,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
process->program_id = metadata.GetTitleID();
process->svc_access_mask.set();
- process->address_mappings = default_address_mappings;
process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
@@ -91,9 +142,30 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) {
if (romfs == nullptr)
- return ResultStatus::ErrorNotUsed;
+ return ResultStatus::ErrorNoRomFS;
dir = romfs;
return ResultStatus::Success;
}
+ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) {
+ if (icon_data.empty())
+ return ResultStatus::ErrorNoIcon;
+ buffer = icon_data;
+ return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) {
+ if (name.empty())
+ return ResultStatus::ErrorNoControl;
+ out_program_id = title_id;
+ return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) {
+ if (name.empty())
+ return ResultStatus::ErrorNoControl;
+ title = name;
+ return ResultStatus::Success;
+}
+
} // namespace Loader
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index 982a037f7..b20804f75 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -7,7 +7,7 @@
#include <string>
#include "common/common_types.h"
#include "core/file_sys/program_metadata.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/loader/loader.h"
namespace Loader {
@@ -22,6 +22,9 @@ class AppLoader_DeconstructedRomDirectory final : public AppLoader {
public:
explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file);
+ // Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
+ explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory);
+
/**
* Returns the type of the file
* @param file std::shared_ptr<VfsFile> open file
@@ -36,10 +39,18 @@ public:
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
+ ResultStatus ReadIcon(std::vector<u8>& buffer) override;
+ ResultStatus ReadProgramId(u64& out_program_id) override;
+ ResultStatus ReadTitle(std::string& title) override;
private:
FileSys::ProgramMetadata metadata;
FileSys::VirtualFile romfs;
+ FileSys::VirtualDir dir;
+
+ std::vector<u8> icon_data;
+ std::string name;
+ u64 title_id{};
};
} // namespace Loader
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 352938dcb..6420a7f11 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -311,11 +311,11 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
CodeSet::Segment* codeset_segment;
u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
if (permission_flags == (PF_R | PF_X)) {
- codeset_segment = &codeset->code;
+ codeset_segment = &codeset->CodeSegment();
} else if (permission_flags == (PF_R)) {
- codeset_segment = &codeset->rodata;
+ codeset_segment = &codeset->RODataSegment();
} else if (permission_flags == (PF_R | PF_W)) {
- codeset_segment = &codeset->data;
+ codeset_segment = &codeset->DataSegment();
} else {
LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i,
p->p_flags);
@@ -390,7 +390,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
std::vector<u8> buffer = file->ReadAllBytes();
if (buffer.size() != file->GetSize())
- return ResultStatus::Error;
+ return ResultStatus::ErrorIncorrectELFFileSize;
ElfReader elf_reader(&buffer[0]);
SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
@@ -398,7 +398,6 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->LoadModule(codeset, codeset->entrypoint);
process->svc_access_mask.set();
- process->address_mappings = default_address_mappings;
// Attach the default resource limit (APPLICATION) to the process
process->resource_limit =
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index cbc4177c6..70ef5d240 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <memory>
+#include <ostream>
#include <string>
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -13,15 +14,10 @@
#include "core/loader/nca.h"
#include "core/loader/nro.h"
#include "core/loader/nso.h"
+#include "core/loader/xci.h"
namespace Loader {
-const std::initializer_list<Kernel::AddressMapping> default_address_mappings = {
- {0x1FF50000, 0x8000, true}, // part of DSP RAM
- {0x1FF70000, 0x8000, true}, // part of DSP RAM
- {0x1F000000, 0x600000, false}, // entire VRAM
-};
-
FileType IdentifyFile(FileSys::VirtualFile file) {
FileType type;
@@ -35,19 +31,18 @@ FileType IdentifyFile(FileSys::VirtualFile file) {
CHECK_TYPE(NSO)
CHECK_TYPE(NRO)
CHECK_TYPE(NCA)
+ CHECK_TYPE(XCI)
#undef CHECK_TYPE
return FileType::Unknown;
}
-FileType IdentifyFile(const std::string& file_name) {
- return IdentifyFile(std::make_shared<FileSys::RealVfsFile>(file_name));
-}
-
FileType GuessFromFilename(const std::string& name) {
if (name == "main")
return FileType::DeconstructedRomDirectory;
+ if (name == "00")
+ return FileType::NCA;
const std::string extension =
Common::ToLower(std::string(FileUtil::GetExtensionFromFilename(name)));
@@ -60,11 +55,13 @@ FileType GuessFromFilename(const std::string& name) {
return FileType::NSO;
if (extension == "nca")
return FileType::NCA;
+ if (extension == "xci")
+ return FileType::XCI;
return FileType::Unknown;
}
-const char* GetFileTypeString(FileType type) {
+std::string GetFileTypeString(FileType type) {
switch (type) {
case FileType::ELF:
return "ELF";
@@ -74,6 +71,8 @@ const char* GetFileTypeString(FileType type) {
return "NSO";
case FileType::NCA:
return "NCA";
+ case FileType::XCI:
+ return "XCI";
case FileType::DeconstructedRomDirectory:
return "Directory";
case FileType::Error:
@@ -84,6 +83,50 @@ const char* GetFileTypeString(FileType type) {
return "unknown";
}
+constexpr std::array<const char*, 36> RESULT_MESSAGES{
+ "The operation completed successfully.",
+ "The loader requested to load is already loaded.",
+ "The operation is not implemented.",
+ "The loader is not initialized properly.",
+ "The NPDM file has a bad header.",
+ "The NPDM has a bad ACID header.",
+ "The NPDM has a bad ACI header,",
+ "The NPDM file has a bad file access control.",
+ "The NPDM has a bad file access header.",
+ "The PFS/HFS partition has a bad header.",
+ "The PFS/HFS partition has incorrect size as determined by the header.",
+ "The NCA file has a bad header.",
+ "The general keyfile could not be found.",
+ "The NCA Header key could not be found.",
+ "The NCA Header key is incorrect or the header is invalid.",
+ "Support for NCA2-type NCAs is not implemented.",
+ "Support for NCA0-type NCAs is not implemented.",
+ "The titlekey for this Rights ID could not be found.",
+ "The titlekek for this crypto revision could not be found.",
+ "The Rights ID in the header is invalid.",
+ "The key area key for this application type and crypto revision could not be found.",
+ "The key area key is incorrect or the section header is invalid.",
+ "The titlekey and/or titlekek is incorrect or the section header is invalid.",
+ "The XCI file is missing a Program-type NCA.",
+ "The NCA file is not an application.",
+ "The ExeFS partition could not be found.",
+ "The XCI file has a bad header.",
+ "The XCI file is missing a partition.",
+ "The file could not be found or does not exist.",
+ "The game is missing a program metadata file (main.npdm).",
+ "The game uses the currently-unimplemented 32-bit architecture.",
+ "The RomFS could not be found.",
+ "The ELF file has incorrect size as determined by the header.",
+ "There was a general error loading the NRO into emulated memory.",
+ "There is no icon available.",
+ "There is no control data available.",
+};
+
+std::ostream& operator<<(std::ostream& os, ResultStatus status) {
+ os << RESULT_MESSAGES.at(static_cast<size_t>(status));
+ return os;
+}
+
/**
* Get a loader for a file with a specific type
* @param file The file to load
@@ -111,6 +154,9 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
case FileType::NCA:
return std::make_unique<AppLoader_NCA>(std::move(file));
+ case FileType::XCI:
+ return std::make_unique<AppLoader_XCI>(std::move(file));
+
// NX deconstructed ROM directory.
case FileType::DeconstructedRomDirectory:
return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file));
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index fbf11e5d0..b74cfbf8a 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -5,7 +5,7 @@
#pragma once
#include <algorithm>
-#include <initializer_list>
+#include <iosfwd>
#include <memory>
#include <string>
#include <utility>
@@ -14,7 +14,7 @@
#include "common/common_types.h"
#include "common/file_util.h"
#include "core/file_sys/vfs.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
namespace Kernel {
struct AddressMapping;
@@ -31,6 +31,7 @@ enum class FileType {
NSO,
NRO,
NCA,
+ XCI,
DeconstructedRomDirectory,
};
@@ -42,14 +43,6 @@ enum class FileType {
FileType IdentifyFile(FileSys::VirtualFile file);
/**
- * Identifies the type of a bootable file based on the magic value in its header.
- * @param file_name path to file
- * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine
- * a filetype, and will never return FileType::Error.
- */
-FileType IdentifyFile(const std::string& file_name);
-
-/**
* Guess the type of a bootable file from its name
* @param name String name of bootable file
* @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine
@@ -60,22 +53,50 @@ FileType GuessFromFilename(const std::string& name);
/**
* Convert a FileType into a string which can be displayed to the user.
*/
-const char* GetFileTypeString(FileType type);
+std::string GetFileTypeString(FileType type);
/// Return type for functions in Loader namespace
-enum class ResultStatus {
+enum class ResultStatus : u16 {
Success,
- Error,
- ErrorInvalidFormat,
- ErrorNotImplemented,
- ErrorNotLoaded,
- ErrorNotUsed,
ErrorAlreadyLoaded,
- ErrorMemoryAllocationFailed,
- ErrorEncrypted,
- ErrorUnsupportedArch,
+ ErrorNotImplemented,
+ ErrorNotInitialized,
+ ErrorBadNPDMHeader,
+ ErrorBadACIDHeader,
+ ErrorBadACIHeader,
+ ErrorBadFileAccessControl,
+ ErrorBadFileAccessHeader,
+ ErrorBadPFSHeader,
+ ErrorIncorrectPFSFileSize,
+ ErrorBadNCAHeader,
+ ErrorMissingProductionKeyFile,
+ ErrorMissingHeaderKey,
+ ErrorIncorrectHeaderKey,
+ ErrorNCA2,
+ ErrorNCA0,
+ ErrorMissingTitlekey,
+ ErrorMissingTitlekek,
+ ErrorInvalidRightsID,
+ ErrorMissingKeyAreaKey,
+ ErrorIncorrectKeyAreaKey,
+ ErrorIncorrectTitlekeyOrTitlekek,
+ ErrorXCIMissingProgramNCA,
+ ErrorNCANotProgram,
+ ErrorNoExeFS,
+ ErrorBadXCIHeader,
+ ErrorXCIMissingPartition,
+ ErrorNullFile,
+ ErrorMissingNPDM,
+ Error32BitISA,
+ ErrorNoRomFS,
+ ErrorIncorrectELFFileSize,
+ ErrorLoadingNRO,
+ ErrorNoIcon,
+ ErrorNoControl,
};
+std::ostream& operator<<(std::ostream& os, ResultStatus status);
+
/// Interface for loading an application
class AppLoader : NonCopyable {
public:
@@ -186,12 +207,6 @@ protected:
};
/**
- * Common address mappings found in most games, used for binary formats that don't have this
- * information.
- */
-extern const std::initializer_list<Kernel::AddressMapping> default_address_mappings;
-
-/**
* Identifies a bootable file and return a suitable loader
* @param file The bootable file
* @return the best loader for this file
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index c80df23be..9d50c7d42 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -3,34 +3,27 @@
// Refer to the license.txt file included.
#include <utility>
-#include <vector>
#include "common/file_util.h"
#include "common/logging/log.h"
-#include "common/string_util.h"
-#include "common/swap.h"
-#include "core/core.h"
#include "core/file_sys/content_archive.h"
-#include "core/file_sys/program_metadata.h"
-#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/nca.h"
-#include "core/loader/nso.h"
-#include "core/memory.h"
namespace Loader {
-AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file) : AppLoader(std::move(file)) {}
+AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file_)
+ : AppLoader(std::move(file_)), nca(std::make_unique<FileSys::NCA>(file)) {}
+
+AppLoader_NCA::~AppLoader_NCA() = default;
FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) {
- // TODO(DarkLordZach): Assuming everything is decrypted. Add crypto support.
- FileSys::NCAHeader header{};
- if (sizeof(FileSys::NCAHeader) != file->ReadObject(&header))
- return FileType::Error;
+ FileSys::NCA nca(file);
- if (IsValidNCA(header) && header.content_type == FileSys::NCAContentType::Program)
+ if (nca.GetStatus() == ResultStatus::Success &&
+ nca.GetType() == FileSys::NCAContentType::Program)
return FileType::NCA;
return FileType::Error;
@@ -41,53 +34,24 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
return ResultStatus::ErrorAlreadyLoaded;
}
- nca = std::make_unique<FileSys::NCA>(file);
- ResultStatus result = nca->GetStatus();
+ const auto result = nca->GetStatus();
if (result != ResultStatus::Success) {
return result;
}
if (nca->GetType() != FileSys::NCAContentType::Program)
- return ResultStatus::ErrorInvalidFormat;
+ return ResultStatus::ErrorNCANotProgram;
- auto exefs = nca->GetExeFS();
+ const auto exefs = nca->GetExeFS();
if (exefs == nullptr)
- return ResultStatus::ErrorInvalidFormat;
-
- result = metadata.Load(exefs->GetFile("main.npdm"));
- if (result != ResultStatus::Success) {
- return result;
- }
- metadata.Print();
+ return ResultStatus::ErrorNoExeFS;
- const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
- if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
- return ResultStatus::ErrorUnsupportedArch;
- }
-
- VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR};
- for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
- "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
- const VAddr load_addr = next_load_addr;
-
- next_load_addr = AppLoader_NSO::LoadModule(exefs->GetFile(module), load_addr);
- if (next_load_addr) {
- LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
- // Register module with GDBStub
- GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
- } else {
- next_load_addr = load_addr;
- }
- }
+ directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs);
- process->program_id = metadata.GetTitleID();
- process->svc_access_mask.set();
- process->address_mappings = default_address_mappings;
- process->resource_limit =
- Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
- metadata.GetMainThreadStackSize());
+ const auto load_result = directory_loader->Load(process);
+ if (load_result != ResultStatus::Success)
+ return load_result;
if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0)
Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
@@ -98,12 +62,19 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
}
ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
- if (nca == nullptr || nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0)
- return ResultStatus::ErrorNotUsed;
+ if (nca == nullptr)
+ return ResultStatus::ErrorNotInitialized;
+ if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0)
+ return ResultStatus::ErrorNoRomFS;
dir = nca->GetRomFS();
return ResultStatus::Success;
}
-AppLoader_NCA::~AppLoader_NCA() = default;
+ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
+ if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
+ return ResultStatus::ErrorNotInitialized;
+ out_program_id = nca->GetTitleId();
+ return ResultStatus::Success;
+}
} // namespace Loader
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index 52c95953a..326f84857 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -4,19 +4,24 @@
#pragma once
-#include <string>
#include "common/common_types.h"
-#include "core/file_sys/content_archive.h"
-#include "core/file_sys/program_metadata.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/file_sys/vfs.h"
+#include "core/hle/kernel/object.h"
#include "core/loader/loader.h"
+namespace FileSys {
+class NCA;
+}
+
namespace Loader {
+class AppLoader_DeconstructedRomDirectory;
+
/// Loads an NCA file
class AppLoader_NCA final : public AppLoader {
public:
explicit AppLoader_NCA(FileSys::VirtualFile file);
+ ~AppLoader_NCA() override;
/**
* Returns the type of the file
@@ -32,13 +37,11 @@ public:
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
-
- ~AppLoader_NCA();
+ ResultStatus ReadProgramId(u64& out_program_id) override;
private:
- FileSys::ProgramMetadata metadata;
-
std::unique_ptr<FileSys::NCA> nca;
+ std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;
};
} // namespace Loader
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 7d3ec2a76..2179cf2ea 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -159,7 +159,7 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
// Resize program image to include .bss section and page align each section
bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
}
- codeset->data.size += bss_size;
+ codeset->DataSegment().size += bss_size;
program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
// Load codeset for current process
@@ -182,11 +182,10 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
if (!LoadNro(file, base_addr)) {
- return ResultStatus::ErrorInvalidFormat;
+ return ResultStatus::ErrorLoadingNRO;
}
process->svc_access_mask.set();
- process->address_mappings = default_address_mappings;
process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
@@ -197,7 +196,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
if (icon_data.empty()) {
- return ResultStatus::ErrorNotUsed;
+ return ResultStatus::ErrorNoIcon;
}
buffer = icon_data;
@@ -206,7 +205,7 @@ ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) {
if (nacp == nullptr) {
- return ResultStatus::ErrorNotUsed;
+ return ResultStatus::ErrorNoControl;
}
out_program_id = nacp->GetTitleId();
@@ -215,7 +214,7 @@ ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) {
ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) {
if (romfs == nullptr) {
- return ResultStatus::ErrorNotUsed;
+ return ResultStatus::ErrorNoRomFS;
}
dir = romfs;
@@ -224,7 +223,7 @@ ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) {
ResultStatus AppLoader_NRO::ReadTitle(std::string& title) {
if (nacp == nullptr) {
- return ResultStatus::ErrorNotUsed;
+ return ResultStatus::ErrorNoControl;
}
title = nacp->GetApplicationName();
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 04a0f497e..bb01c9e25 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -6,7 +6,7 @@
#include <string>
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/loader/linker.h"
#include "core/loader/loader.h"
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 06b1b33f4..a94558ac5 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -127,7 +127,7 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
// Resize program image to include .bss section and page align each section
bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
}
- codeset->data.size += bss_size;
+ codeset->DataSegment().size += bss_size;
const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)};
program_image.resize(image_size);
@@ -152,7 +152,6 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR);
process->svc_access_mask.set();
- process->address_mappings = default_address_mappings;
process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 3f7567500..aaeb1f2a9 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -6,7 +6,7 @@
#include <string>
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
#include "core/loader/linker.h"
#include "core/loader/loader.h"
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
new file mode 100644
index 000000000..4c4979545
--- /dev/null
+++ b/src/core/loader/xci.cpp
@@ -0,0 +1,100 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <vector>
+
+#include "common/common_types.h"
+#include "core/file_sys/card_image.h"
+#include "core/file_sys/content_archive.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/romfs.h"
+#include "core/hle/kernel/process.h"
+#include "core/loader/nca.h"
+#include "core/loader/xci.h"
+
+namespace Loader {
+
+AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
+ : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)),
+ nca_loader(std::make_unique<AppLoader_NCA>(
+ xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {
+ if (xci->GetStatus() != ResultStatus::Success)
+ return;
+ const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control);
+ if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success)
+ return;
+ const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS());
+ if (romfs == nullptr)
+ return;
+ for (const auto& language : FileSys::LANGUAGE_NAMES) {
+ icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat");
+ if (icon_file != nullptr)
+ break;
+ }
+ const auto nacp_raw = romfs->GetFile("control.nacp");
+ if (nacp_raw == nullptr)
+ return;
+ nacp_file = std::make_shared<FileSys::NACP>(nacp_raw);
+}
+
+AppLoader_XCI::~AppLoader_XCI() = default;
+
+FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
+ FileSys::XCI xci(file);
+
+ if (xci.GetStatus() == ResultStatus::Success &&
+ xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr &&
+ AppLoader_NCA::IdentifyType(xci.GetNCAFileByType(FileSys::NCAContentType::Program)) ==
+ FileType::NCA) {
+ return FileType::XCI;
+ }
+
+ return FileType::Error;
+}
+
+ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) {
+ if (is_loaded) {
+ return ResultStatus::ErrorAlreadyLoaded;
+ }
+
+ if (xci->GetStatus() != ResultStatus::Success)
+ return xci->GetStatus();
+
+ if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) {
+ if (!Core::Crypto::KeyManager::KeyFileExists(false))
+ return ResultStatus::ErrorMissingProductionKeyFile;
+ return ResultStatus::ErrorXCIMissingProgramNCA;
+ }
+
+ auto result = nca_loader->Load(process);
+ if (result != ResultStatus::Success)
+ return result;
+
+ is_loaded = true;
+
+ return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& dir) {
+ return nca_loader->ReadRomFS(dir);
+}
+
+ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
+ return nca_loader->ReadProgramId(out_program_id);
+}
+
+ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
+ if (icon_file == nullptr)
+ return ResultStatus::ErrorNoControl;
+ buffer = icon_file->ReadAllBytes();
+ return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_XCI::ReadTitle(std::string& title) {
+ if (nacp_file == nullptr)
+ return ResultStatus::ErrorNoControl;
+ title = nacp_file->GetApplicationName();
+ return ResultStatus::Success;
+}
+} // namespace Loader
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
new file mode 100644
index 000000000..cc4287e17
--- /dev/null
+++ b/src/core/loader/xci.h
@@ -0,0 +1,53 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include "common/common_types.h"
+#include "core/file_sys/vfs.h"
+#include "core/loader/loader.h"
+
+namespace FileSys {
+class NACP;
+class XCI;
+} // namespace FileSys
+
+namespace Loader {
+
+class AppLoader_NCA;
+
+/// Loads an XCI file
+class AppLoader_XCI final : public AppLoader {
+public:
+ explicit AppLoader_XCI(FileSys::VirtualFile file);
+ ~AppLoader_XCI();
+
+ /**
+ * Returns the type of the file
+ * @param file std::shared_ptr<VfsFile> open file
+ * @return FileType found, or FileType::Error if this loader doesn't know it
+ */
+ static FileType IdentifyType(const FileSys::VirtualFile& file);
+
+ FileType GetFileType() override {
+ return IdentifyType(file);
+ }
+
+ ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
+
+ ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
+ ResultStatus ReadProgramId(u64& out_program_id) override;
+ ResultStatus ReadIcon(std::vector<u8>& buffer) override;
+ ResultStatus ReadTitle(std::string& title) override;
+
+private:
+ std::unique_ptr<FileSys::XCI> xci;
+ std::unique_ptr<AppLoader_NCA> nca_loader;
+
+ FileSys::VirtualFile icon_file;
+ std::shared_ptr<FileSys::NACP> nacp_file;
+};
+
+} // namespace Loader
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index e753e3436..1133bcbaf 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -14,7 +14,6 @@
#include "common/swap.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
-#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h"
#include "core/hle/lock.h"
#include "core/memory.h"
@@ -24,8 +23,6 @@
namespace Memory {
-static std::array<u8, Memory::VRAM_SIZE> vram;
-
static PageTable* current_page_table = nullptr;
void SetCurrentPageTable(PageTable* page_table) {
@@ -102,22 +99,6 @@ void RemoveDebugHook(PageTable& page_table, VAddr base, u64 size, MemoryHookPoin
}
/**
- * This function should only be called for virtual addreses with attribute `PageType::Special`.
- */
-static std::set<MemoryHookPointer> GetSpecialHandlers(const PageTable& page_table, VAddr vaddr,
- u64 size) {
- std::set<MemoryHookPointer> result;
- auto interval = boost::icl::discrete_interval<VAddr>::closed(vaddr, vaddr + size - 1);
- auto interval_list = page_table.special_regions.equal_range(interval);
- for (auto it = interval_list.first; it != interval_list.second; ++it) {
- for (const auto& region : it->second) {
- result.insert(region.handler);
- }
- }
- return result;
-}
-
-/**
* Gets a pointer to the exact memory at the virtual address (i.e. not page aligned)
* using a VMA from the current process
*/
@@ -242,10 +223,6 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
}
-bool IsValidPhysicalAddress(const PAddr paddr) {
- return GetPhysicalPointer(paddr) != nullptr;
-}
-
u8* GetPointer(const VAddr vaddr) {
u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
if (page_pointer) {
@@ -274,61 +251,6 @@ std::string ReadCString(VAddr vaddr, std::size_t max_length) {
return string;
}
-u8* GetPhysicalPointer(PAddr address) {
- struct MemoryArea {
- PAddr paddr_base;
- u32 size;
- };
-
- static constexpr MemoryArea memory_areas[] = {
- {VRAM_PADDR, VRAM_SIZE},
- {IO_AREA_PADDR, IO_AREA_SIZE},
- {DSP_RAM_PADDR, DSP_RAM_SIZE},
- {FCRAM_PADDR, FCRAM_N3DS_SIZE},
- };
-
- const auto area =
- std::find_if(std::begin(memory_areas), std::end(memory_areas), [&](const auto& area) {
- return address >= area.paddr_base && address < area.paddr_base + area.size;
- });
-
- if (area == std::end(memory_areas)) {
- LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ 0x{:016X}", address);
- return nullptr;
- }
-
- if (area->paddr_base == IO_AREA_PADDR) {
- LOG_ERROR(HW_Memory, "MMIO mappings are not supported yet. phys_addr={:016X}", address);
- return nullptr;
- }
-
- u64 offset_into_region = address - area->paddr_base;
-
- u8* target_pointer = nullptr;
- switch (area->paddr_base) {
- case VRAM_PADDR:
- target_pointer = vram.data() + offset_into_region;
- break;
- case DSP_RAM_PADDR:
- break;
- case FCRAM_PADDR:
- for (const auto& region : Kernel::memory_regions) {
- if (offset_into_region >= region.base &&
- offset_into_region < region.base + region.size) {
- target_pointer =
- region.linear_heap_memory->data() + offset_into_region - region.base;
- break;
- }
- }
- ASSERT_MSG(target_pointer != nullptr, "Invalid FCRAM address");
- break;
- default:
- UNREACHABLE();
- }
-
- return target_pointer;
-}
-
void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached) {
if (gpu_addr == 0) {
return;
@@ -404,43 +326,45 @@ void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached)
}
void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
+ auto& system_instance = Core::System::GetInstance();
+
// Since pages are unmapped on shutdown after video core is shutdown, the renderer may be
// null here
- if (VideoCore::g_renderer == nullptr) {
+ if (!system_instance.IsPoweredOn()) {
return;
}
VAddr end = start + size;
- auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
+ const auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
if (start >= region_end || end <= region_start) {
// No overlap with region
return;
}
- VAddr overlap_start = std::max(start, region_start);
- VAddr overlap_end = std::min(end, region_end);
+ const VAddr overlap_start = std::max(start, region_start);
+ const VAddr overlap_end = std::min(end, region_end);
- std::vector<Tegra::GPUVAddr> gpu_addresses =
- Core::System::GetInstance().GPU().memory_manager->CpuToGpuAddress(overlap_start);
+ const std::vector<Tegra::GPUVAddr> gpu_addresses =
+ system_instance.GPU().memory_manager->CpuToGpuAddress(overlap_start);
if (gpu_addresses.empty()) {
return;
}
- u64 overlap_size = overlap_end - overlap_start;
+ const u64 overlap_size = overlap_end - overlap_start;
for (const auto& gpu_address : gpu_addresses) {
- auto* rasterizer = VideoCore::g_renderer->Rasterizer();
+ auto& rasterizer = system_instance.Renderer().Rasterizer();
switch (mode) {
case FlushMode::Flush:
- rasterizer->FlushRegion(gpu_address, overlap_size);
+ rasterizer.FlushRegion(gpu_address, overlap_size);
break;
case FlushMode::Invalidate:
- rasterizer->InvalidateRegion(gpu_address, overlap_size);
+ rasterizer.InvalidateRegion(gpu_address, overlap_size);
break;
case FlushMode::FlushAndInvalidate:
- rasterizer->FlushAndInvalidateRegion(gpu_address, overlap_size);
+ rasterizer.FlushAndInvalidateRegion(gpu_address, overlap_size);
break;
}
}
@@ -666,48 +590,4 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size) {
CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size);
}
-boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) {
- if (addr == 0) {
- return 0;
- } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
- return addr - VRAM_VADDR + VRAM_PADDR;
- } else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
- return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR;
- } else if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
- return addr - NEW_LINEAR_HEAP_VADDR + FCRAM_PADDR;
- } else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) {
- return addr - DSP_RAM_VADDR + DSP_RAM_PADDR;
- } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) {
- return addr - IO_AREA_VADDR + IO_AREA_PADDR;
- }
-
- return boost::none;
-}
-
-PAddr VirtualToPhysicalAddress(const VAddr addr) {
- auto paddr = TryVirtualToPhysicalAddress(addr);
- if (!paddr) {
- LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x{:016X}", addr);
- // To help with debugging, set bit on address so that it's obviously invalid.
- return addr | 0x80000000;
- }
- return *paddr;
-}
-
-boost::optional<VAddr> PhysicalToVirtualAddress(const PAddr addr) {
- if (addr == 0) {
- return 0;
- } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
- return addr - VRAM_PADDR + VRAM_VADDR;
- } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
- return addr - FCRAM_PADDR + Core::CurrentProcess()->GetLinearHeapAreaAddress();
- } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
- return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
- } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
- return addr - IO_AREA_PADDR + IO_AREA_VADDR;
- }
-
- return boost::none;
-}
-
} // namespace Memory
diff --git a/src/core/memory.h b/src/core/memory.h
index 8d5d017a4..b7fb3b9ed 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -6,12 +6,9 @@
#include <array>
#include <cstddef>
-#include <map>
#include <string>
#include <tuple>
-#include <vector>
#include <boost/icl/interval_map.hpp>
-#include <boost/optional.hpp>
#include "common/common_types.h"
#include "core/memory_hook.h"
#include "video_core/memory_manager.h"
@@ -85,40 +82,6 @@ struct PageTable {
std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
};
-/// Physical memory regions as seen from the ARM11
-enum : PAddr {
- /// IO register area
- IO_AREA_PADDR = 0x10100000,
- IO_AREA_SIZE = 0x01000000, ///< IO area size (16MB)
- IO_AREA_PADDR_END = IO_AREA_PADDR + IO_AREA_SIZE,
-
- /// MPCore internal memory region
- MPCORE_RAM_PADDR = 0x17E00000,
- MPCORE_RAM_SIZE = 0x00002000, ///< MPCore internal memory size (8KB)
- MPCORE_RAM_PADDR_END = MPCORE_RAM_PADDR + MPCORE_RAM_SIZE,
-
- /// Video memory
- VRAM_PADDR = 0x18000000,
- VRAM_SIZE = 0x00600000, ///< VRAM size (6MB)
- VRAM_PADDR_END = VRAM_PADDR + VRAM_SIZE,
-
- /// DSP memory
- DSP_RAM_PADDR = 0x1FF00000,
- DSP_RAM_SIZE = 0x00080000, ///< DSP memory size (512KB)
- DSP_RAM_PADDR_END = DSP_RAM_PADDR + DSP_RAM_SIZE,
-
- /// AXI WRAM
- AXI_WRAM_PADDR = 0x1FF80000,
- AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size (512KB)
- AXI_WRAM_PADDR_END = AXI_WRAM_PADDR + AXI_WRAM_SIZE,
-
- /// Main FCRAM
- FCRAM_PADDR = 0x20000000,
- FCRAM_SIZE = 0x08000000, ///< FCRAM size on the Old 3DS (128MB)
- FCRAM_N3DS_SIZE = 0x10000000, ///< FCRAM size on the New 3DS (256MB)
- FCRAM_PADDR_END = FCRAM_PADDR + FCRAM_SIZE,
-};
-
/// Virtual user-space memory regions
enum : VAddr {
/// Where the application text, data and bss reside.
@@ -126,24 +89,6 @@ enum : VAddr {
PROCESS_IMAGE_MAX_SIZE = 0x08000000,
PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
- /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical
- /// memory.
- LINEAR_HEAP_VADDR = 0x14000000,
- LINEAR_HEAP_SIZE = 0x08000000,
- LINEAR_HEAP_VADDR_END = LINEAR_HEAP_VADDR + LINEAR_HEAP_SIZE,
-
- /// Maps 1:1 to the IO register area.
- IO_AREA_VADDR = 0x1EC00000,
- IO_AREA_VADDR_END = IO_AREA_VADDR + IO_AREA_SIZE,
-
- /// Maps 1:1 to VRAM.
- VRAM_VADDR = 0x1F000000,
- VRAM_VADDR_END = VRAM_VADDR + VRAM_SIZE,
-
- /// Maps 1:1 to DSP memory.
- DSP_RAM_VADDR = 0x1FF00000,
- DSP_RAM_VADDR_END = DSP_RAM_VADDR + DSP_RAM_SIZE,
-
/// Read-only page containing kernel and system configuration values.
CONFIG_MEMORY_VADDR = 0x1FF80000,
CONFIG_MEMORY_SIZE = 0x00001000,
@@ -154,13 +99,8 @@ enum : VAddr {
SHARED_PAGE_SIZE = 0x00001000,
SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
- /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
- NEW_LINEAR_HEAP_VADDR = 0x30000000,
- NEW_LINEAR_HEAP_SIZE = 0x10000000,
- NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
-
/// Area where TLS (Thread-Local Storage) buffers are allocated.
- TLS_AREA_VADDR = NEW_LINEAR_HEAP_VADDR_END,
+ TLS_AREA_VADDR = 0x40000000,
TLS_ENTRY_SIZE = 0x200,
TLS_AREA_SIZE = 0x10000000,
TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
@@ -200,12 +140,10 @@ void SetCurrentPageTable(PageTable* page_table);
PageTable* GetCurrentPageTable();
/// Determines if the given VAddr is valid for the specified process.
-bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr);
-bool IsValidVirtualAddress(const VAddr addr);
+bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
+bool IsValidVirtualAddress(VAddr vaddr);
/// Determines if the given VAddr is a kernel address
-bool IsKernelVirtualAddress(const VAddr addr);
-
-bool IsValidPhysicalAddress(const PAddr addr);
+bool IsKernelVirtualAddress(VAddr vaddr);
u8 Read8(VAddr addr);
u16 Read16(VAddr addr);
@@ -217,42 +155,17 @@ void Write16(VAddr addr, u16 data);
void Write32(VAddr addr, u32 data);
void Write64(VAddr addr, u64 data);
-void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
- size_t size);
-void ReadBlock(const VAddr src_addr, void* dest_buffer, size_t size);
-void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
+void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, size_t size);
+void ReadBlock(VAddr src_addr, void* dest_buffer, size_t size);
+void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
size_t size);
-void WriteBlock(const VAddr dest_addr, const void* src_buffer, size_t size);
-void ZeroBlock(const VAddr dest_addr, const size_t size);
+void WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size);
+void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, size_t size);
void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size);
-u8* GetPointer(VAddr virtual_address);
-
-std::string ReadCString(VAddr virtual_address, std::size_t max_length);
-
-/**
- * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical
- * address. This should be used by services to translate addresses for use by the hardware.
- */
-boost::optional<PAddr> TryVirtualToPhysicalAddress(VAddr addr);
-
-/**
- * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical
- * address. This should be used by services to translate addresses for use by the hardware.
- *
- * @deprecated Use TryVirtualToPhysicalAddress(), which reports failure.
- */
-PAddr VirtualToPhysicalAddress(VAddr addr);
+u8* GetPointer(VAddr vaddr);
-/**
- * Undoes a mapping performed by VirtualToPhysicalAddress().
- */
-boost::optional<VAddr> PhysicalToVirtualAddress(PAddr addr);
-
-/**
- * Gets a pointer to the memory region beginning at the specified physical address.
- */
-u8* GetPhysicalPointer(PAddr address);
+std::string ReadCString(VAddr vaddr, std::size_t max_length);
enum class FlushMode {
/// Write back modified surfaces to RAM
@@ -266,7 +179,7 @@ enum class FlushMode {
/**
* Mark each page touching the region as cached.
*/
-void RasterizerMarkRegionCached(Tegra::GPUVAddr start, u64 size, bool cached);
+void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached);
/**
* Flushes and invalidates any externally cached rasterizer resources touching the given virtual
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index 5f53b16d3..8e09b9b63 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -40,22 +40,21 @@ void PerfStats::EndGameFrame() {
game_frames += 1;
}
-PerfStats::Results PerfStats::GetAndResetStats(u64 current_system_time_us) {
+PerfStats::Results PerfStats::GetAndResetStats(microseconds current_system_time_us) {
std::lock_guard<std::mutex> lock(object_mutex);
- auto now = Clock::now();
+ const auto now = Clock::now();
// Walltime elapsed since stats were reset
- auto interval = duration_cast<DoubleSecs>(now - reset_point).count();
+ const auto interval = duration_cast<DoubleSecs>(now - reset_point).count();
- auto system_us_per_second =
- static_cast<double>(current_system_time_us - reset_point_system_us) / interval;
+ const auto system_us_per_second = (current_system_time_us - reset_point_system_us) / interval;
Results results{};
results.system_fps = static_cast<double>(system_frames) / interval;
results.game_fps = static_cast<double>(game_frames) / interval;
results.frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() /
static_cast<double>(system_frames);
- results.emulation_speed = system_us_per_second / 1'000'000.0;
+ results.emulation_speed = system_us_per_second.count() / 1'000'000.0;
// Reset counters
reset_point = now;
@@ -74,10 +73,10 @@ double PerfStats::GetLastFrameTimeScale() {
return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH;
}
-void FrameLimiter::DoFrameLimiting(u64 current_system_time_us) {
+void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) {
// Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher
// values increase the time needed to recover and limit framerate again after spikes.
- constexpr microseconds MAX_LAG_TIME_US = 25ms;
+ constexpr microseconds MAX_LAG_TIME_US = 25us;
if (!Settings::values.toggle_framelimit) {
return;
@@ -85,7 +84,7 @@ void FrameLimiter::DoFrameLimiting(u64 current_system_time_us) {
auto now = Clock::now();
- frame_limiting_delta_err += microseconds(current_system_time_us - previous_system_time_us);
+ frame_limiting_delta_err += current_system_time_us - previous_system_time_us;
frame_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime);
frame_limiting_delta_err =
std::clamp(frame_limiting_delta_err, -MAX_LAG_TIME_US, MAX_LAG_TIME_US);
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h
index 362b205c8..6e4619701 100644
--- a/src/core/perf_stats.h
+++ b/src/core/perf_stats.h
@@ -33,7 +33,7 @@ public:
void EndSystemFrame();
void EndGameFrame();
- Results GetAndResetStats(u64 current_system_time_us);
+ Results GetAndResetStats(std::chrono::microseconds current_system_time_us);
/**
* Gets the ratio between walltime and the emulated time of the previous system frame. This is
@@ -47,7 +47,7 @@ private:
/// Point when the cumulative counters were reset
Clock::time_point reset_point = Clock::now();
/// System time when the cumulative counters were reset
- u64 reset_point_system_us = 0;
+ std::chrono::microseconds reset_point_system_us{0};
/// Cumulative duration (excluding v-sync/frame-limiting) of frames since last reset
Clock::duration accumulated_frametime = Clock::duration::zero();
@@ -68,11 +68,11 @@ class FrameLimiter {
public:
using Clock = std::chrono::high_resolution_clock;
- void DoFrameLimiting(u64 current_system_time_us);
+ void DoFrameLimiting(std::chrono::microseconds current_system_time_us);
private:
/// Emulated system time (in microseconds) at the last limiter invocation
- u64 previous_system_time_us = 0;
+ std::chrono::microseconds previous_system_time_us{0};
/// Walltime at the last limiter invocation
Clock::time_point previous_walltime = Clock::now();
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 444bcc387..0da159559 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -2,27 +2,23 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/core.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/service/hid/hid.h"
#include "core/settings.h"
-#include "video_core/video_core.h"
-
-#include "core/frontend/emu_window.h"
+#include "video_core/renderer_base.h"
namespace Settings {
Values values = {};
void Apply() {
-
GDBStub::SetServerPort(values.gdbstub_port);
GDBStub::ToggleServer(values.use_gdbstub);
- VideoCore::g_toggle_framelimit_enabled = values.toggle_framelimit;
-
- if (VideoCore::g_emu_window) {
- auto layout = VideoCore::g_emu_window->GetFramebufferLayout();
- VideoCore::g_emu_window->UpdateCurrentFramebufferLayout(layout.width, layout.height);
+ auto& system_instance = Core::System::GetInstance();
+ if (system_instance.IsPoweredOn()) {
+ system_instance.Renderer().RefreshBaseSettings();
}
Service::HID::ReloadInputDevices();
diff --git a/src/core/settings.h b/src/core/settings.h
index 7150d9755..73dc3061f 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -112,6 +112,8 @@ static const std::array<const char*, NumAnalogs> mapping = {{
struct Values {
// System
bool use_docked_mode;
+ std::string username;
+ int language_index;
// Controls
std::array<std::string, NativeButton::NumButtons> buttons;
@@ -137,6 +139,13 @@ struct Values {
std::string log_filter;
+ bool use_dev_keys;
+
+ // Audio
+ std::string sink_id;
+ std::string audio_device_id;
+ float volume;
+
// Debugging
bool use_gdbstub;
u16 gdbstub_port;
diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp
index 0f0d10f23..525fe6abc 100644
--- a/src/input_common/keyboard.cpp
+++ b/src/input_common/keyboard.cpp
@@ -5,6 +5,7 @@
#include <atomic>
#include <list>
#include <mutex>
+#include <utility>
#include "input_common/keyboard.h"
namespace InputCommon {
@@ -12,9 +13,9 @@ namespace InputCommon {
class KeyButton final : public Input::ButtonDevice {
public:
explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_)
- : key_button_list(key_button_list_) {}
+ : key_button_list(std::move(key_button_list_)) {}
- ~KeyButton();
+ ~KeyButton() override;
bool GetStatus() const override {
return status.load();
diff --git a/src/input_common/motion_emu.cpp b/src/input_common/motion_emu.cpp
index caffe48cb..9570c060e 100644
--- a/src/input_common/motion_emu.cpp
+++ b/src/input_common/motion_emu.cpp
@@ -131,7 +131,7 @@ public:
device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity);
}
- std::tuple<Math::Vec3<float>, Math::Vec3<float>> GetStatus() const {
+ std::tuple<Math::Vec3<float>, Math::Vec3<float>> GetStatus() const override {
return device->GetStatus();
}
diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp
index 8d117c2d4..d1b960fd7 100644
--- a/src/input_common/sdl/sdl.cpp
+++ b/src/input_common/sdl/sdl.cpp
@@ -82,7 +82,7 @@ private:
class SDLButton final : public Input::ButtonDevice {
public:
explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_)
- : joystick(joystick_), button(button_) {}
+ : joystick(std::move(joystick_)), button(button_) {}
bool GetStatus() const override {
return joystick->GetButton(button);
@@ -96,7 +96,7 @@ private:
class SDLDirectionButton final : public Input::ButtonDevice {
public:
explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
- : joystick(joystick_), hat(hat_), direction(direction_) {}
+ : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
bool GetStatus() const override {
return joystick->GetHatDirection(hat, direction);
@@ -112,7 +112,7 @@ class SDLAxisButton final : public Input::ButtonDevice {
public:
explicit SDLAxisButton(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
bool trigger_if_greater_)
- : joystick(joystick_), axis(axis_), threshold(threshold_),
+ : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
trigger_if_greater(trigger_if_greater_) {}
bool GetStatus() const override {
@@ -132,7 +132,7 @@ private:
class SDLAnalog final : public Input::AnalogDevice {
public:
SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_)
- : joystick(joystick_), axis_x(axis_x_), axis_y(axis_y_) {}
+ : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_) {}
std::tuple<float, float> GetStatus() const override {
return joystick->GetAnalog(axis_x, axis_y);
@@ -314,10 +314,6 @@ namespace Polling {
class SDLPoller : public InputCommon::Polling::DevicePoller {
public:
- SDLPoller() = default;
-
- ~SDLPoller() = default;
-
void Start() override {
// SDL joysticks must be opened, otherwise they don't generate events
SDL_JoystickUpdate();
@@ -341,10 +337,6 @@ private:
class SDLButtonPoller final : public SDLPoller {
public:
- SDLButtonPoller() = default;
-
- ~SDLButtonPoller() = default;
-
Common::ParamPackage GetNextInput() override {
SDL_Event event;
while (SDL_PollEvent(&event)) {
@@ -364,10 +356,6 @@ public:
class SDLAnalogPoller final : public SDLPoller {
public:
- SDLAnalogPoller() = default;
-
- ~SDLAnalogPoller() = default;
-
void Start() override {
SDLPoller::Start();
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 6a0a62ecc..4d74bb395 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -3,7 +3,6 @@ add_executable(tests
core/arm/arm_test_common.cpp
core/arm/arm_test_common.h
core/core_timing.cpp
- core/memory/memory.cpp
glad.cpp
tests.cpp
)
diff --git a/src/tests/common/param_package.cpp b/src/tests/common/param_package.cpp
index 19d372236..4c0f9654f 100644
--- a/src/tests/common/param_package.cpp
+++ b/src/tests/common/param_package.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <catch.hpp>
+#include <catch2/catch.hpp>
#include <math.h>
#include "common/param_package.h"
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
index fcaa30990..2242c14cf 100644
--- a/src/tests/core/core_timing.cpp
+++ b/src/tests/core/core_timing.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
-#include <catch.hpp>
+#include <catch2/catch.hpp>
#include <array>
#include <bitset>
diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp
deleted file mode 100644
index 165496a54..000000000
--- a/src/tests/core/memory/memory.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2017 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <catch.hpp>
-#include "core/hle/kernel/memory.h"
-#include "core/hle/kernel/process.h"
-#include "core/memory.h"
-
-TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory][!hide]") {
- SECTION("these regions should not be mapped on an empty process") {
- auto process = Kernel::Process::Create("");
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false);
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false);
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == false);
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == false);
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::TLS_AREA_VADDR) == false);
- }
-
- SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") {
- auto process = Kernel::Process::Create("");
- Kernel::MapSharedPages(process->vm_manager);
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true);
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true);
- }
-
- SECTION("special regions should be valid after mapping them") {
- auto process = Kernel::Process::Create("");
- SECTION("VRAM") {
- Kernel::HandleSpecialMapping(process->vm_manager,
- {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false});
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == true);
- }
-
- SECTION("IO (Not yet implemented)") {
- Kernel::HandleSpecialMapping(
- process->vm_manager, {Memory::IO_AREA_VADDR, Memory::IO_AREA_SIZE, false, false});
- CHECK_FALSE(Memory::IsValidVirtualAddress(*process, Memory::IO_AREA_VADDR) == true);
- }
-
- SECTION("DSP") {
- Kernel::HandleSpecialMapping(
- process->vm_manager, {Memory::DSP_RAM_VADDR, Memory::DSP_RAM_SIZE, false, false});
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::DSP_RAM_VADDR) == true);
- }
- }
-
- SECTION("Unmapping a VAddr should make it invalid") {
- auto process = Kernel::Process::Create("");
- Kernel::MapSharedPages(process->vm_manager);
- process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE);
- CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
- }
-}
diff --git a/src/tests/glad.cpp b/src/tests/glad.cpp
index b0b016440..1797c0e3d 100644
--- a/src/tests/glad.cpp
+++ b/src/tests/glad.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <catch.hpp>
+#include <catch2/catch.hpp>
#include <glad/glad.h>
// This is not an actual test, but a work-around for issue #2183.
diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp
index 73978676f..275b430d9 100644
--- a/src/tests/tests.cpp
+++ b/src/tests/tests.cpp
@@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#define CATCH_CONFIG_MAIN
-#include <catch.hpp>
+#include <catch2/catch.hpp>
// Catch provides the main function since we've given it the
// CATCH_CONFIG_MAIN preprocessor directive.
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 31ea3adad..dc485e811 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -29,10 +29,10 @@ enum class BufferMethods {
};
void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) {
- LOG_WARNING(HW_GPU,
- "Processing method {:08X} on subchannel {} value "
- "{:08X} remaining params {}",
- method, subchannel, value, remaining_params);
+ LOG_TRACE(HW_GPU,
+ "Processing method {:08X} on subchannel {} value "
+ "{:08X} remaining params {}",
+ method, subchannel, value, remaining_params);
if (method == static_cast<u32>(BufferMethods::BindObject)) {
// Bind the current subchannel to the desired engine id.
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h
index f7214ffec..a01153e0b 100644
--- a/src/video_core/command_processor.h
+++ b/src/video_core/command_processor.h
@@ -30,8 +30,7 @@ union CommandHeader {
BitField<29, 3, SubmissionMode> mode;
};
-static_assert(std::is_standard_layout<CommandHeader>::value == true,
- "CommandHeader does not use standard layout");
+static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout");
static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 0e205ed72..68f91cc75 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -19,16 +19,21 @@ namespace Engines {
/// First register id that is actually a Macro call.
constexpr u32 MacroRegistersStart = 0xE00;
-Maxwell3D::Maxwell3D(MemoryManager& memory_manager)
- : memory_manager(memory_manager), macro_interpreter(*this) {}
+Maxwell3D::Maxwell3D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
+ : memory_manager(memory_manager), rasterizer{rasterizer}, macro_interpreter(*this) {}
void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
- auto macro_code = uploaded_macros.find(method);
+ // Reset the current macro.
+ executing_macro = 0;
+
// The requested macro must have been uploaded already.
- ASSERT_MSG(macro_code != uploaded_macros.end(), "Macro %08X was not uploaded", method);
+ auto macro_code = uploaded_macros.find(method);
+ if (macro_code == uploaded_macros.end()) {
+ LOG_ERROR(HW_GPU, "Macro {:04X} was not uploaded", method);
+ return;
+ }
- // Reset the current macro and execute it.
- executing_macro = 0;
+ // Execute the current macro.
macro_interpreter.Execute(macro_code->second, std::move(parameters));
}
@@ -130,7 +135,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
break;
}
- VideoCore::g_renderer->Rasterizer()->NotifyMaxwellRegisterChanged(method);
+ rasterizer.NotifyMaxwellRegisterChanged(method);
if (debug_context) {
debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr);
@@ -217,8 +222,20 @@ void Maxwell3D::DrawArrays() {
debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
}
+ // Both instance configuration registers can not be set at the same time.
+ ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
+ "Illegal combination of instancing parameters");
+
+ if (regs.draw.instance_next) {
+ // Increment the current instance *before* drawing.
+ state.current_instance += 1;
+ } else if (!regs.draw.instance_cont) {
+ // Reset the current instance to 0.
+ state.current_instance = 0;
+ }
+
const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
- VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(is_indexed);
+ rasterizer.AccelerateDrawBatch(is_indexed);
// TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
// the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
@@ -238,6 +255,8 @@ void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {
auto& buffer = shader.const_buffers[bind_data.index];
+ ASSERT(bind_data.index < Regs::MaxConstBuffers);
+
buffer.enabled = bind_data.valid.Value() != 0;
buffer.index = bind_data.index;
buffer.address = regs.const_buffer.BufferAddress();
@@ -285,8 +304,6 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
// TODO(Subv): Different data types for separate components are not supported
ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);
- // TODO(Subv): Only UNORM formats are supported for now.
- ASSERT(r_type == Texture::ComponentType::UNORM);
return tic_entry;
}
@@ -393,7 +410,7 @@ void Maxwell3D::ProcessClearBuffers() {
regs.clear_buffers.R == regs.clear_buffers.B &&
regs.clear_buffers.R == regs.clear_buffers.A);
- VideoCore::g_renderer->Rasterizer()->Clear();
+ rasterizer.Clear();
}
} // namespace Engines
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 3c32f1067..771eb5abc 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -17,6 +17,10 @@
#include "video_core/memory_manager.h"
#include "video_core/textures/texture.h"
+namespace VideoCore {
+class RasterizerInterface;
+}
+
namespace Tegra::Engines {
#define MAXWELL3D_REG_INDEX(field_name) \
@@ -24,7 +28,7 @@ namespace Tegra::Engines {
class Maxwell3D final {
public:
- explicit Maxwell3D(MemoryManager& memory_manager);
+ explicit Maxwell3D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager);
~Maxwell3D() = default;
/// Register structure of the Maxwell3D engine.
@@ -40,7 +44,7 @@ public:
static constexpr size_t MaxShaderProgram = 6;
static constexpr size_t MaxShaderStage = 5;
// Maximum number of const buffers per shader stage.
- static constexpr size_t MaxConstBuffers = 16;
+ static constexpr size_t MaxConstBuffers = 18;
enum class QueryMode : u32 {
Write = 0,
@@ -89,6 +93,7 @@ public:
struct VertexAttribute {
enum class Size : u32 {
+ Invalid = 0x0,
Size_32_32_32_32 = 0x01,
Size_32_32_32 = 0x02,
Size_16_16_16_16 = 0x03,
@@ -253,6 +258,10 @@ public:
bool IsNormalized() const {
return (type == Type::SignedNorm) || (type == Type::UnsignedNorm);
}
+
+ bool IsValid() const {
+ return size != Size::Invalid;
+ }
};
enum class PrimitiveTopology : u32 {
@@ -348,6 +357,27 @@ public:
OneMinusConstantColor = 0x62,
ConstantAlpha = 0x63,
OneMinusConstantAlpha = 0x64,
+
+ // These values are used by Nouveau and some games.
+ ZeroGL = 0x4000,
+ OneGL = 0x4001,
+ SourceColorGL = 0x4300,
+ OneMinusSourceColorGL = 0x4301,
+ SourceAlphaGL = 0x4302,
+ OneMinusSourceAlphaGL = 0x4303,
+ DestAlphaGL = 0x4304,
+ OneMinusDestAlphaGL = 0x4305,
+ DestColorGL = 0x4306,
+ OneMinusDestColorGL = 0x4307,
+ SourceAlphaSaturateGL = 0x4308,
+ ConstantColorGL = 0xc001,
+ OneMinusConstantColorGL = 0xc002,
+ ConstantAlphaGL = 0xc003,
+ OneMinusConstantAlphaGL = 0xc004,
+ Source1ColorGL = 0xc900,
+ OneMinusSource1ColorGL = 0xc901,
+ Source1AlphaGL = 0xc902,
+ OneMinusSource1AlphaGL = 0xc903,
};
u32 separate_alpha;
@@ -608,6 +638,8 @@ public:
union {
u32 vertex_begin_gl;
BitField<0, 16, PrimitiveTopology> topology;
+ BitField<26, 1, u32> instance_next;
+ BitField<27, 1, u32> instance_cont;
};
} draw;
@@ -800,6 +832,7 @@ public:
};
std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages;
+ u32 current_instance = 0; ///< Current instance to be used to simulate instanced rendering.
};
State state{};
@@ -818,6 +851,8 @@ public:
Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, size_t offset) const;
private:
+ VideoCore::RasterizerInterface& rasterizer;
+
std::unordered_map<u32, std::vector<u32>> uploaded_macros;
/// Macro method that is currently being executed / being fed parameters.
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index c7e3fb4b1..b038a9d92 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -74,6 +74,7 @@ union Attribute {
enum class Index : u64 {
Position = 7,
Attribute_0 = 8,
+ Attribute_31 = 39,
// This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex
// shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval
// shader.
@@ -140,6 +141,7 @@ enum class PredCondition : u64 {
NotEqual = 5,
GreaterEqual = 6,
LessThanWithNan = 9,
+ GreaterThanWithNan = 12,
NotEqualWithNan = 13,
// TODO(Subv): Other condition types
};
@@ -199,6 +201,14 @@ enum class IMinMaxExchange : u64 {
XHi = 3,
};
+enum class XmadMode : u64 {
+ None = 0,
+ CLo = 1,
+ CHi = 2,
+ CSfu = 3,
+ CBcc = 4,
+};
+
enum class FlowCondition : u64 {
Always = 0xF,
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
@@ -254,20 +264,15 @@ union Instruction {
BitField<56, 1, u64> invert_b;
} lop32i;
- float GetImm20_19() const {
- float result{};
+ u32 GetImm20_19() const {
u32 imm{static_cast<u32>(imm20_19)};
imm <<= 12;
imm |= negate_imm ? 0x80000000 : 0;
- std::memcpy(&result, &imm, sizeof(imm));
- return result;
+ return imm;
}
- float GetImm20_32() const {
- float result{};
- s32 imm{static_cast<s32>(imm20_32)};
- std::memcpy(&result, &imm, sizeof(imm));
- return result;
+ u32 GetImm20_32() const {
+ return static_cast<u32>(imm20_32);
}
s32 GetSignedImm20_20() const {
@@ -461,6 +466,18 @@ union Instruction {
} bra;
union {
+ BitField<20, 16, u64> imm20_16;
+ BitField<36, 1, u64> product_shift_left;
+ BitField<37, 1, u64> merge_37;
+ BitField<48, 1, u64> sign_a;
+ BitField<49, 1, u64> sign_b;
+ BitField<50, 3, XmadMode> mode;
+ BitField<52, 1, u64> high_b;
+ BitField<53, 1, u64> high_a;
+ BitField<56, 1, u64> merge_56;
+ } xmad;
+
+ union {
BitField<20, 14, u64> offset;
BitField<34, 5, u64> index;
} cbuf34;
@@ -480,8 +497,7 @@ union Instruction {
u64 value;
};
static_assert(sizeof(Instruction) == 0x8, "Incorrect structure size");
-static_assert(std::is_standard_layout<Instruction>::value,
- "Structure does not have standard layout");
+static_assert(std::is_standard_layout_v<Instruction>, "Instruction is not standard layout");
class OpCode {
public:
@@ -598,9 +614,17 @@ public:
IntegerSetPredicate,
PredicateSetPredicate,
Conversion,
+ Xmad,
Unknown,
};
+ /// Returns whether an opcode has an execution predicate field or not (ie, whether it can be
+ /// conditionally executed).
+ static bool IsPredicatedInstruction(Id opcode) {
+ // TODO(Subv): Add the rest of unpredicated instructions.
+ return opcode != Id::SSY;
+ }
+
class Matcher {
public:
Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type)
@@ -780,10 +804,10 @@ private:
INST("010010110101----", Id::ISET_C, Type::IntegerSet, "ISET_C"),
INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),
INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
- INST("0011011-00------", Id::XMAD_IMM, Type::Arithmetic, "XMAD_IMM"),
- INST("0100111---------", Id::XMAD_CR, Type::Arithmetic, "XMAD_CR"),
- INST("010100010-------", Id::XMAD_RC, Type::Arithmetic, "XMAD_RC"),
- INST("0101101100------", Id::XMAD_RR, Type::Arithmetic, "XMAD_RR"),
+ INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
+ INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
+ INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),
+ INST("0101101100------", Id::XMAD_RR, Type::Xmad, "XMAD_RR"),
};
#undef INST
std::stable_sort(table.begin(), table.end(), [](const auto& a, const auto& b) {
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 60c49d672..5a593c1f7 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -2,17 +2,28 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/assert.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/maxwell_compute.h"
#include "video_core/engines/maxwell_dma.h"
#include "video_core/gpu.h"
+#include "video_core/rasterizer_interface.h"
namespace Tegra {
-GPU::GPU() {
+u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
+ switch (format) {
+ case PixelFormat::ABGR8:
+ return 4;
+ }
+
+ UNREACHABLE();
+}
+
+GPU::GPU(VideoCore::RasterizerInterface& rasterizer) {
memory_manager = std::make_unique<MemoryManager>();
- maxwell_3d = std::make_unique<Engines::Maxwell3D>(*memory_manager);
+ maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager);
fermi_2d = std::make_unique<Engines::Fermi2D>(*memory_manager);
maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
maxwell_dma = std::make_unique<Engines::MaxwellDMA>(*memory_manager);
@@ -33,17 +44,59 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
switch (format) {
case RenderTargetFormat::RGBA32_FLOAT:
+ case RenderTargetFormat::RGBA32_UINT:
return 16;
+ case RenderTargetFormat::RGBA16_UINT:
+ case RenderTargetFormat::RGBA16_UNORM:
case RenderTargetFormat::RGBA16_FLOAT:
case RenderTargetFormat::RG32_FLOAT:
+ case RenderTargetFormat::RG32_UINT:
return 8;
case RenderTargetFormat::RGBA8_UNORM:
+ case RenderTargetFormat::RGBA8_SNORM:
+ case RenderTargetFormat::RGBA8_SRGB:
case RenderTargetFormat::RGB10_A2_UNORM:
case RenderTargetFormat::BGRA8_UNORM:
+ case RenderTargetFormat::RG16_UNORM:
+ case RenderTargetFormat::RG16_SNORM:
+ case RenderTargetFormat::RG16_UINT:
+ case RenderTargetFormat::RG16_SINT:
+ case RenderTargetFormat::RG16_FLOAT:
+ case RenderTargetFormat::R32_FLOAT:
+ case RenderTargetFormat::R11G11B10_FLOAT:
+ case RenderTargetFormat::R32_UINT:
return 4;
+ case RenderTargetFormat::R16_UNORM:
+ case RenderTargetFormat::R16_SNORM:
+ case RenderTargetFormat::R16_UINT:
+ case RenderTargetFormat::R16_SINT:
+ case RenderTargetFormat::R16_FLOAT:
+ case RenderTargetFormat::RG8_UNORM:
+ case RenderTargetFormat::RG8_SNORM:
+ return 2;
+ case RenderTargetFormat::R8_UNORM:
+ case RenderTargetFormat::R8_UINT:
+ return 1;
default:
UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format));
}
}
+u32 DepthFormatBytesPerPixel(DepthFormat format) {
+ switch (format) {
+ case DepthFormat::Z32_S8_X24_FLOAT:
+ return 8;
+ case DepthFormat::Z32_FLOAT:
+ case DepthFormat::S8_Z24_UNORM:
+ case DepthFormat::Z24_X8_UNORM:
+ case DepthFormat::Z24_S8_UNORM:
+ case DepthFormat::Z24_C8_UNORM:
+ return 4;
+ case DepthFormat::Z16_UNORM:
+ return 2;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented Depth format {}", static_cast<u32>(format));
+ }
+}
+
} // namespace Tegra
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index de276c559..97dcccb92 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -6,30 +6,48 @@
#include <memory>
#include <unordered_map>
-#include <vector>
#include "common/common_types.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
#include "video_core/memory_manager.h"
+namespace VideoCore {
+class RasterizerInterface;
+}
+
namespace Tegra {
enum class RenderTargetFormat : u32 {
NONE = 0x0,
RGBA32_FLOAT = 0xC0,
RGBA32_UINT = 0xC2,
+ RGBA16_UNORM = 0xC6,
+ RGBA16_UINT = 0xC9,
RGBA16_FLOAT = 0xCA,
RG32_FLOAT = 0xCB,
+ RG32_UINT = 0xCD,
BGRA8_UNORM = 0xCF,
RGB10_A2_UNORM = 0xD1,
RGBA8_UNORM = 0xD5,
RGBA8_SRGB = 0xD6,
+ RGBA8_SNORM = 0xD7,
RG16_UNORM = 0xDA,
RG16_SNORM = 0xDB,
RG16_SINT = 0xDC,
RG16_UINT = 0xDD,
RG16_FLOAT = 0xDE,
R11G11B10_FLOAT = 0xE0,
+ R32_UINT = 0xE4,
+ R32_FLOAT = 0xE5,
+ B5G6R5_UNORM = 0xE8,
+ RG8_UNORM = 0xEA,
+ RG8_SNORM = 0xEB,
+ R16_UNORM = 0xEE,
+ R16_SNORM = 0xEF,
+ R16_SINT = 0xF0,
+ R16_UINT = 0xF1,
+ R16_FLOAT = 0xF2,
R8_UNORM = 0xF3,
+ R8_UINT = 0xF6,
};
enum class DepthFormat : u32 {
@@ -45,6 +63,9 @@ enum class DepthFormat : u32 {
/// Returns the number of bytes per pixel of each rendertarget format.
u32 RenderTargetBytesPerPixel(RenderTargetFormat format);
+/// Returns the number of bytes per pixel of each depth format.
+u32 DepthFormatBytesPerPixel(DepthFormat format);
+
class DebugContext;
/**
@@ -58,14 +79,7 @@ struct FramebufferConfig {
/**
* Returns the number of bytes per pixel.
*/
- static u32 BytesPerPixel(PixelFormat format) {
- switch (format) {
- case PixelFormat::ABGR8:
- return 4;
- }
-
- UNREACHABLE();
- }
+ static u32 BytesPerPixel(PixelFormat format);
VAddr address;
u32 offset;
@@ -96,7 +110,7 @@ enum class EngineID {
class GPU final {
public:
- GPU();
+ explicit GPU(VideoCore::RasterizerInterface& rasterizer);
~GPU();
/// Processes a command list stored at the specified address in GPU memory.
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index 44ece01c1..377bd66ab 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -102,11 +102,11 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
if (taken) {
// Ignore the delay slot if the branch has the annul bit.
if (opcode.branch_annul) {
- pc = base_address + (opcode.immediate << 2);
+ pc = base_address + opcode.GetBranchTarget();
return true;
}
- delayed_pc = base_address + (opcode.immediate << 2);
+ delayed_pc = base_address + opcode.GetBranchTarget();
// Execute one more instruction due to the delay slot.
return Step(code, true);
}
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h
index a71e359d8..7d836b816 100644
--- a/src/video_core/macro_interpreter.h
+++ b/src/video_core/macro_interpreter.h
@@ -91,6 +91,10 @@ private:
u32 GetBitfieldMask() const {
return (1 << bf_size) - 1;
}
+
+ s32 GetBranchTarget() const {
+ return static_cast<s32>(immediate * sizeof(u32));
+ }
};
union MethodAddress {
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 2f814a184..ca923d17d 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -13,8 +13,10 @@ GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
ASSERT(gpu_addr);
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
- ASSERT(PageSlot(*gpu_addr + offset) == static_cast<u64>(PageStatus::Unmapped));
- PageSlot(*gpu_addr + offset) = static_cast<u64>(PageStatus::Allocated);
+ VAddr& slot = PageSlot(*gpu_addr + offset);
+
+ ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
+ slot = static_cast<u64>(PageStatus::Allocated);
}
return *gpu_addr;
@@ -22,8 +24,10 @@ GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
- ASSERT(PageSlot(gpu_addr + offset) == static_cast<u64>(PageStatus::Unmapped));
- PageSlot(gpu_addr + offset) = static_cast<u64>(PageStatus::Allocated);
+ VAddr& slot = PageSlot(gpu_addr + offset);
+
+ ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
+ slot = static_cast<u64>(PageStatus::Allocated);
}
return gpu_addr;
@@ -34,8 +38,10 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
ASSERT(gpu_addr);
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
- ASSERT(PageSlot(*gpu_addr + offset) == static_cast<u64>(PageStatus::Unmapped));
- PageSlot(*gpu_addr + offset) = cpu_addr + offset;
+ VAddr& slot = PageSlot(*gpu_addr + offset);
+
+ ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
+ slot = cpu_addr + offset;
}
MappedRegion region{cpu_addr, *gpu_addr, size};
@@ -48,8 +54,10 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size)
ASSERT((gpu_addr & PAGE_MASK) == 0);
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
- ASSERT(PageSlot(gpu_addr + offset) == static_cast<u64>(PageStatus::Allocated));
- PageSlot(gpu_addr + offset) = cpu_addr + offset;
+ VAddr& slot = PageSlot(gpu_addr + offset);
+
+ ASSERT(slot == static_cast<u64>(PageStatus::Allocated));
+ slot = cpu_addr + offset;
}
MappedRegion region{cpu_addr, gpu_addr, size};
@@ -62,9 +70,11 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
ASSERT((gpu_addr & PAGE_MASK) == 0);
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
- ASSERT(PageSlot(gpu_addr + offset) != static_cast<u64>(PageStatus::Allocated) &&
- PageSlot(gpu_addr + offset) != static_cast<u64>(PageStatus::Unmapped));
- PageSlot(gpu_addr + offset) = static_cast<u64>(PageStatus::Unmapped);
+ VAddr& slot = PageSlot(gpu_addr + offset);
+
+ ASSERT(slot != static_cast<u64>(PageStatus::Allocated) &&
+ slot != static_cast<u64>(PageStatus::Unmapped));
+ slot = static_cast<u64>(PageStatus::Unmapped);
}
// Delete the region mappings that are contained within the unmapped region
@@ -128,9 +138,7 @@ VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) {
auto& block = page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK];
if (!block) {
block = std::make_unique<PageBlock>();
- for (unsigned index = 0; index < PAGE_BLOCK_SIZE; index++) {
- (*block)[index] = static_cast<u64>(PageStatus::Unmapped);
- }
+ block->fill(static_cast<VAddr>(PageStatus::Unmapped));
}
return (*block)[(gpu_addr >> PAGE_BITS) & PAGE_BLOCK_MASK];
}
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index 30075b23c..afd86a83a 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -2,14 +2,37 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <atomic>
#include <memory>
+#include "core/frontend/emu_window.h"
+#include "core/settings.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
-#include "video_core/video_core.h"
+
+namespace VideoCore {
+
+RendererBase::RendererBase(Core::Frontend::EmuWindow& window) : render_window{window} {
+ RefreshBaseSettings();
+}
+
+RendererBase::~RendererBase() = default;
+
+void RendererBase::RefreshBaseSettings() {
+ RefreshRasterizerSetting();
+ UpdateCurrentFramebufferLayout();
+
+ renderer_settings.use_framelimiter = Settings::values.toggle_framelimit;
+}
void RendererBase::RefreshRasterizerSetting() {
if (rasterizer == nullptr) {
- rasterizer = std::make_unique<RasterizerOpenGL>();
+ rasterizer = std::make_unique<RasterizerOpenGL>(render_window);
}
}
+
+void RendererBase::UpdateCurrentFramebufferLayout() {
+ const Layout::FramebufferLayout& layout = render_window.GetFramebufferLayout();
+
+ render_window.UpdateCurrentFramebufferLayout(layout.width, layout.height);
+}
+
+} // namespace VideoCore
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 89a960eaf..d9f16b8e6 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -4,31 +4,31 @@
#pragma once
+#include <atomic>
#include <memory>
#include <boost/optional.hpp>
-#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/rasterizer_interface.h"
+namespace Core::Frontend {
class EmuWindow;
+}
+
+namespace VideoCore {
+
+struct RendererSettings {
+ std::atomic_bool use_framelimiter{false};
+};
class RendererBase : NonCopyable {
public:
- /// Used to reference a framebuffer
- enum kFramebuffer { kFramebuffer_VirtualXFB = 0, kFramebuffer_EFB, kFramebuffer_Texture };
-
- virtual ~RendererBase() {}
+ explicit RendererBase(Core::Frontend::EmuWindow& window);
+ virtual ~RendererBase();
/// Swap buffers (render frame)
virtual void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) = 0;
- /**
- * Set the emulator window to use for renderer
- * @param window EmuWindow handle to emulator window to use for rendering
- */
- virtual void SetWindow(EmuWindow* window) = 0;
-
/// Initialize the renderer
virtual bool Init() = 0;
@@ -46,16 +46,31 @@ public:
return m_current_frame;
}
- VideoCore::RasterizerInterface* Rasterizer() const {
- return rasterizer.get();
+ RasterizerInterface& Rasterizer() {
+ return *rasterizer;
}
- void RefreshRasterizerSetting();
+ const RasterizerInterface& Rasterizer() const {
+ return *rasterizer;
+ }
+
+ /// Refreshes the settings common to all renderers
+ void RefreshBaseSettings();
protected:
- std::unique_ptr<VideoCore::RasterizerInterface> rasterizer;
+ /// Refreshes settings specific to the rasterizer.
+ void RefreshRasterizerSetting();
+
+ Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
+ std::unique_ptr<RasterizerInterface> rasterizer;
f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
int m_current_frame = 0; ///< Current frame, should be set by the renderer
+ RendererSettings renderer_settings;
+
private:
+ /// Updates the framebuffer layout of the contained render window handle.
+ void UpdateCurrentFramebufferLayout();
};
+
+} // namespace VideoCore
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index a1c47bae9..93eadde7a 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -14,7 +14,6 @@
#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/microprofile.h"
-#include "common/scope_exit.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
#include "core/hle/kernel/process.h"
@@ -37,30 +36,21 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
-RasterizerOpenGL::RasterizerOpenGL() {
+RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window)
+ : emu_window{window}, stream_buffer(GL_ARRAY_BUFFER, STREAM_BUFFER_SIZE) {
// Create sampler objects
for (size_t i = 0; i < texture_samplers.size(); ++i) {
texture_samplers[i].Create();
state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
}
- // Create SSBOs
- for (size_t stage = 0; stage < ssbos.size(); ++stage) {
- for (size_t buffer = 0; buffer < ssbos[stage].size(); ++buffer) {
- ssbos[stage][buffer].Create();
- state.draw.const_buffers[stage][buffer].ssbo = ssbos[stage][buffer].handle;
- }
- }
-
GLint ext_num;
glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
for (GLint i = 0; i < ext_num; i++) {
const std::string_view extension{
reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))};
- if (extension == "GL_ARB_buffer_storage") {
- has_ARB_buffer_storage = true;
- } else if (extension == "GL_ARB_direct_state_access") {
+ if (extension == "GL_ARB_direct_state_access") {
has_ARB_direct_state_access = true;
} else if (extension == "GL_ARB_separate_shader_objects") {
has_ARB_separate_shader_objects = true;
@@ -87,47 +77,31 @@ RasterizerOpenGL::RasterizerOpenGL() {
hw_vao.Create();
- stream_buffer = OGLStreamBuffer::MakeBuffer(has_ARB_buffer_storage, GL_ARRAY_BUFFER);
- stream_buffer->Create(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE / 2);
- state.draw.vertex_buffer = stream_buffer->GetHandle();
+ state.draw.vertex_buffer = stream_buffer.GetHandle();
shader_program_manager = std::make_unique<GLShader::ProgramManager>();
state.draw.shader_program = 0;
state.draw.vertex_array = hw_vao.handle;
state.Apply();
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer->GetHandle());
-
- for (unsigned index = 0; index < uniform_buffers.size(); ++index) {
- auto& buffer = uniform_buffers[index];
- buffer.Create();
- glBindBuffer(GL_UNIFORM_BUFFER, buffer.handle);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(GLShader::MaxwellUniformData), nullptr,
- GL_STREAM_COPY);
- glBindBufferBase(GL_UNIFORM_BUFFER, index, buffer.handle);
- }
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer.GetHandle());
glEnable(GL_BLEND);
+ glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
+
LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
}
-RasterizerOpenGL::~RasterizerOpenGL() {
- if (stream_buffer != nullptr) {
- state.draw.vertex_buffer = stream_buffer->GetHandle();
- state.Apply();
- stream_buffer->Release();
- }
-}
+RasterizerOpenGL::~RasterizerOpenGL() {}
std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
GLintptr buffer_offset) {
MICROPROFILE_SCOPE(OpenGL_VAO);
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager;
state.draw.vertex_array = hw_vao.handle;
- state.draw.vertex_buffer = stream_buffer->GetHandle();
+ state.draw.vertex_buffer = stream_buffer.GetHandle();
state.Apply();
// Upload all guest vertex arrays sequentially to our buffer
@@ -142,16 +116,15 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
ASSERT(end > start);
u64 size = end - start + 1;
- // Copy vertex array data
- Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size);
+ GLintptr vertex_buffer_offset;
+ std::tie(array_ptr, buffer_offset, vertex_buffer_offset) =
+ UploadMemory(array_ptr, buffer_offset, start, size);
// Bind the vertex array to the buffer at the current offset.
- glBindVertexBuffer(index, stream_buffer->GetHandle(), buffer_offset, vertex_array.stride);
-
- ASSERT_MSG(vertex_array.divisor == 0, "Vertex buffer divisor unimplemented");
+ glBindVertexBuffer(index, stream_buffer.GetHandle(), vertex_buffer_offset,
+ vertex_array.stride);
- array_ptr += size;
- buffer_offset += size;
+ ASSERT_MSG(vertex_array.divisor == 0, "Instanced vertex arrays are not supported");
}
// Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL.
@@ -162,16 +135,27 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
// assume every shader uses them all.
for (unsigned index = 0; index < 16; ++index) {
auto& attrib = regs.vertex_attrib_format[index];
- LOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
+
+ // Ignore invalid attributes.
+ if (!attrib.IsValid())
+ continue;
+
+ auto& buffer = regs.vertex_array[attrib.buffer];
+ LOG_TRACE(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
attrib.offset.Value(), attrib.IsNormalized());
- auto& buffer = regs.vertex_array[attrib.buffer];
ASSERT(buffer.IsEnabled());
glEnableVertexAttribArray(index);
- glVertexAttribFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
- attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
+ if (attrib.type == Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::SignedInt ||
+ attrib.type == Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::UnsignedInt) {
+ glVertexAttribIFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
+ attrib.offset);
+ } else {
+ glVertexAttribFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
+ attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
+ }
glVertexAttribBinding(index, attrib.buffer);
}
@@ -191,22 +175,12 @@ static GLShader::ProgramCode GetShaderProgramCode(Maxwell::ShaderProgram program
return program_code;
}
-void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
- // Helper function for uploading uniform data
- const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) {
- if (has_ARB_direct_state_access) {
- glCopyNamedBufferSubData(stream_buffer->GetHandle(), handle, offset, 0, size);
- } else {
- glBindBuffer(GL_COPY_WRITE_BUFFER, handle);
- glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size);
- }
- };
-
+std::pair<u8*, GLintptr> RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
// Next available bindpoints to use when uploading the const buffers and textures to the GLSL
// shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
- u32 current_constbuffer_bindpoint = uniform_buffers.size();
+ u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
u32 current_texture_bindpoint = 0;
for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
@@ -218,22 +192,21 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
continue;
}
+ std::tie(buffer_ptr, buffer_offset) =
+ AlignBuffer(buffer_ptr, buffer_offset, static_cast<size_t>(uniform_buffer_alignment));
+
const size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5
GLShader::MaxwellUniformData ubo{};
ubo.SetFromRegs(gpu.state.shader_stages[stage]);
std::memcpy(buffer_ptr, &ubo, sizeof(ubo));
- // Flush the buffer so that the GPU can see the data we just wrote.
- glFlushMappedBufferRange(GL_ARRAY_BUFFER, buffer_offset, sizeof(ubo));
-
- // Upload uniform data as one UBO per stage
- const GLintptr ubo_offset = buffer_offset;
- copy_buffer(uniform_buffers[stage].handle, ubo_offset,
- sizeof(GLShader::MaxwellUniformData));
+ // Bind the buffer
+ glBindBufferRange(GL_UNIFORM_BUFFER, stage, stream_buffer.GetHandle(), buffer_offset,
+ sizeof(ubo));
- buffer_ptr += sizeof(GLShader::MaxwellUniformData);
- buffer_offset += sizeof(GLShader::MaxwellUniformData);
+ buffer_ptr += sizeof(ubo);
+ buffer_offset += sizeof(ubo);
GLShader::ShaderSetup setup{GetShaderProgramCode(program)};
GLShader::ShaderEntries shader_resources;
@@ -272,9 +245,9 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
static_cast<Maxwell::ShaderStage>(stage));
// Configure the const buffers for this shader stage.
- current_constbuffer_bindpoint =
- SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program,
- current_constbuffer_bindpoint, shader_resources.const_buffer_entries);
+ std::tie(buffer_ptr, buffer_offset, current_constbuffer_bindpoint) = SetupConstBuffers(
+ buffer_ptr, buffer_offset, static_cast<Maxwell::ShaderStage>(stage), gl_stage_program,
+ current_constbuffer_bindpoint, shader_resources.const_buffer_entries);
// Configure the textures for this shader stage.
current_texture_bindpoint =
@@ -289,6 +262,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
}
shader_program_manager->UseTrivialGeometryShader();
+
+ return {buffer_ptr, buffer_offset};
}
size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
@@ -319,11 +294,14 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c
bool using_depth_fb) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+ if (regs.rt[0].format == Tegra::RenderTargetFormat::NONE) {
+ LOG_ERROR(HW_GPU, "RenderTargetFormat is not configured");
+ using_color_fb = false;
+ }
+
// TODO(bunnei): Implement this
const bool has_stencil = false;
- const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
-
const bool write_color_fb =
state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE;
@@ -336,9 +314,10 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c
Surface depth_surface;
MathUtil::Rectangle<u32> surfaces_rect;
std::tie(color_surface, depth_surface, surfaces_rect) =
- res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect);
+ res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb);
- MathUtil::Rectangle<u32> draw_rect{
+ const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
+ const MathUtil::Rectangle<u32> draw_rect{
static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left,
surfaces_rect.left, surfaces_rect.right)), // Left
static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top,
@@ -395,7 +374,7 @@ void RasterizerOpenGL::Clear() {
if (clear_mask == 0)
return;
- ScopeAcquireGLContext acquire_context;
+ ScopeAcquireGLContext acquire_context{emu_window};
auto [dirty_color_surface, dirty_depth_surface] =
ConfigureFramebuffers(use_color_fb, use_depth_fb);
@@ -418,6 +397,31 @@ void RasterizerOpenGL::Clear() {
}
}
+std::pair<u8*, GLintptr> RasterizerOpenGL::AlignBuffer(u8* buffer_ptr, GLintptr buffer_offset,
+ size_t alignment) {
+ // Align the offset, not the mapped pointer
+ GLintptr offset_aligned =
+ static_cast<GLintptr>(Common::AlignUp(static_cast<size_t>(buffer_offset), alignment));
+ return {buffer_ptr + (offset_aligned - buffer_offset), offset_aligned};
+}
+
+std::tuple<u8*, GLintptr, GLintptr> RasterizerOpenGL::UploadMemory(u8* buffer_ptr,
+ GLintptr buffer_offset,
+ Tegra::GPUVAddr gpu_addr,
+ size_t size, size_t alignment) {
+ std::tie(buffer_ptr, buffer_offset) = AlignBuffer(buffer_ptr, buffer_offset, alignment);
+ GLintptr uploaded_offset = buffer_offset;
+
+ const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager;
+ const boost::optional<VAddr> cpu_addr{memory_manager->GpuToCpuAddress(gpu_addr)};
+ Memory::ReadBlock(*cpu_addr, buffer_ptr, size);
+
+ buffer_ptr += size;
+ buffer_offset += size;
+
+ return {buffer_ptr, buffer_offset, uploaded_offset};
+}
+
void RasterizerOpenGL::DrawArrays() {
if (accelerate_draw == AccelDraw::Disabled)
return;
@@ -425,7 +429,7 @@ void RasterizerOpenGL::DrawArrays() {
MICROPROFILE_SCOPE(OpenGL_Drawing);
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- ScopeAcquireGLContext acquire_context;
+ ScopeAcquireGLContext acquire_context{emu_window};
auto [dirty_color_surface, dirty_depth_surface] =
ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0);
@@ -442,7 +446,7 @@ void RasterizerOpenGL::DrawArrays() {
const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count};
- state.draw.vertex_buffer = stream_buffer->GetHandle();
+ state.draw.vertex_buffer = stream_buffer.GetHandle();
state.Apply();
size_t buffer_size = CalculateVertexArraysSize();
@@ -452,41 +456,31 @@ void RasterizerOpenGL::DrawArrays() {
}
// Uniform space for the 5 shader stages
- buffer_size = Common::AlignUp<size_t>(buffer_size, 4) +
- sizeof(GLShader::MaxwellUniformData) * Maxwell::MaxShaderStage;
+ buffer_size =
+ Common::AlignUp<size_t>(buffer_size, 4) +
+ (sizeof(GLShader::MaxwellUniformData) + uniform_buffer_alignment) * Maxwell::MaxShaderStage;
+
+ // Add space for at least 18 constant buffers
+ buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment);
u8* buffer_ptr;
GLintptr buffer_offset;
- std::tie(buffer_ptr, buffer_offset) =
- stream_buffer->Map(static_cast<GLsizeiptr>(buffer_size), 4);
-
- u8* offseted_buffer;
- std::tie(offseted_buffer, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset);
+ std::tie(buffer_ptr, buffer_offset, std::ignore) =
+ stream_buffer.Map(static_cast<GLsizeiptr>(buffer_size), 4);
+ u8* buffer_ptr_base = buffer_ptr;
- offseted_buffer =
- reinterpret_cast<u8*>(Common::AlignUp(reinterpret_cast<size_t>(offseted_buffer), 4));
- buffer_offset = Common::AlignUp<size_t>(buffer_offset, 4);
+ std::tie(buffer_ptr, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset);
// If indexed mode, copy the index buffer
GLintptr index_buffer_offset = 0;
if (is_indexed) {
- const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager;
- const boost::optional<VAddr> index_data_addr{
- memory_manager->GpuToCpuAddress(regs.index_array.StartAddress())};
- Memory::ReadBlock(*index_data_addr, offseted_buffer, index_buffer_size);
-
- index_buffer_offset = buffer_offset;
- offseted_buffer += index_buffer_size;
- buffer_offset += index_buffer_size;
+ std::tie(buffer_ptr, buffer_offset, index_buffer_offset) = UploadMemory(
+ buffer_ptr, buffer_offset, regs.index_array.StartAddress(), index_buffer_size);
}
- offseted_buffer =
- reinterpret_cast<u8*>(Common::AlignUp(reinterpret_cast<size_t>(offseted_buffer), 4));
- buffer_offset = Common::AlignUp<size_t>(buffer_offset, 4);
-
- SetupShaders(offseted_buffer, buffer_offset);
+ std::tie(buffer_ptr, buffer_offset) = SetupShaders(buffer_ptr, buffer_offset);
- stream_buffer->Unmap();
+ stream_buffer.Unmap(buffer_ptr - buffer_ptr_base);
shader_program_manager->ApplyTo(state);
state.Apply();
@@ -633,42 +627,32 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
}
}
-u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint program,
- u32 current_bindpoint,
- const std::vector<GLShader::ConstBufferEntry>& entries) {
+std::tuple<u8*, GLintptr, u32> RasterizerOpenGL::SetupConstBuffers(
+ u8* buffer_ptr, GLintptr buffer_offset, Maxwell::ShaderStage stage, GLuint program,
+ u32 current_bindpoint, const std::vector<GLShader::ConstBufferEntry>& entries) {
const auto& gpu = Core::System::GetInstance().GPU();
const auto& maxwell3d = gpu.Maxwell3D();
- // Reset all buffer draw state for this stage.
- for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) {
- buffer.bindpoint = 0;
- buffer.enabled = false;
- }
-
// Upload only the enabled buffers from the 16 constbuffers of each shader stage
const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
const auto& used_buffer = entries[bindpoint];
const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()];
- auto& buffer_draw_state =
- state.draw.const_buffers[static_cast<size_t>(stage)][used_buffer.GetIndex()];
-
- ASSERT_MSG(buffer.enabled, "Attempted to upload disabled constbuffer");
- buffer_draw_state.enabled = true;
- buffer_draw_state.bindpoint = current_bindpoint + bindpoint;
- boost::optional<VAddr> addr = gpu.memory_manager->GpuToCpuAddress(buffer.address);
+ if (!buffer.enabled) {
+ continue;
+ }
size_t size = 0;
if (used_buffer.IsIndirect()) {
// Buffer is accessed indirectly, so upload the entire thing
- size = buffer.size * sizeof(float);
+ size = buffer.size;
if (size > MaxConstbufferSize) {
- LOG_ERROR(HW_GPU, "indirect constbuffer size {} exceeds maximum {}", size,
- MaxConstbufferSize);
+ LOG_CRITICAL(HW_GPU, "indirect constbuffer size {} exceeds maximum {}", size,
+ MaxConstbufferSize);
size = MaxConstbufferSize;
}
} else {
@@ -681,25 +665,26 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr
size = Common::AlignUp(size, sizeof(GLvec4));
ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big");
- std::vector<u8> data(size);
- Memory::ReadBlock(*addr, data.data(), data.size());
+ GLintptr const_buffer_offset;
+ std::tie(buffer_ptr, buffer_offset, const_buffer_offset) =
+ UploadMemory(buffer_ptr, buffer_offset, buffer.address, size,
+ static_cast<size_t>(uniform_buffer_alignment));
- glBindBuffer(GL_UNIFORM_BUFFER, buffer_draw_state.ssbo);
- glBufferData(GL_UNIFORM_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ glBindBufferRange(GL_UNIFORM_BUFFER, current_bindpoint + bindpoint,
+ stream_buffer.GetHandle(), const_buffer_offset, size);
// Now configure the bindpoint of the buffer inside the shader
const std::string buffer_name = used_buffer.GetName();
const GLuint index =
glGetProgramResourceIndex(program, GL_UNIFORM_BLOCK, buffer_name.c_str());
if (index != GL_INVALID_INDEX) {
- glUniformBlockBinding(program, index, buffer_draw_state.bindpoint);
+ glUniformBlockBinding(program, index, current_bindpoint + bindpoint);
}
}
state.Apply();
- return current_bindpoint + static_cast<u32>(entries.size());
+ return {buffer_ptr, buffer_offset, current_bindpoint + static_cast<u32>(entries.size())};
}
u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit,
@@ -799,9 +784,7 @@ void RasterizerOpenGL::SyncClipCoef() {
void RasterizerOpenGL::SyncCullMode() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- // TODO(bunnei): Enable the below once more things work - until then, this may hide regressions
- // state.cull.enabled = regs.cull.enabled != 0;
- state.cull.enabled = false;
+ state.cull.enabled = regs.cull.enabled != 0;
if (state.cull.enabled) {
state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index e150be58f..74307f626 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -7,6 +7,7 @@
#include <array>
#include <cstddef>
#include <memory>
+#include <tuple>
#include <utility>
#include <vector>
#include <glad/glad.h>
@@ -23,9 +24,13 @@
struct ScreenInfo;
+namespace Core::Frontend {
+class EmuWindow;
+}
+
class RasterizerOpenGL : public VideoCore::RasterizerInterface {
public:
- RasterizerOpenGL();
+ explicit RasterizerOpenGL(Core::Frontend::EmuWindow& renderer);
~RasterizerOpenGL() override;
void DrawArrays() override;
@@ -96,9 +101,10 @@ private:
* @param entries Vector describing the buffers that are actually used in the guest shader.
* @returns The next available bindpoint for use in the next shader stage.
*/
- u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, GLuint program,
- u32 current_bindpoint,
- const std::vector<GLShader::ConstBufferEntry>& entries);
+ std::tuple<u8*, GLintptr, u32> SetupConstBuffers(
+ u8* buffer_ptr, GLintptr buffer_offset, Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
+ GLuint program, u32 current_bindpoint,
+ const std::vector<GLShader::ConstBufferEntry>& entries);
/*
* Configures the current textures to use for the draw command.
@@ -135,7 +141,6 @@ private:
/// Syncs the blend state to match the guest state
void SyncBlendState();
- bool has_ARB_buffer_storage = false;
bool has_ARB_direct_state_access = false;
bool has_ARB_separate_shader_objects = false;
bool has_ARB_vertex_attrib_binding = false;
@@ -144,27 +149,31 @@ private:
RasterizerCacheOpenGL res_cache;
+ Core::Frontend::EmuWindow& emu_window;
+
std::unique_ptr<GLShader::ProgramManager> shader_program_manager;
OGLVertexArray sw_vao;
OGLVertexArray hw_vao;
std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers;
- std::array<std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers>,
- Tegra::Engines::Maxwell3D::Regs::MaxShaderStage>
- ssbos;
static constexpr size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
- std::unique_ptr<OGLStreamBuffer> stream_buffer;
+ OGLStreamBuffer stream_buffer;
OGLBuffer uniform_buffer;
OGLFramebuffer framebuffer;
+ GLint uniform_buffer_alignment;
size_t CalculateVertexArraysSize() const;
std::pair<u8*, GLintptr> SetupVertexArrays(u8* array_ptr, GLintptr buffer_offset);
- std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> uniform_buffers;
+ std::pair<u8*, GLintptr> SetupShaders(u8* buffer_ptr, GLintptr buffer_offset);
+
+ std::pair<u8*, GLintptr> AlignBuffer(u8* buffer_ptr, GLintptr buffer_offset, size_t alignment);
- void SetupShaders(u8* buffer_ptr, GLintptr buffer_offset);
+ std::tuple<u8*, GLintptr, GLintptr> UploadMemory(u8* buffer_ptr, GLintptr buffer_offset,
+ Tegra::GPUVAddr gpu_addr, size_t size,
+ size_t alignment = 4);
enum class AccelDraw { Disabled, Arrays, Indexed };
AccelDraw accelerate_draw = AccelDraw::Disabled;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index a4d9707cb..38aa067b6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -46,6 +46,8 @@ struct FormatTuple {
params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
params.unaligned_height = config.tic.Height();
params.size_in_bytes = params.SizeInBytes();
+ params.cache_width = Common::AlignUp(params.width, 16);
+ params.cache_height = Common::AlignUp(params.height, 16);
return params;
}
@@ -63,6 +65,8 @@ struct FormatTuple {
params.height = config.height;
params.unaligned_height = config.height;
params.size_in_bytes = params.SizeInBytes();
+ params.cache_width = Common::AlignUp(params.width, 16);
+ params.cache_height = Common::AlignUp(params.height, 16);
return params;
}
@@ -82,17 +86,23 @@ struct FormatTuple {
params.height = zeta_height;
params.unaligned_height = zeta_height;
params.size_in_bytes = params.SizeInBytes();
+ params.cache_width = Common::AlignUp(params.width, 16);
+ params.cache_height = Common::AlignUp(params.height, 16);
return params;
}
static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
- {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8
- {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5
+ {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
+ {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
+ {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U
{GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm,
- false}, // A2B10G10R10
- {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5
- {GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8
+ false}, // A2B10G10R10U
+ {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U
+ {GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8U
+ {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // R8UI
{GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F
+ {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // RGBA16U
+ {GL_RGBA16UI, GL_RGBA, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RGBA16UI
{GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float,
false}, // R11FG11FB10F
{GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI
@@ -103,31 +113,45 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
{GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // DXT45
{GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXN1
- {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
+ {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
+ true}, // DXN2UNORM
+ {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM
+ {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // BC7U
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
- {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8
+ {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
+ {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // G8R8S
{GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8
{GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false}, // RGBA32F
{GL_RG32F, GL_RG, GL_FLOAT, ComponentType::Float, false}, // RG32F
{GL_R32F, GL_RED, GL_FLOAT, ComponentType::Float, false}, // R32F
{GL_R16F, GL_RED, GL_HALF_FLOAT, ComponentType::Float, false}, // R16F
- {GL_R16, GL_RED, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // R16UNORM
+ {GL_R16, GL_RED, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // R16U
+ {GL_R16_SNORM, GL_RED, GL_SHORT, ComponentType::SNorm, false}, // R16S
+ {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // R16UI
+ {GL_R16I, GL_RED_INTEGER, GL_SHORT, ComponentType::SInt, false}, // R16I
{GL_RG16, GL_RG, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // RG16
{GL_RG16F, GL_RG, GL_HALF_FLOAT, ComponentType::Float, false}, // RG16F
{GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RG16UI
{GL_RG16I, GL_RG_INTEGER, GL_SHORT, ComponentType::SInt, false}, // RG16I
{GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S
+ {GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false}, // RGB32F
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // SRGBA8
+ {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U
+ {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S
+ {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI
+ {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI
+
+ // Depth formats
+ {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
+ {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, ComponentType::UNorm,
+ false}, // Z16
// DepthStencil formats
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
false}, // Z24S8
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
- false}, // S8Z24
- {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
- {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, ComponentType::UNorm,
- false}, // Z16
+ false}, // S8Z24
{GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
ComponentType::Float, false}, // Z32FS8
}};
@@ -173,92 +197,156 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect() const {
return {0, actual_height, width, 0};
}
+/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
+static bool IsFormatBCn(PixelFormat format) {
+ switch (format) {
+ case PixelFormat::DXT1:
+ case PixelFormat::DXT23:
+ case PixelFormat::DXT45:
+ case PixelFormat::DXN1:
+ case PixelFormat::DXN2SNORM:
+ case PixelFormat::DXN2UNORM:
+ case PixelFormat::BC7U:
+ return true;
+ }
+ return false;
+}
+
template <bool morton_to_gl, PixelFormat format>
-void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, Tegra::GPUVAddr addr) {
+void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_buffer,
+ Tegra::GPUVAddr addr) {
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
const auto& gpu = Core::System::GetInstance().GPU();
if (morton_to_gl) {
- if (SurfaceParams::GetFormatType(format) == SurfaceType::ColorTexture) {
- auto data = Tegra::Texture::UnswizzleTexture(
- *gpu.memory_manager->GpuToCpuAddress(addr),
- SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height);
- std::memcpy(gl_buffer, data.data(), data.size());
- } else {
- auto data = Tegra::Texture::UnswizzleDepthTexture(
- *gpu.memory_manager->GpuToCpuAddress(addr),
- SurfaceParams::DepthFormatFromPixelFormat(format), stride, height, block_height);
- std::memcpy(gl_buffer, data.data(), data.size());
- }
+ // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
+ // pixel values.
+ const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
+ const std::vector<u8> data =
+ Tegra::Texture::UnswizzleTexture(*gpu.memory_manager->GpuToCpuAddress(addr), tile_size,
+ bytes_per_pixel, stride, height, block_height);
+ const size_t size_to_copy{std::min(gl_buffer.size(), data.size())};
+ gl_buffer.assign(data.begin(), data.begin() + size_to_copy);
} else {
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should
// check the configuration for this and perform more generic un/swizzle
LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
VideoCore::MortonCopyPixels128(
stride, height, bytes_per_pixel, gl_bytes_per_pixel,
- Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(addr)), gl_buffer,
+ Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(addr)), gl_buffer.data(),
morton_to_gl);
}
}
-static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
+static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
SurfaceParams::MaxPixelFormat>
morton_to_gl_fns = {
- MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>,
- MortonCopy<true, PixelFormat::A2B10G10R10>, MortonCopy<true, PixelFormat::A1B5G5R5>,
- MortonCopy<true, PixelFormat::R8>, MortonCopy<true, PixelFormat::RGBA16F>,
- MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>,
- MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
- MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>,
- MortonCopy<true, PixelFormat::BC7U>, MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
- MortonCopy<true, PixelFormat::G8R8>, MortonCopy<true, PixelFormat::BGRA8>,
- MortonCopy<true, PixelFormat::RGBA32F>, MortonCopy<true, PixelFormat::RG32F>,
- MortonCopy<true, PixelFormat::R32F>, MortonCopy<true, PixelFormat::R16F>,
- MortonCopy<true, PixelFormat::R16UNORM>, MortonCopy<true, PixelFormat::RG16>,
- MortonCopy<true, PixelFormat::RG16F>, MortonCopy<true, PixelFormat::RG16UI>,
- MortonCopy<true, PixelFormat::RG16I>, MortonCopy<true, PixelFormat::RG16S>,
- MortonCopy<true, PixelFormat::SRGBA8>, MortonCopy<true, PixelFormat::Z24S8>,
- MortonCopy<true, PixelFormat::S8Z24>, MortonCopy<true, PixelFormat::Z32F>,
- MortonCopy<true, PixelFormat::Z16>, MortonCopy<true, PixelFormat::Z32FS8>,
+ // clang-format off
+ MortonCopy<true, PixelFormat::ABGR8U>,
+ MortonCopy<true, PixelFormat::ABGR8S>,
+ MortonCopy<true, PixelFormat::B5G6R5U>,
+ MortonCopy<true, PixelFormat::A2B10G10R10U>,
+ MortonCopy<true, PixelFormat::A1B5G5R5U>,
+ MortonCopy<true, PixelFormat::R8U>,
+ MortonCopy<true, PixelFormat::R8UI>,
+ MortonCopy<true, PixelFormat::RGBA16F>,
+ MortonCopy<true, PixelFormat::RGBA16U>,
+ MortonCopy<true, PixelFormat::RGBA16UI>,
+ MortonCopy<true, PixelFormat::R11FG11FB10F>,
+ MortonCopy<true, PixelFormat::RGBA32UI>,
+ MortonCopy<true, PixelFormat::DXT1>,
+ MortonCopy<true, PixelFormat::DXT23>,
+ MortonCopy<true, PixelFormat::DXT45>,
+ MortonCopy<true, PixelFormat::DXN1>,
+ MortonCopy<true, PixelFormat::DXN2UNORM>,
+ MortonCopy<true, PixelFormat::DXN2SNORM>,
+ MortonCopy<true, PixelFormat::BC7U>,
+ MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
+ MortonCopy<true, PixelFormat::G8R8U>,
+ MortonCopy<true, PixelFormat::G8R8S>,
+ MortonCopy<true, PixelFormat::BGRA8>,
+ MortonCopy<true, PixelFormat::RGBA32F>,
+ MortonCopy<true, PixelFormat::RG32F>,
+ MortonCopy<true, PixelFormat::R32F>,
+ MortonCopy<true, PixelFormat::R16F>,
+ MortonCopy<true, PixelFormat::R16U>,
+ MortonCopy<true, PixelFormat::R16S>,
+ MortonCopy<true, PixelFormat::R16UI>,
+ MortonCopy<true, PixelFormat::R16I>,
+ MortonCopy<true, PixelFormat::RG16>,
+ MortonCopy<true, PixelFormat::RG16F>,
+ MortonCopy<true, PixelFormat::RG16UI>,
+ MortonCopy<true, PixelFormat::RG16I>,
+ MortonCopy<true, PixelFormat::RG16S>,
+ MortonCopy<true, PixelFormat::RGB32F>,
+ MortonCopy<true, PixelFormat::SRGBA8>,
+ MortonCopy<true, PixelFormat::RG8U>,
+ MortonCopy<true, PixelFormat::RG8S>,
+ MortonCopy<true, PixelFormat::RG32UI>,
+ MortonCopy<true, PixelFormat::R32UI>,
+ MortonCopy<true, PixelFormat::Z32F>,
+ MortonCopy<true, PixelFormat::Z16>,
+ MortonCopy<true, PixelFormat::Z24S8>,
+ MortonCopy<true, PixelFormat::S8Z24>,
+ MortonCopy<true, PixelFormat::Z32FS8>,
+ // clang-format on
};
-static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
+static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
SurfaceParams::MaxPixelFormat>
gl_to_morton_fns = {
- MortonCopy<false, PixelFormat::ABGR8>,
- MortonCopy<false, PixelFormat::B5G6R5>,
- MortonCopy<false, PixelFormat::A2B10G10R10>,
- MortonCopy<false, PixelFormat::A1B5G5R5>,
- MortonCopy<false, PixelFormat::R8>,
+ // clang-format off
+ MortonCopy<false, PixelFormat::ABGR8U>,
+ MortonCopy<false, PixelFormat::ABGR8S>,
+ MortonCopy<false, PixelFormat::B5G6R5U>,
+ MortonCopy<false, PixelFormat::A2B10G10R10U>,
+ MortonCopy<false, PixelFormat::A1B5G5R5U>,
+ MortonCopy<false, PixelFormat::R8U>,
+ MortonCopy<false, PixelFormat::R8UI>,
MortonCopy<false, PixelFormat::RGBA16F>,
+ MortonCopy<false, PixelFormat::RGBA16U>,
+ MortonCopy<false, PixelFormat::RGBA16UI>,
MortonCopy<false, PixelFormat::R11FG11FB10F>,
MortonCopy<false, PixelFormat::RGBA32UI>,
- // TODO(Subv): Swizzling DXT1/DXT23/DXT45/DXN1/BC7U/ASTC_2D_4X4 formats is not supported
+ // TODO(Subv): Swizzling DXT1/DXT23/DXT45/DXN1/DXN2/BC7U/ASTC_2D_4X4 formats is not
+ // supported
+ nullptr,
+ nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
- MortonCopy<false, PixelFormat::G8R8>,
+ MortonCopy<false, PixelFormat::G8R8U>,
+ MortonCopy<false, PixelFormat::G8R8S>,
MortonCopy<false, PixelFormat::BGRA8>,
MortonCopy<false, PixelFormat::RGBA32F>,
MortonCopy<false, PixelFormat::RG32F>,
MortonCopy<false, PixelFormat::R32F>,
MortonCopy<false, PixelFormat::R16F>,
- MortonCopy<false, PixelFormat::R16UNORM>,
+ MortonCopy<false, PixelFormat::R16U>,
+ MortonCopy<false, PixelFormat::R16S>,
+ MortonCopy<false, PixelFormat::R16UI>,
+ MortonCopy<false, PixelFormat::R16I>,
MortonCopy<false, PixelFormat::RG16>,
MortonCopy<false, PixelFormat::RG16F>,
MortonCopy<false, PixelFormat::RG16UI>,
MortonCopy<false, PixelFormat::RG16I>,
MortonCopy<false, PixelFormat::RG16S>,
+ MortonCopy<false, PixelFormat::RGB32F>,
MortonCopy<false, PixelFormat::SRGBA8>,
- MortonCopy<false, PixelFormat::Z24S8>,
- MortonCopy<false, PixelFormat::S8Z24>,
+ MortonCopy<false, PixelFormat::RG8U>,
+ MortonCopy<false, PixelFormat::RG8S>,
+ MortonCopy<false, PixelFormat::RG32UI>,
+ MortonCopy<false, PixelFormat::R32UI>,
MortonCopy<false, PixelFormat::Z32F>,
MortonCopy<false, PixelFormat::Z16>,
+ MortonCopy<false, PixelFormat::Z24S8>,
+ MortonCopy<false, PixelFormat::S8Z24>,
MortonCopy<false, PixelFormat::Z32FS8>,
+ // clang-format on
};
// Allocate an uninitialized texture of appropriate size and format for the surface
@@ -378,7 +466,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
}
static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
- const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8)};
+ const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)};
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
const size_t offset{bpp * (y * width + x)};
@@ -410,7 +498,8 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
ConvertS8Z24ToZ24S8(data, width, height);
break;
- case PixelFormat::G8R8:
+ case PixelFormat::G8R8U:
+ case PixelFormat::G8R8S:
// Convert the G8R8 color format to R8G8, as OpenGL does not support G8R8.
ConvertG8R8ToR8G8(data, width, height);
break;
@@ -438,22 +527,24 @@ MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64
void CachedSurface::LoadGLBuffer() {
ASSERT(params.type != SurfaceType::Fill);
- u8* const texture_src_data = Memory::GetPointer(params.GetCpuAddr());
+ const u8* const texture_src_data = Memory::GetPointer(params.GetCpuAddr());
ASSERT(texture_src_data);
- gl_buffer.resize(params.width * params.height * GetGLBytesPerPixel(params.pixel_format));
+ const u32 bytes_per_pixel = GetGLBytesPerPixel(params.pixel_format);
+ const u32 copy_size = params.width * params.height * bytes_per_pixel;
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
- if (!params.is_tiled) {
- const u32 bytes_per_pixel{params.GetFormatBpp() >> 3};
+ if (params.is_tiled) {
+ gl_buffer.resize(copy_size);
- std::memcpy(gl_buffer.data(), texture_src_data,
- bytes_per_pixel * params.width * params.height);
- } else {
morton_to_gl_fns[static_cast<size_t>(params.pixel_format)](
- params.width, params.block_height, params.height, gl_buffer.data(), params.addr);
+ params.width, params.block_height, params.height, gl_buffer, params.addr);
+ } else {
+ const u8* const texture_src_data_end = texture_src_data + copy_size;
+
+ gl_buffer.assign(texture_src_data, texture_src_data_end);
}
ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height);
@@ -476,7 +567,7 @@ void CachedSurface::FlushGLBuffer() {
std::memcpy(dst_buffer, gl_buffer.data(), params.size_in_bytes);
} else {
gl_to_morton_fns[static_cast<size_t>(params.pixel_format)](
- params.width, params.block_height, params.height, gl_buffer.data(), params.addr);
+ params.width, params.block_height, params.height, gl_buffer, params.addr);
}
}
@@ -591,8 +682,8 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
return GetSurface(SurfaceParams::CreateForTexture(config));
}
-SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
- bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport) {
+SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(bool using_color_fb,
+ bool using_depth_fb) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
// TODO(bunnei): This is hard corded to use just the first render buffer
@@ -677,12 +768,12 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) {
// If use_accurate_framebuffers is enabled, always load from memory
FlushSurface(surface);
UnregisterSurface(surface);
- } else if (surface->GetSurfaceParams() != params) {
- // If surface parameters changed, recreate the surface from the old one
- return RecreateSurface(surface, params);
- } else {
+ } else if (surface->GetSurfaceParams().IsCompatibleSurface(params)) {
// Use the cached surface as-is
return surface;
+ } else {
+ // If surface parameters changed, recreate the surface from the old one
+ return RecreateSurface(surface, params);
}
}
@@ -699,8 +790,6 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
// Verify surface is compatible for blitting
const auto& params{surface->GetSurfaceParams()};
ASSERT(params.type == new_params.type);
- ASSERT(params.pixel_format == new_params.pixel_format);
- ASSERT(params.component_type == new_params.component_type);
// Create a new surface with the new parameters, and blit the previous surface to it
Surface new_surface{std::make_shared<CachedSurface>(new_params)};
@@ -748,10 +837,12 @@ void RasterizerCacheOpenGL::FlushRegion(Tegra::GPUVAddr /*addr*/, size_t /*size*
}
void RasterizerCacheOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, size_t size) {
- for (const auto& pair : surface_cache) {
- const auto& surface{pair.second};
+ for (auto iter = surface_cache.cbegin(); iter != surface_cache.cend();) {
+ const auto& surface{iter->second};
const auto& params{surface->GetSurfaceParams()};
+ ++iter;
+
if (params.IsOverlappingRegion(addr, size)) {
UnregisterSurface(surface);
}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index bb39c0a6f..beec01746 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -9,6 +9,7 @@
#include <memory>
#include <vector>
#include <boost/icl/interval_map.hpp>
+
#include "common/common_types.h"
#include "common/math_util.h"
#include "video_core/engines/maxwell_3d.h"
@@ -22,42 +23,61 @@ using PageMap = boost::icl::interval_map<u64, int>;
struct SurfaceParams {
enum class PixelFormat {
- ABGR8 = 0,
- B5G6R5 = 1,
- A2B10G10R10 = 2,
- A1B5G5R5 = 3,
- R8 = 4,
- RGBA16F = 5,
- R11FG11FB10F = 6,
- RGBA32UI = 7,
- DXT1 = 8,
- DXT23 = 9,
- DXT45 = 10,
- DXN1 = 11, // This is also known as BC4
- BC7U = 12,
- ASTC_2D_4X4 = 13,
- G8R8 = 14,
- BGRA8 = 15,
- RGBA32F = 16,
- RG32F = 17,
- R32F = 18,
- R16F = 19,
- R16UNORM = 20,
- RG16 = 21,
- RG16F = 22,
- RG16UI = 23,
- RG16I = 24,
- RG16S = 25,
- SRGBA8 = 26,
+ ABGR8U = 0,
+ ABGR8S = 1,
+ B5G6R5U = 2,
+ A2B10G10R10U = 3,
+ A1B5G5R5U = 4,
+ R8U = 5,
+ R8UI = 6,
+ RGBA16F = 7,
+ RGBA16U = 8,
+ RGBA16UI = 9,
+ R11FG11FB10F = 10,
+ RGBA32UI = 11,
+ DXT1 = 12,
+ DXT23 = 13,
+ DXT45 = 14,
+ DXN1 = 15, // This is also known as BC4
+ DXN2UNORM = 16,
+ DXN2SNORM = 17,
+ BC7U = 18,
+ ASTC_2D_4X4 = 19,
+ G8R8U = 20,
+ G8R8S = 21,
+ BGRA8 = 22,
+ RGBA32F = 23,
+ RG32F = 24,
+ R32F = 25,
+ R16F = 26,
+ R16U = 27,
+ R16S = 28,
+ R16UI = 29,
+ R16I = 30,
+ RG16 = 31,
+ RG16F = 32,
+ RG16UI = 33,
+ RG16I = 34,
+ RG16S = 35,
+ RGB32F = 36,
+ SRGBA8 = 37,
+ RG8U = 38,
+ RG8S = 39,
+ RG32UI = 40,
+ R32UI = 41,
MaxColorFormat,
+ // Depth formats
+ Z32F = 42,
+ Z16 = 43,
+
+ MaxDepthFormat,
+
// DepthStencil formats
- Z24S8 = 27,
- S8Z24 = 28,
- Z32F = 29,
- Z16 = 30,
- Z32FS8 = 31,
+ Z24S8 = 44,
+ S8Z24 = 45,
+ Z32FS8 = 46,
MaxDepthStencilFormat,
@@ -95,37 +115,52 @@ struct SurfaceParams {
return 0;
constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
- 1, // ABGR8
- 1, // B5G6R5
- 1, // A2B10G10R10
- 1, // A1B5G5R5
- 1, // R8
+ 1, // ABGR8U
+ 1, // ABGR8S
+ 1, // B5G6R5U
+ 1, // A2B10G10R10U
+ 1, // A1B5G5R5U
+ 1, // R8U
+ 1, // R8UI
1, // RGBA16F
+ 1, // RGBA16U
+ 1, // RGBA16UI
1, // R11FG11FB10F
1, // RGBA32UI
4, // DXT1
4, // DXT23
4, // DXT45
4, // DXN1
+ 4, // DXN2UNORM
+ 4, // DXN2SNORM
4, // BC7U
4, // ASTC_2D_4X4
- 1, // G8R8
+ 1, // G8R8U
+ 1, // G8R8S
1, // BGRA8
1, // RGBA32F
1, // RG32F
1, // R32F
1, // R16F
- 1, // R16UNORM
+ 1, // R16U
+ 1, // R16S
+ 1, // R16UI
+ 1, // R16I
1, // RG16
1, // RG16F
1, // RG16UI
1, // RG16I
1, // RG16S
+ 1, // RGB32F
1, // SRGBA8
- 1, // Z24S8
- 1, // S8Z24
+ 1, // RG8U
+ 1, // RG8S
+ 1, // RG32UI
+ 1, // R32UI
1, // Z32F
1, // Z16
+ 1, // Z24S8
+ 1, // S8Z24
1, // Z32FS8
}};
@@ -138,37 +173,52 @@ struct SurfaceParams {
return 0;
constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
- 32, // ABGR8
- 16, // B5G6R5
- 32, // A2B10G10R10
- 16, // A1B5G5R5
- 8, // R8
+ 32, // ABGR8U
+ 32, // ABGR8S
+ 16, // B5G6R5U
+ 32, // A2B10G10R10U
+ 16, // A1B5G5R5U
+ 8, // R8U
+ 8, // R8UI
64, // RGBA16F
+ 64, // RGBA16U
+ 64, // RGBA16UI
32, // R11FG11FB10F
128, // RGBA32UI
64, // DXT1
128, // DXT23
128, // DXT45
64, // DXN1
+ 128, // DXN2UNORM
+ 128, // DXN2SNORM
128, // BC7U
32, // ASTC_2D_4X4
- 16, // G8R8
+ 16, // G8R8U
+ 16, // G8R8S
32, // BGRA8
128, // RGBA32F
64, // RG32F
32, // R32F
16, // R16F
- 16, // R16UNORM
+ 16, // R16U
+ 16, // R16S
+ 16, // R16UI
+ 16, // R16I
32, // RG16
32, // RG16F
32, // RG16UI
32, // RG16I
32, // RG16S
+ 96, // RGB32F
32, // SRGBA8
- 32, // Z24S8
- 32, // S8Z24
+ 16, // RG8U
+ 16, // RG8S
+ 64, // RG32UI
+ 32, // R32UI
32, // Z32F
16, // Z16
+ 32, // Z24S8
+ 32, // S8Z24
64, // Z32FS8
}};
@@ -200,26 +250,37 @@ struct SurfaceParams {
static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
switch (format) {
+ // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
+ // gamma.
case Tegra::RenderTargetFormat::RGBA8_SRGB:
- return PixelFormat::SRGBA8;
case Tegra::RenderTargetFormat::RGBA8_UNORM:
- return PixelFormat::ABGR8;
+ return PixelFormat::ABGR8U;
+ case Tegra::RenderTargetFormat::RGBA8_SNORM:
+ return PixelFormat::ABGR8S;
case Tegra::RenderTargetFormat::BGRA8_UNORM:
return PixelFormat::BGRA8;
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
- return PixelFormat::A2B10G10R10;
+ return PixelFormat::A2B10G10R10U;
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
return PixelFormat::RGBA16F;
+ case Tegra::RenderTargetFormat::RGBA16_UNORM:
+ return PixelFormat::RGBA16U;
+ case Tegra::RenderTargetFormat::RGBA16_UINT:
+ return PixelFormat::RGBA16UI;
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
return PixelFormat::RGBA32F;
case Tegra::RenderTargetFormat::RG32_FLOAT:
return PixelFormat::RG32F;
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
return PixelFormat::R11FG11FB10F;
+ case Tegra::RenderTargetFormat::B5G6R5_UNORM:
+ return PixelFormat::B5G6R5U;
case Tegra::RenderTargetFormat::RGBA32_UINT:
return PixelFormat::RGBA32UI;
case Tegra::RenderTargetFormat::R8_UNORM:
- return PixelFormat::R8;
+ return PixelFormat::R8U;
+ case Tegra::RenderTargetFormat::R8_UINT:
+ return PixelFormat::R8UI;
case Tegra::RenderTargetFormat::RG16_FLOAT:
return PixelFormat::RG16F;
case Tegra::RenderTargetFormat::RG16_UINT:
@@ -230,7 +291,26 @@ struct SurfaceParams {
return PixelFormat::RG16;
case Tegra::RenderTargetFormat::RG16_SNORM:
return PixelFormat::RG16S;
-
+ case Tegra::RenderTargetFormat::RG8_UNORM:
+ return PixelFormat::RG8U;
+ case Tegra::RenderTargetFormat::RG8_SNORM:
+ return PixelFormat::RG8S;
+ case Tegra::RenderTargetFormat::R16_FLOAT:
+ return PixelFormat::R16F;
+ case Tegra::RenderTargetFormat::R16_UNORM:
+ return PixelFormat::R16U;
+ case Tegra::RenderTargetFormat::R16_SNORM:
+ return PixelFormat::R16S;
+ case Tegra::RenderTargetFormat::R16_UINT:
+ return PixelFormat::R16UI;
+ case Tegra::RenderTargetFormat::R16_SINT:
+ return PixelFormat::R16I;
+ case Tegra::RenderTargetFormat::R32_FLOAT:
+ return PixelFormat::R32F;
+ case Tegra::RenderTargetFormat::R32_UINT:
+ return PixelFormat::R32UI;
+ case Tegra::RenderTargetFormat::RG32_UINT:
+ return PixelFormat::RG32UI;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
@@ -242,21 +322,77 @@ struct SurfaceParams {
// TODO(Subv): Properly implement this
switch (format) {
case Tegra::Texture::TextureFormat::A8R8G8B8:
- return PixelFormat::ABGR8;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::UNORM:
+ return PixelFormat::ABGR8U;
+ case Tegra::Texture::ComponentType::SNORM:
+ return PixelFormat::ABGR8S;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::B5G6R5:
- return PixelFormat::B5G6R5;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::UNORM:
+ return PixelFormat::B5G6R5U;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::A2B10G10R10:
- return PixelFormat::A2B10G10R10;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::UNORM:
+ return PixelFormat::A2B10G10R10U;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::A1B5G5R5:
- return PixelFormat::A1B5G5R5;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::UNORM:
+ return PixelFormat::A1B5G5R5U;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::R8:
- return PixelFormat::R8;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::UNORM:
+ return PixelFormat::R8U;
+ case Tegra::Texture::ComponentType::UINT:
+ return PixelFormat::R8UI;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::G8R8:
- return PixelFormat::G8R8;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::UNORM:
+ return PixelFormat::G8R8U;
+ case Tegra::Texture::ComponentType::SNORM:
+ return PixelFormat::G8R8S;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
- return PixelFormat::RGBA16F;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::UNORM:
+ return PixelFormat::RGBA16U;
+ case Tegra::Texture::ComponentType::FLOAT:
+ return PixelFormat::RGBA16F;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::BF10GF11RF11:
- return PixelFormat::R11FG11FB10F;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::FLOAT:
+ return PixelFormat::R11FG11FB10F;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
switch (component_type) {
case Tegra::Texture::ComponentType::FLOAT:
@@ -268,21 +404,53 @@ struct SurfaceParams {
static_cast<u32>(component_type));
UNREACHABLE();
case Tegra::Texture::TextureFormat::R32_G32:
- return PixelFormat::RG32F;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::FLOAT:
+ return PixelFormat::RG32F;
+ case Tegra::Texture::ComponentType::UINT:
+ return PixelFormat::RG32UI;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
+ case Tegra::Texture::TextureFormat::R32_G32_B32:
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::FLOAT:
+ return PixelFormat::RGB32F;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::R16:
switch (component_type) {
case Tegra::Texture::ComponentType::FLOAT:
return PixelFormat::R16F;
case Tegra::Texture::ComponentType::UNORM:
- return PixelFormat::R16UNORM;
+ return PixelFormat::R16U;
+ case Tegra::Texture::ComponentType::SNORM:
+ return PixelFormat::R16S;
+ case Tegra::Texture::ComponentType::UINT:
+ return PixelFormat::R16UI;
+ case Tegra::Texture::ComponentType::SINT:
+ return PixelFormat::R16I;
}
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
static_cast<u32>(component_type));
UNREACHABLE();
case Tegra::Texture::TextureFormat::R32:
- return PixelFormat::R32F;
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::FLOAT:
+ return PixelFormat::R32F;
+ case Tegra::Texture::ComponentType::UINT:
+ return PixelFormat::R32UI;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::ZF32:
return PixelFormat::Z32F;
+ case Tegra::Texture::TextureFormat::Z16:
+ return PixelFormat::Z16;
case Tegra::Texture::TextureFormat::Z24S8:
return PixelFormat::Z24S8;
case Tegra::Texture::TextureFormat::DXT1:
@@ -293,6 +461,16 @@ struct SurfaceParams {
return PixelFormat::DXT45;
case Tegra::Texture::TextureFormat::DXN1:
return PixelFormat::DXN1;
+ case Tegra::Texture::TextureFormat::DXN2:
+ switch (component_type) {
+ case Tegra::Texture::ComponentType::UNORM:
+ return PixelFormat::DXN2UNORM;
+ case Tegra::Texture::ComponentType::SNORM:
+ return PixelFormat::DXN2SNORM;
+ }
+ LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
+ static_cast<u32>(component_type));
+ UNREACHABLE();
case Tegra::Texture::TextureFormat::BC7U:
return PixelFormat::BC7U;
case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
@@ -320,87 +498,6 @@ struct SurfaceParams {
}
}
- static Tegra::Texture::TextureFormat TextureFormatFromPixelFormat(PixelFormat format) {
- // TODO(Subv): Properly implement this
- switch (format) {
- case PixelFormat::ABGR8:
- case PixelFormat::SRGBA8:
- return Tegra::Texture::TextureFormat::A8R8G8B8;
- case PixelFormat::B5G6R5:
- return Tegra::Texture::TextureFormat::B5G6R5;
- case PixelFormat::A2B10G10R10:
- return Tegra::Texture::TextureFormat::A2B10G10R10;
- case PixelFormat::A1B5G5R5:
- return Tegra::Texture::TextureFormat::A1B5G5R5;
- case PixelFormat::R8:
- return Tegra::Texture::TextureFormat::R8;
- case PixelFormat::G8R8:
- return Tegra::Texture::TextureFormat::G8R8;
- case PixelFormat::RGBA16F:
- return Tegra::Texture::TextureFormat::R16_G16_B16_A16;
- case PixelFormat::R11FG11FB10F:
- return Tegra::Texture::TextureFormat::BF10GF11RF11;
- case PixelFormat::RGBA32UI:
- return Tegra::Texture::TextureFormat::R32_G32_B32_A32;
- case PixelFormat::DXT1:
- return Tegra::Texture::TextureFormat::DXT1;
- case PixelFormat::DXT23:
- return Tegra::Texture::TextureFormat::DXT23;
- case PixelFormat::DXT45:
- return Tegra::Texture::TextureFormat::DXT45;
- case PixelFormat::DXN1:
- return Tegra::Texture::TextureFormat::DXN1;
- case PixelFormat::BC7U:
- return Tegra::Texture::TextureFormat::BC7U;
- case PixelFormat::ASTC_2D_4X4:
- return Tegra::Texture::TextureFormat::ASTC_2D_4X4;
- case PixelFormat::BGRA8:
- // TODO(bunnei): This is fine for unswizzling (since we just need the right component
- // sizes), but could be a bug if we used this function in different ways.
- return Tegra::Texture::TextureFormat::A8R8G8B8;
- case PixelFormat::RGBA32F:
- return Tegra::Texture::TextureFormat::R32_G32_B32_A32;
- case PixelFormat::RG32F:
- return Tegra::Texture::TextureFormat::R32_G32;
- case PixelFormat::R32F:
- return Tegra::Texture::TextureFormat::R32;
- case PixelFormat::R16F:
- case PixelFormat::R16UNORM:
- return Tegra::Texture::TextureFormat::R16;
- case PixelFormat::Z32F:
- return Tegra::Texture::TextureFormat::ZF32;
- case PixelFormat::Z24S8:
- return Tegra::Texture::TextureFormat::Z24S8;
- case PixelFormat::RG16F:
- case PixelFormat::RG16:
- case PixelFormat::RG16UI:
- case PixelFormat::RG16I:
- case PixelFormat::RG16S:
- return Tegra::Texture::TextureFormat::R16_G16;
- default:
- LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
- UNREACHABLE();
- }
- }
-
- static Tegra::DepthFormat DepthFormatFromPixelFormat(PixelFormat format) {
- switch (format) {
- case PixelFormat::S8Z24:
- return Tegra::DepthFormat::S8_Z24_UNORM;
- case PixelFormat::Z24S8:
- return Tegra::DepthFormat::Z24_S8_UNORM;
- case PixelFormat::Z32F:
- return Tegra::DepthFormat::Z32_FLOAT;
- case PixelFormat::Z16:
- return Tegra::DepthFormat::Z16_UNORM;
- case PixelFormat::Z32FS8:
- return Tegra::DepthFormat::Z32_S8_X24_FLOAT;
- default:
- LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
- UNREACHABLE();
- }
- }
-
static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
// TODO(Subv): Implement more component types
switch (type) {
@@ -429,19 +526,34 @@ struct SurfaceParams {
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
case Tegra::RenderTargetFormat::R8_UNORM:
case Tegra::RenderTargetFormat::RG16_UNORM:
+ case Tegra::RenderTargetFormat::R16_UNORM:
+ case Tegra::RenderTargetFormat::B5G6R5_UNORM:
+ case Tegra::RenderTargetFormat::RG8_UNORM:
+ case Tegra::RenderTargetFormat::RGBA16_UNORM:
return ComponentType::UNorm;
+ case Tegra::RenderTargetFormat::RGBA8_SNORM:
case Tegra::RenderTargetFormat::RG16_SNORM:
+ case Tegra::RenderTargetFormat::R16_SNORM:
+ case Tegra::RenderTargetFormat::RG8_SNORM:
return ComponentType::SNorm;
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
case Tegra::RenderTargetFormat::RG32_FLOAT:
case Tegra::RenderTargetFormat::RG16_FLOAT:
+ case Tegra::RenderTargetFormat::R16_FLOAT:
+ case Tegra::RenderTargetFormat::R32_FLOAT:
return ComponentType::Float;
case Tegra::RenderTargetFormat::RGBA32_UINT:
+ case Tegra::RenderTargetFormat::RGBA16_UINT:
case Tegra::RenderTargetFormat::RG16_UINT:
+ case Tegra::RenderTargetFormat::R8_UINT:
+ case Tegra::RenderTargetFormat::R16_UINT:
+ case Tegra::RenderTargetFormat::RG32_UINT:
+ case Tegra::RenderTargetFormat::R32_UINT:
return ComponentType::UInt;
case Tegra::RenderTargetFormat::RG16_SINT:
+ case Tegra::RenderTargetFormat::R16_SINT:
return ComponentType::SInt;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
@@ -452,7 +564,7 @@ struct SurfaceParams {
static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
switch (format) {
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
- return PixelFormat::ABGR8;
+ return PixelFormat::ABGR8U;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
@@ -479,6 +591,10 @@ struct SurfaceParams {
return SurfaceType::ColorTexture;
}
+ if (static_cast<size_t>(pixel_format) < static_cast<size_t>(PixelFormat::MaxDepthFormat)) {
+ return SurfaceType::Depth;
+ }
+
if (static_cast<size_t>(pixel_format) <
static_cast<size_t>(PixelFormat::MaxDepthStencilFormat)) {
return SurfaceType::DepthStencil;
@@ -534,6 +650,12 @@ struct SurfaceParams {
return !operator==(other);
}
+ /// Checks if surfaces are compatible for caching
+ bool IsCompatibleSurface(const SurfaceParams& other) const {
+ return std::tie(pixel_format, type, cache_width, cache_height) ==
+ std::tie(other.pixel_format, other.type, other.cache_width, other.cache_height);
+ }
+
Tegra::GPUVAddr addr;
bool is_tiled;
u32 block_height;
@@ -544,6 +666,10 @@ struct SurfaceParams {
u32 height;
u32 unaligned_height;
size_t size_in_bytes;
+
+ // Parameters used for caching only
+ u32 cache_width;
+ u32 cache_height;
};
class CachedSurface final {
@@ -588,8 +714,7 @@ public:
Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config);
/// Get the color and depth surfaces based on the framebuffer configuration
- SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
- const MathUtil::Rectangle<s32>& viewport);
+ SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb);
/// Flushes the surface to Switch memory
void FlushSurface(const Surface& surface);
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index acf067050..bb01b3c27 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -141,6 +141,15 @@ private:
ExitMethod jmp = Scan(target, end, labels);
return exit_method = ParallelExit(no_jmp, jmp);
}
+ case OpCode::Id::SSY: {
+ // The SSY instruction uses a similar encoding as the BRA instruction.
+ ASSERT_MSG(instr.bra.constant_buffer == 0,
+ "Constant buffer SSY is not supported");
+ u32 target = offset + instr.bra.GetBranchTarget();
+ labels.insert(target);
+ // Continue scanning for an exit method.
+ break;
+ }
}
}
}
@@ -347,35 +356,43 @@ public:
* @param reg The register to use as the source value.
*/
void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
- std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
+ std::string dest = GetOutputAttribute(attribute);
std::string src = GetRegisterAsFloat(reg);
- shader.AddLine(dest + " = " + src + ';');
+
+ if (!dest.empty()) {
+ // Can happen with unknown/unimplemented output attributes, in which case we ignore the
+ // instruction for now.
+ shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';');
+ }
}
/// Generates code representing a uniform (C buffer) register, interpreted as the input type.
- std::string GetUniform(u64 index, u64 offset, GLSLRegister::Type type) {
+ std::string GetUniform(u64 index, u64 offset, GLSLRegister::Type type,
+ Register::Size size = Register::Size::Word) {
declr_const_buffers[index].MarkAsUsed(index, offset, stage);
std::string value = 'c' + std::to_string(index) + '[' + std::to_string(offset / 4) + "][" +
std::to_string(offset % 4) + ']';
if (type == GLSLRegister::Type::Float) {
- return value;
+ // Do nothing, default
} else if (type == GLSLRegister::Type::Integer) {
- return "floatBitsToInt(" + value + ')';
+ value = "floatBitsToInt(" + value + ')';
+ } else if (type == GLSLRegister::Type::UnsignedInteger) {
+ value = "floatBitsToUint(" + value + ')';
} else {
UNREACHABLE();
}
+
+ return ConvertIntegerSize(value, size);
}
- std::string GetUniformIndirect(u64 index, s64 offset, const Register& index_reg,
+ std::string GetUniformIndirect(u64 cbuf_index, s64 offset, const std::string& index_str,
GLSLRegister::Type type) {
- declr_const_buffers[index].MarkAsUsedIndirect(index, stage);
+ declr_const_buffers[cbuf_index].MarkAsUsedIndirect(cbuf_index, stage);
- std::string final_offset = "((floatBitsToInt(" + GetRegister(index_reg, 0) + ") + " +
- std::to_string(offset) + ") / 4)";
-
- std::string value =
- 'c' + std::to_string(index) + '[' + final_offset + " / 4][" + final_offset + " % 4]";
+ std::string final_offset = fmt::format("({} + {})", index_str, offset / 4);
+ std::string value = 'c' + std::to_string(cbuf_index) + '[' + final_offset + " / 4][" +
+ final_offset + " % 4]";
if (type == GLSLRegister::Type::Float) {
return value;
@@ -412,7 +429,6 @@ public:
}
declarations.AddNewLine();
- unsigned const_buffer_layout = 0;
for (const auto& entry : GetConstBuffersDeclarations()) {
declarations.AddLine("layout(std140) uniform " + entry.GetName());
declarations.AddLine('{');
@@ -420,7 +436,6 @@ public:
"[MAX_CONSTBUFFER_ELEMENTS];");
declarations.AddLine("};");
declarations.AddNewLine();
- ++const_buffer_layout;
}
declarations.AddNewLine();
@@ -509,6 +524,8 @@ private:
/// Build the GLSL register list.
void BuildRegisterList() {
+ regs.reserve(Register::NumRegisters);
+
for (size_t index = 0; index < Register::NumRegisters; ++index) {
regs.emplace_back(index, suffix);
}
@@ -524,18 +541,21 @@ private:
// vertex shader, and what's the value of the fourth element when inside a Tess Eval
// shader.
ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex);
- return "vec4(0, 0, uintBitsToFloat(gl_InstanceID), uintBitsToFloat(gl_VertexID))";
+ return "vec4(0, 0, uintBitsToFloat(instance_id.x), uintBitsToFloat(gl_VertexID))";
default:
const u32 index{static_cast<u32>(attribute) -
static_cast<u32>(Attribute::Index::Attribute_0)};
- if (attribute >= Attribute::Index::Attribute_0) {
+ if (attribute >= Attribute::Index::Attribute_0 &&
+ attribute <= Attribute::Index::Attribute_31) {
declr_input_attribute.insert(attribute);
return "input_attribute_" + std::to_string(index);
}
- LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index);
+ LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", static_cast<u32>(attribute));
UNREACHABLE();
}
+
+ return "vec4(0, 0, 0, 0)";
}
/// Generates code representing an output attribute register.
@@ -553,6 +573,7 @@ private:
LOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index);
UNREACHABLE();
+ return {};
}
}
@@ -604,12 +625,12 @@ private:
/// Generates code representing a 19-bit immediate value
static std::string GetImmediate19(const Instruction& instr) {
- return std::to_string(instr.alu.GetImm20_19());
+ return fmt::format("uintBitsToFloat({})", instr.alu.GetImm20_19());
}
/// Generates code representing a 32-bit immediate value
static std::string GetImmediate32(const Instruction& instr) {
- return std::to_string(instr.alu.GetImm20_32());
+ return fmt::format("uintBitsToFloat({})", instr.alu.GetImm20_32());
}
/// Generates code representing a texture sampler.
@@ -652,16 +673,17 @@ private:
* @param instr Instruction to generate the if condition for.
* @returns string containing the predicate condition.
*/
- std::string GetPredicateCondition(u64 index, bool negate) const {
+ std::string GetPredicateCondition(u64 index, bool negate) {
using Tegra::Shader::Pred;
std::string variable;
// Index 7 is used as an 'Always True' condition.
- if (index == static_cast<u64>(Pred::UnusedIndex))
+ if (index == static_cast<u64>(Pred::UnusedIndex)) {
variable = "true";
- else
+ } else {
variable = 'p' + std::to_string(index) + '_' + suffix;
-
+ declr_predicates.insert(variable);
+ }
if (negate) {
return "!(" + variable + ')';
}
@@ -681,10 +703,11 @@ private:
const std::string& op_a, const std::string& op_b) const {
using Tegra::Shader::PredCondition;
static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = {
- {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="},
- {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"},
- {PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="},
- {PredCondition::LessThanWithNan, "<"}, {PredCondition::NotEqualWithNan, "!="},
+ {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="},
+ {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"},
+ {PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="},
+ {PredCondition::LessThanWithNan, "<"}, {PredCondition::NotEqualWithNan, "!="},
+ {PredCondition::GreaterThanWithNan, ">"},
};
const auto& comparison{PredicateComparisonStrings.find(condition)};
@@ -693,7 +716,8 @@ private:
std::string predicate{'(' + op_a + ") " + comparison->second + " (" + op_b + ')'};
if (condition == PredCondition::LessThanWithNan ||
- condition == PredCondition::NotEqualWithNan) {
+ condition == PredCondition::NotEqualWithNan ||
+ condition == PredCondition::GreaterThanWithNan) {
predicate += " || isnan(" + op_a + ") || isnan(" + op_b + ')';
}
@@ -768,13 +792,16 @@ private:
// goes into gpr28+0 and gpr28+1
size_t texs_offset{};
+ size_t src_elem{};
for (const auto& dest : {instr.gpr0.Value(), instr.gpr28.Value()}) {
+ size_t dest_elem{};
for (unsigned elem = 0; elem < 2; ++elem) {
- if (!instr.texs.IsComponentEnabled(elem)) {
+ if (!instr.texs.IsComponentEnabled(src_elem++)) {
// Skip disabled components
continue;
}
- regs.SetRegisterToFloat(dest, elem + texs_offset, texture, 1, 4, false, elem);
+ regs.SetRegisterToFloat(dest, elem + texs_offset, texture, 1, 4, false,
+ dest_elem++);
}
if (!instr.texs.HasTwoDestinations()) {
@@ -817,7 +844,11 @@ private:
ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
"NeverExecute predicate not implemented");
- if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
+ // Some instructions (like SSY) don't have a predicate field, they are always
+ // unconditionally executed.
+ bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->GetId());
+
+ if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
shader.AddLine("if (" +
GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) +
')');
@@ -1221,20 +1252,41 @@ private:
op_a = "abs(" + op_a + ')';
}
+ if (instr.conversion.negate_a) {
+ op_a = "-(" + op_a + ')';
+ }
+
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
1, instr.alu.saturate_d, 0, instr.conversion.dest_size);
break;
}
- case OpCode::Id::I2F_R: {
+ case OpCode::Id::I2F_R:
+ case OpCode::Id::I2F_C: {
ASSERT_MSG(instr.conversion.dest_size == Register::Size::Word, "Unimplemented");
ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
- std::string op_a = regs.GetRegisterAsInteger(
- instr.gpr20, 0, instr.conversion.is_input_signed, instr.conversion.src_size);
+
+ std::string op_a{};
+
+ if (instr.is_b_gpr) {
+ op_a =
+ regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_input_signed,
+ instr.conversion.src_size);
+ } else {
+ op_a = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
+ instr.conversion.is_input_signed
+ ? GLSLRegister::Type::Integer
+ : GLSLRegister::Type::UnsignedInteger,
+ instr.conversion.src_size);
+ }
if (instr.conversion.abs_a) {
op_a = "abs(" + op_a + ')';
}
+ if (instr.conversion.negate_a) {
+ op_a = "-(" + op_a + ')';
+ }
+
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
break;
}
@@ -1243,6 +1295,14 @@ private:
ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented");
std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
+ if (instr.conversion.abs_a) {
+ op_a = "abs(" + op_a + ')';
+ }
+
+ if (instr.conversion.negate_a) {
+ op_a = "-(" + op_a + ')';
+ }
+
switch (instr.conversion.f2f.rounding) {
case Tegra::Shader::F2fRoundingOp::None:
break;
@@ -1265,21 +1325,29 @@ private:
break;
}
- if (instr.conversion.abs_a) {
- op_a = "abs(" + op_a + ')';
- }
-
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
break;
}
- case OpCode::Id::F2I_R: {
+ case OpCode::Id::F2I_R:
+ case OpCode::Id::F2I_C: {
ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented");
- std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
+ std::string op_a{};
+
+ if (instr.is_b_gpr) {
+ op_a = regs.GetRegisterAsFloat(instr.gpr20);
+ } else {
+ op_a = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
+ GLSLRegister::Type::Float);
+ }
if (instr.conversion.abs_a) {
op_a = "abs(" + op_a + ')';
}
+ if (instr.conversion.negate_a) {
+ op_a = "-(" + op_a + ')';
+ }
+
switch (instr.conversion.f2i.rounding) {
case Tegra::Shader::F2iRoundingOp::None:
break;
@@ -1327,11 +1395,16 @@ private:
case OpCode::Id::LD_C: {
ASSERT_MSG(instr.ld_c.unknown == 0, "Unimplemented");
+ // Add an extra scope and declare the index register inside to prevent
+ // overwriting it in case it is used as an output of the LD instruction.
+ shader.AddLine("{");
+ ++shader.scope;
+
+ shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
+ " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);");
+
std::string op_a =
- regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 0, instr.gpr8,
- GLSLRegister::Type::Float);
- std::string op_b =
- regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 4, instr.gpr8,
+ regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 0, "index",
GLSLRegister::Type::Float);
switch (instr.ld_c.type.Value()) {
@@ -1339,16 +1412,22 @@ private:
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
break;
- case Tegra::Shader::UniformType::Double:
+ case Tegra::Shader::UniformType::Double: {
+ std::string op_b =
+ regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 4,
+ "index", GLSLRegister::Type::Float);
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
regs.SetRegisterToFloat(instr.gpr0.Value() + 1, 0, op_b, 1, 1);
break;
-
+ }
default:
LOG_CRITICAL(HW_GPU, "Unhandled type: {}",
static_cast<unsigned>(instr.ld_c.type.Value()));
UNREACHABLE();
}
+
+ --shader.scope;
+ shader.AddLine("}");
break;
}
case OpCode::Id::ST_A: {
@@ -1604,6 +1683,99 @@ private:
}
break;
}
+ case OpCode::Type::Xmad: {
+ ASSERT_MSG(!instr.xmad.sign_a, "Unimplemented");
+ ASSERT_MSG(!instr.xmad.sign_b, "Unimplemented");
+
+ std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)};
+ std::string op_b;
+ std::string op_c;
+
+ // TODO(bunnei): Needs to be fixed once op_a or op_b is signed
+ ASSERT_MSG(instr.xmad.sign_a == instr.xmad.sign_b, "Unimplemented");
+ const bool is_signed{instr.xmad.sign_a == 1};
+
+ bool is_merge{};
+ switch (opcode->GetId()) {
+ case OpCode::Id::XMAD_CR: {
+ is_merge = instr.xmad.merge_56;
+ op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
+ instr.xmad.sign_b ? GLSLRegister::Type::Integer
+ : GLSLRegister::Type::UnsignedInteger);
+ op_c += regs.GetRegisterAsInteger(instr.gpr39, 0, is_signed);
+ break;
+ }
+ case OpCode::Id::XMAD_RR: {
+ is_merge = instr.xmad.merge_37;
+ op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.xmad.sign_b);
+ op_c += regs.GetRegisterAsInteger(instr.gpr39, 0, is_signed);
+ break;
+ }
+ case OpCode::Id::XMAD_RC: {
+ op_b += regs.GetRegisterAsInteger(instr.gpr39, 0, instr.xmad.sign_b);
+ op_c += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
+ is_signed ? GLSLRegister::Type::Integer
+ : GLSLRegister::Type::UnsignedInteger);
+ break;
+ }
+ case OpCode::Id::XMAD_IMM: {
+ is_merge = instr.xmad.merge_37;
+ op_b += std::to_string(instr.xmad.imm20_16);
+ op_c += regs.GetRegisterAsInteger(instr.gpr39, 0, is_signed);
+ break;
+ }
+ default: {
+ LOG_CRITICAL(HW_GPU, "Unhandled XMAD instruction: {}", opcode->GetName());
+ UNREACHABLE();
+ }
+ }
+
+ // TODO(bunnei): Ensure this is right with signed operands
+ if (instr.xmad.high_a) {
+ op_a = "((" + op_a + ") >> 16)";
+ } else {
+ op_a = "((" + op_a + ") & 0xFFFF)";
+ }
+
+ std::string src2 = '(' + op_b + ')'; // Preserve original source 2
+ if (instr.xmad.high_b) {
+ op_b = '(' + src2 + " >> 16)";
+ } else {
+ op_b = '(' + src2 + " & 0xFFFF)";
+ }
+
+ std::string product = '(' + op_a + " * " + op_b + ')';
+ if (instr.xmad.product_shift_left) {
+ product = '(' + product + " << 16)";
+ }
+
+ switch (instr.xmad.mode) {
+ case Tegra::Shader::XmadMode::None:
+ break;
+ case Tegra::Shader::XmadMode::CLo:
+ op_c = "((" + op_c + ") & 0xFFFF)";
+ break;
+ case Tegra::Shader::XmadMode::CHi:
+ op_c = "((" + op_c + ") >> 16)";
+ break;
+ case Tegra::Shader::XmadMode::CBcc:
+ op_c = "((" + op_c + ") + (" + src2 + "<< 16))";
+ break;
+ default: {
+ LOG_CRITICAL(HW_GPU, "Unhandled XMAD mode: {}",
+ static_cast<u32>(instr.xmad.mode.Value()));
+ UNREACHABLE();
+ }
+ }
+
+ std::string sum{'(' + product + " + " + op_c + ')'};
+ if (is_merge) {
+ sum = "((" + sum + " & 0xFFFF) | (" + src2 + "<< 16))";
+ }
+
+ regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1);
+ break;
+ }
default: {
switch (opcode->GetId()) {
case OpCode::Id::EXIT: {
@@ -1641,7 +1813,15 @@ private:
}
case OpCode::Id::KIL: {
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
+
+ // Enclose "discard" in a conditional, so that GLSL compilation does not complain
+ // about unexecuted instructions that may follow this.
+ shader.AddLine("if (true) {");
+ ++shader.scope;
shader.AddLine("discard;");
+ --shader.scope;
+ shader.AddLine("}");
+
break;
}
case OpCode::Id::BRA: {
@@ -1657,16 +1837,25 @@ private:
break;
}
case OpCode::Id::SSY: {
- // The SSY opcode tells the GPU where to re-converge divergent execution paths, we
- // can ignore this when generating GLSL code.
+ // The SSY opcode tells the GPU where to re-converge divergent execution paths, it
+ // sets the target of the jump that the SYNC instruction will make. The SSY opcode
+ // has a similar structure to the BRA opcode.
+ ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported");
+
+ u32 target = offset + instr.bra.GetBranchTarget();
+ shader.AddLine("ssy_target = " + std::to_string(target) + "u;");
break;
}
- case OpCode::Id::SYNC:
+ case OpCode::Id::SYNC: {
+ // The SYNC opcode jumps to the address previously set by the SSY opcode
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
+ shader.AddLine("{ jmp_to = ssy_target; break; }");
+ break;
+ }
case OpCode::Id::DEPBAR: {
- // TODO(Subv): Find out if we actually have to care about these instructions or if
+ // TODO(Subv): Find out if we actually have to care about this instruction or if
// the GLSL compiler takes care of that for us.
- LOG_WARNING(HW_GPU, "DEPBAR/SYNC instruction is stubbed");
+ LOG_WARNING(HW_GPU, "DEPBAR instruction is stubbed");
break;
}
default: {
@@ -1680,7 +1869,7 @@ private:
}
// Close the predicate condition scope.
- if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
+ if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
--shader.scope;
shader.AddLine('}');
}
@@ -1731,6 +1920,7 @@ private:
} else {
labels.insert(subroutine.begin);
shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
+ shader.AddLine("uint ssy_target = 0u;");
shader.AddLine("while (true) {");
++shader.scope;
@@ -1746,7 +1936,7 @@ private:
u32 compile_end = CompileRange(label, next_label);
if (compile_end > next_label && compile_end != PROGRAM_END) {
// This happens only when there is a label inside a IF/LOOP block
- shader.AddLine("{ jmp_to = " + std::to_string(compile_end) + "u; break; }");
+ shader.AddLine(" jmp_to = " + std::to_string(compile_end) + "u; break; }");
labels.emplace(compile_end);
}
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 129c777d1..57e0e1726 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -38,6 +38,7 @@ out vec4 position;
layout (std140) uniform vs_config {
vec4 viewport_flip;
+ uvec4 instance_id;
};
void main() {
@@ -90,6 +91,7 @@ out vec4 color;
layout (std140) uniform fs_config {
vec4 viewport_flip;
+ uvec4 instance_id;
};
void main() {
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index e81fcbbc4..f0886caac 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -13,15 +13,16 @@ namespace Impl {
static void SetShaderUniformBlockBinding(GLuint shader, const char* name,
Maxwell3D::Regs::ShaderStage binding,
size_t expected_size) {
- GLuint ub_index = glGetUniformBlockIndex(shader, name);
- if (ub_index != GL_INVALID_INDEX) {
- GLint ub_size = 0;
- glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size);
- ASSERT_MSG(ub_size == expected_size,
- "Uniform block size did not match! Got {}, expected {}",
- static_cast<int>(ub_size), expected_size);
- glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding));
+ const GLuint ub_index = glGetUniformBlockIndex(shader, name);
+ if (ub_index == GL_INVALID_INDEX) {
+ return;
}
+
+ GLint ub_size = 0;
+ glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size);
+ ASSERT_MSG(static_cast<size_t>(ub_size) == expected_size,
+ "Uniform block size did not match! Got {}, expected {}", ub_size, expected_size);
+ glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding));
}
void SetShaderUniformBlockBindings(GLuint shader) {
@@ -36,11 +37,16 @@ void SetShaderUniformBlockBindings(GLuint shader) {
} // namespace Impl
void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage) {
- const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+ const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
+ const auto& regs = gpu.regs;
+ const auto& state = gpu.state;
// TODO(bunnei): Support more than one viewport
viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f;
viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f;
+
+ // We only assign the instance to the first component of the vector, the rest is just padding.
+ instance_id[0] = state.current_instance;
}
} // namespace GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index e29d551e1..75fa73605 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -24,14 +24,15 @@ void SetShaderUniformBlockBindings(GLuint shader);
} // namespace Impl
/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
-// NOTE: Always keep a vec4 at the end. The GL spec is not clear wether the alignment at
+// NOTE: Always keep a vec4 at the end. The GL spec is not clear whether the alignment at
// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not.
// Not following that rule will cause problems on some AMD drivers.
struct MaxwellUniformData {
void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage);
alignas(16) GLvec4 viewport_flip;
+ alignas(16) GLuvec4 instance_id;
};
-static_assert(sizeof(MaxwellUniformData) == 16, "MaxwellUniformData structure size is incorrect");
+static_assert(sizeof(MaxwellUniformData) == 32, "MaxwellUniformData structure size is incorrect");
static_assert(sizeof(MaxwellUniformData) < 16384,
"MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
@@ -105,20 +106,20 @@ public:
}
ShaderEntries UseProgrammableVertexShader(const MaxwellVSConfig& config,
- const ShaderSetup setup) {
+ const ShaderSetup& setup) {
ShaderEntries result;
std::tie(current.vs, result) = vertex_shaders.Get(config, setup);
return result;
}
ShaderEntries UseProgrammableFragmentShader(const MaxwellFSConfig& config,
- const ShaderSetup setup) {
+ const ShaderSetup& setup) {
ShaderEntries result;
std::tie(current.fs, result) = fragment_shaders.Get(config, setup);
return result;
}
- GLuint GetCurrentProgramStage(Maxwell3D::Regs::ShaderStage stage) {
+ GLuint GetCurrentProgramStage(Maxwell3D::Regs::ShaderStage stage) const {
switch (stage) {
case Maxwell3D::Regs::ShaderStage::Vertex:
return current.vs;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 68bacd4c5..1d1975179 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -203,21 +203,6 @@ void OpenGLState::Apply() const {
}
}
- // Constbuffers
- for (std::size_t stage = 0; stage < draw.const_buffers.size(); ++stage) {
- for (std::size_t buffer_id = 0; buffer_id < draw.const_buffers[stage].size(); ++buffer_id) {
- const auto& current = cur_state.draw.const_buffers[stage][buffer_id];
- const auto& new_state = draw.const_buffers[stage][buffer_id];
-
- if (current.enabled != new_state.enabled || current.bindpoint != new_state.bindpoint ||
- current.ssbo != new_state.ssbo) {
- if (new_state.enabled) {
- glBindBufferBase(GL_UNIFORM_BUFFER, new_state.bindpoint, new_state.ssbo);
- }
- }
- }
- }
-
// Framebuffer
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 3398d7c04..bdb02ba25 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -7,6 +7,10 @@
#include <array>
#include <glad/glad.h>
+#include "video_core/engines/maxwell_3d.h"
+
+using Regs = Tegra::Engines::Maxwell3D::Regs;
+
namespace TextureUnits {
struct TextureUnit {
@@ -82,7 +86,7 @@ public:
GLenum logic_op; // GL_LOGIC_OP_MODE
// 3 texture units - one for each that is used in PICA fragment shader emulation
- struct {
+ struct TextureUnit {
GLuint texture_2d; // GL_TEXTURE_BINDING_2D
GLuint sampler; // GL_SAMPLER_BINDING
struct {
@@ -104,7 +108,8 @@ public:
Unbind();
sampler = 0;
}
- } texture_units[32];
+ };
+ std::array<TextureUnit, 32> texture_units;
struct {
GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
@@ -114,12 +119,6 @@ public:
GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING
GLuint shader_program; // GL_CURRENT_PROGRAM
GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
- struct ConstBufferConfig {
- bool enabled = false;
- GLuint bindpoint;
- GLuint ssbo;
- };
- std::array<std::array<ConstBufferConfig, 16>, 5> const_buffers{};
} draw;
struct {
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index a2713e9f0..03a8ed8b7 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -9,174 +9,91 @@
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_stream_buffer.h"
-class OrphanBuffer : public OGLStreamBuffer {
-public:
- explicit OrphanBuffer(GLenum target) : OGLStreamBuffer(target) {}
- ~OrphanBuffer() override;
-
-private:
- void Create(size_t size, size_t sync_subdivide) override;
- void Release() override;
-
- std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
- void Unmap() override;
-
- std::vector<u8> data;
-};
-
-class StorageBuffer : public OGLStreamBuffer {
-public:
- explicit StorageBuffer(GLenum target) : OGLStreamBuffer(target) {}
- ~StorageBuffer() override;
-
-private:
- void Create(size_t size, size_t sync_subdivide) override;
- void Release() override;
-
- std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
- void Unmap() override;
-
- struct Fence {
- OGLSync sync;
- size_t offset;
- };
- std::deque<Fence> head;
- std::deque<Fence> tail;
-
- u8* mapped_ptr;
-};
-
-OGLStreamBuffer::OGLStreamBuffer(GLenum target) {
- gl_target = target;
-}
-
-GLuint OGLStreamBuffer::GetHandle() const {
- return gl_buffer.handle;
-}
+OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent)
+ : gl_target(target), buffer_size(size) {
+ gl_buffer.Create();
+ glBindBuffer(gl_target, gl_buffer.handle);
-std::unique_ptr<OGLStreamBuffer> OGLStreamBuffer::MakeBuffer(bool storage_buffer, GLenum target) {
- if (storage_buffer) {
- return std::make_unique<StorageBuffer>(target);
+ GLsizeiptr allocate_size = size;
+ if (target == GL_ARRAY_BUFFER) {
+ // On AMD GPU there is a strange crash in indexed drawing. The crash happens when the buffer
+ // read position is near the end and is an out-of-bound access to the vertex buffer. This is
+ // probably a bug in the driver and is related to the usage of vec3<byte> attributes in the
+ // vertex array. Doubling the allocation size for the vertex buffer seems to avoid the
+ // crash.
+ allocate_size *= 2;
}
- return std::make_unique<OrphanBuffer>(target);
-}
-OrphanBuffer::~OrphanBuffer() {
- Release();
+ if (GLAD_GL_ARB_buffer_storage) {
+ persistent = true;
+ coherent = prefer_coherent;
+ GLbitfield flags =
+ GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0);
+ glBufferStorage(gl_target, allocate_size, nullptr, flags);
+ mapped_ptr = static_cast<u8*>(glMapBufferRange(
+ gl_target, 0, buffer_size, flags | (coherent ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)));
+ } else {
+ glBufferData(gl_target, allocate_size, nullptr, GL_STREAM_DRAW);
+ }
}
-void OrphanBuffer::Create(size_t size, size_t /*sync_subdivide*/) {
- buffer_pos = 0;
- buffer_size = size;
- data.resize(buffer_size);
-
- if (gl_buffer.handle == 0) {
- gl_buffer.Create();
+OGLStreamBuffer::~OGLStreamBuffer() {
+ if (persistent) {
glBindBuffer(gl_target, gl_buffer.handle);
+ glUnmapBuffer(gl_target);
}
-
- glBufferData(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, GL_STREAM_DRAW);
-}
-
-void OrphanBuffer::Release() {
gl_buffer.Release();
}
-std::pair<u8*, GLintptr> OrphanBuffer::Map(size_t size, size_t alignment) {
- buffer_pos = Common::AlignUp(buffer_pos, alignment);
-
- if (buffer_pos + size > buffer_size) {
- Create(std::max(buffer_size, size), 0);
- }
-
- mapped_size = size;
- return std::make_pair(&data[buffer_pos], static_cast<GLintptr>(buffer_pos));
-}
-
-void OrphanBuffer::Unmap() {
- glBufferSubData(gl_target, static_cast<GLintptr>(buffer_pos),
- static_cast<GLsizeiptr>(mapped_size), &data[buffer_pos]);
- buffer_pos += mapped_size;
-}
-
-StorageBuffer::~StorageBuffer() {
- Release();
+GLuint OGLStreamBuffer::GetHandle() const {
+ return gl_buffer.handle;
}
-void StorageBuffer::Create(size_t size, size_t sync_subdivide) {
- if (gl_buffer.handle != 0)
- return;
-
- buffer_pos = 0;
- buffer_size = size;
- buffer_sync_subdivide = std::max<size_t>(sync_subdivide, 1);
-
- gl_buffer.Create();
- glBindBuffer(gl_target, gl_buffer.handle);
-
- glBufferStorage(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr,
- GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
- mapped_ptr = reinterpret_cast<u8*>(
- glMapBufferRange(gl_target, 0, static_cast<GLsizeiptr>(buffer_size),
- GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
+GLsizeiptr OGLStreamBuffer::GetSize() const {
+ return buffer_size;
}
-void StorageBuffer::Release() {
- if (gl_buffer.handle == 0)
- return;
-
- glUnmapBuffer(gl_target);
-
- gl_buffer.Release();
- head.clear();
- tail.clear();
-}
-
-std::pair<u8*, GLintptr> StorageBuffer::Map(size_t size, size_t alignment) {
+std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr alignment) {
ASSERT(size <= buffer_size);
+ ASSERT(alignment <= buffer_size);
+ mapped_size = size;
- OGLSync sync;
-
- buffer_pos = Common::AlignUp(buffer_pos, alignment);
- size_t effective_offset = Common::AlignDown(buffer_pos, buffer_sync_subdivide);
-
- if (!head.empty() &&
- (effective_offset > head.back().offset || buffer_pos + size > buffer_size)) {
- ASSERT(head.back().sync.handle == 0);
- head.back().sync.Create();
+ if (alignment > 0) {
+ buffer_pos = Common::AlignUp<size_t>(buffer_pos, alignment);
}
+ bool invalidate = false;
if (buffer_pos + size > buffer_size) {
- if (!tail.empty()) {
- std::swap(sync, tail.back().sync);
- tail.clear();
- }
- std::swap(tail, head);
buffer_pos = 0;
- effective_offset = 0;
- }
+ invalidate = true;
- while (!tail.empty() && buffer_pos + size > tail.front().offset) {
- std::swap(sync, tail.front().sync);
- tail.pop_front();
+ if (persistent) {
+ glUnmapBuffer(gl_target);
+ }
}
- if (sync.handle != 0) {
- glClientWaitSync(sync.handle, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
- sync.Release();
+ if (invalidate | !persistent) {
+ GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
+ (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
+ (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
+ mapped_ptr = static_cast<u8*>(
+ glMapBufferRange(gl_target, buffer_pos, buffer_size - buffer_pos, flags));
+ mapped_offset = buffer_pos;
}
- if (head.empty() || effective_offset > head.back().offset) {
- head.emplace_back();
- head.back().offset = effective_offset;
+ return std::make_tuple(mapped_ptr + buffer_pos - mapped_offset, buffer_pos, invalidate);
+}
+
+void OGLStreamBuffer::Unmap(GLsizeiptr size) {
+ ASSERT(size <= mapped_size);
+
+ if (!coherent && size > 0) {
+ glFlushMappedBufferRange(gl_target, buffer_pos - mapped_offset, size);
}
- mapped_size = size;
- return std::make_pair(&mapped_ptr[buffer_pos], static_cast<GLintptr>(buffer_pos));
-}
+ if (!persistent) {
+ glUnmapBuffer(gl_target);
+ }
-void StorageBuffer::Unmap() {
- glFlushMappedBufferRange(gl_target, static_cast<GLintptr>(buffer_pos),
- static_cast<GLsizeiptr>(mapped_size));
- buffer_pos += mapped_size;
+ buffer_pos += size;
}
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.h b/src/video_core/renderer_opengl/gl_stream_buffer.h
index e78dc5784..45592daaf 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.h
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.h
@@ -2,35 +2,41 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#pragma once
-
-#include <memory>
+#include <tuple>
#include <glad/glad.h>
#include "common/common_types.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
class OGLStreamBuffer : private NonCopyable {
public:
- explicit OGLStreamBuffer(GLenum target);
- virtual ~OGLStreamBuffer() = default;
-
-public:
- static std::unique_ptr<OGLStreamBuffer> MakeBuffer(bool storage_buffer, GLenum target);
-
- virtual void Create(size_t size, size_t sync_subdivide) = 0;
- virtual void Release() {}
+ explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent = false);
+ ~OGLStreamBuffer();
GLuint GetHandle() const;
+ GLsizeiptr GetSize() const;
+
+ /*
+ * Allocates a linear chunk of memory in the GPU buffer with at least "size" bytes
+ * and the optional alignment requirement.
+ * If the buffer is full, the whole buffer is reallocated which invalidates old chunks.
+ * The return values are the pointer to the new chunk, the offset within the buffer,
+ * and the invalidation flag for previous chunks.
+ * The actual used size must be specified on unmapping the chunk.
+ */
+ std::tuple<u8*, GLintptr, bool> Map(GLsizeiptr size, GLintptr alignment = 0);
- virtual std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) = 0;
- virtual void Unmap() = 0;
+ void Unmap(GLsizeiptr size);
-protected:
+private:
OGLBuffer gl_buffer;
GLenum gl_target;
- size_t buffer_pos = 0;
- size_t buffer_size = 0;
- size_t buffer_sync_subdivide = 0;
- size_t mapped_size = 0;
+ bool coherent = false;
+ bool persistent = false;
+
+ GLintptr buffer_pos = 0;
+ GLsizeiptr buffer_size = 0;
+ GLintptr mapped_offset = 0;
+ GLsizeiptr mapped_size = 0;
+ u8* mapped_ptr = nullptr;
};
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 16b1bd606..8f719fdd8 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -24,13 +24,25 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
switch (attrib.type) {
+ case Maxwell::VertexAttribute::Type::UnsignedInt:
case Maxwell::VertexAttribute::Type::UnsignedNorm: {
switch (attrib.size) {
+ case Maxwell::VertexAttribute::Size::Size_8:
+ case Maxwell::VertexAttribute::Size::Size_8_8:
+ case Maxwell::VertexAttribute::Size::Size_8_8_8:
case Maxwell::VertexAttribute::Size::Size_8_8_8_8:
return GL_UNSIGNED_BYTE;
+ case Maxwell::VertexAttribute::Size::Size_16:
case Maxwell::VertexAttribute::Size::Size_16_16:
+ case Maxwell::VertexAttribute::Size::Size_16_16_16:
+ case Maxwell::VertexAttribute::Size::Size_16_16_16_16:
return GL_UNSIGNED_SHORT;
+ case Maxwell::VertexAttribute::Size::Size_32:
+ case Maxwell::VertexAttribute::Size::Size_32_32:
+ case Maxwell::VertexAttribute::Size::Size_32_32_32:
+ case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
+ return GL_UNSIGNED_INT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return GL_UNSIGNED_INT_2_10_10_10_REV;
}
@@ -40,13 +52,25 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
return {};
}
+ case Maxwell::VertexAttribute::Type::SignedInt:
case Maxwell::VertexAttribute::Type::SignedNorm: {
switch (attrib.size) {
+ case Maxwell::VertexAttribute::Size::Size_8:
+ case Maxwell::VertexAttribute::Size::Size_8_8:
+ case Maxwell::VertexAttribute::Size::Size_8_8_8:
case Maxwell::VertexAttribute::Size::Size_8_8_8_8:
return GL_BYTE;
+ case Maxwell::VertexAttribute::Size::Size_16:
case Maxwell::VertexAttribute::Size::Size_16_16:
+ case Maxwell::VertexAttribute::Size::Size_16_16_16:
+ case Maxwell::VertexAttribute::Size::Size_16_16_16_16:
return GL_SHORT;
+ case Maxwell::VertexAttribute::Size::Size_32:
+ case Maxwell::VertexAttribute::Size::Size_32_32:
+ case Maxwell::VertexAttribute::Size::Size_32_32_32:
+ case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
+ return GL_INT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return GL_INT_2_10_10_10_REV;
}
@@ -56,9 +80,6 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
return {};
}
- case Maxwell::VertexAttribute::Type::UnsignedInt:
- return GL_UNSIGNED_INT;
-
case Maxwell::VertexAttribute::Type::Float:
return GL_FLOAT;
}
@@ -84,6 +105,10 @@ inline GLenum IndexFormat(Maxwell::IndexFormat index_format) {
inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
switch (topology) {
+ case Maxwell::PrimitiveTopology::Points:
+ return GL_POINTS;
+ case Maxwell::PrimitiveTopology::LineStrip:
+ return GL_LINE_STRIP;
case Maxwell::PrimitiveTopology::Triangles:
return GL_TRIANGLES;
case Maxwell::PrimitiveTopology::TriangleStrip:
@@ -149,42 +174,61 @@ inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
switch (factor) {
case Maxwell::Blend::Factor::Zero:
+ case Maxwell::Blend::Factor::ZeroGL:
return GL_ZERO;
case Maxwell::Blend::Factor::One:
+ case Maxwell::Blend::Factor::OneGL:
return GL_ONE;
case Maxwell::Blend::Factor::SourceColor:
+ case Maxwell::Blend::Factor::SourceColorGL:
return GL_SRC_COLOR;
case Maxwell::Blend::Factor::OneMinusSourceColor:
+ case Maxwell::Blend::Factor::OneMinusSourceColorGL:
return GL_ONE_MINUS_SRC_COLOR;
case Maxwell::Blend::Factor::SourceAlpha:
+ case Maxwell::Blend::Factor::SourceAlphaGL:
return GL_SRC_ALPHA;
case Maxwell::Blend::Factor::OneMinusSourceAlpha:
+ case Maxwell::Blend::Factor::OneMinusSourceAlphaGL:
return GL_ONE_MINUS_SRC_ALPHA;
case Maxwell::Blend::Factor::DestAlpha:
+ case Maxwell::Blend::Factor::DestAlphaGL:
return GL_DST_ALPHA;
case Maxwell::Blend::Factor::OneMinusDestAlpha:
+ case Maxwell::Blend::Factor::OneMinusDestAlphaGL:
return GL_ONE_MINUS_DST_ALPHA;
case Maxwell::Blend::Factor::DestColor:
+ case Maxwell::Blend::Factor::DestColorGL:
return GL_DST_COLOR;
case Maxwell::Blend::Factor::OneMinusDestColor:
+ case Maxwell::Blend::Factor::OneMinusDestColorGL:
return GL_ONE_MINUS_DST_COLOR;
case Maxwell::Blend::Factor::SourceAlphaSaturate:
+ case Maxwell::Blend::Factor::SourceAlphaSaturateGL:
return GL_SRC_ALPHA_SATURATE;
case Maxwell::Blend::Factor::Source1Color:
+ case Maxwell::Blend::Factor::Source1ColorGL:
return GL_SRC1_COLOR;
case Maxwell::Blend::Factor::OneMinusSource1Color:
+ case Maxwell::Blend::Factor::OneMinusSource1ColorGL:
return GL_ONE_MINUS_SRC1_COLOR;
case Maxwell::Blend::Factor::Source1Alpha:
+ case Maxwell::Blend::Factor::Source1AlphaGL:
return GL_SRC1_ALPHA;
case Maxwell::Blend::Factor::OneMinusSource1Alpha:
+ case Maxwell::Blend::Factor::OneMinusSource1AlphaGL:
return GL_ONE_MINUS_SRC1_ALPHA;
case Maxwell::Blend::Factor::ConstantColor:
+ case Maxwell::Blend::Factor::ConstantColorGL:
return GL_CONSTANT_COLOR;
case Maxwell::Blend::Factor::OneMinusConstantColor:
+ case Maxwell::Blend::Factor::OneMinusConstantColorGL:
return GL_ONE_MINUS_CONSTANT_COLOR;
case Maxwell::Blend::Factor::ConstantAlpha:
+ case Maxwell::Blend::Factor::ConstantAlphaGL:
return GL_CONSTANT_ALPHA;
case Maxwell::Blend::Factor::OneMinusConstantAlpha:
+ case Maxwell::Blend::Factor::OneMinusConstantAlphaGL:
return GL_ONE_MINUS_CONSTANT_ALPHA;
}
LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 7810b9147..bf30eda6d 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -18,7 +18,6 @@
#include "core/tracer/recorder.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/utils.h"
-#include "video_core/video_core.h"
static const char vertex_shader[] = R"(
#version 150 core
@@ -92,23 +91,26 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
return matrix;
}
-ScopeAcquireGLContext::ScopeAcquireGLContext() {
+ScopeAcquireGLContext::ScopeAcquireGLContext(Core::Frontend::EmuWindow& emu_window_)
+ : emu_window{emu_window_} {
if (Settings::values.use_multi_core) {
- VideoCore::g_emu_window->MakeCurrent();
+ emu_window.MakeCurrent();
}
}
ScopeAcquireGLContext::~ScopeAcquireGLContext() {
if (Settings::values.use_multi_core) {
- VideoCore::g_emu_window->DoneCurrent();
+ emu_window.DoneCurrent();
}
}
-RendererOpenGL::RendererOpenGL() = default;
+RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& window)
+ : VideoCore::RendererBase{window} {}
+
RendererOpenGL::~RendererOpenGL() = default;
/// Swap buffers (render frame)
void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) {
- ScopeAcquireGLContext acquire_context;
+ ScopeAcquireGLContext acquire_context{render_window};
Core::System::GetInstance().perf_stats.EndSystemFrame();
@@ -130,10 +132,10 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&
// Load the framebuffer from memory, draw it to the screen, and swap buffers
LoadFBToScreenInfo(*framebuffer, screen_info);
DrawScreen();
- render_window->SwapBuffers();
+ render_window.SwapBuffers();
}
- render_window->PollEvents();
+ render_window.PollEvents();
Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs());
Core::System::GetInstance().perf_stats.BeginSystemFrame();
@@ -160,8 +162,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
// only allows rows to have a memory alignement of 4.
ASSERT(framebuffer.stride % 4 == 0);
- if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride,
- screen_info)) {
+ if (!rasterizer->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride,
+ screen_info)) {
// Reset the screen info's display texture to its own permanent texture
screen_info.display_texture = screen_info.texture.resource.handle;
@@ -356,7 +358,7 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
* Draws the emulated screens to the emulator window.
*/
void RendererOpenGL::DrawScreen() {
- const auto& layout = render_window->GetFramebufferLayout();
+ const auto& layout = render_window.GetFramebufferLayout();
const auto& screen = layout.screen;
glViewport(0, 0, layout.width, layout.height);
@@ -380,14 +382,6 @@ void RendererOpenGL::DrawScreen() {
/// Updates the framerate
void RendererOpenGL::UpdateFramerate() {}
-/**
- * Set the emulator window to use for renderer
- * @param window EmuWindow handle to emulator window to use for rendering
- */
-void RendererOpenGL::SetWindow(EmuWindow* window) {
- render_window = window;
-}
-
static const char* GetSource(GLenum source) {
#define RET(s) \
case GL_DEBUG_SOURCE_##s: \
@@ -431,21 +425,21 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
- LOG_ERROR(Render_OpenGL, format, str_source, str_type, id, message);
+ LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message);
break;
case GL_DEBUG_SEVERITY_MEDIUM:
LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message);
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
case GL_DEBUG_SEVERITY_LOW:
- LOG_DEBUG(Render_OpenGL, format, str_source, str_type, id, message);
+ LOG_TRACE(Render_OpenGL, format, str_source, str_type, id, message);
break;
}
}
/// Initialize the renderer
bool RendererOpenGL::Init() {
- ScopeAcquireGLContext acquire_context;
+ ScopeAcquireGLContext acquire_context{render_window};
if (GLAD_GL_KHR_debug) {
glEnable(GL_DEBUG_OUTPUT);
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 59d92a3dc..a5eab6997 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -12,7 +12,9 @@
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_state.h"
+namespace Core::Frontend {
class EmuWindow;
+}
/// Structure used for storing information about the textures for the Switch screen
struct TextureInfo {
@@ -34,24 +36,21 @@ struct ScreenInfo {
/// Helper class to acquire/release OpenGL context within a given scope
class ScopeAcquireGLContext : NonCopyable {
public:
- ScopeAcquireGLContext();
+ explicit ScopeAcquireGLContext(Core::Frontend::EmuWindow& window);
~ScopeAcquireGLContext();
+
+private:
+ Core::Frontend::EmuWindow& emu_window;
};
-class RendererOpenGL : public RendererBase {
+class RendererOpenGL : public VideoCore::RendererBase {
public:
- RendererOpenGL();
+ explicit RendererOpenGL(Core::Frontend::EmuWindow& window);
~RendererOpenGL() override;
/// Swap buffers (render frame)
void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) override;
- /**
- * Set the emulator window to use for renderer
- * @param window EmuWindow handle to emulator window to use for rendering
- */
- void SetWindow(EmuWindow* window) override;
-
/// Initialize the renderer
bool Init() override;
@@ -72,8 +71,6 @@ private:
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
const TextureInfo& texture);
- EmuWindow* render_window; ///< Handle to render window
-
OpenGLState state;
// OpenGL object IDs
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index d794f8402..70746a34e 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -54,9 +54,12 @@ u32 BytesPerPixel(TextureFormat format) {
return 8;
case TextureFormat::DXT23:
case TextureFormat::DXT45:
+ case TextureFormat::DXN2:
case TextureFormat::BC7U:
// In this case a 'pixel' actually refers to a 4x4 tile.
return 16;
+ case TextureFormat::R32_G32_B32:
+ return 12;
case TextureFormat::ASTC_2D_4X4:
case TextureFormat::A8R8G8B8:
case TextureFormat::A2B10G10R10:
@@ -83,86 +86,11 @@ u32 BytesPerPixel(TextureFormat format) {
}
}
-static u32 DepthBytesPerPixel(DepthFormat format) {
- switch (format) {
- case DepthFormat::Z16_UNORM:
- return 2;
- case DepthFormat::S8_Z24_UNORM:
- case DepthFormat::Z24_S8_UNORM:
- case DepthFormat::Z32_FLOAT:
- return 4;
- case DepthFormat::Z32_S8_X24_FLOAT:
- return 8;
- default:
- UNIMPLEMENTED_MSG("Format not implemented");
- break;
- }
-}
-
-std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
- u32 block_height) {
- u8* data = Memory::GetPointer(address);
- u32 bytes_per_pixel = BytesPerPixel(format);
-
- std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
-
- switch (format) {
- case TextureFormat::DXT1:
- case TextureFormat::DXT23:
- case TextureFormat::DXT45:
- case TextureFormat::DXN1:
- case TextureFormat::BC7U:
- // In the DXT and DXN formats, each 4x4 tile is swizzled instead of just individual pixel
- // values.
- CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data,
- unswizzled_data.data(), true, block_height);
- break;
- case TextureFormat::A8R8G8B8:
- case TextureFormat::A2B10G10R10:
- case TextureFormat::A1B5G5R5:
- case TextureFormat::B5G6R5:
- case TextureFormat::R8:
- case TextureFormat::G8R8:
- case TextureFormat::R16_G16_B16_A16:
- case TextureFormat::R32_G32_B32_A32:
- case TextureFormat::R32_G32:
- case TextureFormat::R32:
- case TextureFormat::R16:
- case TextureFormat::R16_G16:
- case TextureFormat::BF10GF11RF11:
- case TextureFormat::ASTC_2D_4X4:
- CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
- unswizzled_data.data(), true, block_height);
- break;
- default:
- UNIMPLEMENTED_MSG("Format not implemented");
- break;
- }
-
- return unswizzled_data;
-}
-
-std::vector<u8> UnswizzleDepthTexture(VAddr address, DepthFormat format, u32 width, u32 height,
- u32 block_height) {
- u8* data = Memory::GetPointer(address);
- u32 bytes_per_pixel = DepthBytesPerPixel(format);
-
+std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
+ u32 height, u32 block_height) {
std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
-
- switch (format) {
- case DepthFormat::Z16_UNORM:
- case DepthFormat::S8_Z24_UNORM:
- case DepthFormat::Z24_S8_UNORM:
- case DepthFormat::Z32_FLOAT:
- case DepthFormat::Z32_S8_X24_FLOAT:
- CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
- unswizzled_data.data(), true, block_height);
- break;
- default:
- UNIMPLEMENTED_MSG("Format not implemented");
- break;
- }
-
+ CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
+ Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
return unswizzled_data;
}
@@ -176,6 +104,7 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
case TextureFormat::DXT23:
case TextureFormat::DXT45:
case TextureFormat::DXN1:
+ case TextureFormat::DXN2:
case TextureFormat::BC7U:
case TextureFormat::ASTC_2D_4X4:
case TextureFormat::A8R8G8B8:
@@ -190,6 +119,7 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
case TextureFormat::R32:
case TextureFormat::R16:
case TextureFormat::R16_G16:
+ case TextureFormat::R32_G32_B32:
// TODO(Subv): For the time being just forward the same data without any decoding.
rgba_data = texture_data;
break;
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index 73a4924d1..1f7b731be 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -13,8 +13,8 @@ namespace Tegra::Texture {
/**
* Unswizzles a swizzled texture without changing its format.
*/
-std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
- u32 block_height = TICEntry::DefaultBlockHeight);
+std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
+ u32 height, u32 block_height = TICEntry::DefaultBlockHeight);
/**
* Unswizzles a swizzled depth texture without changing its format.
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 289140f31..6780d1c16 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -3,40 +3,14 @@
// Refer to the license.txt file included.
#include <memory>
-#include "common/logging/log.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/video_core.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Video Core namespace
-
namespace VideoCore {
-EmuWindow* g_emu_window = nullptr; ///< Frontend emulator window
-std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin
-
-std::atomic<bool> g_toggle_framelimit_enabled;
-
-/// Initialize the video core
-bool Init(EmuWindow* emu_window) {
- g_emu_window = emu_window;
- g_renderer = std::make_unique<RendererOpenGL>();
- g_renderer->SetWindow(g_emu_window);
- if (g_renderer->Init()) {
- LOG_DEBUG(Render, "initialized OK");
- } else {
- LOG_CRITICAL(Render, "initialization failed !");
- return false;
- }
- return true;
-}
-
-/// Shutdown the video core
-void Shutdown() {
- g_renderer.reset();
-
- LOG_DEBUG(Render, "shutdown OK");
+std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window) {
+ return std::make_unique<RendererOpenGL>(emu_window);
}
} // namespace VideoCore
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 37da62436..f79f85dfe 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -4,33 +4,22 @@
#pragma once
-#include <atomic>
#include <memory>
+namespace Core::Frontend {
class EmuWindow;
-class RendererBase;
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Video Core namespace
+}
namespace VideoCore {
-enum class Renderer { Software, OpenGL };
-
-extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin
-extern EmuWindow* g_emu_window; ///< Emu window
-
-// TODO: Wrap these in a user settings struct along with any other graphics settings (often set from
-// qt ui)
-extern std::atomic<bool> g_toggle_framelimit_enabled;
-
-/// Start the video core
-void Start();
-
-/// Initialize the video core
-bool Init(EmuWindow* emu_window);
+class RendererBase;
-/// Shutdown the video core
-void Shutdown();
+/**
+ * Creates a renderer instance.
+ *
+ * @note The returned renderer instance is simply allocated. Its Init()
+ * function still needs to be called to fully complete its setup.
+ */
+std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window);
} // namespace VideoCore
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 7de919a8e..46ed232d8 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -11,10 +11,14 @@ add_executable(yuzu
bootmanager.h
configuration/config.cpp
configuration/config.h
+ configuration/configure_audio.cpp
+ configuration/configure_audio.h
configuration/configure_debug.cpp
configuration/configure_debug.h
configuration/configure_dialog.cpp
configuration/configure_dialog.h
+ configuration/configure_gamelist.cpp
+ configuration/configure_gamelist.h
configuration/configure_general.cpp
configuration/configure_general.h
configuration/configure_graphics.cpp
@@ -55,7 +59,9 @@ add_executable(yuzu
set(UIS
aboutdialog.ui
configuration/configure.ui
+ configuration/configure_audio.ui
configuration/configure_debug.ui
+ configuration/configure_gamelist.ui
configuration/configure_general.ui
configuration/configure_graphics.ui
configuration/configure_input.ui
diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp
index d6647eeea..a81ad2888 100644
--- a/src/yuzu/about_dialog.cpp
+++ b/src/yuzu/about_dialog.cpp
@@ -10,8 +10,9 @@
AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) {
ui->setupUi(this);
ui->labelLogo->setPixmap(QIcon::fromTheme("yuzu").pixmap(200));
- ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg(
- Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc));
+ ui->labelBuildInfo->setText(
+ ui->labelBuildInfo->text().arg(Common::g_build_name, Common::g_scm_branch,
+ Common::g_scm_desc, QString(Common::g_build_date).left(10)));
}
-AboutDialog::~AboutDialog() {}
+AboutDialog::~AboutDialog() = default;
diff --git a/src/yuzu/about_dialog.h b/src/yuzu/about_dialog.h
index 2eb6e28f5..18e8c11a7 100644
--- a/src/yuzu/about_dialog.h
+++ b/src/yuzu/about_dialog.h
@@ -16,7 +16,7 @@ class AboutDialog : public QDialog {
public:
explicit AboutDialog(QWidget* parent);
- ~AboutDialog();
+ ~AboutDialog() override;
private:
std::unique_ptr<Ui::AboutDialog> ui;
diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui
index 2680480cc..f122ba39d 100644
--- a/src/yuzu/aboutdialog.ui
+++ b/src/yuzu/aboutdialog.ui
@@ -70,7 +70,7 @@
</sizepolicy>
</property>
<property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@@ -115,7 +115,7 @@ p, li { white-space: pre-wrap; }
<item>
<widget class="QLabel" name="labelLinks">
<property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Website&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Source Code&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/graphs/contributors&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;Contributors&lt;/span&gt;&lt;/a&gt; | &lt;a href=&quot;https://github.com/yuzu-emu/yuzu/blob/master/license.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;License&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 130bc613b..f133bfadf 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -101,12 +101,12 @@ signals:
void ErrorThrown(Core::System::ResultStatus, std::string);
};
-class GRenderWindow : public QWidget, public EmuWindow {
+class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
Q_OBJECT
public:
GRenderWindow(QWidget* parent, EmuThread* emu_thread);
- ~GRenderWindow();
+ ~GRenderWindow() override;
// EmuWindow implementation
void SwapBuffers() override;
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 98969fe10..0bd46dbac 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -92,16 +92,26 @@ void Config::ReadValues() {
Settings::values.bg_blue = qt_config->value("bg_blue", 0.0).toFloat();
qt_config->endGroup();
+ qt_config->beginGroup("Audio");
+ Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
+ Settings::values.audio_device_id =
+ qt_config->value("output_device", "auto").toString().toStdString();
+ Settings::values.volume = qt_config->value("volume", 1).toFloat();
+ qt_config->endGroup();
+
qt_config->beginGroup("Data Storage");
Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
qt_config->endGroup();
qt_config->beginGroup("System");
Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool();
+ Settings::values.username = qt_config->value("username", "yuzu").toString().toStdString();
+ Settings::values.language_index = qt_config->value("language_index", 1).toInt();
qt_config->endGroup();
qt_config->beginGroup("Miscellaneous");
Settings::values.log_filter = qt_config->value("log_filter", "*:Info").toString().toStdString();
+ Settings::values.use_dev_keys = qt_config->value("use_dev_keys", false).toBool();
qt_config->endGroup();
qt_config->beginGroup("Debugging");
@@ -112,6 +122,13 @@ void Config::ReadValues() {
qt_config->beginGroup("UI");
UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString();
+ qt_config->beginGroup("UIGameList");
+ UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool();
+ UISettings::values.icon_size = qt_config->value("icon_size", 48).toUInt();
+ UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 0).toUInt();
+ UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 3).toUInt();
+ qt_config->endGroup();
+
qt_config->beginGroup("UILayout");
UISettings::values.geometry = qt_config->value("geometry").toByteArray();
UISettings::values.state = qt_config->value("state").toByteArray();
@@ -195,16 +212,25 @@ void Config::SaveValues() {
qt_config->setValue("bg_blue", (double)Settings::values.bg_blue);
qt_config->endGroup();
+ qt_config->beginGroup("Audio");
+ qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
+ qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id));
+ qt_config->setValue("volume", Settings::values.volume);
+ qt_config->endGroup();
+
qt_config->beginGroup("Data Storage");
qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
qt_config->endGroup();
qt_config->beginGroup("System");
qt_config->setValue("use_docked_mode", Settings::values.use_docked_mode);
+ qt_config->setValue("username", QString::fromStdString(Settings::values.username));
+ qt_config->setValue("language_index", Settings::values.language_index);
qt_config->endGroup();
qt_config->beginGroup("Miscellaneous");
qt_config->setValue("log_filter", QString::fromStdString(Settings::values.log_filter));
+ qt_config->setValue("use_dev_keys", Settings::values.use_dev_keys);
qt_config->endGroup();
qt_config->beginGroup("Debugging");
@@ -215,6 +241,13 @@ void Config::SaveValues() {
qt_config->beginGroup("UI");
qt_config->setValue("theme", UISettings::values.theme);
+ qt_config->beginGroup("UIGameList");
+ qt_config->setValue("show_unknown", UISettings::values.show_unknown);
+ qt_config->setValue("icon_size", UISettings::values.icon_size);
+ qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id);
+ qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id);
+ qt_config->endGroup();
+
qt_config->beginGroup("UILayout");
qt_config->setValue("geometry", UISettings::values.geometry);
qt_config->setValue("state", UISettings::values.state);
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index c5303851c..20f120134 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -24,6 +24,11 @@
<string>General</string>
</attribute>
</widget>
+ <widget class="ConfigureGameList" name="gameListTab">
+ <attribute name="title">
+ <string>Game List</string>
+ </attribute>
+ </widget>
<widget class="ConfigureSystem" name="systemTab">
<attribute name="title">
<string>System</string>
@@ -34,11 +39,16 @@
<string>Input</string>
</attribute>
</widget>
- <widget class="ConfigureGraphics" name="graphicsTab">
- <attribute name="title">
- <string>Graphics</string>
- </attribute>
- </widget>
+ <widget class="ConfigureGraphics" name="graphicsTab">
+ <attribute name="title">
+ <string>Graphics</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureAudio" name="audioTab">
+ <attribute name="title">
+ <string>Audio</string>
+ </attribute>
+ </widget>
<widget class="ConfigureDebug" name="debugTab">
<attribute name="title">
<string>Debug</string>
@@ -62,6 +72,12 @@
<header>configuration/configure_general.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>ConfigureGameList</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_gamelist.h</header>
+ <container>1</container>
+ </customwidget>
<customwidget>
<class>ConfigureSystem</class>
<extends>QWidget</extends>
@@ -69,6 +85,12 @@
<container>1</container>
</customwidget>
<customwidget>
+ <class>ConfigureAudio</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_audio.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
<class>ConfigureDebug</class>
<extends>QWidget</extends>
<header>configuration/configure_debug.h</header>
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
new file mode 100644
index 000000000..fbb813f6c
--- /dev/null
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -0,0 +1,90 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "audio_core/sink.h"
+#include "audio_core/sink_details.h"
+#include "core/core.h"
+#include "core/settings.h"
+#include "ui_configure_audio.h"
+#include "yuzu/configuration/configure_audio.h"
+
+ConfigureAudio::ConfigureAudio(QWidget* parent)
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()) {
+ ui->setupUi(this);
+
+ ui->output_sink_combo_box->clear();
+ ui->output_sink_combo_box->addItem("auto");
+ for (const auto& sink_detail : AudioCore::g_sink_details) {
+ ui->output_sink_combo_box->addItem(sink_detail.id);
+ }
+
+ connect(ui->volume_slider, &QSlider::valueChanged, [this] {
+ ui->volume_indicator->setText(tr("%1 %").arg(ui->volume_slider->sliderPosition()));
+ });
+
+ this->setConfiguration();
+ connect(ui->output_sink_combo_box,
+ static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+ &ConfigureAudio::updateAudioDevices);
+
+ ui->output_sink_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn());
+ ui->audio_device_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn());
+}
+
+ConfigureAudio::~ConfigureAudio() = default;
+
+void ConfigureAudio::setConfiguration() {
+ int new_sink_index = 0;
+ for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
+ if (ui->output_sink_combo_box->itemText(index).toStdString() == Settings::values.sink_id) {
+ new_sink_index = index;
+ break;
+ }
+ }
+ ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
+
+ // The device list cannot be pre-populated (nor listed) until the output sink is known.
+ updateAudioDevices(new_sink_index);
+
+ int new_device_index = -1;
+ for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
+ if (ui->audio_device_combo_box->itemText(index).toStdString() ==
+ Settings::values.audio_device_id) {
+ new_device_index = index;
+ break;
+ }
+ }
+ ui->audio_device_combo_box->setCurrentIndex(new_device_index);
+
+ ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum());
+ ui->volume_indicator->setText(tr("%1 %").arg(ui->volume_slider->sliderPosition()));
+}
+
+void ConfigureAudio::applyConfiguration() {
+ Settings::values.sink_id =
+ ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
+ .toStdString();
+ Settings::values.audio_device_id =
+ ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
+ .toStdString();
+ Settings::values.volume =
+ static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum();
+}
+
+void ConfigureAudio::updateAudioDevices(int sink_index) {
+ ui->audio_device_combo_box->clear();
+ ui->audio_device_combo_box->addItem(AudioCore::auto_device_name);
+
+ std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString();
+ std::vector<std::string> device_list = AudioCore::GetSinkDetails(sink_id).list_devices();
+ for (const auto& device : device_list) {
+ ui->audio_device_combo_box->addItem(device.c_str());
+ }
+}
+
+void ConfigureAudio::retranslateUi() {
+ ui->retranslateUi(this);
+}
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
new file mode 100644
index 000000000..4f0af4163
--- /dev/null
+++ b/src/yuzu/configuration/configure_audio.h
@@ -0,0 +1,31 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QWidget>
+
+namespace Ui {
+class ConfigureAudio;
+}
+
+class ConfigureAudio : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit ConfigureAudio(QWidget* parent = nullptr);
+ ~ConfigureAudio();
+
+ void applyConfiguration();
+ void retranslateUi();
+
+public slots:
+ void updateAudioDevices(int sink_index);
+
+private:
+ void setConfiguration();
+
+ std::unique_ptr<Ui::ConfigureAudio> ui;
+};
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
new file mode 100644
index 000000000..ef67890dc
--- /dev/null
+++ b/src/yuzu/configuration/configure_audio.ui
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureAudio</class>
+ <widget class="QWidget" name="ConfigureAudio">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>188</width>
+ <height>246</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Audio</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Output Engine:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="output_sink_combo_box"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Audio Device:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="audio_device_combo_box"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Volume:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSlider" name="volume_slider">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="pageStep">
+ <number>10</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="volume_indicator">
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>0 %</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>167</width>
+ <height>55</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 5e66239ff..45d84f19a 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -24,7 +24,7 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::Co
});
}
-ConfigureDebug::~ConfigureDebug() {}
+ConfigureDebug::~ConfigureDebug() = default;
void ConfigureDebug::setConfiguration() {
ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub);
@@ -44,5 +44,4 @@ void ConfigureDebug::applyConfiguration() {
Log::Filter filter;
filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(filter);
- Settings::Apply();
}
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 118e91cf1..5ae7276bd 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -23,13 +23,6 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
- <widget class="QLabel" name="label_1">
- <property name="text">
- <string>The GDB Stub only works correctly when the CPU JIT is off.</string>
- </property>
- </widget>
- </item>
- <item>
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<widget class="QCheckBox" name="toggle_gdbstub">
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 358f33005..daa4cc0d9 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -6,21 +6,26 @@
#include "ui_configure.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_dialog.h"
+#include "yuzu/hotkeys.h"
-ConfigureDialog::ConfigureDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ConfigureDialog) {
+ConfigureDialog::ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry)
+ : QDialog(parent), ui(new Ui::ConfigureDialog) {
ui->setupUi(this);
+ ui->generalTab->PopulateHotkeyList(registry);
this->setConfiguration();
}
-ConfigureDialog::~ConfigureDialog() {}
+ConfigureDialog::~ConfigureDialog() = default;
void ConfigureDialog::setConfiguration() {}
void ConfigureDialog::applyConfiguration() {
ui->generalTab->applyConfiguration();
+ ui->gameListTab->applyConfiguration();
ui->systemTab->applyConfiguration();
ui->inputTab->applyConfiguration();
ui->graphicsTab->applyConfiguration();
+ ui->audioTab->applyConfiguration();
ui->debugTab->applyConfiguration();
Settings::Apply();
}
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 21fa1f501..bbbdacc29 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -7,6 +7,8 @@
#include <memory>
#include <QDialog>
+class HotkeyRegistry;
+
namespace Ui {
class ConfigureDialog;
}
@@ -15,7 +17,7 @@ class ConfigureDialog : public QDialog {
Q_OBJECT
public:
- explicit ConfigureDialog(QWidget* parent);
+ explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry);
~ConfigureDialog();
void applyConfiguration();
diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp
new file mode 100644
index 000000000..1ae3423cf
--- /dev/null
+++ b/src/yuzu/configuration/configure_gamelist.cpp
@@ -0,0 +1,63 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/core.h"
+#include "core/settings.h"
+#include "ui_configure_gamelist.h"
+#include "ui_settings.h"
+#include "yuzu/configuration/configure_gamelist.h"
+
+ConfigureGameList::ConfigureGameList(QWidget* parent)
+ : QWidget(parent), ui(new Ui::ConfigureGameList) {
+ ui->setupUi(this);
+
+ static const std::vector<std::pair<u32, std::string>> default_icon_sizes{
+ std::make_pair(0, "None"), std::make_pair(32, "Small"),
+ std::make_pair(64, "Standard"), std::make_pair(128, "Large"),
+ std::make_pair(256, "Full Size"),
+ };
+
+ for (const auto& size : default_icon_sizes) {
+ ui->icon_size_combobox->addItem(QString::fromStdString(size.second + " (" +
+ std::to_string(size.first) + "x" +
+ std::to_string(size.first) + ")"),
+ size.first);
+ }
+
+ static const std::vector<std::string> row_text_names{
+ "Filename",
+ "Filetype",
+ "Title ID",
+ "Title Name",
+ };
+
+ for (size_t i = 0; i < row_text_names.size(); ++i) {
+ ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]),
+ QVariant::fromValue(i));
+ ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]),
+ QVariant::fromValue(i));
+ }
+
+ this->setConfiguration();
+}
+
+ConfigureGameList::~ConfigureGameList() {}
+
+void ConfigureGameList::setConfiguration() {
+ ui->show_unknown->setChecked(UISettings::values.show_unknown);
+ ui->icon_size_combobox->setCurrentIndex(
+ ui->icon_size_combobox->findData(UISettings::values.icon_size));
+ ui->row_1_text_combobox->setCurrentIndex(
+ ui->row_1_text_combobox->findData(UISettings::values.row_1_text_id));
+ ui->row_2_text_combobox->setCurrentIndex(
+ ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id));
+}
+
+void ConfigureGameList::applyConfiguration() {
+ UISettings::values.show_unknown = ui->show_unknown->isChecked();
+ UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
+ UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
+ UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt();
+ Settings::Apply();
+}
diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h
new file mode 100644
index 000000000..94fba6373
--- /dev/null
+++ b/src/yuzu/configuration/configure_gamelist.h
@@ -0,0 +1,28 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QWidget>
+
+namespace Ui {
+class ConfigureGameList;
+}
+
+class ConfigureGameList : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit ConfigureGameList(QWidget* parent = nullptr);
+ ~ConfigureGameList();
+
+ void applyConfiguration();
+
+private:
+ void setConfiguration();
+
+private:
+ std::unique_ptr<Ui::ConfigureGameList> ui;
+};
diff --git a/src/yuzu/configuration/configure_gamelist.ui b/src/yuzu/configuration/configure_gamelist.ui
new file mode 100644
index 000000000..7471fdb60
--- /dev/null
+++ b/src/yuzu/configuration/configure_gamelist.ui
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureGameList</class>
+ <widget class="QWidget" name="ConfigureGeneral">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>300</width>
+ <height>377</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="HorizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="VerticalLayout">
+ <item>
+ <widget class="QGroupBox" name="GeneralGroupBox">
+ <property name="title">
+ <string>General</string>
+ </property>
+ <layout class="QHBoxLayout" name="GeneralHorizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="GeneralVerticalLayout">
+ <item>
+ <widget class="QCheckBox" name="show_unknown">
+ <property name="text">
+ <string>Show files with type 'Unknown'</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="IconSizeGroupBox">
+ <property name="title">
+ <string>Icon Size</string>
+ </property>
+ <layout class="QHBoxLayout" name="icon_size_qhbox_layout">
+ <item>
+ <layout class="QVBoxLayout" name="icon_size_qvbox_layout">
+ <item>
+ <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
+ <item>
+ <widget class="QLabel" name="icon_size_label">
+ <property name="text">
+ <string>Icon Size:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="icon_size_combobox"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="RowGroupBox">
+ <property name="title">
+ <string>Row Text</string>
+ </property>
+ <layout class="QHBoxLayout" name="RowHorizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="RowVerticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="row_1_qhbox_layout">
+ <item>
+ <widget class="QLabel" name="row_1_label">
+ <property name="text">
+ <string>Row 1 Text:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="row_1_text_combobox"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="row_2_qhbox_layout">
+ <item>
+ <widget class="QLabel" name="row_2_label">
+ <property name="text">
+ <string>Row 2 Text:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="row_2_text_combobox"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index baa558667..d8caee1e8 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -24,7 +24,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ui->use_docked_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn());
}
-ConfigureGeneral::~ConfigureGeneral() {}
+ConfigureGeneral::~ConfigureGeneral() = default;
void ConfigureGeneral::setConfiguration() {
ui->toggle_deepscan->setChecked(UISettings::values.gamedir_deepscan);
@@ -35,6 +35,10 @@ void ConfigureGeneral::setConfiguration() {
ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
}
+void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
+ ui->widget->Populate(registry);
+}
+
void ConfigureGeneral::applyConfiguration() {
UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked();
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
@@ -44,5 +48,4 @@ void ConfigureGeneral::applyConfiguration() {
Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
Settings::values.use_multi_core = ui->use_multi_core->isChecked();
Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
- Settings::Apply();
}
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 447552d8c..4770034cc 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -7,6 +7,8 @@
#include <memory>
#include <QWidget>
+class HotkeyRegistry;
+
namespace Ui {
class ConfigureGeneral;
}
@@ -18,11 +20,11 @@ public:
explicit ConfigureGeneral(QWidget* parent = nullptr);
~ConfigureGeneral();
+ void PopulateHotkeyList(const HotkeyRegistry& registry);
void applyConfiguration();
private:
void setConfiguration();
-private:
std::unique_ptr<Ui::ConfigureGeneral> ui;
};
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 7664880d5..4afe0f81b 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -14,7 +14,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
this->setConfiguration();
}
-ConfigureGraphics::~ConfigureGraphics() {}
+ConfigureGraphics::~ConfigureGraphics() = default;
enum class Resolution : int {
Auto,
@@ -67,5 +67,4 @@ void ConfigureGraphics::applyConfiguration() {
ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex()));
Settings::values.toggle_framelimit = ui->toggle_framelimit->isChecked();
Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked();
- Settings::Apply();
}
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 78559e2bb..5e7badedf 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -191,8 +191,6 @@ void ConfigureInput::applyConfiguration() {
[](const Common::ParamPackage& param) { return param.Serialize(); });
std::transform(analogs_param.begin(), analogs_param.end(), Settings::values.analogs.begin(),
[](const Common::ParamPackage& param) { return param.Serialize(); });
-
- Settings::Apply();
}
void ConfigureInput::loadConfiguration() {
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index d09505a0f..e9ed9c38f 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -4,9 +4,10 @@
#include <QMessageBox>
#include "core/core.h"
+#include "core/settings.h"
#include "ui_configure_system.h"
#include "yuzu/configuration/configure_system.h"
-#include "yuzu/ui_settings.h"
+#include "yuzu/main.h"
static const std::array<int, 12> days_in_month = {{
31,
@@ -34,10 +35,12 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::
this->setConfiguration();
}
-ConfigureSystem::~ConfigureSystem() {}
+ConfigureSystem::~ConfigureSystem() = default;
void ConfigureSystem::setConfiguration() {
enabled = !Core::System::GetInstance().IsPoweredOn();
+ ui->edit_username->setText(QString::fromStdString(Settings::values.username));
+ ui->combo_language->setCurrentIndex(Settings::values.language_index);
}
void ConfigureSystem::ReadSystemSettings() {}
@@ -45,6 +48,9 @@ void ConfigureSystem::ReadSystemSettings() {}
void ConfigureSystem::applyConfiguration() {
if (!enabled)
return;
+ Settings::values.username = ui->edit_username->text().toStdString();
+ Settings::values.language_index = ui->combo_language->currentIndex();
+ Settings::Apply();
}
void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) {
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index 8caf49623..f3f8db038 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -38,7 +38,7 @@
</sizepolicy>
</property>
<property name="maxLength">
- <number>10</number>
+ <number>32</number>
</property>
</widget>
</item>
@@ -164,7 +164,7 @@
</item>
<item>
<property name="text">
- <string>Simplified Chinese (简体中文)</string>
+ <string>Chinese</string>
</property>
</item>
<item>
@@ -187,6 +187,31 @@
<string>Russian (Русский)</string>
</property>
</item>
+ <item>
+ <property name="text">
+ <string>Taiwanese</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>British English</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Canadian French</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Latin American Spanish</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Simplified Chinese</string>
+ </property>
+ </item>
<item>
<property name="text">
<string>Traditional Chinese (正體中文)</string>
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp
index d6d61a739..5f459ccfb 100644
--- a/src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp
+++ b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp
@@ -10,12 +10,12 @@ BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Tegra::DebugConte
: QDockWidget(title, parent), BreakPointObserver(debug_context) {
qRegisterMetaType<Tegra::DebugContext::Event>("Tegra::DebugContext::Event");
- connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed()));
+ connect(this, &BreakPointObserverDock::Resumed, this, &BreakPointObserverDock::OnResumed);
// NOTE: This signal is emitted from a non-GUI thread, but connect() takes
// care of delaying its handling to the GUI thread.
- connect(this, SIGNAL(BreakPointHit(Tegra::DebugContext::Event, void*)), this,
- SLOT(OnBreakPointHit(Tegra::DebugContext::Event, void*)), Qt::BlockingQueuedConnection);
+ connect(this, &BreakPointObserverDock::BreakPointHit, this,
+ &BreakPointObserverDock::OnBreakPointHit, Qt::BlockingQueuedConnection);
}
void BreakPointObserverDock::OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) {
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoint_observer.h b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.h
index 9d05493cf..ab32f0115 100644
--- a/src/yuzu/debugger/graphics/graphics_breakpoint_observer.h
+++ b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.h
@@ -23,11 +23,11 @@ public:
void OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) override;
void OnMaxwellResume() override;
-private slots:
- virtual void OnBreakPointHit(Tegra::DebugContext::Event event, void* data) = 0;
- virtual void OnResumed() = 0;
-
signals:
void Resumed();
void BreakPointHit(Tegra::DebugContext::Event event, void* data);
+
+private:
+ virtual void OnBreakPointHit(Tegra::DebugContext::Event event, void* data) = 0;
+ virtual void OnResumed() = 0;
};
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoints.cpp b/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
index f98cc8152..eb16a38a0 100644
--- a/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
+++ b/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
@@ -144,21 +144,25 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(
qRegisterMetaType<Tegra::DebugContext::Event>("Tegra::DebugContext::Event");
- connect(breakpoint_list, SIGNAL(doubleClicked(const QModelIndex&)), this,
- SLOT(OnItemDoubleClicked(const QModelIndex&)));
+ connect(breakpoint_list, &QTreeView::doubleClicked, this,
+ &GraphicsBreakPointsWidget::OnItemDoubleClicked);
- connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested()));
+ connect(resume_button, &QPushButton::clicked, this,
+ &GraphicsBreakPointsWidget::OnResumeRequested);
- connect(this, SIGNAL(BreakPointHit(Tegra::DebugContext::Event, void*)), this,
- SLOT(OnBreakPointHit(Tegra::DebugContext::Event, void*)), Qt::BlockingQueuedConnection);
- connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed()));
+ connect(this, &GraphicsBreakPointsWidget::BreakPointHit, this,
+ &GraphicsBreakPointsWidget::OnBreakPointHit, Qt::BlockingQueuedConnection);
+ connect(this, &GraphicsBreakPointsWidget::Resumed, this, &GraphicsBreakPointsWidget::OnResumed);
- connect(this, SIGNAL(BreakPointHit(Tegra::DebugContext::Event, void*)), breakpoint_model,
- SLOT(OnBreakPointHit(Tegra::DebugContext::Event)), Qt::BlockingQueuedConnection);
- connect(this, SIGNAL(Resumed()), breakpoint_model, SLOT(OnResumed()));
+ connect(this, &GraphicsBreakPointsWidget::BreakPointHit, breakpoint_model,
+ &BreakPointModel::OnBreakPointHit, Qt::BlockingQueuedConnection);
+ connect(this, &GraphicsBreakPointsWidget::Resumed, breakpoint_model,
+ &BreakPointModel::OnResumed);
- connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&, const QModelIndex&)),
- breakpoint_model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)));
+ connect(this, &GraphicsBreakPointsWidget::BreakPointsChanged,
+ [this](const QModelIndex& top_left, const QModelIndex& bottom_right) {
+ breakpoint_model->dataChanged(top_left, bottom_right);
+ });
QWidget* main_widget = new QWidget;
auto main_layout = new QVBoxLayout;
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoints.h b/src/yuzu/debugger/graphics/graphics_breakpoints.h
index ae0ede2e8..a920a2ae5 100644
--- a/src/yuzu/debugger/graphics/graphics_breakpoints.h
+++ b/src/yuzu/debugger/graphics/graphics_breakpoints.h
@@ -26,18 +26,17 @@ public:
void OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) override;
void OnMaxwellResume() override;
-public slots:
- void OnBreakPointHit(Tegra::DebugContext::Event event, void* data);
- void OnItemDoubleClicked(const QModelIndex&);
- void OnResumeRequested();
- void OnResumed();
-
signals:
void Resumed();
void BreakPointHit(Tegra::DebugContext::Event event, void* data);
void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
private:
+ void OnBreakPointHit(Tegra::DebugContext::Event event, void* data);
+ void OnItemDoubleClicked(const QModelIndex&);
+ void OnResumeRequested();
+ void OnResumed();
+
QLabel* status_text;
QPushButton* resume_button;
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoints_p.h b/src/yuzu/debugger/graphics/graphics_breakpoints_p.h
index 35a6876ae..7112b87e6 100644
--- a/src/yuzu/debugger/graphics/graphics_breakpoints_p.h
+++ b/src/yuzu/debugger/graphics/graphics_breakpoints_p.h
@@ -25,7 +25,6 @@ public:
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
-public slots:
void OnBreakPointHit(Tegra::DebugContext::Event event);
void OnResumed();
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index c41ff693b..e037223c2 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
@@ -34,7 +34,8 @@ static Tegra::Texture::TextureFormat ConvertToTextureFormat(
SurfacePicture::SurfacePicture(QWidget* parent, GraphicsSurfaceWidget* surface_widget_)
: QLabel(parent), surface_widget(surface_widget_) {}
-SurfacePicture::~SurfacePicture() {}
+
+SurfacePicture::~SurfacePicture() = default;
void SurfacePicture::mousePressEvent(QMouseEvent* event) {
// Only do something while the left mouse button is held down
@@ -153,22 +154,24 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext
save_surface = new QPushButton(QIcon::fromTheme("document-save"), tr("Save"));
// Connections
- connect(this, SIGNAL(Update()), this, SLOT(OnUpdate()));
- connect(surface_source_list, SIGNAL(currentIndexChanged(int)), this,
- SLOT(OnSurfaceSourceChanged(int)));
- connect(surface_address_control, SIGNAL(ValueChanged(qint64)), this,
- SLOT(OnSurfaceAddressChanged(qint64)));
- connect(surface_width_control, SIGNAL(valueChanged(int)), this,
- SLOT(OnSurfaceWidthChanged(int)));
- connect(surface_height_control, SIGNAL(valueChanged(int)), this,
- SLOT(OnSurfaceHeightChanged(int)));
- connect(surface_format_control, SIGNAL(currentIndexChanged(int)), this,
- SLOT(OnSurfaceFormatChanged(int)));
- connect(surface_picker_x_control, SIGNAL(valueChanged(int)), this,
- SLOT(OnSurfacePickerXChanged(int)));
- connect(surface_picker_y_control, SIGNAL(valueChanged(int)), this,
- SLOT(OnSurfacePickerYChanged(int)));
- connect(save_surface, SIGNAL(clicked()), this, SLOT(SaveSurface()));
+ connect(this, &GraphicsSurfaceWidget::Update, this, &GraphicsSurfaceWidget::OnUpdate);
+ connect(surface_source_list,
+ static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+ &GraphicsSurfaceWidget::OnSurfaceSourceChanged);
+ connect(surface_address_control, &CSpinBox::ValueChanged, this,
+ &GraphicsSurfaceWidget::OnSurfaceAddressChanged);
+ connect(surface_width_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ this, &GraphicsSurfaceWidget::OnSurfaceWidthChanged);
+ connect(surface_height_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ this, &GraphicsSurfaceWidget::OnSurfaceHeightChanged);
+ connect(surface_format_control,
+ static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+ &GraphicsSurfaceWidget::OnSurfaceFormatChanged);
+ connect(surface_picker_x_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ this, &GraphicsSurfaceWidget::OnSurfacePickerXChanged);
+ connect(surface_picker_y_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ this, &GraphicsSurfaceWidget::OnSurfacePickerYChanged);
+ connect(save_surface, &QPushButton::clicked, this, &GraphicsSurfaceWidget::SaveSurface);
auto main_widget = new QWidget;
auto main_layout = new QVBoxLayout;
@@ -380,8 +383,10 @@ void GraphicsSurfaceWidget::OnUpdate() {
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
boost::optional<VAddr> address = gpu.memory_manager->GpuToCpuAddress(surface_address);
- auto unswizzled_data =
- Tegra::Texture::UnswizzleTexture(*address, surface_format, surface_width, surface_height);
+ // TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles.
+ // Needs to be fixed if we plan to use this feature more, otherwise we may remove it.
+ auto unswizzled_data = Tegra::Texture::UnswizzleTexture(
+ *address, 1, Tegra::Texture::BytesPerPixel(surface_format), surface_width, surface_height);
auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format,
surface_width, surface_height);
diff --git a/src/yuzu/debugger/graphics/graphics_surface.h b/src/yuzu/debugger/graphics/graphics_surface.h
index 6a344bdfc..323e39d94 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.h
+++ b/src/yuzu/debugger/graphics/graphics_surface.h
@@ -22,11 +22,11 @@ class SurfacePicture : public QLabel {
public:
explicit SurfacePicture(QWidget* parent = nullptr,
GraphicsSurfaceWidget* surface_widget = nullptr);
- ~SurfacePicture();
+ ~SurfacePicture() override;
protected slots:
- virtual void mouseMoveEvent(QMouseEvent* event);
- virtual void mousePressEvent(QMouseEvent* event);
+ void mouseMoveEvent(QMouseEvent* event) override;
+ void mousePressEvent(QMouseEvent* event) override;
private:
GraphicsSurfaceWidget* surface_widget;
@@ -65,16 +65,15 @@ public slots:
void OnSurfacePickerYChanged(int new_value);
void OnUpdate();
-private slots:
+signals:
+ void Update();
+
+private:
void OnBreakPointHit(Tegra::DebugContext::Event event, void* data) override;
void OnResumed() override;
void SaveSurface();
-signals:
- void Update();
-
-private:
QComboBox* surface_source_list;
CSpinBox* surface_address_control;
QSpinBox* surface_width_control;
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 2b45b8573..d0926d723 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -14,7 +14,7 @@
#include "core/hle/kernel/timer.h"
#include "core/hle/kernel/wait_object.h"
-WaitTreeItem::~WaitTreeItem() {}
+WaitTreeItem::~WaitTreeItem() = default;
QColor WaitTreeItem::GetColor() const {
return QColor(Qt::GlobalColor::black);
@@ -316,7 +316,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const {
list.push_back(std::make_unique<WaitTreeText>(
tr("reset type = %1")
- .arg(GetResetTypeQString(static_cast<const Kernel::Event&>(object).reset_type))));
+ .arg(GetResetTypeQString(static_cast<const Kernel::Event&>(object).GetResetType()))));
return list;
}
@@ -328,11 +328,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const {
const auto& timer = static_cast<const Kernel::Timer&>(object);
list.push_back(std::make_unique<WaitTreeText>(
- tr("reset type = %1").arg(GetResetTypeQString(timer.reset_type))));
+ tr("reset type = %1").arg(GetResetTypeQString(timer.GetResetType()))));
list.push_back(
- std::make_unique<WaitTreeText>(tr("initial delay = %1").arg(timer.initial_delay)));
+ std::make_unique<WaitTreeText>(tr("initial delay = %1").arg(timer.GetInitialDelay())));
list.push_back(
- std::make_unique<WaitTreeText>(tr("interval delay = %1").arg(timer.interval_delay)));
+ std::make_unique<WaitTreeText>(tr("interval delay = %1").arg(timer.GetIntervalDelay())));
return list;
}
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index 10fc9e968..513b3c45d 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -9,7 +9,7 @@
#include <QTreeView>
#include <boost/container/flat_set.hpp>
#include "core/core.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
class EmuThread;
@@ -25,11 +25,13 @@ class WaitTreeThread;
class WaitTreeItem : public QObject {
Q_OBJECT
public:
+ ~WaitTreeItem() override;
+
virtual bool IsExpandable() const;
virtual std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const;
virtual QString GetText() const = 0;
virtual QColor GetColor() const;
- virtual ~WaitTreeItem();
+
void Expand();
WaitTreeItem* Parent() const;
const std::vector<std::unique_ptr<WaitTreeItem>>& Children() const;
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 99e6634a1..f867118d9 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <regex>
#include <QApplication>
#include <QDir>
#include <QFileInfo>
@@ -9,9 +10,13 @@
#include <QKeyEvent>
#include <QMenu>
#include <QThreadPool>
+#include <boost/container/flat_map.hpp>
#include "common/common_paths.h"
#include "common/logging/log.h"
#include "common/string_util.h"
+#include "core/file_sys/content_archive.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/romfs.h"
#include "core/file_sys/vfs_real.h"
#include "core/loader/loader.h"
#include "game_list.h"
@@ -162,15 +167,15 @@ void GameList::onTextChanged(const QString& newText) {
}
search_field->setFilterResult(rowCount, rowCount);
} else {
- QStandardItem* child_file;
- QString file_path, file_name, file_title, file_programmid;
int result_count = 0;
for (int i = 0; i < rowCount; ++i) {
- child_file = item_model->item(i, 0);
- file_path = child_file->data(GameListItemPath::FullPathRole).toString().toLower();
- file_name = file_path.mid(file_path.lastIndexOf("/") + 1);
- file_title = child_file->data(GameListItemPath::TitleRole).toString().toLower();
- file_programmid =
+ const QStandardItem* child_file = item_model->item(i, 0);
+ const QString file_path =
+ child_file->data(GameListItemPath::FullPathRole).toString().toLower();
+ QString file_name = file_path.mid(file_path.lastIndexOf('/') + 1);
+ const QString file_title =
+ child_file->data(GameListItemPath::TitleRole).toString().toLower();
+ const QString file_programmid =
child_file->data(GameListItemPath::ProgramIdRole).toString().toLower();
// Only items which filename in combination with its title contains all words
@@ -194,7 +199,8 @@ void GameList::onFilterCloseClicked() {
main_window->filterBarSetChecked(false);
}
-GameList::GameList(GMainWindow* parent) : QWidget{parent} {
+GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent)
+ : QWidget{parent}, vfs(std::move(vfs)) {
watcher = new QFileSystemWatcher(this);
connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory);
@@ -258,18 +264,20 @@ void GameList::AddEntry(const QList<QStandardItem*>& entry_items) {
void GameList::ValidateEntry(const QModelIndex& item) {
// We don't care about the individual QStandardItem that was selected, but its row.
- int row = item_model->itemFromIndex(item)->row();
- QStandardItem* child_file = item_model->invisibleRootItem()->child(row, COLUMN_NAME);
- QString file_path = child_file->data(GameListItemPath::FullPathRole).toString();
+ const int row = item_model->itemFromIndex(item)->row();
+ const QStandardItem* child_file = item_model->invisibleRootItem()->child(row, COLUMN_NAME);
+ const QString file_path = child_file->data(GameListItemPath::FullPathRole).toString();
if (file_path.isEmpty())
return;
- std::string std_file_path(file_path.toStdString());
- if (!FileUtil::Exists(std_file_path))
+
+ if (!QFileInfo::exists(file_path))
return;
- if (FileUtil::IsDirectory(std_file_path)) {
- QDir dir(std_file_path.c_str());
- QStringList matching_main = dir.entryList(QStringList("main"), QDir::Files);
+
+ const QFileInfo file_info{file_path};
+ if (file_info.isDir()) {
+ const QDir dir{file_path};
+ const QStringList matching_main = dir.entryList(QStringList("main"), QDir::Files);
if (matching_main.size() == 1) {
emit GameChosen(dir.path() + DIR_SEP + matching_main[0]);
}
@@ -336,7 +344,7 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
emit ShouldCancelWorker();
- GameListWorker* worker = new GameListWorker(dir_path, deep_scan);
+ GameListWorker* worker = new GameListWorker(vfs, dir_path, deep_scan);
connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection);
connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating,
@@ -365,24 +373,26 @@ void GameList::LoadInterfaceLayout() {
item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder());
}
-const QStringList GameList::supported_file_extensions = {"nso", "nro", "nca"};
+const QStringList GameList::supported_file_extensions = {"nso", "nro", "nca", "xci"};
static bool HasSupportedFileExtension(const std::string& file_name) {
- QFileInfo file = QFileInfo(file_name.c_str());
+ const QFileInfo file = QFileInfo(QString::fromStdString(file_name));
return GameList::supported_file_extensions.contains(file.suffix(), Qt::CaseInsensitive);
}
static bool IsExtractedNCAMain(const std::string& file_name) {
- return QFileInfo(file_name.c_str()).fileName() == "main";
+ return QFileInfo(QString::fromStdString(file_name)).fileName() == "main";
}
static QString FormatGameName(const std::string& physical_name) {
- QFileInfo file_info(physical_name.c_str());
+ const QString physical_name_as_qstring = QString::fromStdString(physical_name);
+ const QFileInfo file_info(physical_name_as_qstring);
+
if (IsExtractedNCAMain(physical_name)) {
return file_info.dir().path();
- } else {
- return QString::fromStdString(physical_name);
}
+
+ return physical_name_as_qstring;
}
void GameList::RefreshGameDirectory() {
@@ -393,6 +403,91 @@ void GameList::RefreshGameDirectory() {
}
}
+static void GetMetadataFromControlNCA(const std::shared_ptr<FileSys::NCA>& nca,
+ std::vector<u8>& icon, std::string& name) {
+ const auto control_dir = FileSys::ExtractRomFS(nca->GetRomFS());
+ if (control_dir == nullptr)
+ return;
+
+ const auto nacp_file = control_dir->GetFile("control.nacp");
+ if (nacp_file == nullptr)
+ return;
+ FileSys::NACP nacp(nacp_file);
+ name = nacp.GetApplicationName();
+
+ FileSys::VirtualFile icon_file = nullptr;
+ for (const auto& language : FileSys::LANGUAGE_NAMES) {
+ icon_file = control_dir->GetFile("icon_" + std::string(language) + ".dat");
+ if (icon_file != nullptr) {
+ icon = icon_file->ReadAllBytes();
+ break;
+ }
+ }
+}
+
+void GameListWorker::AddInstalledTitlesToGameList() {
+ const auto usernand = Service::FileSystem::GetUserNANDContents();
+ const auto installed_games = usernand->ListEntriesFilter(FileSys::TitleType::Application,
+ FileSys::ContentRecordType::Program);
+
+ for (const auto& game : installed_games) {
+ const auto& file = usernand->GetEntryRaw(game);
+ std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file);
+ if (!loader)
+ continue;
+
+ std::vector<u8> icon;
+ std::string name;
+ u64 program_id;
+ loader->ReadProgramId(program_id);
+
+ const auto& control =
+ usernand->GetEntry(game.title_id, FileSys::ContentRecordType::Control);
+ if (control != nullptr)
+ GetMetadataFromControlNCA(control, icon, name);
+ emit EntryReady({
+ new GameListItemPath(
+ FormatGameName(file->GetFullPath()), icon, QString::fromStdString(name),
+ QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
+ program_id),
+ new GameListItem(
+ QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
+ new GameListItemSize(file->GetSize()),
+ });
+ }
+
+ const auto control_data = usernand->ListEntriesFilter(FileSys::TitleType::Application,
+ FileSys::ContentRecordType::Control);
+
+ for (const auto& entry : control_data) {
+ const auto nca = usernand->GetEntry(entry);
+ if (nca != nullptr)
+ nca_control_map.insert_or_assign(entry.title_id, nca);
+ }
+}
+
+void GameListWorker::FillControlMap(const std::string& dir_path) {
+ const auto nca_control_callback = [this](u64* num_entries_out, const std::string& directory,
+ const std::string& virtual_name) -> bool {
+ std::string physical_name = directory + DIR_SEP + virtual_name;
+
+ if (stop_processing)
+ return false; // Breaks the callback loop.
+
+ bool is_dir = FileUtil::IsDirectory(physical_name);
+ QFileInfo file_info(physical_name.c_str());
+ if (!is_dir && file_info.suffix().toStdString() == "nca") {
+ auto nca =
+ std::make_shared<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read));
+ if (nca->GetType() == FileSys::NCAContentType::Control)
+ nca_control_map.insert_or_assign(nca->GetTitleId(), nca);
+ }
+ return true;
+ };
+
+ FileUtil::ForeachDirectoryEntry(nullptr, dir_path, nca_control_callback);
+}
+
void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) {
const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory,
const std::string& virtual_name) -> bool {
@@ -405,18 +500,35 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
if (!is_dir &&
(HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
std::unique_ptr<Loader::AppLoader> loader =
- Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name));
- if (!loader)
+ Loader::GetLoader(vfs->OpenFile(physical_name, FileSys::Mode::Read));
+ if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown ||
+ loader->GetFileType() == Loader::FileType::Error) &&
+ !UISettings::values.show_unknown))
return true;
- std::vector<u8> smdh;
- loader->ReadIcon(smdh);
+ std::vector<u8> icon;
+ const auto res1 = loader->ReadIcon(icon);
- u64 program_id = 0;
- loader->ReadProgramId(program_id);
+ u64 program_id;
+ const auto res2 = loader->ReadProgramId(program_id);
+
+ std::string name = " ";
+ const auto res3 = loader->ReadTitle(name);
+
+ if (res1 != Loader::ResultStatus::Success && res3 != Loader::ResultStatus::Success &&
+ res2 == Loader::ResultStatus::Success) {
+ // Use from metadata pool.
+ if (nca_control_map.find(program_id) != nca_control_map.end()) {
+ const auto nca = nca_control_map[program_id];
+ GetMetadataFromControlNCA(nca, icon, name);
+ }
+ }
emit EntryReady({
- new GameListItemPath(FormatGameName(physical_name), smdh, program_id),
+ new GameListItemPath(
+ FormatGameName(physical_name), icon, QString::fromStdString(name),
+ QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
+ program_id),
new GameListItem(
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
new GameListItemSize(FileUtil::GetSize(physical_name)),
@@ -435,7 +547,10 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
void GameListWorker::run() {
stop_processing = false;
watch_list.append(dir_path);
+ FillControlMap(dir_path.toStdString());
+ AddInstalledTitlesToGameList();
AddFstEntriesToGameList(dir_path.toStdString(), deep_scan ? 256 : 0);
+ nca_control_map.clear();
emit Finished(watch_list);
}
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 3bc14f07f..afe624b32 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -59,7 +59,7 @@ public:
QToolButton* button_filter_close = nullptr;
};
- explicit GameList(GMainWindow* parent = nullptr);
+ explicit GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent = nullptr);
~GameList() override;
void clearFilter();
@@ -90,6 +90,7 @@ private:
void PopupContextMenu(const QPoint& menu_location);
void RefreshGameDirectory();
+ FileSys::VirtualFilesystem vfs;
SearchField* search_field;
GMainWindow* main_window = nullptr;
QVBoxLayout* layout = nullptr;
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index a758b77aa..10c2ef075 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -4,12 +4,15 @@
#pragma once
+#include <array>
#include <atomic>
+#include <utility>
#include <QImage>
#include <QRunnable>
#include <QStandardItem>
#include <QString>
#include "common/string_util.h"
+#include "ui_settings.h"
#include "yuzu/util/util.h"
/**
@@ -17,8 +20,7 @@
* @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
* @return QPixmap default icon
*/
-static QPixmap GetDefaultIcon(bool large) {
- int size = large ? 48 : 24;
+static QPixmap GetDefaultIcon(u32 size) {
QPixmap icon(size, size);
icon.fill(Qt::transparent);
return icon;
@@ -27,9 +29,8 @@ static QPixmap GetDefaultIcon(bool large) {
class GameListItem : public QStandardItem {
public:
- GameListItem() : QStandardItem() {}
- GameListItem(const QString& string) : QStandardItem(string) {}
- virtual ~GameListItem() override {}
+ GameListItem() = default;
+ explicit GameListItem(const QString& string) : QStandardItem(string) {}
};
/**
@@ -39,17 +40,29 @@ public:
* If this class receives valid SMDH data, it will also display game icons and titles.
*/
class GameListItemPath : public GameListItem {
-
public:
static const int FullPathRole = Qt::UserRole + 1;
static const int TitleRole = Qt::UserRole + 2;
static const int ProgramIdRole = Qt::UserRole + 3;
+ static const int FileTypeRole = Qt::UserRole + 4;
- GameListItemPath() : GameListItem() {}
- GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id)
- : GameListItem() {
+ GameListItemPath() = default;
+ GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data,
+ const QString& game_name, const QString& game_type, u64 program_id) {
setData(game_path, FullPathRole);
+ setData(game_name, TitleRole);
setData(qulonglong(program_id), ProgramIdRole);
+ setData(game_type, FileTypeRole);
+
+ const u32 size = UISettings::values.icon_size;
+
+ QPixmap picture;
+ if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
+ picture = GetDefaultIcon(size);
+ }
+ picture = picture.scaled(size, size);
+
+ setData(picture, Qt::DecorationRole);
}
QVariant data(int role) const override {
@@ -57,11 +70,26 @@ public:
std::string filename;
Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename,
nullptr);
- QString title = data(TitleRole).toString();
- return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n " + title);
- } else {
- return GameListItem::data(role);
+
+ const std::array<QString, 4> row_data{{
+ QString::fromStdString(filename),
+ data(FileTypeRole).toString(),
+ QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())),
+ data(TitleRole).toString(),
+ }};
+
+ const auto& row1 = row_data.at(UISettings::values.row_1_text_id);
+ const auto& row2 = row_data.at(UISettings::values.row_2_text_id);
+
+ if (row1.isEmpty() || row1 == row2)
+ return row2;
+ if (row2.isEmpty())
+ return row1;
+
+ return row1 + "\n " + row2;
}
+
+ return GameListItem::data(role);
}
};
@@ -75,8 +103,8 @@ class GameListItemSize : public GameListItem {
public:
static const int SizeRole = Qt::UserRole + 1;
- GameListItemSize() : GameListItem() {}
- GameListItemSize(const qulonglong size_bytes) : GameListItem() {
+ GameListItemSize() = default;
+ explicit GameListItemSize(const qulonglong size_bytes) {
setData(size_bytes, SizeRole);
}
@@ -110,8 +138,8 @@ class GameListWorker : public QObject, public QRunnable {
Q_OBJECT
public:
- GameListWorker(QString dir_path, bool deep_scan)
- : QObject(), QRunnable(), dir_path(dir_path), deep_scan(deep_scan) {}
+ GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan)
+ : vfs(std::move(vfs)), dir_path(std::move(dir_path)), deep_scan(deep_scan) {}
public slots:
/// Starts the processing of directory tree information.
@@ -134,10 +162,14 @@ signals:
void Finished(QStringList watch_list);
private:
+ FileSys::VirtualFilesystem vfs;
+ std::map<u64, std::shared_ptr<FileSys::NCA>> nca_control_map;
QStringList watch_list;
QString dir_path;
bool deep_scan;
std::atomic_bool stop_processing;
+ void AddInstalledTitlesToGameList();
+ void FillControlMap(const std::string& dir_path);
void AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion = 0);
};
diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp
index 61acb38ee..dce399774 100644
--- a/src/yuzu/hotkeys.cpp
+++ b/src/yuzu/hotkeys.cpp
@@ -10,58 +10,53 @@
#include "yuzu/hotkeys.h"
#include "yuzu/ui_settings.h"
-struct Hotkey {
- Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {}
+HotkeyRegistry::HotkeyRegistry() = default;
+HotkeyRegistry::~HotkeyRegistry() = default;
- QKeySequence keyseq;
- QShortcut* shortcut;
- Qt::ShortcutContext context;
-};
-
-typedef std::map<QString, Hotkey> HotkeyMap;
-typedef std::map<QString, HotkeyMap> HotkeyGroupMap;
-
-HotkeyGroupMap hotkey_groups;
-
-void SaveHotkeys() {
- UISettings::values.shortcuts.clear();
- for (auto group : hotkey_groups) {
- for (auto hotkey : group.second) {
- UISettings::values.shortcuts.emplace_back(
- UISettings::Shortcut(group.first + "/" + hotkey.first,
- UISettings::ContextualShortcut(hotkey.second.keyseq.toString(),
- hotkey.second.context)));
- }
- }
-}
-
-void LoadHotkeys() {
+void HotkeyRegistry::LoadHotkeys() {
// Make sure NOT to use a reference here because it would become invalid once we call
// beginGroup()
for (auto shortcut : UISettings::values.shortcuts) {
- QStringList cat = shortcut.first.split("/");
+ const QStringList cat = shortcut.first.split('/');
Q_ASSERT(cat.size() >= 2);
// RegisterHotkey assigns default keybindings, so use old values as default parameters
Hotkey& hk = hotkey_groups[cat[0]][cat[1]];
if (!shortcut.second.first.isEmpty()) {
hk.keyseq = QKeySequence::fromString(shortcut.second.first);
- hk.context = (Qt::ShortcutContext)shortcut.second.second;
+ hk.context = static_cast<Qt::ShortcutContext>(shortcut.second.second);
}
if (hk.shortcut)
hk.shortcut->setKey(hk.keyseq);
}
}
-void RegisterHotkey(const QString& group, const QString& action, const QKeySequence& default_keyseq,
- Qt::ShortcutContext default_context) {
- if (hotkey_groups[group].find(action) == hotkey_groups[group].end()) {
- hotkey_groups[group][action].keyseq = default_keyseq;
- hotkey_groups[group][action].context = default_context;
+void HotkeyRegistry::SaveHotkeys() {
+ UISettings::values.shortcuts.clear();
+ for (const auto& group : hotkey_groups) {
+ for (const auto& hotkey : group.second) {
+ UISettings::values.shortcuts.emplace_back(
+ UISettings::Shortcut(group.first + '/' + hotkey.first,
+ UISettings::ContextualShortcut(hotkey.second.keyseq.toString(),
+ hotkey.second.context)));
+ }
}
}
-QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget) {
+void HotkeyRegistry::RegisterHotkey(const QString& group, const QString& action,
+ const QKeySequence& default_keyseq,
+ Qt::ShortcutContext default_context) {
+ auto& hotkey_group = hotkey_groups[group];
+ if (hotkey_group.find(action) != hotkey_group.end()) {
+ return;
+ }
+
+ auto& hotkey_action = hotkey_groups[group][action];
+ hotkey_action.keyseq = default_keyseq;
+ hotkey_action.context = default_context;
+}
+
+QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) {
Hotkey& hk = hotkey_groups[group][action];
if (!hk.shortcut)
@@ -72,10 +67,12 @@ QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widge
GHotkeysDialog::GHotkeysDialog(QWidget* parent) : QWidget(parent) {
ui.setupUi(this);
+}
- for (auto group : hotkey_groups) {
+void GHotkeysDialog::Populate(const HotkeyRegistry& registry) {
+ for (const auto& group : registry.hotkey_groups) {
QTreeWidgetItem* toplevel_item = new QTreeWidgetItem(QStringList(group.first));
- for (auto hotkey : group.second) {
+ for (const auto& hotkey : group.second) {
QStringList columns;
columns << hotkey.first << hotkey.second.keyseq.toString();
QTreeWidgetItem* item = new QTreeWidgetItem(columns);
diff --git a/src/yuzu/hotkeys.h b/src/yuzu/hotkeys.h
index a4ccc193b..f38e6c002 100644
--- a/src/yuzu/hotkeys.h
+++ b/src/yuzu/hotkeys.h
@@ -4,6 +4,7 @@
#pragma once
+#include <map>
#include "ui_hotkeys.h"
class QDialog;
@@ -11,47 +12,69 @@ class QKeySequence;
class QSettings;
class QShortcut;
-/**
- * Register a hotkey.
- *
- * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger")
- * @param action Name of the action (e.g. "Start Emulation", "Load Image")
- * @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the settings
- * file before
- * @param default_context Default context to assign if the hotkey wasn't present in the settings
- * file before
- * @warning Both the group and action strings will be displayed in the hotkey settings dialog
- */
-void RegisterHotkey(const QString& group, const QString& action,
- const QKeySequence& default_keyseq = QKeySequence(),
- Qt::ShortcutContext default_context = Qt::WindowShortcut);
-
-/**
- * Returns a QShortcut object whose activated() signal can be connected to other QObjects' slots.
- *
- * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger").
- * @param action Name of the action (e.g. "Start Emulation", "Load Image").
- * @param widget Parent widget of the returned QShortcut.
- * @warning If multiple QWidgets' call this function for the same action, the returned QShortcut
- * will be the same. Thus, you shouldn't rely on the caller really being the QShortcut's parent.
- */
-QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget);
-
-/**
- * Saves all registered hotkeys to the settings file.
- *
- * @note Each hotkey group will be stored a settings group; For each hotkey inside that group, a
- * settings group will be created to store the key sequence and the hotkey context.
- */
-void SaveHotkeys();
-
-/**
- * Loads hotkeys from the settings file.
- *
- * @note Yet unregistered hotkeys which are present in the settings will automatically be
- * registered.
- */
-void LoadHotkeys();
+class HotkeyRegistry final {
+public:
+ friend class GHotkeysDialog;
+
+ explicit HotkeyRegistry();
+ ~HotkeyRegistry();
+
+ /**
+ * Loads hotkeys from the settings file.
+ *
+ * @note Yet unregistered hotkeys which are present in the settings will automatically be
+ * registered.
+ */
+ void LoadHotkeys();
+
+ /**
+ * Saves all registered hotkeys to the settings file.
+ *
+ * @note Each hotkey group will be stored a settings group; For each hotkey inside that group, a
+ * settings group will be created to store the key sequence and the hotkey context.
+ */
+ void SaveHotkeys();
+
+ /**
+ * Returns a QShortcut object whose activated() signal can be connected to other QObjects'
+ * slots.
+ *
+ * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger").
+ * @param action Name of the action (e.g. "Start Emulation", "Load Image").
+ * @param widget Parent widget of the returned QShortcut.
+ * @warning If multiple QWidgets' call this function for the same action, the returned QShortcut
+ * will be the same. Thus, you shouldn't rely on the caller really being the
+ * QShortcut's parent.
+ */
+ QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget);
+
+ /**
+ * Register a hotkey.
+ *
+ * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger")
+ * @param action Name of the action (e.g. "Start Emulation", "Load Image")
+ * @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the
+ * settings file before
+ * @param default_context Default context to assign if the hotkey wasn't present in the settings
+ * file before
+ * @warning Both the group and action strings will be displayed in the hotkey settings dialog
+ */
+ void RegisterHotkey(const QString& group, const QString& action,
+ const QKeySequence& default_keyseq = {},
+ Qt::ShortcutContext default_context = Qt::WindowShortcut);
+
+private:
+ struct Hotkey {
+ QKeySequence keyseq;
+ QShortcut* shortcut = nullptr;
+ Qt::ShortcutContext context = Qt::WindowShortcut;
+ };
+
+ using HotkeyMap = std::map<QString, Hotkey>;
+ using HotkeyGroupMap = std::map<QString, HotkeyMap>;
+
+ HotkeyGroupMap hotkey_groups;
+};
class GHotkeysDialog : public QWidget {
Q_OBJECT
@@ -59,6 +82,8 @@ class GHotkeysDialog : public QWidget {
public:
explicit GHotkeysDialog(QWidget* parent = nullptr);
+ void Populate(const HotkeyRegistry& registry);
+
private:
Ui::hotkeys ui;
};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 3c2726498..2df65023a 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -6,7 +6,10 @@
#include <clocale>
#include <memory>
#include <thread>
+
+#include <fmt/ostream.h>
#include <glad/glad.h>
+
#define QT_NO_OPENGL
#include <QDesktopWidget>
#include <QFileDialog>
@@ -23,6 +26,9 @@
#include "common/scope_exit.h"
#include "common/string_util.h"
#include "core/core.h"
+#include "core/crypto/key_manager.h"
+#include "core/file_sys/card_image.h"
+#include "core/file_sys/vfs_real.h"
#include "core/gdbstub/gdbstub.h"
#include "core/loader/loader.h"
#include "core/settings.h"
@@ -80,7 +86,11 @@ static void ShowCalloutMessage(const QString& message, CalloutFlag flag) {
void GMainWindow::ShowCallouts() {}
-GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
+const int GMainWindow::max_recent_files_item;
+
+GMainWindow::GMainWindow()
+ : config(new Config()), emu_thread(nullptr),
+ vfs(std::make_shared<FileSys::RealVfsFilesystem>()) {
debug_context = Tegra::DebugContext::Construct();
@@ -101,11 +111,16 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
ConnectMenuEvents();
ConnectWidgetEvents();
+ LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_name, Common::g_scm_branch,
+ Common::g_scm_desc);
setWindowTitle(QString("yuzu %1| %2-%3")
.arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc));
show();
+ // Necessary to load titles from nand in gamelist.
+ Service::FileSystem::RegisterBIS(std::make_unique<FileSys::BISFactory>(vfs->OpenDirectory(
+ FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite)));
game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
// Show one-time "callout" messages to the user
@@ -127,7 +142,7 @@ void GMainWindow::InitializeWidgets() {
render_window = new GRenderWindow(this, emu_thread.get());
render_window->hide();
- game_list = new GameList(this);
+ game_list = new GameList(vfs, this);
ui.horizontalLayout->addWidget(game_list);
// Create status bar
@@ -203,27 +218,46 @@ void GMainWindow::InitializeRecentFileMenuActions() {
}
void GMainWindow::InitializeHotkeys() {
- RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
- RegisterHotkey("Main Window", "Start Emulation");
- RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen);
- RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape),
- Qt::ApplicationShortcut);
- LoadHotkeys();
-
- connect(GetHotkey("Main Window", "Load File", this), &QShortcut::activated, this,
- &GMainWindow::OnMenuLoadFile);
- connect(GetHotkey("Main Window", "Start Emulation", this), &QShortcut::activated, this,
- &GMainWindow::OnStartGame);
- connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activated,
- ui.action_Fullscreen, &QAction::trigger);
- connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activatedAmbiguously,
- ui.action_Fullscreen, &QAction::trigger);
- connect(GetHotkey("Main Window", "Exit Fullscreen", this), &QShortcut::activated, this, [&] {
- if (emulation_running) {
- ui.action_Fullscreen->setChecked(false);
- ToggleFullscreen();
- }
- });
+ hotkey_registry.RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
+ hotkey_registry.RegisterHotkey("Main Window", "Start Emulation");
+ hotkey_registry.RegisterHotkey("Main Window", "Continue/Pause", QKeySequence(Qt::Key_F4));
+ hotkey_registry.RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen);
+ hotkey_registry.RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape),
+ Qt::ApplicationShortcut);
+ hotkey_registry.RegisterHotkey("Main Window", "Toggle Speed Limit", QKeySequence("CTRL+Z"),
+ Qt::ApplicationShortcut);
+ hotkey_registry.LoadHotkeys();
+
+ connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated,
+ this, &GMainWindow::OnMenuLoadFile);
+ connect(hotkey_registry.GetHotkey("Main Window", "Start Emulation", this),
+ &QShortcut::activated, this, &GMainWindow::OnStartGame);
+ connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause", this), &QShortcut::activated,
+ this, [&] {
+ if (emulation_running) {
+ if (emu_thread->IsRunning()) {
+ OnPauseGame();
+ } else {
+ OnStartGame();
+ }
+ }
+ });
+ connect(hotkey_registry.GetHotkey("Main Window", "Fullscreen", render_window),
+ &QShortcut::activated, ui.action_Fullscreen, &QAction::trigger);
+ connect(hotkey_registry.GetHotkey("Main Window", "Fullscreen", render_window),
+ &QShortcut::activatedAmbiguously, ui.action_Fullscreen, &QAction::trigger);
+ connect(hotkey_registry.GetHotkey("Main Window", "Exit Fullscreen", this),
+ &QShortcut::activated, this, [&] {
+ if (emulation_running) {
+ ui.action_Fullscreen->setChecked(false);
+ ToggleFullscreen();
+ }
+ });
+ connect(hotkey_registry.GetHotkey("Main Window", "Toggle Speed Limit", this),
+ &QShortcut::activated, this, [&] {
+ Settings::values.toggle_framelimit = !Settings::values.toggle_framelimit;
+ UpdateStatusBar();
+ });
}
void GMainWindow::SetDefaultUIGeometry() {
@@ -282,6 +316,8 @@ void GMainWindow::ConnectMenuEvents() {
// File
connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile);
connect(ui.action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder);
+ connect(ui.action_Install_File_NAND, &QAction::triggered, this,
+ &GMainWindow::OnMenuInstallToNAND);
connect(ui.action_Select_Game_List_Root, &QAction::triggered, this,
&GMainWindow::OnMenuSelectGameListRoot);
connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close);
@@ -302,7 +338,8 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
// Fullscreen
- ui.action_Fullscreen->setShortcut(GetHotkey("Main Window", "Fullscreen", this)->key());
+ ui.action_Fullscreen->setShortcut(
+ hotkey_registry.GetHotkey("Main Window", "Fullscreen", this)->key());
connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
// Help
@@ -381,10 +418,11 @@ bool GMainWindow::LoadROM(const QString& filename) {
}
Core::System& system{Core::System::GetInstance()};
+ system.SetFilesystem(vfs);
system.SetGPUDebugContext(debug_context);
- const Core::System::ResultStatus result{system.Load(render_window, filename.toStdString())};
+ const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
render_window->DoneCurrent();
@@ -395,39 +433,14 @@ bool GMainWindow::LoadROM(const QString& filename) {
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("The ROM format is not supported."));
break;
- case Core::System::ResultStatus::ErrorUnsupportedArch:
- LOG_CRITICAL(Frontend, "Unsupported architecture detected!", filename.toStdString());
- QMessageBox::critical(this, tr("Error while loading ROM!"),
- tr("The ROM uses currently unusable 32-bit architecture"));
- break;
case Core::System::ResultStatus::ErrorSystemMode:
LOG_CRITICAL(Frontend, "Failed to load ROM!");
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("Could not determine the system mode."));
break;
-
- case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: {
- QMessageBox::critical(
- this, tr("Error while loading ROM!"),
- tr("The game that you are trying to load must be decrypted before being used with "
- "yuzu. A real Switch is required.<br/><br/>"
- "For more information on dumping and decrypting games, please see the following "
- "wiki pages: <ul>"
- "<li><a href='https://yuzu-emu.org/wiki/dumping-game-cartridges/'>Dumping Game "
- "Cartridges</a></li>"
- "<li><a href='https://yuzu-emu.org/wiki/dumping-installed-titles/'>Dumping "
- "Installed Titles</a></li>"
- "</ul>"));
- break;
- }
- case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
- QMessageBox::critical(this, tr("Error while loading ROM!"),
- tr("The ROM format is not supported."));
- break;
-
case Core::System::ResultStatus::ErrorVideoCore:
QMessageBox::critical(
- this, tr("An error occured in the video core."),
+ this, tr("An error occurred initializing the video core."),
tr("yuzu has encountered an error while running the video core, please see the "
"log for more details."
"For more information on accessing the log, please see the following page: "
@@ -439,9 +452,23 @@ bool GMainWindow::LoadROM(const QString& filename) {
break;
default:
- QMessageBox::critical(
- this, tr("Error while loading ROM!"),
- tr("An unknown error occured. Please see the log for more details."));
+ if (static_cast<u32>(result) >
+ static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) {
+ LOG_CRITICAL(Frontend, "Failed to load ROM!");
+ const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader);
+ const u16 error_id = static_cast<u16>(result) - loader_id;
+ QMessageBox::critical(
+ this, tr("Error while loading ROM!"),
+ QString::fromStdString(fmt::format(
+ "While attempting to load the ROM requested, an error occured. Please "
+ "refer to the yuzu wiki for more information or the yuzu discord for "
+ "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
+ loader_id, error_id, static_cast<Loader::ResultStatus>(error_id))));
+ } else {
+ QMessageBox::critical(
+ this, tr("Error while loading ROM!"),
+ tr("An unknown error occurred. Please see the log for more details."));
+ }
break;
}
return false;
@@ -529,11 +556,11 @@ void GMainWindow::StoreRecentFile(const QString& filename) {
}
void GMainWindow::UpdateRecentFiles() {
- unsigned int num_recent_files =
- std::min(UISettings::values.recent_files.size(), static_cast<int>(max_recent_files_item));
+ const int num_recent_files =
+ std::min(UISettings::values.recent_files.size(), max_recent_files_item);
- for (unsigned int i = 0; i < num_recent_files; i++) {
- QString text = QString("&%1. %2").arg(i + 1).arg(
+ for (int i = 0; i < num_recent_files; i++) {
+ const QString text = QString("&%1. %2").arg(i + 1).arg(
QFileInfo(UISettings::values.recent_files[i]).fileName());
actions_recent_files[i]->setText(text);
actions_recent_files[i]->setData(UISettings::values.recent_files[i]);
@@ -545,12 +572,8 @@ void GMainWindow::UpdateRecentFiles() {
actions_recent_files[j]->setVisible(false);
}
- // Grey out the recent files menu if the list is empty
- if (num_recent_files == 0) {
- ui.menu_recent_files->setEnabled(false);
- } else {
- ui.menu_recent_files->setEnabled(true);
- }
+ // Enable the recent files menu if the list isn't empty
+ ui.menu_recent_files->setEnabled(num_recent_files != 0);
}
void GMainWindow::OnGameListLoadFile(QString game_path) {
@@ -581,9 +604,15 @@ void GMainWindow::OnMenuLoadFile() {
}
void GMainWindow::OnMenuLoadFolder() {
- QDir dir = QFileDialog::getExistingDirectory(this, tr("Open Extracted ROM Directory"));
+ const QString dir_path =
+ QFileDialog::getExistingDirectory(this, tr("Open Extracted ROM Directory"));
- QStringList matching_main = dir.entryList(QStringList("main"), QDir::Files);
+ if (dir_path.isNull()) {
+ return;
+ }
+
+ const QDir dir{dir_path};
+ const QStringList matching_main = dir.entryList(QStringList("main"), QDir::Files);
if (matching_main.size() == 1) {
BootGame(dir.path() + DIR_SEP + matching_main[0]);
} else {
@@ -592,6 +621,148 @@ void GMainWindow::OnMenuLoadFolder() {
}
}
+void GMainWindow::OnMenuInstallToNAND() {
+ const QString file_filter =
+ tr("Installable Switch File (*.nca *.xci);;Nintendo Content Archive (*.nca);;NX Cartridge "
+ "Image (*.xci)");
+ QString filename = QFileDialog::getOpenFileName(this, tr("Install File"),
+ UISettings::values.roms_path, file_filter);
+
+ if (filename.isEmpty()) {
+ return;
+ }
+
+ const auto qt_raw_copy = [this](FileSys::VirtualFile src, FileSys::VirtualFile dest) {
+ if (src == nullptr || dest == nullptr)
+ return false;
+ if (!dest->Resize(src->GetSize()))
+ return false;
+
+ std::array<u8, 0x1000> buffer{};
+ const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size());
+
+ QProgressDialog progress(
+ tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())),
+ tr("Cancel"), 0, progress_maximum, this);
+ progress.setWindowModality(Qt::WindowModal);
+
+ for (size_t i = 0; i < src->GetSize(); i += buffer.size()) {
+ if (progress.wasCanceled()) {
+ dest->Resize(0);
+ return false;
+ }
+
+ const int progress_value = static_cast<int>(i / buffer.size());
+ progress.setValue(progress_value);
+
+ const auto read = src->Read(buffer.data(), buffer.size(), i);
+ dest->Write(buffer.data(), read, i);
+ }
+
+ return true;
+ };
+
+ const auto success = [this]() {
+ QMessageBox::information(this, tr("Successfully Installed"),
+ tr("The file was successfully installed."));
+ game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
+ };
+
+ const auto failed = [this]() {
+ QMessageBox::warning(
+ this, tr("Failed to Install"),
+ tr("There was an error while attempting to install the provided file. It "
+ "could have an incorrect format or be missing metadata. Please "
+ "double-check your file and try again."));
+ };
+
+ const auto overwrite = [this]() {
+ return QMessageBox::question(this, tr("Failed to Install"),
+ tr("The file you are attempting to install already exists "
+ "in the cache. Would you like to overwrite it?")) ==
+ QMessageBox::Yes;
+ };
+
+ if (filename.endsWith("xci", Qt::CaseInsensitive)) {
+ const auto xci = std::make_shared<FileSys::XCI>(
+ vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
+ if (xci->GetStatus() != Loader::ResultStatus::Success) {
+ failed();
+ return;
+ }
+ const auto res =
+ Service::FileSystem::GetUserNANDContents()->InstallEntry(xci, false, qt_raw_copy);
+ if (res == FileSys::InstallResult::Success) {
+ success();
+ } else {
+ if (res == FileSys::InstallResult::ErrorAlreadyExists) {
+ if (overwrite()) {
+ const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
+ xci, true, qt_raw_copy);
+ if (res2 == FileSys::InstallResult::Success) {
+ success();
+ } else {
+ failed();
+ }
+ }
+ } else {
+ failed();
+ }
+ }
+ } else {
+ const auto nca = std::make_shared<FileSys::NCA>(
+ vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
+ if (nca->GetStatus() != Loader::ResultStatus::Success) {
+ failed();
+ return;
+ }
+
+ const QStringList tt_options{tr("System Application"),
+ tr("System Archive"),
+ tr("System Application Update"),
+ tr("Firmware Package (Type A)"),
+ tr("Firmware Package (Type B)"),
+ tr("Game"),
+ tr("Game Update"),
+ tr("Game DLC"),
+ tr("Delta Title")};
+ bool ok;
+ const auto item = QInputDialog::getItem(
+ this, tr("Select NCA Install Type..."),
+ tr("Please select the type of title you would like to install this NCA as:\n(In "
+ "most instances, the default 'Game' is fine.)"),
+ tt_options, 5, false, &ok);
+
+ auto index = tt_options.indexOf(item);
+ if (!ok || index == -1) {
+ QMessageBox::warning(this, tr("Failed to Install"),
+ tr("The title type you selected for the NCA is invalid."));
+ return;
+ }
+
+ if (index >= 5)
+ index += 0x7B;
+
+ const auto res = Service::FileSystem::GetUserNANDContents()->InstallEntry(
+ nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
+ if (res == FileSys::InstallResult::Success) {
+ success();
+ } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
+ if (overwrite()) {
+ const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
+ nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
+ if (res2 == FileSys::InstallResult::Success) {
+ success();
+ } else {
+ failed();
+ }
+ }
+ } else {
+ failed();
+ }
+ }
+}
+
void GMainWindow::OnMenuSelectGameListRoot() {
QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
if (!dir_path.isEmpty()) {
@@ -604,9 +775,8 @@ void GMainWindow::OnMenuRecentFile() {
QAction* action = qobject_cast<QAction*>(sender());
assert(action);
- QString filename = action->data().toString();
- QFileInfo file_info(filename);
- if (file_info.exists()) {
+ const QString filename = action->data().toString();
+ if (QFileInfo::exists(filename)) {
BootGame(filename);
} else {
// Display an error message and remove the file from the list.
@@ -704,11 +874,14 @@ void GMainWindow::ToggleWindowMode() {
}
void GMainWindow::OnConfigure() {
- ConfigureDialog configureDialog(this);
+ ConfigureDialog configureDialog(this, hotkey_registry);
+ auto old_theme = UISettings::values.theme;
auto result = configureDialog.exec();
if (result == QDialog::Accepted) {
configureDialog.applyConfiguration();
- UpdateUITheme();
+ if (UISettings::values.theme != old_theme)
+ UpdateUITheme();
+ game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
config->Save();
}
}
@@ -841,7 +1014,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
UISettings::values.first_start = false;
game_list->SaveInterfaceLayout();
- SaveHotkeys();
+ hotkey_registry.SaveHotkeys();
// Shutdown session if the emu thread is active...
if (emu_thread != nullptr)
@@ -895,15 +1068,14 @@ void GMainWindow::UpdateUITheme() {
QStringList theme_paths(default_theme_paths);
if (UISettings::values.theme != UISettings::themes[0].second &&
!UISettings::values.theme.isEmpty()) {
- QString theme_uri(":" + UISettings::values.theme + "/style.qss");
+ const QString theme_uri(":" + UISettings::values.theme + "/style.qss");
QFile f(theme_uri);
- if (!f.exists()) {
- LOG_ERROR(Frontend, "Unable to set style, stylesheet file not found");
- } else {
- f.open(QFile::ReadOnly | QFile::Text);
+ if (f.open(QFile::ReadOnly | QFile::Text)) {
QTextStream ts(&f);
qApp->setStyleSheet(ts.readAll());
GMainWindow::setStyleSheet(ts.readAll());
+ } else {
+ LOG_ERROR(Frontend, "Unable to set style, stylesheet file not found");
}
theme_paths.append(QStringList{":/icons/default", ":/icons/" + UISettings::values.theme});
QIcon::setThemeName(":/icons/" + UISettings::values.theme);
@@ -939,7 +1111,6 @@ int main(int argc, char* argv[]) {
QCoreApplication::setOrganizationName("yuzu team");
QCoreApplication::setApplicationName("yuzu");
- QApplication::setAttribute(Qt::AA_X11InitThreads);
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
QApplication app(argc, argv);
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 074bba3f9..5f4d2ab9a 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -9,6 +9,7 @@
#include <QTimer>
#include "core/core.h"
#include "ui_main.h"
+#include "yuzu/hotkeys.h"
class Config;
class EmuThread;
@@ -43,7 +44,7 @@ public:
void filterBarSetChecked(bool state);
void UpdateUITheme();
GMainWindow();
- ~GMainWindow();
+ ~GMainWindow() override;
signals:
@@ -124,6 +125,7 @@ private slots:
void OnGameListOpenSaveFolder(u64 program_id);
void OnMenuLoadFile();
void OnMenuLoadFolder();
+ void OnMenuInstallToNAND();
/// Called whenever a user selects the "File->Select Game List Root" menu item
void OnMenuSelectGameListRoot();
void OnMenuRecentFile();
@@ -160,6 +162,9 @@ private:
bool emulation_running = false;
std::unique_ptr<EmuThread> emu_thread;
+ // FS
+ FileSys::VirtualFilesystem vfs;
+
// Debugger panes
ProfilerWidget* profilerWidget;
MicroProfileDialog* microProfileDialog;
@@ -172,6 +177,8 @@ private:
// stores default icon theme search paths for the platform
QStringList default_theme_paths;
+ HotkeyRegistry hotkey_registry;
+
protected:
void dropEvent(QDropEvent* event) override;
void dragEnterEvent(QDragEnterEvent* event) override;
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 22c4cad08..a3bfb2af3 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -57,6 +57,8 @@
<string>Recent Files</string>
</property>
</widget>
+ <addaction name="action_Install_File_NAND" />
+ <addaction name="separator"/>
<addaction name="action_Load_File"/>
<addaction name="action_Load_Folder"/>
<addaction name="separator"/>
@@ -102,6 +104,11 @@
<addaction name="menu_View"/>
<addaction name="menu_Help"/>
</widget>
+ <action name="action_Install_File_NAND">
+ <property name="text">
+ <string>Install File to NAND...</string>
+ </property>
+ </action>
<action name="action_Load_File">
<property name="text">
<string>Load File...</string>
diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h
index 2286c2559..051494bc5 100644
--- a/src/yuzu/ui_settings.h
+++ b/src/yuzu/ui_settings.h
@@ -54,6 +54,12 @@ struct Values {
// logging
bool show_console;
+
+ // Game List
+ bool show_unknown;
+ uint32_t icon_size;
+ uint8_t row_1_text_id;
+ uint8_t row_2_text_id;
};
extern Values values;
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index cea1a5e62..9bf26717f 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -105,6 +105,11 @@ void Config::ReadValues() {
Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 0.0);
Settings::values.bg_blue = (float)sdl2_config->GetReal("Renderer", "bg_blue", 0.0);
+ // Audio
+ Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
+ Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
+ Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1);
+
// Data Storage
Settings::values.use_virtual_sd =
sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
@@ -114,6 +119,7 @@ void Config::ReadValues() {
// Miscellaneous
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
+ Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false);
// Debugging
Settings::values.use_gdbstub = sdl2_config->GetBoolean("Debugging", "use_gdbstub", false);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 5eca38b48..9a935a0d5 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -118,7 +118,7 @@ bg_green =
layout_option =
# Toggle custom layout (using the settings below) on or off.
-# 0 (default): Off , 1: On
+# 0 (default): Off, 1: On
custom_layout =
# Screen placement when using Custom layout option
@@ -143,19 +143,17 @@ swap_screen =
[Audio]
# Which audio output engine to use.
-# auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available)
+# auto (default): Auto-select, null: No audio output, cubeb: Cubeb audio engine (if available)
output_engine =
-# Whether or not to enable the audio-stretching post-processing effect.
-# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter,
-# at the cost of increasing audio latency.
-# 0: No, 1 (default): Yes
-enable_audio_stretching =
-
# Which audio device to use.
# auto (default): Auto-select
output_device =
+# Output volume.
+# 1.0 (default): 100%, 0.0; mute
+volume =
+
[Data Storage]
# Whether to create a virtual SD card.
# 1 (default): Yes, 0: No
@@ -166,6 +164,16 @@ use_virtual_sd =
# 1: Yes, 0 (default): No
use_docked_mode =
+# Sets the account username, max length is 32 characters
+# yuzu (default)
+username =
+
+# Sets the systems language index
+# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,
+# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French,
+# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese
+language_index =
+
# The system region that yuzu will use during emulation
# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
region_value =
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 72ba7d49c..e2945b6cf 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -164,6 +164,8 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
OnResize();
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
SDL_PumpEvents();
+ LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_name, Common::g_scm_branch,
+ Common::g_scm_desc);
DoneCurrent();
}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index 1d835c3c6..d34902109 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -10,7 +10,7 @@
struct SDL_Window;
-class EmuWindow_SDL2 : public EmuWindow {
+class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
public:
explicit EmuWindow_SDL2(bool fullscreen);
~EmuWindow_SDL2();
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index b5392c499..9095cf27d 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -7,6 +7,8 @@
#include <string>
#include <thread>
+#include <fmt/ostream.h>
+
#include "common/common_paths.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
@@ -23,6 +25,7 @@
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
#include <getopt.h>
+#include "core/crypto/key_manager.h"
#ifndef _MSC_VER
#include <unistd.h>
#endif
@@ -71,6 +74,7 @@ static void InitializeLogging() {
/// Application entry point
int main(int argc, char** argv) {
Config config;
+
int option_index = 0;
bool use_gdbstub = Settings::values.use_gdbstub;
u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port);
@@ -159,10 +163,11 @@ int main(int argc, char** argv) {
}
Core::System& system{Core::System::GetInstance()};
+ system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
SCOPE_EXIT({ system.Shutdown(); });
- const Core::System::ResultStatus load_result{system.Load(emu_window.get(), filepath)};
+ const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)};
switch (load_result) {
case Core::System::ResultStatus::ErrorGetLoader:
@@ -171,15 +176,6 @@ int main(int argc, char** argv) {
case Core::System::ResultStatus::ErrorLoader:
LOG_CRITICAL(Frontend, "Failed to load ROM!");
return -1;
- case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted:
- LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before "
- "being used with yuzu. \n\n For more information on dumping and "
- "decrypting games, please refer to: "
- "https://yuzu-emu.org/wiki/dumping-game-cartridges/");
- return -1;
- case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
- LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported.");
- return -1;
case Core::System::ResultStatus::ErrorNotInitialized:
LOG_CRITICAL(Frontend, "CPUCore not initialized");
return -1;
@@ -187,10 +183,21 @@ int main(int argc, char** argv) {
LOG_CRITICAL(Frontend, "Failed to determine system mode!");
return -1;
case Core::System::ResultStatus::ErrorVideoCore:
- LOG_CRITICAL(Frontend, "VideoCore not initialized");
+ LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!");
return -1;
case Core::System::ResultStatus::Success:
break; // Expected case
+ default:
+ if (static_cast<u32>(load_result) >
+ static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) {
+ const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader);
+ const u16 error_id = static_cast<u16>(load_result) - loader_id;
+ LOG_CRITICAL(Frontend,
+ "While attempting to load the ROM requested, an error occured. Please "
+ "refer to the yuzu wiki for more information or the yuzu discord for "
+ "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
+ loader_id, error_id, static_cast<Loader::ResultStatus>(error_id));
+ }
}
Core::Telemetry().AddField(Telemetry::FieldType::App, "Frontend", "SDL");