Compare commits

..

470 Commits

Author SHA1 Message Date
c9942b35bb Revert "vk_instance: Always use geometry shaders if available"
This reverts commit 0a976f30c1.
2023-03-29 20:53:01 +03:00
ffe6904502 vk_master_semaphore: Remove timeout 2023-03-26 11:53:19 +03:00
fcf9d29a62 Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2 2023-03-26 11:50:15 +03:00
d9d0fc63ec applet: Fix HLE applet pre-start lifecycle. (#6362) 2023-03-25 22:36:14 +01:00
44097c2a8d gl_shader_disk_cache: Avoid reopening files every time a shader need to be written. (#6344)
Hopefully reduces stutters with Android SAF
2023-03-25 23:35:17 +02:00
9d7e68b7fc gl_shader_gen: Disable logging 2023-03-25 22:14:59 +02:00
fdb7ab47ff Merge pull request #6364 from Steveice10/break_error
kernel: Set system error status on svcBreak.
2023-03-25 01:18:26 -07:00
0a976f30c1 vk_instance: Always use geometry shaders if available
* Fixes broken lighting in some games
2023-03-25 09:12:39 +02:00
8e05af4389 vk_instance: Blacklist broken extensions on newer qualcomm/arm drivers 2023-03-25 09:11:51 +02:00
5317c00c45 Merge pull request #6368 from GPUCode/msvc-dup
Check fd before using dup
2023-03-24 10:29:55 -05:00
c7f8bc5582 file_util: Check fd before using dup 2023-03-24 16:56:31 +02:00
d2b719ac5a vk_scheduler: split work queue waits and execution waits 2023-03-24 14:22:28 +02:00
4accbeba0d Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2 2023-03-24 11:17:21 +02:00
54385a54eb citra_qt: Prevent OS sleep on Linux when a game is running (#6249) 2023-03-23 19:37:10 +01:00
343717e683 citra_android: Implement edge-to-edge (#6349) 2023-03-23 19:36:54 +01:00
8d563d37b4 citra_android: Storage Access Framework implementation (#6313) 2023-03-23 14:30:52 +01:00
Mai
8c12eb4905 Merge pull request #6360 from SachinVin/b
common\common_funcs.h:  use __builtin_trap for Crash()
2023-03-21 21:55:35 -04:00
f1c282775d kernel: Set system error status on svcBreak. 2023-03-21 14:19:42 -07:00
0c3fe272b6 citra_qt: Add enhancement options to per-game (#6308)
Co-authored-by: Tobias <thm.frey@gmail.com>
2023-03-21 22:12:13 +01:00
8434d30768 common\common_funcs.h: use __builtin_trap for Crash() 2023-03-21 22:34:06 +05:30
fbf53686c3 apt: Fix exiting to game list on application close. (#6353) 2023-03-21 17:07:49 +01:00
794d051f0c common\CMakeLists.txt: add missing arch.h (#6359) 2023-03-21 17:06:28 +01:00
3fb48716c5 CreateThread invalid processor ID return error instead of assert. (#6354) 2023-03-21 17:06:07 +01:00
359a1b3296 citra_android: Fix input shifting in emulation activity (#6352) 2023-03-21 17:05:42 +01:00
a2fd43deab Revert "citra_android: Use androidx splash screen (#6355)" (#6357)
This reverts commit 27c280534d.
2023-03-17 10:34:00 +02:00
27c280534d citra_android: Use androidx splash screen (#6355) 2023-03-16 08:30:47 +02:00
e18e30a8cc citra_android: Enable themed icon (#6351) 2023-03-15 09:21:54 +02:00
6fbc54b0c5 citra-qt: fixes to per game settings (#6298)
* citra-qt config: small misc changes

Remove unused ReadSettingGlobal

Remove unused WriteSetting overload

ReadGlobalSetting: rename default value variable

* qt config: fix u16 values being written as QMetaType

* qt config: rework post processing shader setting

handles post processing setting properly when per-game settings are used.
the anaglyph shader is given its own setting, separate from the post
processing name.

* qt config: use u32 instead of unsigned int when casting
2023-03-13 23:02:07 +02:00
49acfe428a citra_android: Bundle speex by default (#6348)
Without this, builds will fail on linux
2023-03-13 22:46:22 +02:00
ee26b5b82f vk_shader_gen_spv: Return when gas mode is used
* Otherwise the shader compiler will crash since OpFunctionEnd was called
2023-03-13 18:55:04 +02:00
aa8df317af citra_android: fix DiskShaderCacheProgress crash (#6346) 2023-03-13 11:16:38 +05:30
2cbf6fbb17 qt: Fix keys tutorial link in update downloader. (#6343) 2023-03-12 21:28:04 +05:30
12a5265db1 citra_qt: Fix per-game graphics api option
* This was a pain to implement due to the sheer amount of combinations. I hope there aren't any bugs...
2023-03-12 00:06:54 +02:00
eb8b463ca8 Merge branch 'vulkan-2' of https://github.com/GPUCode/citra into vulkan-2 2023-03-11 20:46:54 +02:00
72c1785bf0 renderer_vulkan: Revert some recent present changes
* Fixes the deadlocking on mingw until I rewrite presentation again
2023-03-11 20:45:19 +02:00
a2aca3dde6 Merge branch 'master' into vulkan-2 2023-03-11 13:15:41 +02:00
27be16ee31 Update AndroidManifest for Android TV (#6330) 2023-03-10 00:44:45 +01:00
c96f54f022 Implement app management support (suspend, resume, close, etc) (#6322) 2023-03-10 00:44:26 +01:00
d2caf2d386 citra_android: Start material 3 migration (#6335) 2023-03-09 23:22:11 +01:00
1cca713e3b citra_android: New settings fragment animations (#6332) 2023-03-09 21:54:32 +05:30
c5f2267306 renderer_vulkan: Emulate 3 component formats when unsupported
* Using uscaled formats isn't enough for all targets, the steam deck for example still crashes. The previous approach involved breaking the attribute to vec2 + vec1 and combining them. This commit implements something much simpler; the attribute is replaced with the 4 component version and the shader then zeros the w component. Since the fixed binding is at least 16bytes and exists at the end of the vertex data, we always have adequate space to alias so tihs shouldn't break.
2023-03-09 16:02:21 +02:00
976995ba08 cfg: Set system setup complete flag when formatting save. (#6331) 2023-03-09 00:05:00 +01:00
911fe5610c vk_renderpass_cache: Bring back flushes
* Idk why they were removed
2023-03-08 16:01:32 +02:00
b3e0078041 vk_resource_pool: Increase buffer descriptors 2023-03-08 15:20:10 +02:00
eeb1ff7965 rasterizer_cache: Avoid redundant texture copies when using texcubes 2023-03-08 10:11:47 +02:00
07e02a1acf Port multiplayer related PRs from yuzu (yuzu-emu/yuzu#9661 and yuzu-emu/yuzu#9713) (#6319)
Co-authored-by: SoRadGaming <sohorhab.azizdel@outlook.com>
Co-authored-by: Luke Sawczak <luke@unfamiliarplace.com>
2023-03-08 00:51:46 +01:00
8721456944 renderer_vulkan: Use dynamic uniform buffers
* Reduce descriptor update overhead
2023-03-07 23:38:48 +02:00
a23fbae391 vk_resource_pool: Add back eSampledImage
* It's used by format reinterpreter
2023-03-06 22:28:31 +02:00
0a8f11ca63 renderer_vulkan: Small cleanups 2023-03-05 17:34:35 +02:00
8f194b5fff rasterizer_cache: Handle null surface id in GetTextureSurface
* Pokemon X tries to use a texture with zero width. The previous code handled this so will we
2023-03-05 16:36:19 +02:00
3b050668bb vk_texture_mailbox: Fix shutdown 2023-03-05 14:12:29 +02:00
d054eea0c4 rasterizer_cache: Handle null surface cubes properly 2023-03-05 14:05:22 +02:00
b9021ea469 renderer_vulkan: Address various sync issues
* Drop Common::SPSCQueue as it sometimes gives garbage frames.

* Reduce master semaphore timeout to allow the wait to recover in cases wher it gets stuck
2023-03-05 01:27:39 +02:00
223627c381 vk_scheduler: Prevent DispatchWork stalls
* Now that Finish no longer depends on the queue being empty of not we can move the chunk execution out of the work_mutex scope
2023-03-04 22:33:25 +02:00
ad4339464a renderer_vulkan: Submit present frames from the EmuThread
* This commit also reworks scheduler synchronization somewhat to be more reliable. Flush is given an atomic_bool is signal when the submit is done
2023-03-04 22:24:56 +02:00
32cb44d2b9 vk_descriptor_manager: Cache descriptor sets 2023-03-03 23:06:16 +02:00
39edca2cf7 vk_texture_runtime: Disable anisotropic filtering if unsupported 2023-03-03 22:47:27 +02:00
0a3acc25d2 ci: Bump macOS target to 11 (Big Sur) (#6325) 2023-03-03 22:47:27 +02:00
3f0bcf5913 Revert "ci: Disable uploading final macOS artifacts until ready to resume producing." 2023-03-03 22:47:27 +02:00
2384c8f811 vk_texture_runtime: Bring back FramebufferView
* Also move the usage hint flags to the allocation. If an allocation is used as framebuffer there's a high chance it will be used again as such. In addition is helps keeping pipeline barriers correct even when the surface is destoyed and recreated (happens often with framebuffers)
2023-03-03 16:28:01 +02:00
c26cb68a0c vk_renderpass_cache: Commonize setup between renderpass and dynamic rendering implementations
* Also fix small issue that caused broken rendering on the latter
2023-03-03 16:24:10 +02:00
455a0198d9 ci: Bump macOS target to 11 (Big Sur) (#6325) 2023-03-03 15:04:31 +02:00
c34bc45bf1 custom_tex_manager: Fix a race with async decoding 2023-03-02 16:20:32 +02:00
19617f32c8 custom_tex_manager: Multithread custom texture loading and decode
* Each texture has an atomic flag to signal to the backend when decoding is finished

* Don't store the file data as well to conserve RAM.
2023-03-02 16:20:32 +02:00
8396ce0b47 rasterizer_cache: Improve debugging
* Give surfaces an object label viewable in renderdoc with useful information

* Break up the Cache Mgmt microprofile scope and commonize it
2023-03-02 16:20:32 +02:00
07f85cf639 vk_shader_gen_spv: Emulate fog
* Fixes the intro of MM3D
2023-03-02 16:20:32 +02:00
dfd8ded206 vk_pipeline_cache: Improve async pipeline android fallback
* When VK_EXT_pipeline_creation_feedback is unavailable don't synchronously compile the pipeline, this is slow

* Compile the pipeline asynchrounsly instead and have the record thread wait for it. This way we can have multiple pipelines compiling at once
2023-03-02 16:20:32 +02:00
06caa535d6 rasterizer_cache: Remove usage of shared_ptr 2023-03-02 16:20:32 +02:00
42bed30b98 custom_tex_manager: Fix dumping issues
* Use the proper hash for dumping

* Add the mipmap as a postfix to help pack creators
2023-03-02 16:20:32 +02:00
74e75f1996 rasterizer_cache: More texture pack nonsense
* Some packs turn out have mipmaps but not the base level of a texture. Handle this to avoid black textures at a distance
2023-03-02 16:20:32 +02:00
f04a6a4d83 vk_rasterizer: Reduce stream buffer size
* 64MB is more than enough, any higher and it fills up the 256MB device local-host visible heap
2023-03-02 16:20:32 +02:00
33be1b744b rasterizer_cache: Limit mipmap skip to custom surfaces
* Fixes missing mipmaps when custom textures is enabled but the game does not have any pack

* Also fixes black textures in cases where a custom texture was not provided
2023-03-02 16:20:32 +02:00
2c9e0ec723 video_core: Add more ASTC formats 2023-03-02 16:20:32 +02:00
d1ac33b18b Revert "Revert "vk_scheduler: wait for command processing to complete""
* No longer needed after async present and causes sync issues during swapchain recreation

This reverts commit 0381081c5d.
2023-03-02 16:20:32 +02:00
c00bdc4214 gl_texture_runtime: Generate all mipmaps 2023-03-02 16:20:32 +02:00
74be64b60a vk_stream_buffer: Fix synchronization during buffer overflow
* Especially with custom textures the bufer would fill up but didn't wait any watchers on overflow overriding some textures
2023-03-02 16:20:32 +02:00
11ca327951 renderer_vulkan: Optimize stream buffer usage
* Use vma for allocating the memory. In addition place upload/download buffers on the cpu, they don't need to be device local
2023-03-02 16:20:32 +02:00
631da59392 renderer_vulkan: Allow vsync change during gameplay 2023-03-02 16:20:32 +02:00
e861c456c9 custom_tex: Fix hash read on windows 2023-03-02 16:20:31 +02:00
c3ab060576 externals: Trim down zlib-ng build 2023-03-02 16:20:31 +02:00
94ee7c68fc video_core: Clear runtime on rasterizer cache flush
* When changing res scale or custom textures a large number of textures will be replaced so better not keep the old ones
2023-03-02 16:20:31 +02:00
8e8097e7c0 renderer_vulkan: Use combined image samplers
* Less descriptors = good
2023-03-02 16:20:31 +02:00
52683adedd video_core: Rewrite custom textures 2023-03-02 16:20:31 +02:00
e47c47245f rasterizer_cache: Add support for texture dumping 2023-03-02 16:20:31 +02:00
004b83c978 rasterizer_cache: Fix surface validation
* Sometimes the copy interval might be larger than the validation interval
2023-03-02 16:20:31 +02:00
4bff44c9a9 common: Move image decoders to common
* Replace the various image interfaces with spng which is very lightweight and fast. Also add a dds header which will be useful when support for that format is implemented
2023-03-02 16:20:31 +02:00
18ff007ff2 rasterizer_cache: Remove expanded surface immediately
* Since allocations are recycled under the hood there's not risk of a texture being in use
2023-03-02 16:20:31 +02:00
e41ceb3c88 rasterizer_cache: Explicit type in traits 2023-03-02 16:20:31 +02:00
14880862bc video_core: Cleanup surface interface
* Remove unused FramebufferView and make the opengl handles private
2023-03-02 16:20:31 +02:00
e651bb41bc video_core: Cleanup microprofiles
* Remove upload/download targets these are covered by the rasterizer cache
2023-03-02 16:20:31 +02:00
8e93039ef9 rasterizer_cache: Support multi-level surfaces
* With this commit the cache can now directly upload and use mipmaps
  without needing to sync them with watchers. By using native mimaps
  directly this also adds support for mipmap for cube

* Since watchers have been removed texture cubes still work but are uncached
  so slower as well. Will be fixed soon.
2023-03-02 16:20:31 +02:00
65b02f35c7 rasterizer_cache: Cleanup texture clears 2023-03-02 16:20:31 +02:00
d42ccb387a rasterizer_cache: Wrap common draw operation in FramebufferBase
* Makes the rasterizer draw method much cleaner
2023-03-02 16:20:31 +02:00
ee0a7476b3 rasterizer_cache: Simplify SurfaceBase
* The casts are bit ugly but will be refactored soon
2023-03-02 16:20:30 +02:00
45ffc56733 video_core: Manage samplers in the rasterizer cache 2023-03-02 16:20:30 +02:00
be8ee3d706 rasterizer_cache: Remove BlitSurfaces
* Choose copy or blit based on the caller instead
2023-03-02 16:20:30 +02:00
ab688170f0 rasterizer_cache: Commonize texture acceleration functions
* They don't contain any backend specific code so don't duplicate them
2023-03-02 16:20:30 +02:00
274f6093f3 rasterizer_cache: Move microprofile to the top 2023-03-02 16:20:30 +02:00
9662425337 rasterizer_cache: Remove Invalid match flags
* It was specified in every FindMatch. Only copy did not specify it, but copy surfaces ignore the flag regardless making it superflous
2023-03-02 16:20:30 +02:00
6fde9b3354 rasterizer_cache: Switch to page table
* Should be more efficient for surface storage than the interval map
2023-03-02 16:20:30 +02:00
e5907f0979 Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2 2023-03-02 16:19:54 +02:00
8f2a5374c3 ci: Build macOS architectures separately and combine (#6321)
* ci: Build macOS for different architectures separately.

* ci: Combine macOS builds into universal binary.

* ci: Disable uploading final macOS artifacts until ready to resume producing.
2023-03-01 19:58:09 +02:00
c961ecb9a4 jni\native.cpp: Log g_build_fullname on Android (#6318) 2023-02-28 21:59:30 +05:30
c6f9fd3b65 qt: Remove status bar 3D controls due to issues. (#6317)
The 3D toggle does not behave correctly as it does not have some
special logic from the enhancements configuration UI that determines
the post-processing shader defaults to use. Because of that, plus
an uptick in people seemingly accidentally enabling 3D options and
not being sure why Citra is rendering differently, just remove the
new UI components for now until better ideas for 3D control can
be worked out.
2023-02-28 14:10:14 +02:00
3c15398f9e apt: Implement additional applet state management. (#6303)
* apt: Implement additional library applet state management.

* kernel: Clear process handle table on exit.

* apt: Implement system applet commands.

* apt: Pop MediaType from command buffers with correct size.

* apt: Improve accuracy of parameters and HLE applet lifecycle.

* apt: General cleanup.

* file_sys: Make system save data open error code more correct.

Not sure if this is the exact right error code, but it's at least
more correct than before as Game Notes will now create its system
save data instead of throwing a fatal error.

* apt: Fix launching New 3DS Internet Browser.

* frd: Correct fix to GetMyScreenName response.
2023-02-28 14:09:54 +02:00
2855d30815 Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2 2023-02-26 21:33:52 +02:00
8b116aaa04 externals: Fix mismatched CryptoPP definitions between compile time and header use. (#6314) 2023-02-25 12:58:38 +02:00
cc5ea21f1c citra_qt: Write to config file on important config changes (#6311)
Qt isn't always writing changes on save. This causes config to be lost on crash. This PR ensures all changes are always saved on the file.

Ported from yuzu.

Co-authored-by: Narr the Reg <5944268+german77@users.noreply.github.com>
2023-02-25 12:57:59 +02:00
546c7b3bfd Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2 2023-02-19 16:05:11 +02:00
286f750c6c citra_qt: Move CPU speed slider to debug tab and Report Comptaibility to help menu (#6250) 2023-02-18 23:24:15 +01:00
d8c9335ef0 Resolve Black Screen on Intel GPU Regression (#6306)
* Get value for swap screen setting and check mono_render_option again

* resolve clang-format issue

* do not disable opengl blending since it is enabled by default

* reset blending state to default values after drawing second screen

* prevent resetting state blending when custom opacity is not used
2023-02-18 18:54:12 +02:00
cda358443f nim: Fully stub nim:u service. (#6290) 2023-02-17 19:30:47 +01:00
bf73cb57ca am: Return installed titles in GetNumTickets and GetTicketList stubs. (#6292) 2023-02-17 16:20:56 +02:00
9eb1cd2875 Added an option to set the proportion of the screens when using layout "Large Screen Small Screen", to allow the user to define how much bigger the large screen should be with respect to the smaller screen. Currently the value must be between 1 and 16, but I could set a different maximum value if that would be desired. Thank you very much! (#6252) 2023-02-17 16:19:52 +02:00
bb8dde8480 aes: Fix derivation of slot 0x25 key X from NATIVE_FIRM. (#6283) 2023-02-16 15:35:17 +02:00
41c10cd5a7 Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2 2023-02-16 12:59:33 +02:00
5aa80873e2 qt: Enable application options for system applications. (#6286) 2023-02-15 21:24:54 +01:00
5215468ff6 core\file_sys\archive_sdmc.cpp: Log error message if file failed to open. (#6284) 2023-02-14 22:19:45 +01:00
68162c29b4 cfg: Initialize backlight controls config blocks. (#6291) 2023-02-14 22:10:07 +01:00
a8e4e11cd5 Better Support for Picture-in-Picture Custom Layouts (Based on #6127) (#6247) 2023-02-14 22:06:11 +01:00
ab8d1c7d8b github: Improve Readme and add better issue templates (#6276)
* README: Update with latest information and better design

* .github: Add better issue templates

* Readme: Address review comments
2023-02-13 14:51:09 +01:00
1ab9b60a60 Services/APT: Implement PrepareToStartApplication, StartApplication, and WakeupApplication (#6280)
* Services/APT: Implemented PrepareToStartApplication and StartApplication.

This allows games to be launched from the Home Menu, however, there is still a bug with the GSP where the Home Menu doesn't release the GPU rights. It is unknown if the Home Menu should terminate itself after launching a new application.

To get the Home Menu to not hang when launching stuff, you need to have config block 0xF0006 (size 40 flags 8) in your config savegame, it doesn't matter if it's filled with zeros.

* Services/APT: Implement WakeupApplication.

With this, the Home Menu is now able to launch games when using an LLE NIM imlementation.

* Services/APT: Reset the app_start_parameters after launching the application with StartApplication.

* Services/APT: Simplify the StartApplication code by directly calling WakeupApplication.

---------

Co-authored-by: Subv <subv2112@gmail.com>
2023-02-12 08:47:08 +02:00
c2903a6b9d citra_qt: Hide updates on per-game config (#6296) 2023-02-12 08:45:43 +02:00
849d795f0e Port yuzu-emu/yuzu#8367: "Logging: Report Post Windows 10 2004 versions, like Windows 11" (#6295)
Co-authored-by: Kyle K <190571+Docteh@users.noreply.github.com>
2023-02-11 23:22:58 +01:00
bc77e16653 rasterizer_cache: Check levels when finding exact match
* Fixes validation errors in multiple games
2023-02-11 17:54:42 +02:00
6ba83db6dd externals: Switch back to upstream dynarmic
* Thanks mary for the quickfix
2023-02-11 17:29:55 +02:00
96effa46e4 vk_pipeline_cache: Reduce flickering on android 2023-02-11 13:17:32 +02:00
e7a1318773 externals: Switch to older dynarmic
* Upstream has lag issues
2023-02-11 13:17:12 +02:00
ffc9e34281 vk_rasterizer: Fix broken software shaders 2023-02-11 00:29:04 +02:00
20fc09df13 externals: Update dynarmic 2023-02-11 00:15:24 +02:00
6c78abb015 android: Perform AGP upgrades 2023-02-10 22:13:34 +02:00
0d3434734a vk_rasterizer: Skip draw if no attachments 2023-02-10 21:58:06 +02:00
42a6f7a42e vk_renderpass_cache: Flush on qcom as well 2023-02-10 21:53:13 +02:00
a40cde7f76 msvc: fix missing qtconcurrent dll (#6294) 2023-02-10 15:36:36 -03:00
95e6428d33 config: Remove async recording option
* There's no reason to turn this off aside from debugging. So use renderer_debug to to deduce whether to use a worker thread or not
2023-02-10 16:35:23 +02:00
d9ed4600ca video_core: Fix some struct formatting 2023-02-10 16:14:18 +02:00
612647f94f video_core: Only allocate needed levels
* Especially with high res scaling allocating so many levels increases memory usage. Also clamp level size to 8x8, since on  tiled textures it doesn't make sense to have any smaller than that. Fixes portal3DS and log spam on ZLBW
2023-02-10 16:07:55 +02:00
5eb72e9489 main: Enable High DPI fixes for Qt >= 5.14 (#6262)
Fixes https://github.com/citra-emu/citra/issues/4175
Fixes https://github.com/citra-emu/citra/issues/4977
2023-02-10 01:19:43 +01:00
6bef34852c Add option to configure to download system files from Nintendo Update Service (#6269)
Co-authored-by: B3n30 <benediktthomas@gmail.com>
2023-02-09 21:58:08 +02:00
691cb43871 Add shortcuts and status bar widgets to toggle and set 3D factor (#6277) 2023-02-09 21:57:06 +02:00
6a16a8f60d android: Enable async shaders by default 2023-02-09 17:50:49 +02:00
1ffd9f08af surface_params: Cleanup 2023-02-09 17:11:28 +02:00
c855d84492 texture_codec: Use namespace Color
* Makes the code somewhat cleaner
2023-02-09 17:04:22 +02:00
d461778296 vk_rasterizer: Small cleanup 2023-02-09 16:08:40 +02:00
3fe0130fdb vk_instance: Enable image view format reinterpretation 2023-02-09 14:41:42 +02:00
b0880f0ef8 video_core: Move rasterizer cache template definitions to separate file
* Helps with build times
2023-02-06 22:52:18 +02:00
0bb2e8c618 renderer_vulkan: More strict barriers 2023-02-06 22:30:34 +02:00
84ccb45c5c vk_rasterizer: Move vertex array setup to AccelerateDrawBatch
* Avoids state invalidating due to scheduler flushes
2023-02-06 21:34:24 +02:00
f8b853d001 video_core: Limit g_state usage in rasterizers
* Makes the code cleaner and should help in future refactoring endeavors
2023-02-06 20:46:43 +02:00
61e0725d9d renderer_vulkan: Barrier frame attachment 2023-02-06 18:24:40 +02:00
2b9ab33af3 Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2 2023-02-05 21:57:29 +02:00
09350f71e8 renderer_vulkan: Fix present mailbox shutdown sequence 2023-02-05 21:56:12 +02:00
582c438441 vk_rasterizer: Properly set fixed attrib offset
* There was a small chance the main attrib exactly fit the buffer which caused the fixed offset to be 0x8000000 and crash
2023-02-05 21:09:54 +02:00
bc10681156 renderer_vulkan: Cleanup renderpass code 2023-02-05 18:42:29 +02:00
faefc5cfe1 renderer_vulkan: Use separate present thread 2023-02-05 18:29:49 +02:00
f66d03dd48 citra_qt: Improvements to hotkeys and ui state management (#6224) 2023-02-04 19:06:20 +01:00
fd09f1471e common: Make equality operators explicit for Rectangle 2023-02-04 20:01:19 +02:00
c1c68a3487 renderer_vulkan: Move microprofile defines to top of file 2023-02-04 20:01:19 +02:00
5849d29fc1 video_core: Move RendererBase to VideoCore 2023-02-04 20:01:19 +02:00
b31b6e35a2 renderer_opengl: Rewrite stream buffer
* New implementation is based on Dolphin's MapAndSync and BufferStorage buffers.
  Replacing orphaning with syncrhonization which should make it much faster than before.

* Texture downloads don't use PBO anymore since it didn't offer any speed benefits. Finally
  a bug was fixed that only affected the glBufferData fallback path and should fix android/gles
2023-02-04 20:01:16 +02:00
79a53c8003 video_core: Remove Init method
* The constructor can do the same
2023-02-04 13:08:42 +02:00
fd9525acc2 video_core: Use interval map for cached_pages
* Also eliminate g_memory in hardware renderers
2023-02-04 12:57:57 +02:00
9b49d94644 Lower log level of some sdmc logs (#6266) 2023-02-03 23:41:06 +01:00
78cb48b23c common: Make TrimSourcePath constexpr (#6279) 2023-02-03 19:01:10 +01:00
3a6a17c708 externals: Bundle cryptopp as submodule. (#6272)
fix https://github.com/citra-emu/citra/issues/6271
2023-02-02 16:26:21 +01:00
938ec204f5 qt: Fix paintEvent not being called until window resize on macOS. (#25)
* qt: Remove need for AppleSurfaceHelper.

* qt: Fix paintEvent not being called until window resize on macOS.
2023-02-02 15:41:41 +02:00
3d3dd2d162 Merge pull request #6275 from zhaowenlan1779/tx-migrate
dist/languages: Migrate to new tx client
2023-02-02 16:51:13 +08:00
7c8bfbb078 Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2 2023-02-01 23:27:12 +02:00
d7bf139e85 renderer_vulkan: Add pipeline barriers for attachments 2023-02-01 23:26:44 +02:00
df7f1b13cb polyfill_thread: satisfy execution ordering requirements of stop_callback 2023-02-01 23:26:44 +02:00
e08e644e73 video_core: Move present globals to RendererSettings 2023-02-01 23:26:44 +02:00
ccf36b5e25 video_core: Remove global screenshot state 2023-02-01 23:26:44 +02:00
b6427d0ee0 renderer_vulkan: Cleanup code 2023-02-01 23:26:44 +02:00
5c401b8ea0 renderer_vulkan: Async presentation
* This rewrites a large portion of the presentation engine to be more thread safe
  and moves all swapchain usage to the presentation thread. Previously acquires were
  done on the main thread which required the next frame to wait for the previous one
  to finish presenting
* The new implementation is based on the OpenGL mailbox system, simplified. The screens
  are drawn on separate render frames that get sent to the presentation thread to be
  presented. Queue access is now thread safe as well.
2023-02-01 23:26:44 +02:00
bd3571db5a vk_blit_helper: Fix android crashes 2023-02-01 23:26:44 +02:00
b18710e4df renderer_vulkan: Emulate depth-stencil blits with VK_EXT_shader_stencil_export
* Should fix depth blits on AMD
2023-02-01 23:26:44 +02:00
99c3eb21b0 dist/languages: Migrate to new tx client 2023-02-01 14:57:12 +08:00
bb8cb3ff82 main: Globally disable the "?" button on dialogs (#6263)
Sets the AA_DisableWindowContextHelpButton attribute to disable this useless button globally. This is disabled by default on Qt6.
2023-01-28 21:38:15 +05:30
69b66cb41d renderer_vulkan: Implement VK_KHR_dynamic_rendering
* Removes the need for framebuffers/renderpass on desktop
2023-01-27 16:35:58 +02:00
0f6478a928 Fix crash when plugin has missing text section (#6264) 2023-01-27 15:06:35 +02:00
a5f86e9813 renderer_vulkan: Move framebuffer handling to the renderpass cache 2023-01-27 00:27:26 +02:00
920492925c vk_shader_gen: Disable clip plane 1 when unused
* Fixes Star Fox 3D missing half the screen
2023-01-26 22:30:27 +02:00
0381081c5d Revert "vk_scheduler: wait for command processing to complete"
* This causes DispatchWork to stall and everything that calls it resulting in noticeable slowdown
2023-01-26 22:05:38 +02:00
382b64d3c0 surface_base: Fix issue with GetCopyableInterval 2023-01-26 15:04:15 +02:00
a629aa0dde renderer_vulkan: Check for VK_EXT_pipeline_creation_feedback
* Unused at the moment but will be useful later
2023-01-26 14:32:58 +02:00
b29f263e1b renderer_vulkan: Support additional dynamic states 2023-01-25 22:46:35 +02:00
48d3093fc8 vk_instance: Rework feature management
* Use a helper macro to always check for features. Previously it was assumed extension availability was also feature availability but this isn't the case. This is inspired by skyline's trait_manager
2023-01-25 22:46:10 +02:00
f77491196c vk_renderpass_cache: Create renderpasses on demand 2023-01-25 22:41:50 +02:00
0fce3e556f externals: Update vulkan-headers 2023-01-25 00:29:47 +02:00
12e69913c2 renderer_vulkan: Rework attribute format handling
* Centralize format support query to the instance similar to pixel formats
  In addition drop the component splitting. Favour scaled formats which don't require
  any shader casting to work and fallback to uint if necessary. Using scaled formats
  also has the benefit of reducing vertex shader permutations.
2023-01-25 00:25:08 +02:00
89217f8c4b vk_shader_gen_spv: Fix scissor test 2023-01-24 22:17:05 +02:00
247b6900c7 vk_swapchain: Fix incorrect image_count
* Sometimes the swapchain won't create as many images as requested. Adjust image_count for fix that
2023-01-23 23:30:06 +02:00
84e54a52a6 core: Detect and return error if GBA virtual console is loaded. (#6257) 2023-01-23 15:21:57 +05:30
d704c6a3ac common: Support macOS application data path conventions. (#6258) 2023-01-23 15:20:50 +05:30
1e42a40640 vk_shader_gen: Remove defines
* Causes shader compiler errors
2023-01-22 23:29:54 +02:00
7eab7b4151 android: Expose async shaders in the GUI 2023-01-22 10:33:19 +02:00
e9ccd51286 renderer_vulkan: Trim down used features 2023-01-22 10:33:19 +02:00
9f385ddeb7 vk_instance: Only check the portability extension on apple platforms 2023-01-22 10:33:19 +02:00
ab73566acc renderer_vulkan: Add suport for VK_EXT_debug_report
* Used in older android devices
2023-01-22 10:33:19 +02:00
1e3971038f vk_swapchain: Create semaphores at swapchain creation time
* Sometimes minImageCount is higher than 3 and that caused crashes
2023-01-22 10:33:19 +02:00
306943532c renderer_vulkan: Preliminary screenshot support
* It's broken for now but at least it doesn't crash
2023-01-22 10:33:19 +02:00
27698b0c93 vk_instance: Manually enable features
* We need these features so better force enable them and have the driver crash if they're unavailable.
2023-01-22 10:33:18 +02:00
d6cab3ab40 renderer_vulkan: Flush scheduler on renderpass end
* Follows the Mali guide recommendation and fixes performance regression introduced by async shaders commit
2023-01-22 10:33:18 +02:00
cbd9a6ffe3 vk_swapchain: Prefer scheduler finish
* The scheduler might have recorded a present that uses the to-be-destroyed semaphores. vkWaitIdle might miss this
2023-01-22 10:33:18 +02:00
4752818920 renderer_vulkan: Async shaders 2023-01-22 10:33:18 +02:00
9b20bcea0f android: Allow opening in-emulation menu by pressing Back (#6248)
It seems like the menu isn't showing up for users on Android 13.
We're not sure what's wrong, and the approach we've been using for the
menu hasn't been entirely reliable in the past either (in particular
not on non-mobile form factors like Chromebooks and VR devices),
so let's make it possible to open the menu by pressing Back,
an action that works reliably on most kinds of Android devices.
(Not sure if there's an equivalent of Back on devices like watches,
but I think we can pretty safely ignore those for now.)
2023-01-22 13:12:27 +05:30
131129062b ci: Fix macOS script permissions. (#24) 2023-01-17 20:47:40 +02:00
fad1ee7140 Merge branch 'master' into vulkan-2 2023-01-17 18:39:04 +02:00
b9ca7bef3f rasterizer_cache: Handle texture swizzle case with unaligned offsets in same tile. (#23) 2023-01-17 13:42:47 +02:00
0e0771ad74 Merge from latest upstream (#22)
* externals: bump xbyak to v6.68

* externals: point to upstream dynarmic

* build: Update to support multi-arch builds.

* ci: Generate universal macOS build.

* macOS: Make Citra show up in the Launchpad Games folder (#6245)

* Instead of there being an "Abort/Continue" prompt when a savestate fails to save or load, it just brings up a warning box. (#6236)

* This fixes #6041 by changing OnCoreError. Instead of there being an "Abort/Continue" prompt when a savestate fails to save or load, it just brings up a warning box.

I also changed "Abort/Continue" to "Quit Game/Continue" for better clarity

* Fixed formatting

* externals: Switch to newer cryptopp-cmake. (#6242)

* Implement svcGetHandleInfo, svcOpenProcess/Thread, svcGetProcessList (#6243)

* Implement svcGetHandleInfo, svcOpenProcess/Thread, svcGetProcessList

* Apply suggestions

* Add comment to stubbed enum values in svcGetHandleInfo

* Revert u32 -> size_t

Co-authored-by: SachinVin <sachinvinayak2000@gmail.com>
Co-authored-by: SachinVin <26602104+SachinVin@users.noreply.github.com>
Co-authored-by: UltraHDR <108294295+UltraHDR@users.noreply.github.com>
Co-authored-by: upadsamay387 <56898833+upadsamay387@users.noreply.github.com>
Co-authored-by: PabloMK7 <hackyglitch2@gmail.com>
2023-01-17 13:11:41 +02:00
9c6035f254 Implement svcGetHandleInfo, svcOpenProcess/Thread, svcGetProcessList (#6243)
* Implement svcGetHandleInfo, svcOpenProcess/Thread, svcGetProcessList

* Apply suggestions

* Add comment to stubbed enum values in svcGetHandleInfo

* Revert u32 -> size_t
2023-01-15 21:50:54 +05:30
a298e4969b externals: Switch to newer cryptopp-cmake. (#6242) 2023-01-15 21:45:42 +05:30
bd1cabce86 Instead of there being an "Abort/Continue" prompt when a savestate fails to save or load, it just brings up a warning box. (#6236)
* This fixes #6041 by changing OnCoreError. Instead of there being an "Abort/Continue" prompt when a savestate fails to save or load, it just brings up a warning box.

I also changed "Abort/Continue" to "Quit Game/Continue" for better clarity

* Fixed formatting
2023-01-15 21:45:16 +05:30
489248e77f video_core: De-duplicate texture format conversion logic. (#21)
* video_core: De-duplicate texture format conversion logic.

* video_core: Replace std::byte with u8 and remove excess linear texture converters.

* video_core: Remove implicit RGBA conversions from convert table for now, add comments explaining omissions.
2023-01-13 13:54:42 +02:00
f593268476 rasterizer_cache: Add converted swizzle mapping for D24 and log error for missing (un)swizzle functions. (#20) 2023-01-13 00:51:31 +02:00
8fcc3d2121 rasterizer_cache: Add morton conversion for D24 <-> D32 (#19) 2023-01-12 13:33:12 +02:00
a3a8964d46 renderer_vulkan: Centralize pixel format trait management. (#18)
* renderer_vulkan: Centralize pixel format trait management.

* renderer_vulkan: Add D24 <-> D32 conversion support.
2023-01-12 10:43:40 +02:00
c8d614139c vk_shader_gen_spv: Implement scissor testing
* Fixes weird looking map in LBW
2023-01-11 22:20:53 +02:00
25fe723fa6 renderer_vulkan: Support self copy
FE games copy parts of the framebuffer to itself. Don't switch layout in that case
2023-01-11 20:48:20 +02:00
2335b47f4b code: Run clang format 2023-01-11 20:48:20 +02:00
10a7b60b12 ci: Fix android builds 2023-01-11 20:48:20 +02:00
98ab3c9610 common: Log more vulkan settings 2023-01-11 20:48:20 +02:00
0ca25b64e1 renderer_vulkan: Improve storage reinterpretation barriers 2023-01-11 20:48:20 +02:00
694e49b857 renderer_vulkan: Remove master semaphore fence
* Wasn't used anywhere
2023-01-11 20:48:20 +02:00
381db8452b renderer_vulkan: Gate reduced shadow binding count to Android only. (#17) 2023-01-11 15:03:11 +02:00
e2076f2385 shader: Handle out-of-bounds uniform access via address register. (#16) 2023-01-10 13:23:39 +02:00
ad2cbe2b26 macOS: Make Citra show up in the Launchpad Games folder (#6245) 2023-01-10 01:27:11 +01:00
9c206db630 video_core: Move some common state management out of specific render backends. (#15) 2023-01-09 19:28:18 +02:00
447f29285f renderer_vulkan: Add fence implementation of MasterSemaphore 2023-01-08 15:04:28 +02:00
26a9002d97 vk_swapchain: Lower image count to 3 2023-01-08 13:57:00 +02:00
a12748d79e vk_shader_gen_spv: Emulate logic ops 2023-01-08 13:02:23 +02:00
5abfdff66a android: Query window size from surface 2023-01-08 00:55:41 +02:00
8a315d0c8f vk_rasterizer: Initialize uniform buffers
* Pokemon Y crashes without this
2023-01-07 23:51:33 +02:00
4ee36e05b6 renderer_vulkan: Proper barriers on renderpass clear 2023-01-07 23:12:56 +02:00
e60a816d89 Merge pull request #6240 from Steveice10/universal
ci: Generate universal macOS build.
2023-01-07 19:39:22 +05:30
5d0e60a6aa ci: Generate universal macOS build. 2023-01-07 01:09:36 -08:00
a8848cce43 build: Update to support multi-arch builds. 2023-01-07 01:09:32 -08:00
11061f36e6 renderer_vulkan: Surface recreation works 2023-01-06 21:15:52 +02:00
6d286d5f8c vk_instance: Avoid enabling debug messenger when unsupported 2023-01-06 20:29:54 +02:00
0e325255f3 externals: point to upstream dynarmic 2023-01-06 06:41:51 -08:00
21fe65c29c externals: bump xbyak to v6.68 2023-01-06 06:41:51 -08:00
4619ed086c android: Add new graphics API options to GUI 2023-01-06 14:39:50 +02:00
3843122cf8 video_core: Update usage of tex_lod_bias 2023-01-06 09:37:11 +02:00
d320eef663 Fix opengl and auto resolution crashes (#14)
* video_core: fix UniformData size on opengl

* video_core: check for renderer on auto resolution

The rasterizer cache constructor will call GetResolutionScaleFactor
before the renderer is initialized on the vulkan backend, so
check for that case and return 1 as a placeholder scale factor.
2023-01-06 09:05:21 +02:00
a7a9b94a30 common: Update thread library from yuzu 2023-01-05 17:34:47 +02:00
a9f2a69487 renderer_vulkan: Remove dead code 2023-01-05 17:06:40 +02:00
78965ba18d ci: Install macOS Vulkan dependencies from official SDK release. (#13) 2023-01-05 10:03:43 +02:00
52c41d185b renderer_vulkan: Set up and configure VK_KHR_portability_subset extension according to spec. (#12)
* renderer_vulkan: Set up and configure VK_KHR_portability_subset extension according to spec.

* renderer_vulkan: Move mipmap LOD bias to shaders for compatibility.
2023-01-04 10:43:08 +02:00
c5c041de89 Merge branch 'citra-emu:master' into vulkan-2 2023-01-04 00:44:52 +02:00
f5ed7c775d qt: Fix global settings being inaccessible on macOS. (#6235) 2023-01-03 23:58:04 +02:00
e46a88f24a vulkan: Align vertex strides according to portability subset requirements. (#11) 2023-01-03 00:36:06 +02:00
8779cb7785 renderer_opengl: Fix shader compilation
* Also use glCopyImageSubData to do texture copies'
2023-01-02 16:22:51 +02:00
a6ca7dca61 vk_instance: Don't specify uint8 extension twice
* I have no idea why this happened
2023-01-02 15:40:06 +02:00
cce6a79a91 vk_shader_gen_spv: Fix OpCompositeConstruct bug
* Fixes graphics on the 2d_shapes homebrew and maybe other games
2023-01-02 15:40:00 +02:00
230a463a39 msvc ci: Setup Vulkan SDK for glslangValidator 2023-01-02 00:25:28 +02:00
f18437e59f android: Close soft keyboard on panel close in cheats activity (#6234)
This prevents the keyboard from being stuck in an open state if the user
slides the panel while focused on a text box. Now it closes gracefully.

Co-authored-by: Charles Lombardo <clombardo169@gmail.com>
2023-01-01 16:55:05 +05:30
83e734bd6a vk_shader_gen: new is a reserved keyword on Metal 2022-12-31 20:24:31 +02:00
72ee29669a renderer_vulkan: Add support for VK_KHR_image_format_list
* May help drivers when using mutable images
2022-12-31 18:20:08 +02:00
b1a02e1710 renderer_vulkan: Remove upload_cmdbuf
* No longer needed with the new stream buffer
2022-12-31 17:44:15 +02:00
2c34f41747 vk_rasterizer: Don't bind redundant bindings 2022-12-31 10:07:35 +02:00
60d59730a9 Revert "ci: Fix macOS upload script calling wrong macpack."
This reverts commit 3b9ed5234d.
2022-12-30 18:08:20 +02:00
850ec1f8b8 vk_common: Enable beta extensions
* Required to access the portability subset'
2022-12-30 16:22:53 +02:00
3da6c25fd8 renderer_vulkan: Fallback to software shaders on unsupported topology
* MoltenVK does not support triangle fans
2022-12-30 15:25:27 +02:00
0e987959a6 renderer_vulkan: Rewrite data streaming
* Most GPUs nowadays provide a device local/host visible memory heap which is useful for avoiding copies between staging and local memory and especially beneficial for mobile and APUs that are mostly the target of this backend.

* This commit ports the old yuzu stream buffer with some changes to suit our needs and gets rid of the buffer flush methods
2022-12-30 11:10:49 +02:00
410b8b8809 vk_texture_runtime: Tune barriers
* Using eAllCommandBit is really bad for Mali GPUs. Also most access flags were redundant mostly for edge cases.

* To address this track surface usage and decide the best barrier flags at runtime. This gives a significant performance boost to mobile GPUs
2022-12-29 21:56:57 +02:00
d3392ae0b1 renderer_vulkan: Properly format structs 2022-12-29 20:11:57 +02:00
98e0ecf6a7 renderer_vulkan: Add fallback path for VK_EXT_index_type_uint8
* Also remove some flush barriers
2022-12-29 19:07:09 +02:00
ad45b9880d android: Add vulkan support to frontend 2022-12-28 14:01:50 +02:00
0d1646e4df Revert "vk_scheduler: Enable usage of jthread on macos"
This reverts commit 09dcd48257.
2022-12-26 17:15:21 +02:00
96f0746ab9 HACK: Skip normquat lerp to drop geometry shader requirement 2022-12-26 15:50:11 +02:00
09dcd48257 vk_scheduler: Enable usage of jthread on macos
- Import the yuzu polyfill libraries
2022-12-26 11:17:23 +02:00
62fc1f835e ci: Provide glslang 2022-12-26 09:01:05 +02:00
3b351c33d1 android: Fix build 2022-12-26 08:53:30 +02:00
793485d201 renderer_vulkan: Revert some stream buffer changes
* The previous design was much less prone to errors so switch back to that. Also make 16 byte alignment standard
2022-12-25 23:48:11 +02:00
3ef5ab7323 video_core: Move pixel format functions to cpp file 2022-12-25 23:37:28 +02:00
618c80c803 vk_instance: Address small issues 2022-12-25 23:21:44 +02:00
f7cb308243 video_core/host_shaders: Add CMake integration for string shaders 2022-12-25 23:17:39 +02:00
b8583f9af3 renderer_vulkan: Port per-game to vulkan renderer 2022-12-25 23:06:30 +02:00
33bf2b7c2d renderer_vulkan: Forward validation errors to logfile 2022-12-25 22:31:27 +02:00
d48e6c04ce video_core: Move most pica register handling to RasterizerAccelerated 2022-12-25 22:31:27 +02:00
88f34a7d69 vk_shader_gen_spv: Implement proctex sampler
* Fixes MHS menu and probably other games
2022-12-25 22:31:27 +02:00
c8e9b465e2 renderer_vulkan: Proper telemetry reporting 2022-12-25 22:31:27 +02:00
278198f5f5 vk_shader_gen_spv: Implement shadow plane sampling 2022-12-25 22:31:27 +02:00
58718e6bd6 renderer_vulkan: Fix LMDM crashes
* Cache vertex format lookups to avoid crashing the driver when the game does too many lookups

* Increase watcher count. For some reason the game uses way too many watchers

* Fix other misc SPIRV bugs and don't crash when shadow is requested
2022-12-25 22:31:27 +02:00
a814b21693 vk_shader_gen_spv: Implement alpha testing
* Should fix all current graphical bugs
2022-12-25 22:31:27 +02:00
5478a4d634 vk_instance: Make DynamicLoader static
* That way we don't construct/destroy it all the time
2022-12-25 22:31:27 +02:00
8f87586495 citra_qt: Add SPIR-V shader option 2022-12-25 22:31:27 +02:00
7e3a0f524c externals: Update sirit 2022-12-25 22:29:05 +02:00
922019cc22 renderer_vulkan: Move fragment shader microprofile to a better place 2022-12-25 22:29:05 +02:00
41e9cdb645 shader_cache: Fix type deduction 2022-12-25 22:29:05 +02:00
e90add52d2 cmake: Fork sirit
* Upstream is missing some required instructions
2022-12-25 22:29:04 +02:00
3c6ca2cc82 renderer_vulkan: Begin new fragment shader SPIR-V emitter 2022-12-25 22:29:04 +02:00
d1039d9a81 code: Address build issues 2022-12-25 22:29:04 +02:00
8b8cee1a5a vk_instance: Remove depth clip control feature
* To not crash drivers that don't support it since we don't require it anymore
2022-12-25 22:28:49 +02:00
5dc92cd72b ci: Bundle MoltenVK with macOS builds. 2022-12-25 22:28:49 +02:00
d1503605a7 vulkan: Fix supported extension check 2022-12-25 22:28:49 +02:00
6426f7a319 vulkan: Use required portability instance extension on macOS. 2022-12-25 22:28:49 +02:00
3b9ed5234d ci: Fix macOS upload script calling wrong macpack. 2022-12-25 22:28:49 +02:00
763127605e qt: Extract CAMetalLayer from NSView to pass to MoltenVK. 2022-12-25 22:28:49 +02:00
b86b19d366 renderer_vulkan: Drop requirement for VK_EXT_depth_clip_control 2022-12-25 22:28:49 +02:00
3dd74c69c5 Revert "CI: dont upload macos artifacts (#6121)"
This reverts commit 30831e6367.
2022-12-25 22:28:49 +02:00
01af8e3f2c renderer_vulkan: Integrate MacOS wsi 2022-12-25 22:28:49 +02:00
474cccda33 video_core: Fix build issues on macos 2022-12-25 22:28:49 +02:00
6057b18172 renderer_vulkan: Emulate 3-component vertex formats when unsupported
* This fixes the crashes on AMD
2022-12-25 22:28:48 +02:00
6a4ff8fa24 renderer_vulkan: Emulate logic op when unsupported
* Similar to GLES this is done to prepare for the android port
2022-12-25 22:28:48 +02:00
3c79360fd3 gl_rasterizer: Cleanup and fix bugs 2022-12-25 22:28:48 +02:00
939aafed40 vk_texture_runtime: Implement RGBA4 converter
* Fixes graphics in NES Remix. Need to also do a reinterpreter some time, but this will suffice for now
2022-12-25 22:28:48 +02:00
23417787f8 texture_downloader_es: Remove invalid operations 2022-12-25 22:28:48 +02:00
8946c1a7de gl_texture_runtime: Use OGLStreamBuffer for uploads/downloads
* Much better than the current implementation
2022-12-25 22:28:48 +02:00
5fe910b18f vk_stream_buffer: Cleanup flush barrier 2022-12-25 22:28:48 +02:00
3944cbdc19 video_core: Reorder microprofile defines 2022-12-25 22:28:48 +02:00
8ac3dd1840 renderer_vulkan: Rewrite stream buffer, again...
* The previous implemention was fine, but it wasted space. Buckets now are just ticks attached to a particular buffer region, which means we can flush/map arbitrary regions

* A bug in the texture runtime is also fixed which commited to the same buffer twice
2022-12-25 22:28:15 +02:00
ff34287e4b renderer_vulkan: Pack PicaFSConfig
* Using bitfields the struct size was reduced from 420 to 190 bytes. which should speed up hashing and copying to the worker thread
2022-12-25 22:28:15 +02:00
81f2a0eaa1 renderer_vulkan: Cleanup vertex array setup
* Also the function would commit more data then it requested leading to out of bound crashes
2022-12-25 22:28:15 +02:00
f11715a4f4 renderer_vulkan: Remove AttribType
* Use VertexAttributeFormat to avoid unnecessary enum casts
2022-12-25 22:28:15 +02:00
89c51371f7 video_core: Move HardwareVertex to RasterizerAccelerated 2022-12-25 22:28:15 +02:00
8076d893db video_core: Move api agnostic uniform updates to RasterizerAccelerated 2022-12-25 22:28:15 +02:00
72f8d520c9 renderer_vulkan: Fix swapchain resizing 2022-12-25 22:28:15 +02:00
f9274f8b9a renderer_vulkan: Add single-thread record ability to the scheduler
* Async is pretty nice but games that do a lot of flushes might have worse performance due to thread synchronization overhead

* I haven't noticed any cases of this yet but it doesn't hurt making this a UI option
2022-12-25 22:28:15 +02:00
3c09c03180 citra_qt: Refuse to enable debug option if the layers are not available 2022-12-25 22:24:28 +02:00
52251e3908 renderer_vulkan: Scheduler and presentation rewrite
* This commit ports yuzu's async scheduler replacing our older and crummier version
  Commands are recorded by the scheduler and processed by a separate worker thread.

* Queue submission is also moved to the worker thread which should alliviate slowdowns related to vkQueueSubmit stalls

* Fragment shader compilation and queue submission are also moved to that thread to reduce stutters
2022-12-25 22:23:46 +02:00
921444c2c9 externals: Update vulkan-headers 2022-12-25 22:23:46 +02:00
89d234f642 common: Remove concepts usage 2022-12-25 22:23:46 +02:00
13771b805b renderer_vulkan: Fix shader hash type 2022-12-25 22:23:46 +02:00
2a71059490 code: Remove usages of std::ranges
* MacOS is still runining my C++ 20 fun
2022-12-25 22:23:46 +02:00
053221f155 renderer_vulkan: Prefer immediate over mailbox present mode 2022-12-25 22:23:46 +02:00
4868c361e7 renderer_vulkan: Bump vertex buffer size
* So software shaders don't crash
2022-12-25 22:23:46 +02:00
0c30dbf33e renderer_vulkan: Add more microprofile targets 2022-12-25 22:23:46 +02:00
53370e81e2 renderer_vulkan: Improve StreamBuffer API and use it in TextureRuntime
* Also use separate upload and download buffers optimized for write and readback respectively. This gives a huge 20+ FPS boost in most games which were bottlenecked by slow reads
2022-12-25 22:23:46 +02:00
b3fb260c84 renderer_vulkan: Fix allocation caching bug 2022-12-25 22:23:46 +02:00
599ca7caf7 renderer_opengl: Port scaled upload/download code from vulkan 2022-12-25 22:23:46 +02:00
abc0fd5e7b renderer_vulkan: Include algorithm in vk_common
* Appears to be a bug in vulkan-hpp
2022-12-25 22:23:46 +02:00
309b25d201 renderer_vulkan: Use linear filtering when possible
* Fixes blocky artifacts in Samus Returns
2022-12-25 22:23:46 +02:00
9ac7ef20b0 renderer_vulkan: Abstract descriptor management
* The pipeline cache was starting to get cluttered
2022-12-25 22:23:46 +02:00
ebade3594d renderer_vulkan: Bump descriptor set allocation limit 2022-12-25 22:23:46 +02:00
dca159d79f renderer_vulkan: Fix storage descriptor binding and respect color mask
* RGBA8 surfaces now expose an additional R32Uint view used for storage descriptors. The format is guaranteed by the spec to support atomic loads/stores. This requires the mutable flag which incurs a performance cost, but might be better than breaking the current renderpass each draw when rendering shadows, especially on mobile

* Color mask is also implemented which fixes Street Fighter and Monster Hunter Stories
2022-12-25 22:23:46 +02:00
7007d5822a renderer_vulkan: Implement depth uploads with blit 2022-12-25 22:23:46 +02:00
6f0fdf037f renderer_vulkan: Use intermediate copy when framebuffer is used both as attachment and shader input 2022-12-25 22:23:46 +02:00
58621b0eb6 renderer_vulkan: Respect disk shader option 2022-12-25 22:23:46 +02:00
e8eef5c586 renderer_vulkan: Fix staging buffer size 2022-12-25 22:23:46 +02:00
2b37997a95 renderer_vulkan: Catch and log more runtime errors
* Also add the ability to enable command buffer dumping which is very useful
2022-12-25 22:23:15 +02:00
558062efd7 renderer_vulkan: Batch allocate descriptor sets
* Less driver calls should lead to better performance
2022-12-25 22:20:22 +02:00
5e880a4f26 renderer_vulkan: Emulate border color if possible 2022-12-25 22:20:22 +02:00
238956f773 renderer_vulkan: Implement scaled uploads and downloads
* This commit includes large changes to have textures are handling. Instead of using ImageAlloc, Surface is used instead which provides multiple benefits: automatic recycling on destruction and ability to use the TextureRuntime interface to simplify operations

* Layout tracking is also implemented which allows transitioning of individual mip levels without errors

* This fixes graphical errors in multiple games which relied on framebuffer uploads
2022-12-25 22:20:22 +02:00
a5351bc596 renderer_vulkan: Fix renderpass issues
* The cache didn't take into account the framebuffer and render area used, so if these changed the renderpass wouldn't restart. This caused graphical bugs in Pokemon X/Y
2022-12-25 22:20:22 +02:00
5b6e99b194 renderer_vulkan: Update stencil compare mask 2022-12-25 22:20:22 +02:00
3f3b4a2802 citra_qt: Fix graphics api indicator alignment 2022-12-25 22:20:22 +02:00
c19e8d36c9 renderer_opengl: Fix OpenGLES issues
* Always request a 4.4 context until I figure out how to get Qt to cooperate

* Use RGBA for BGR since the converted table will do that conversion
2022-12-25 22:20:22 +02:00
2ec31f404b renderer_vulkan: Report perf stats 2022-12-25 22:20:21 +02:00
28a2805450 renderer_vulkan: Better error handling 2022-12-25 22:20:21 +02:00
2601a1df6c renderer_vulkan: Allow direct allocation of images 2022-12-25 22:19:26 +02:00
96d5bb553b renderer_vulkan: Fix incorrect depth format detection
* Intel iGPUs don't support blit on all depth/stencil formats which caused issues since the runtime checks for this while the renderpass cache does not
2022-12-25 22:19:26 +02:00
b4d0f442c8 renderer_vulkan: Actually minize state changes
* Keep track of the current state and only update it when needed. Previously games would set the same state over and over cluttering renderdoc logs
2022-12-25 22:19:25 +02:00
2a68cab7d6 renderer_vulkan: Fix broken sync without timeline semaphores 2022-12-25 22:19:25 +02:00
009d73fdf6 renderer_vulkan: Allocate descriptor sets during reinterpretation 2022-12-25 22:19:25 +02:00
42af22f8fd renderer_vulkan: Enable logic ops and fix swapchain resizing 2022-12-25 22:19:25 +02:00
b85d15b035 renderer_vulkan: Clear stencil with renderpass
* Fixes outline retension in pokemon games
2022-12-25 22:19:25 +02:00
130e376c0c renderer_vulkan: Fix pipeline cache crashes 2022-12-25 22:19:25 +02:00
f884986257 renderer_vulkan: Optimize tiled format convertion + fix vertex buffer alignment
* Integrate format convertion to the morton copy function, removing the need for an intermediate copy and convertion pass. This should be beneficial for performance especially since most games use tiled textures

* Also bump vertex buffer size to avoid crashes with hardware shaders and provide correct offset on normal draws which fixes glitches in pokemon Y

* Reduce the local group size to 8 in the D24S8 compute shader which fixes graphical issues in the afformentioned pokemon games at native resolution

* Set LOD to 0 instead of 0.25 to fix another glitch in pokemon y
2022-12-25 22:19:25 +02:00
e23dc3efb1 renderer_opengl: Fix broken texture copy
* Resolves graphical bugs in Professor Layton vs Ace Attorney when using OpenGL
2022-12-25 22:19:25 +02:00
dd5e95d7c6 renderer_vulkan: Pipeline cache fixes
* Delete cache file if found invalid

* Name it after the vendor/device ids so each physical devices gets a separate cache
2022-12-25 22:19:25 +02:00
b72289eadd video_core: Fix renderpass cache bug and introduce RGBA -> BGR converter 2022-12-25 22:19:25 +02:00
7a5d4f03da renderer_opengl: Specify precision in compute shader and add RGB5A1 converter
* Fixes OpenGLES crash
2022-12-25 22:19:25 +02:00
18fa277c71 renderer_vulkan: Complete hardware shader support
* With these changes all commercial games I tested work fine and get a massive performance boost
2022-12-25 22:19:25 +02:00
73cc764091 renderer_vulkan: Begin hardware shader support
* Still experimental and works only with homebrew
2022-12-25 22:19:25 +02:00
9dea514d45 citra: Fix build issues with MinGW and MSVC 2022-12-25 22:19:25 +02:00
0bfaa035b9 renderer_vulkan: Fix warnings and cleanup 2022-12-25 22:19:06 +02:00
85df778785 code: Run clang-format 2022-12-25 22:19:06 +02:00
e54a92c252 code: Address build issues 2022-12-25 22:18:04 +02:00
9145d4cec8 video_core: Re-implement format reinterpretation
* Same as before but D24S8 to RGBA8 is switched to a compute shader which should provide better throughput and is much simpler to implement in Vulkan
2022-12-25 22:18:04 +02:00
c611592db6 citra_qt: Add physical device selection dialog 2022-12-25 22:18:04 +02:00
6aba809da8 renderer_opengl: Unbind unused framebuffer targets
* Fixes graphical glitches in many games for some reason
2022-12-25 22:12:42 +02:00
f0449d79fd renderer_opengl: Emulate texture copy with blit for now 2022-12-25 22:12:42 +02:00
33481ada7f renderer_opengl: Address buffer overflow 2022-12-25 22:12:42 +02:00
67195974e7 video_core: Small code improvements 2022-12-25 22:12:42 +02:00
70c2376fd0 renderer_vulkan: Don't sample from mipmaps when using texture cubes
* Mipmaps for texture cubes are unimplemented in the rasterizer cache, so sampling from mipmaps will return nothing
2022-12-25 22:12:42 +02:00
177c7de4f9 input_common: Small fix 2022-12-25 22:12:42 +02:00
eea914ba84 citra_qt: Improve graphics API intergration
* Add renderer debug option which toggles debug output in OpenGL/validation layers in Vulkan

* Fix many warnings and replace deprecated Qt functionailty with newer alternatives
2022-12-25 22:12:41 +02:00
62e88fbeb3 rasterizer_cache: Code cleanup
* Merge utils and types to a single header
2022-12-25 22:07:46 +02:00
5ce27d8341 texture_decode: Prefer std::memcpy where possible 2022-12-25 22:07:46 +02:00
eaf62eb635 renderer_vulkan: Rework format handling
* This is a pretty large commit that aims to solve some issues with the current format system
* The instance now builds at application initialization an array of format traits for each pixel format
  that includes information such as blit/attachment/storage support and fallback formats
* The runtime doesn't ask the instance for formats but receives these traits and can dedice on its own what to build
  For now we do the same as before, we require both blit and attachment support

* Morton swizzling also sees many bug fixes. The previous code was very hacky and didn't work for partial
  texture updates. It was also inconsistent, as it would take a tiled_buffer and write to the middle of linear
* Now the functions have been greatly simplified and adjusted to work better with std::span. This fixes out of bounds
  errors and texture glitches (like the display in Mario Kart 7)
2022-12-25 22:07:46 +02:00
9675811bbe renderer_vulkan: Add experimental Vulkan renderer 2022-12-25 22:07:46 +02:00
945faf8e92 externals: Add vulkan headers and vma 2022-12-25 22:02:59 +02:00
9403049671 rasterizer_cache: Refactor texture cube interface
* Reuse our Surface class instead of having a separate one, to avoid reimplementing stuff in the backend
2022-12-25 22:02:59 +02:00
40159d9779 gl_texture_runtime: Clean up texture upload/download code
* Improve readability and code clarity
2022-12-25 22:02:59 +02:00
f63653a5b9 rasterizer_cache: Use Common::Rectangle everywhere
* Make a nice alias for it and use it instead of having Rect2D/Region2D. Makes the new design less intrusive to the current cache
2022-12-25 22:02:59 +02:00
c71dbb5d19 rasterizer_cache: Make into template
* This is the final step, now RasterizerCache is compltely decoupled from OpenGL (technically not yet, but that's talking details). For now texture filtering and some GLES paths have been disabled and will be reimplemented in the following commits
2022-12-25 22:02:59 +02:00
0f4df2c012 rasterizer_cache: Use PBO staging buffer cache for texture uploads/downloads 2022-12-25 22:02:11 +02:00
c6fc4f5a87 rasterizer_cache: Reorder methods 2022-12-25 22:02:11 +02:00
916afa194d rasterizer_cache: Remove remnants of cached_pages 2022-12-25 22:02:11 +02:00
6f2cd11a85 rasterizer_cache: Fix texture cube blitting
* The target was GL_TEXTURE_2D instead of GL_TEXTURE_CUBE_MAP_*
2022-12-25 22:02:11 +02:00
14652d52bc morton_swizzle: Implement texture formats in UNSWIZZLE_TABLE
* I can now remove that loop that has been messing with my OCD
2022-12-25 22:02:11 +02:00
a57ee7cdf2 morton_swizzle: Use tiled_buffer instead of reading data from g_memory
* It's much safer and removes hardcoded global state usage
2022-12-25 22:02:11 +02:00
dbd3e6c29b rasterizer_accelerated: Zero intialize cached_pages
* Resolves random crashes because count takes random values
2022-12-25 22:02:11 +02:00
665cbca17c texture_runtime: Add staging buffer lock mechanism 2022-12-25 22:02:11 +02:00
efb9e9f40f cached_surface: Remove custom texture logic
* Makes things more complicated and is in the way. It's probably already
broken by recent changes, so I'll need to reimplement it anyway
2022-12-25 22:02:11 +02:00
8d35118f63 renderer_opengl: Add driver class to report info/bugs 2022-12-25 22:02:11 +02:00
553c85456e rasterizer_cache: Add staging buffer cache for uploads/downloads
*  In addition bump context version to 4.4 to enforce ARB_buffer_storage and use EXT_buffer_storage for GLES which is support on many mobile devices
2022-12-25 22:02:11 +02:00
68ca206d53 rasterizer_cache: Improve TextureRuntime API
* This makes every operation more explicit and mimics more the Vulkan API
2022-12-25 22:02:11 +02:00
e30e977140 renderer_opengl: Encapsulate sync objects in OGLSync 2022-12-25 22:02:10 +02:00
f13738d252 morton_swizzle: Optimize and use std::span 2022-12-25 22:02:10 +02:00
04b927ab7f morton_swizzle: Avoid buffer underflow
* Check the y coordinate before decrementing linear_buffer
2022-12-25 22:02:10 +02:00
993d172de9 morton_swizzle: Move out of bounds texture check out of the decode loop
* Running relative expensive checks like this on a hot path causes small but measurable performance loss. Tested SMD wit this and it doesn't crash
2022-12-25 22:02:10 +02:00
695447611e rasterizer_cache: Use SurfaceType instead of Aspect
* It was doing pointless enum conversions when both enums described the same thing
2022-12-25 22:02:10 +02:00
06bacfbd72 rasterizer_cache: Separate texture swizzling to utils 2022-12-25 22:02:10 +02:00
cf8bc35d46 rasterizer_cache: Remove OpenGL references from morton_swizzle 2022-12-25 22:02:10 +02:00
ef859bab84 citra_qt: Forbid renderer change during runtime
* It's an endless source of problems and isn't usefull
2022-12-25 22:02:10 +02:00
a2d0669562 rasterizer_cache: Touch up MatchFlags comments 2022-12-25 22:02:10 +02:00
95365ad6ba rasterizer_cache: Drop OpenGL postfix 2022-12-25 22:02:10 +02:00
1963b649e8 rasterizer_cache: Shorten filenames and general cleanup
* AllocateSurfaceTexture now takes the PixelFormat directly as FormatTuple is an OpenGL struct and will be moved there
2022-12-25 22:02:10 +02:00
db7cdb741c video_core: Move UpdatePagesCachedCount to RasterizerAccelerated 2022-12-25 22:02:10 +02:00
0fe61ba040 citra_qt: Prepare GUI for Vulkan support 2022-12-25 22:02:06 +02:00
b588d6181b qt_multimedia_camera: fix image handling in Qt 5.15+ ... (#6231)
... In Qt 5.15+ the QImage will not accept non-natively handled pixel
formats anymore. We can however use the newly added conversion method
provided in `QVideoFrame` to convert it to `QImage` instead
2022-12-24 11:45:31 +05:30
c8ff1d744a Change Monoscopic Render mode to a dropdown (#6215) 2022-12-24 03:17:49 +01:00
ae3d50f71f Port yuzu-emu/yuzu#2968: configure_input: Fix input handling for ZL and ZR from controllers with analog triggers (#4984)
Co-authored-by: Frederic L. <freddyfunk@users.noreply.github.com>
2022-12-17 16:11:49 +01:00
ccb50e7f2c Port yuzu-emu/yuzu#9300: "CMake: Use precompiled headers to improve compile times" (#6213)
Co-authored-by: Ameer J <52414509+ameerj@users.noreply.github.com>
2022-12-17 16:06:38 +01:00
51e252c7ed Hide mouse: fix for secondary window and single window mode (#6220) 2022-12-17 16:05:51 +01:00
517e0bc342 Camera fixes (#6181) 2022-12-17 16:05:04 +01:00
812c4fa059 Per-Game Settings: options to reset game settings (#6219) 2022-12-17 16:04:31 +01:00
cb82ffbe20 code: Small cleanups and fixes to lambda captures (#6191)
Co-authored-by: v1993 <v19930312@gmail.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
2022-12-17 16:04:10 +01:00
9d5ae8e1c2 service/nwm_uds: Add NetworkStatusChangeReason (#5377)
fixes https://github.com/citra-emu/citra/issues/3975
2022-12-17 16:03:59 +01:00
06a9f69d88 hle/service/cfg: Add Config block enums documented by 3dbrew... (#6206) 2022-12-14 01:48:41 +01:00
84eada8c50 Fix "auto" resolution factor (#6218) 2022-12-13 01:05:08 +01:00
016ce6c286 Add 3GX plugin loader (#6172)
* Initial plugin loader support

* More plugin loader progress

* Organize code and more plugin features

* Fix clang-format

* Fix compilation and add android gui

* Fix clang-format

* Fix macos build

* Fix copy-paste bug and clang-format

* More merge fixes

* Make suggestions

* Move global variable to static member

* Fix typo

* Apply suggestions

* Proper initialization order

* Allocate plugin memory from SYSTEM instead of APPLICATION

* Do not mark free pages as RWX

* Fix plugins in old 3DS mode.

* Implement KernelSetState and notif 0x203

* Apply changes

* Remove unused variable

* Fix dynarmic commit

* Sublicense files with MIT License

* Remove non-ascii characters from license
2022-12-11 10:08:58 +02:00
48ee112ceb Add per game configuration options (#6187)
* common: Move settings to common from core.

- Removes a dependency on core and input_common from common.

* code: Wrap settings values

* Port from yuzu to allow per game settings

* citra_qt: Initial per-game settings dialog

* citra_qt: Use new API for read/save of config values

* citra_qt: Per game audio settings

* citra_qt: Per game graphics settings

* citra_qt: Per game system settings

* citra_qt: Per game general settings

* citra_qt: Document and run clang format

* citra_qt: Make icon smaller and centered

* citra_qt: Remove version number

* Not sure how to extract that, can always add it back later

* citra_qt: Wrap UISettings

* citra_qt: Fix unthottled fps setting

* citra_qt: Remove margin in emulation tab

* citra_qt: Implement some suggestions

* Bring back speed switch hotkey

* Allow configuration when game is running

* Rename/adjust UI stuff

* citra_qt: Fix build with separate windows

* citra_qt: Address feedback

* citra_qt: Log per-game settings before launching games

* citra_qt: Add shader cache options

* Also fix android build

* citra_qt: Add DLC menu option

* citra_qt: Run clang-format

* citra_qt: Adjust for time offset

* citra_qt: Implement suggestions

* Run clang-format

Co-authored-by: bunnei <bunneidev@gmail.com>
2022-12-08 13:27:25 +02:00
f261daf2fa Attempt to hotfix Android CI (assume /usr/bin/apksigner is no longer a jar) (#6210) 2022-12-08 07:25:11 +05:30
0fc177e268 configure_motion_touch: do not move engine parameter (#6208)
fixes an error stemmed from miscommunication
2022-12-06 21:52:25 -03:00
d1171328c9 Qt: Implement more hotkeys for secondary window (#6198) 2022-11-24 19:25:27 +05:30
850e5bf81c Merge pull request #6194 from merryhime/more-accurate-cycle-counting
arm/dynarmic: More accurate cycle counting
2022-11-24 19:25:01 +05:30
6da59d581e arm_tick_counts: Thumb implementation 2022-11-22 22:52:37 +00:00
9c0fad21db arm_tick_counts: Implement ARM cycle counting 2022-11-22 22:52:37 +00:00
0f250bed89 arm_tick_counts: Skeleton implementation 2022-11-22 22:52:37 +00:00
7cae35024f common: Add StringLiteral 2022-11-22 22:52:37 +00:00
f298278f37 arm/dynarmic: Initial implementation for instruction tick counts 2022-11-22 22:52:37 +00:00
2238e6c3ef externals: Update dynarmic to 7a926d689bcc1cc39dd26d5bba379dffcc6815a3 2022-11-22 22:52:37 +00:00
d09f6d97f6 Merge pull request #6196 from vitor-k/stoll-exception
Resolve C4101 warning
2022-11-21 19:50:15 -03:00
1e6507d792 Resolve C4101 warning
and catch logic_error instead of exception, as stoll should only throw std::invalid_argument and std::out_of_range, and both inherit from it.
2022-11-20 22:41:33 -03:00
64062162c6 feat: add system time offset setting (#6139)
* Add setting for system time offset

Add a setting to displace citra system time by days, hours, minutes
or seconds
Add UI for the setting which is only visible when clock is set to
system time
Change core/settings.h to include the setting

* Add system time offset to kernel

Actually makes use of the time offset.

* Fix time offset calculatioon in core/movie.cpp

* Replace C++20 chrono::days with seconds

Hopefully fixes the build.
2022-11-20 17:34:53 +02:00
3b6ffd9c27 Add MSVC binaries for Windows on releases (#6190)
* Improve directory creation in WindowsCopyFiles.cmake

* Release msvc compiled binaries as an alternative to mingw releases

* msvc: do not ship .pdb files

* msvc: Copy necessary files to the release

* windows-msvc: enable compatibility reporting

translation was disabled because the bundled qt doesn't have
the necessary component

Co-authored-by: Michał Janiszewski <janisozaur@users.noreply.github.com>
2022-11-19 22:22:10 +02:00
f44c95d638 Add "Separate Windows" LayoutOption (#6177) 2022-11-17 16:37:30 +01:00
4f715b6718 Add nearest neighbor texture filter (#6189)
Closes https://github.com/citra-emu/citra/issues/4707
closes https://github.com/citra-emu/citra/issues/5274
2022-11-16 18:55:14 +01:00
664562f988 add mono_render_left_eye option (#6140) 2022-11-16 18:54:26 +01:00
2967068b87 Merge pull request #5380 from FearlessTobi/port-3954
Port yuzu-emu/yuzu#3954: "main: Log host system memory parameters"
2022-11-15 11:31:59 +00:00
d89a6d491e Merge pull request #5526 from FearlessTobi/port-4535-4548
Port yuzu-emu/yuzu#4535 and yuzu-emu/yuzu#4548: Changes to the Common namespace
2022-11-15 11:30:21 +00:00
95c7bac8a6 Resolve compilation errors related to the Color namespace change 2022-11-15 11:25:51 +01:00
81bf21283f common/color: Migrate code over to the Common namespace
No external code makes use of this header, so we can freely change the
namespace.
2022-11-15 11:25:51 +01:00
de1fe7e6e3 Address review comments 2022-11-15 11:20:35 +01:00
35f7f5e3e3 common: switch to nullptr for sysctl's empty new value 2022-11-15 10:34:56 +01:00
6dabf10009 common: add sysconf() fallback
src/common/memory_detect.cpp:15:10: fatal error: 'sys/sysinfo.h' file not found
 #include <sys/sysinfo.h>
          ^~~~~~~~~~~~~~~
2022-11-15 10:34:56 +01:00
cb8b72069f Fix macOS code and change "Swapfile" to "Swap" 2022-11-15 10:34:56 +01:00
a67f205cfe main: Log host system memory parameters
Logs both physical memory and swapfile sizes, this is useful for support.
2022-11-15 10:34:56 +01:00
94d0399876 fix clang format on mingw/msys2 (#6188) 2022-11-13 09:22:05 +02:00
f6320c8de9 Reduce bugginess when texture filtering and custom textures both enabled (#6184)
* fixed some (but not all) glitchy behavior when texture filtering & custom textures both enabled

* fix clang format
2022-11-12 08:08:26 +02:00
a76ef97f15 citra_qt: ask for confirmation when changing games from the game list (#6186)
Co-authored-by: nobody <nobody>
2022-11-12 10:39:53 +05:30
bb05d8c12a src/CMakeLists: Enforce multiple warnings on MSVC (#5692) 2022-11-09 23:14:28 +01:00
38b8bf12de Merge pull request #6168 from PabloMK7/cia_update_fix
Fix handling of auto-updating ncch apps
2022-11-09 17:35:16 +02:00
d04d71e4c9 Remove misplaced return statement 2022-11-09 16:25:52 +01:00
b9d9ae35e4 Merge pull request #6183 from GPUCode/master
citra_qt: Avoid null reference capture when taking screenshots
2022-11-09 16:50:31 +02:00
bd84dbc8d3 citra_qt: Avoid null reference capture when taking screenshots 2022-11-09 16:50:05 +02:00
c7e259366d CMake: Use qt-5.15.7 bundled externals for VS 2019/2022 (#6176) 2022-11-07 10:09:23 +05:30
92ad651890 Port yuzu-emu/yuzu#4290 and yuzu-emu/yuzu#4318: Changes for C++20 support (#5459)
Co-authored-by: Lioncash <mathew1800@gmail.com>
2022-11-06 03:35:20 +01:00
3201943423 Port yuzu-emu/yuzu#4437: "core_timing: Make use of uintptr_t to represent user_data" (#5499)
Co-authored-by: LC <lioncash@users.noreply.github.com>
2022-11-06 02:24:45 +01:00
7801907288 externals: Update dynarmic (#6175) 2022-11-05 11:19:50 +05:30
1ddea27ac8 code: Cleanup and warning fixes from the Vulkan PR (#6163)
Co-authored-by: emufan4568 <geoster3d@gmail.com>
Co-authored-by: Kyle Kienapfel <Docteh@users.noreply.github.com>
2022-11-04 23:32:57 +01:00
aa84022704 Port yuzu-emu/yuzu#4164: "hotkeys: Add a "Mute Audio" hotkey" (#5463)
Co-authored-by: Kewlan <colin_rehn@hotmail.com>
2022-11-04 20:25:57 +01:00
14924e9db3 Backport review comments from yuzu-emu/yuzu#4382: "yuzu: Add motion and touch configuration from Citra" (#5543) 2022-11-04 20:25:50 +01:00
e14b9f7a25 Fix clang-format and unused include 2022-10-27 01:09:18 +02:00
fd7ada2a9c Fix chainloading for all apps 2022-10-23 22:55:50 +02:00
d396944487 Fix self updating ncch app jump 2022-10-21 01:12:29 +02:00
c49379442d Fix auto updating ncch files 2022-10-20 23:14:57 +02:00
669 changed files with 44953 additions and 18989 deletions

View File

@ -17,7 +17,7 @@ then
echo "Signing apk..."
base64 --decode <<< "${ANDROID_KEYSTORE_B64}" > ks.jks
java -jar $(which apksigner) sign --ks ks.jks \
apksigner sign --ks ks.jks \
--ks-key-alias "${ANDROID_KEY_ALIAS}" \
--ks-pass env:ANDROID_KEYSTORE_PASS "artifacts/${REV_NAME}.apk"
fi

View File

@ -2,7 +2,6 @@
set -o pipefail
export Qt5_DIR=$(brew --prefix)/opt/qt5
export PATH="/usr/local/opt/ccache/libexec:$PATH"
# ccache configurations
export CCACHE_CPP2=yes
@ -16,16 +15,22 @@ export ASM="clang"
ccache -s
mkdir build && cd build
# TODO: LibreSSL ASM disabled due to platform detection issues in build.
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_ARCHITECTURES="$TARGET_ARCH" \
-DENABLE_QT_TRANSLATION=ON \
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DUSE_DISCORD_PRESENCE=ON \
-DENABLE_FFMPEG_AUDIO_DECODER=ON \
-DENABLE_FFMPEG_VIDEO_DUMPER=ON \
-DENABLE_ASM=OFF \
-GNinja
ninja
ccache -s
ctest -VV -C Release
CURRENT_ARCH=`arch`
if [ "$TARGET_ARCH" = "$CURRENT_ARCH" ]; then
ctest -VV -C Release
fi

View File

@ -1,23 +1,27 @@
#!/bin/sh -ex
brew update
brew unlink python@2 || true
rm '/usr/local/bin/2to3' || true
brew install qt5 p7zip ccache ninja || true
brew install ccache ninja || true
pip3 install macpack
export SDL_VER=2.0.16
export FFMPEG_VER=4.4
export FFMPEG_VER=5.1
export QT_VER=5.15.8
export VULKAN_SDK_VER=1.3.236.0
mkdir tmp
cd tmp/
# install SDL
wget https://github.com/SachinVin/ext-macos-bin/raw/main/sdl2/sdl-${SDL_VER}.7z
7z x sdl-${SDL_VER}.7z
cp -rv $(pwd)/sdl-${SDL_VER}/* /
# install FFMPEG
wget https://github.com/SachinVin/ext-macos-bin/raw/main/ffmpeg/ffmpeg-${FFMPEG_VER}.7z
7z x ffmpeg-${FFMPEG_VER}.7z
cp -rv $(pwd)/ffmpeg-${FFMPEG_VER}/* /
# install Qt
wget https://github.com/SachinVin/ext-macos-bin/raw/main/qt/qt-${QT_VER}.7z
7z x qt-${QT_VER}.7z
sudo cp -rv $(pwd)/qt-${QT_VER}/* /usr/local/
# install Vulkan SDK
wget https://sdk.lunarg.com/sdk/download/1.3.236.0/mac/vulkansdk-macos-${VULKAN_SDK_VER}.dmg
hdiutil attach vulkansdk-macos-${VULKAN_SDK_VER}.dmg
sudo /Volumes/vulkansdk-macos-${VULKAN_SDK_VER}/InstallVulkan.app/Contents/MacOS/InstallVulkan install --accept-licenses --confirm-command --default-answer com.lunarg.vulkan.core com.lunarg.vulkan.usr
hdiutil detach /Volumes/vulkansdk-macos-${VULKAN_SDK_VER}

45
.ci/macos/universal.sh Executable file
View File

@ -0,0 +1,45 @@
#!/bin/bash -ex
. .ci/common/pre-upload.sh
REV_NAME="citra-osx-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.gz"
COMPRESSION_FLAGS="-czvf"
ARTIFACTS_LIST=($ARTIFACTS)
# Set up the base artifact to combine into.
BASE_ARTIFACT=${ARTIFACTS_LIST[0]}
BASE_ARTIFACT_ARCH="${BASE_ARTIFACT##*-}"
tar xf $BASE_ARTIFACT/$REV_NAME.tar.gz -C $BASE_ARTIFACT
mv $BASE_ARTIFACT/$REV_NAME $REV_NAME
# Executable binary paths that need to be combined.
BIN_PATHS=(citra citra-room citra-qt.app/Contents/MacOS/citra-qt)
# Dylib paths that need to be combined.
IFS=$'\n'
DYLIB_PATHS=($(cd $REV_NAME && find . -name '*.dylib'))
unset IFS
# Combine all of the executable binaries and dylibs.
for OTHER_ARTIFACT in "${ARTIFACTS_LIST[@]:1}"; do
OTHER_ARTIFACT_ARCH="${OTHER_ARTIFACT##*-}"
tar xf $OTHER_ARTIFACT/$REV_NAME.tar.gz -C $OTHER_ARTIFACT
for BIN_PATH in "${BIN_PATHS[@]}"; do
lipo -create -output $REV_NAME/$BIN_PATH $REV_NAME/$BIN_PATH $OTHER_ARTIFACT/$REV_NAME/$BIN_PATH
done
for DYLIB_PATH in "${DYLIB_PATHS[@]}"; do
# Only merge if the libraries do not have conflicting arches, otherwise it will fail.
DYLIB_INFO=`file $REV_NAME/$DYLIB_PATH`
OTHER_DYLIB_INFO=`file $OTHER_ARTIFACT/$REV_NAME/$DYLIB_PATH`
if ! [[ "$DYLIB_INFO" =~ "$OTHER_ARTIFACT_ARCH" ]] && ! [[ "$OTHER_DYLIB_INFO" =~ "$BASE_ARTIFACT_ARCH" ]]; then
lipo -create -output $REV_NAME/$DYLIB_PATH $REV_NAME/$DYLIB_PATH $OTHER_ARTIFACT/$REV_NAME/$DYLIB_PATH
fi
done
done
. .ci/common/post-upload.sh

View File

@ -12,20 +12,37 @@ cp build/bin/Release/citra "$REV_NAME"
cp -r build/bin/Release/citra-qt.app "$REV_NAME"
cp build/bin/Release/citra-room "$REV_NAME"
# move libs into folder for deployment
macpack "${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt" -d "../Frameworks"
# move qt frameworks into app bundle for deployment
$(brew --prefix)/opt/qt5/bin/macdeployqt "${REV_NAME}/citra-qt.app" -executable="${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt"
BUNDLE_PATH="$REV_NAME/citra-qt.app"
BUNDLE_CONTENTS_PATH="$BUNDLE_PATH/Contents"
BUNDLE_EXECUTABLE_PATH="$BUNDLE_CONTENTS_PATH/MacOS/citra-qt"
BUNDLE_FRAMEWORKS_PATH="$BUNDLE_CONTENTS_PATH/Frameworks"
BUNDLE_RESOURCES_PATH="$BUNDLE_CONTENTS_PATH/Resources"
CITRA_STANDALONE_PATH="$REV_NAME/citra"
# move libs into folder for deployment
macpack "${REV_NAME}/citra" -d "libs"
macpack $BUNDLE_EXECUTABLE_PATH -d "../Frameworks"
# move qt frameworks into app bundle for deployment
macdeployqt $BUNDLE_PATH -executable=$BUNDLE_EXECUTABLE_PATH
# move libs into folder for deployment
macpack $CITRA_STANDALONE_PATH -d "libs"
# bundle MoltenVK
VULKAN_SDK_PATH=~/VulkanSDK/*/macOS
cp $VULKAN_SDK_PATH/lib/libvulkan.dylib $BUNDLE_FRAMEWORKS_PATH
cp $VULKAN_SDK_PATH/lib/libMoltenVK.dylib $BUNDLE_FRAMEWORKS_PATH
cp $VULKAN_SDK_PATH/lib/libVkLayer_*.dylib $BUNDLE_FRAMEWORKS_PATH
cp -r $VULKAN_SDK_PATH/share/vulkan $BUNDLE_RESOURCES_PATH
find $BUNDLE_RESOURCES_PATH/vulkan -type f -name "*.json" -exec sed -i'' -e 's/..\/..\/..\/lib/..\/..\/..\/Frameworks/g' {} \;
install_name_tool -add_rpath "@loader_path/../Frameworks/" $BUNDLE_EXECUTABLE_PATH
# workaround for libc++
install_name_tool -change @loader_path/../Frameworks/libc++.1.0.dylib /usr/lib/libc++.1.dylib "${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt"
install_name_tool -change @loader_path/libs/libc++.1.0.dylib /usr/lib/libc++.1.dylib "${REV_NAME}/citra"
install_name_tool -change @loader_path/../Frameworks/libc++.1.0.dylib /usr/lib/libc++.1.dylib $BUNDLE_EXECUTABLE_PATH
install_name_tool -change @loader_path/libs/libc++.1.0.dylib /usr/lib/libc++.1.dylib $CITRA_STANDALONE_PATH
# Make the launching script executable
chmod +x ${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt
chmod +x $BUNDLE_EXECUTABLE_PATH
# Verify loader instructions
find "$REV_NAME" -type f -exec otool -L {} \;

View File

@ -1,7 +1,18 @@
#!/bin/sh -ex
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MSVCCache.cmake" -DCITRA_USE_CCACHE=ON -DCITRA_USE_BUNDLED_QT=1 -DCITRA_USE_BUNDLED_SDL2=1 -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_MF=ON -DENABLE_FFMPEG_VIDEO_DUMPER=ON
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-G Ninja \
-DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MSVCCache.cmake" \
-DCITRA_USE_CCACHE=ON \
-DCITRA_USE_BUNDLED_QT=1 \
-DENABLE_QT_TRANSLATION=OFF \
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DUSE_DISCORD_PRESENCE=ON \
-DENABLE_MF=ON \
-DENABLE_FFMPEG_VIDEO_DUMPER=ON
ninja
# show the caching efficiency

View File

@ -0,0 +1,41 @@
$GITDATE = $(git show -s --date=short --format='%ad') -replace "-", ""
$GITREV = $(git show -s --format='%h')
# Find out what release we are building
if ( $GIT_TAG_NAME ) {
$RELEASE_NAME = ${GIT_TAG_NAME}.split("-")[0]
$RELEASE_NAME = "${RELEASE_NAME}-msvc"
}
else {
$RELEASE_NAME = "head"
}
$MSVC_BUILD_ZIP = "citra-windows-msvc-$GITDATE-$GITREV.zip" -replace " ", ""
$MSVC_SEVENZIP = "citra-windows-msvc-$GITDATE-$GITREV.7z" -replace " ", ""
$BUILD_DIR = ".\build\bin\Release"
# Create artifact directories
mkdir $RELEASE_NAME
mkdir "artifacts"
echo "Starting to pack ${RELEASE_NAME}"
Copy-Item $BUILD_DIR\* -Destination $RELEASE_NAME -Recurse
Remove-Item $RELEASE_NAME\tests.* -ErrorAction ignore
Remove-Item $RELEASE_NAME\*.pdb -ErrorAction ignore
# Copy documentation
Copy-Item license.txt -Destination $RELEASE_NAME
Copy-Item README.md -Destination $RELEASE_NAME
# Copy cross-platform scripting support
Copy-Item dist\scripting -Destination $RELEASE_NAME -Recurse
# Build the final release artifacts
7z a -tzip $MSVC_BUILD_ZIP $RELEASE_NAME\*
7z a $MSVC_SEVENZIP $RELEASE_NAME
Copy-Item $MSVC_BUILD_ZIP -Destination "artifacts"
Copy-Item $MSVC_SEVENZIP -Destination "artifacts"

View File

@ -0,0 +1,10 @@
name: New Issue (Developers Only)
description: A blank issue template for developers only. If you are not a developer, do not use this issue template. Your issue WILL BE CLOSED if you do not use the appropriate issue template.
body:
- type: markdown
attributes:
value: |
**If you are not a developer, do not use this issue template. Your issue WILL BE CLOSED if you do not use the appropriate issue template.**
- type: textarea
attributes:
label: "Issue"

View File

@ -1,35 +0,0 @@
---
name: Bug Report / Feature Request
about: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with Citra or you are requesting a feature you believe would make Citra better.
title: ''
labels: ''
assignees: ''
---
<!---
Please read the FAQ:
https://citra-emu.org/wiki/faq/
THIS IS NOT A SUPPORT FORUM, FOR SUPPORT GO TO:
https://community.citra-emu.org/
If the FAQ does not answer your question, please go to:
https://community.citra-emu.org/
====================================================
When submitting an issue, please check the following:
- You have read the above.
- You have provided the version (commit hash) of Citra you are using.
- You have provided sufficient detail for the issue to be reproduced.
- You have provided system specs (if relevant).
- Please also provide:
- For any issues, a log file
- For crashes, a backtrace.
- For graphical issues, comparison screenshots with real hardware.
- For emulation inaccuracies, a test-case (if able).
--->

64
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: Bug Report
description: File a bug report
body:
- type: markdown
attributes:
value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with Citra.
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing issues
required: true
- type: input
attributes:
label: Affected Build(s)
description: List the affected build(s) that this issue applies to.
placeholder: Nightly 1234 / Canary 1234
validations:
required: true
- type: textarea
id: issue-desc
attributes:
label: Description of Issue
description: A brief description of the issue encountered along with any images and/or videos.
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: A brief description of how it is expected to work along with any images and/or videos.
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: Reproduction Steps
description: A brief explanation of how to reproduce this issue. If possible, provide a save file to aid in reproducing the issue.
validations:
required: true
- type: textarea
id: log
attributes:
label: Log File
description: A log file will help our developers to better diagnose and fix the issue.
validations:
required: true
- type: textarea
id: system-config
attributes:
label: System Configuration
placeholder: |
CPU: Intel i5-10400 / AMD Ryzen 5 3600
GPU/Driver: NVIDIA GeForce GTX 1060 (Driver 512.95)
RAM: 16GB DDR4-3200
OS: Windows 11 22H2 (Build 22621.819)
value: |
CPU:
GPU/Driver:
RAM:
OS:
validations:
required: true

View File

@ -6,6 +6,3 @@ contact_links:
- name: Community forums
url: https://community.citra-emu.org
about: This is an alternative place for tech support, however helpers there are not as active.
- name: Citra Android
url: https://github.com/citra-emu/citra-android
about: If you need tech support on Citra Android, you should use either of the above two options. If you want to file an issue, you should go to the Android repo linked here.

View File

@ -0,0 +1,28 @@
name: Feature Request
description: File a feature request
labels: "request"
body:
- type: markdown
attributes:
value: Tech support does not belong here. You should only file an issue here if you are requesting a feature you believe would make Citra better.
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the feature you are requesting.
options:
- label: I have searched the existing issues
required: true
- type: textarea
id: what-feature
attributes:
label: What feature are you suggesting?
description: A brief description of the requested feature.
validations:
required: true
- type: textarea
id: why-feature
attributes:
label: Why would this feature be useful?
description: A brief description of why this feature would make Citra better.
validations:
required: true

View File

@ -74,6 +74,9 @@ jobs:
path: artifacts/
macos:
runs-on: macos-latest
strategy:
matrix:
arch: ["x86_64", "arm64"]
steps:
- uses: actions/checkout@v3
with:
@ -82,9 +85,9 @@ jobs:
uses: actions/cache@v3
with:
path: ~/Library/Caches/ccache
key: ${{ runner.os }}-macos-${{ github.sha }}
key: ${{ runner.os }}-macos-${{ matrix.arch }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-macos-
${{ runner.os }}-macos-${{ matrix.arch }}-
- name: Query tag name
uses: little-core-labs/get-git-tag@v3.0.2
id: tagName
@ -93,8 +96,51 @@ jobs:
- name: Build
run: ./.ci/macos/build.sh
env:
MACOSX_DEPLOYMENT_TARGET: "10.13"
MACOSX_DEPLOYMENT_TARGET: "11"
ENABLE_COMPATIBILITY_REPORTING: "ON"
TARGET_ARCH: ${{ matrix.arch }}
- name: Pack
run: ./.ci/macos/upload.sh
- name: Upload
uses: actions/upload-artifact@v3
with:
name: macos-${{ matrix.arch }}
path: artifacts/
macos-universal:
runs-on: macos-latest
needs: macos
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Query tag name
uses: little-core-labs/get-git-tag@v3.0.2
id: tagName
- name: Download x86 build
uses: actions/download-artifact@master
with:
name: macos-x86_64
path: macos-x86_64/
- name: Download ARM64 build
uses: actions/download-artifact@master
with:
name: macos-arm64
path: macos-arm64/
- name: Create universal app
run: ./.ci/macos/universal.sh
env:
ARTIFACTS: macos-x86_64 macos-arm64
- name: Upload
uses: actions/upload-artifact@v3
with:
name: macos
path: artifacts/
- name: Delete intermediate artifacts
uses: geekyeggo/delete-artifact@v2
with:
name: |
macos-x86_64
macos-arm64
windows:
runs-on: windows-latest
steps:
@ -108,16 +154,34 @@ jobs:
key: ${{ runner.os }}-win-${{ github.sha }}
restore-keys: |
${{ runner.os }}-win-
- name: Query tag name
uses: little-core-labs/get-git-tag@v3.0.2
id: tagName
- name: Install dependencies
run: ./.ci/windows-msvc/deps.sh
shell: bash
- name: Set up MSVC
uses: ilammy/msvc-dev-cmd@v1
- name: Setup Vulkan SDK
uses: humbletim/setup-vulkan-sdk@v1.2.0
with:
vulkan-query-version: latest
vulkan-components: Glslang
vulkan-use-cache: true
- name: Test glslangValidator
run: glslangValidator --version
- name: Build
run: ./.ci/windows-msvc/build.sh
shell: bash
env:
ENABLE_COMPATIBILITY_REPORTING: "ON"
- name: Pack
run: ./.ci/windows-msvc/upload.ps1
- name: Upload
uses: actions/upload-artifact@v3
with:
name: msvc
path: artifacts/
android:
runs-on: ubuntu-latest
steps:
@ -141,6 +205,9 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install ccache apksigner -y
sudo add-apt-repository -y ppa:savoury1/ffmpeg4
sudo apt-get update -y
sudo apt-get install --no-install-recommends -y glslang-dev glslang-tools
- name: Build
run: ./.ci/android/build.sh
- name: Copy and sign artifacts
@ -168,7 +235,7 @@ jobs:
TRANSIFEX_API_TOKEN: ${{ secrets.TRANSIFEX_API_TOKEN }}
release:
runs-on: ubuntu-latest
needs: [build, android, macos, source]
needs: [build, android, macos-universal, source, windows]
if: ${{ startsWith(github.ref, 'refs/tags/') }}
steps:
- uses: actions/download-artifact@v3

36
.gitmodules vendored
View File

@ -12,13 +12,10 @@
url = https://github.com/catchorg/Catch2
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/citra-emu/dynarmic.git
url = https://github.com/merryhime/dynarmic.git
[submodule "xbyak"]
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
[submodule "cryptopp"]
path = externals/cryptopp/cryptopp
url = https://github.com/weidai11/cryptopp.git
[submodule "fmt"]
path = externals/fmt
url = https://github.com/fmtlib/fmt.git
@ -46,9 +43,6 @@
[submodule "teakra"]
path = externals/teakra
url = https://github.com/wwylele/teakra.git
[submodule "lodepng"]
path = externals/lodepng/lodepng
url = https://github.com/lvandeve/lodepng.git
[submodule "zstd"]
path = externals/zstd
url = https://github.com/facebook/zstd.git
@ -56,14 +50,26 @@
path = externals/libyuv
url = https://github.com/lemenkov/libyuv.git
[submodule "sdl2"]
path = externals/sdl2/SDL
url = https://github.com/libsdl-org/SDL
path = externals/sdl2/SDL
url = https://github.com/libsdl-org/SDL
[submodule "cryptopp-cmake"]
path = externals/cryptopp-cmake
url = https://github.com/abdes/cryptopp-cmake.git
[submodule "cryptopp"]
path = externals/cryptopp
url = https://github.com/weidai11/cryptopp.git
[submodule "vulkan-headers"]
path = externals/vulkan-headers
url = https://github.com/KhronosGroup/Vulkan-Headers
path = externals/vulkan-headers
url = https://github.com/KhronosGroup/Vulkan-Headers
[submodule "glslang"]
path = externals/glslang
url = https://github.com/KhronosGroup/glslang
path = externals/glslang
url = https://github.com/KhronosGroup/glslang
[submodule "glm"]
path = externals/glm
url = https://github.com/g-truc/glm
path = externals/glm
url = https://github.com/g-truc/glm
[submodule "sirit"]
path = externals/sirit
url = https://github.com/GPUCode/sirit
[submodule "zlib-ng"]
path = externals/zlib-ng/zlib-ng
url = https://github.com/zlib-ng/zlib-ng

View File

@ -1,5 +1,5 @@
# CMake 3.12 required for 20 to be a valid value for CXX_STANDARD
cmake_minimum_required(VERSION 3.14)
cmake_minimum_required(VERSION 3.15)
# Don't override the warning flags in MSVC:
cmake_policy(SET CMP0092 NEW)
@ -43,6 +43,8 @@ CMAKE_DEPENDENT_OPTION(CITRA_USE_BUNDLED_FFMPEG "Download bundled FFmpeg binarie
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
option(CITRA_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
CMAKE_DEPENDENT_OPTION(ENABLE_MF "Use Media Foundation decoder (preferred over FFmpeg)" ON "WIN32" OFF)
CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ON "MINGW" OFF)
@ -51,6 +53,23 @@ option(USE_SYSTEM_BOOST "Use the system Boost libs (instead of the bundled ones)
CMAKE_DEPENDENT_OPTION(ENABLE_FDK "Use FDK AAC decoder" OFF "NOT ENABLE_FFMPEG_AUDIO_DECODER;NOT ENABLE_MF" OFF)
if (CITRA_USE_PRECOMPILED_HEADERS)
if (MSVC AND CCACHE)
# buildcache does not properly cache PCH files, leading to compilation errors.
# See https://github.com/mbitsnbites/buildcache/discussions/230
message(WARNING "Buildcache does not properly support Precompiled Headers. Disabling PCH")
set(CITRA_USE_PRECOMPILED_HEADERS OFF)
endif()
if(APPLE)
message(WARNING "Precompiled Headers currently do not work on Apple. Disabling PCH")
set(CITRA_USE_PRECOMPILED_HEADERS OFF)
endif()
endif()
if (CITRA_USE_PRECOMPILED_HEADERS)
message(STATUS "Using Precompiled Headers.")
set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
endif()
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
message(STATUS "Copying pre-commit hook")
file(COPY hooks/pre-commit
@ -128,14 +147,14 @@ function(detect_architecture symbol arch)
# CMake's crazy scope rules will keep it defined
if (ARCHITECTURE_${arch})
set(ARCHITECTURE "${arch}" PARENT_SCOPE)
set(ARCHITECTURE_${arch} 1 PARENT_SCOPE)
add_definitions(-DARCHITECTURE_${arch}=1)
endif()
endif()
endfunction()
if (NOT ENABLE_GENERIC)
if (MSVC)
if (CMAKE_OSX_ARCHITECTURES)
set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
elseif (MSVC)
detect_architecture("_M_AMD64" x86_64)
detect_architecture("_M_IX86" x86)
detect_architecture("_M_ARM" arm)
@ -149,8 +168,6 @@ if (NOT ENABLE_GENERIC)
endif()
if (NOT DEFINED ARCHITECTURE)
set(ARCHITECTURE "GENERIC")
set(ARCHITECTURE_GENERIC 1)
add_definitions(-DARCHITECTURE_GENERIC=1)
endif()
message(STATUS "Target architecture: ${ARCHITECTURE}")
@ -158,6 +175,8 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
# Configure C++ standard
# ===========================
# boost asio's concept usage doesn't play nicely with some compilers yet.
add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -174,8 +193,8 @@ find_package(Threads REQUIRED)
if (ENABLE_QT)
if (CITRA_USE_BUNDLED_QT)
if (MSVC_VERSION GREATER_EQUAL 1930 AND ARCHITECTURE_x86_64)
set(QT_VER qt-5.15.5-msvc2022_64)
if (MSVC_VERSION GREATER_EQUAL 1920 AND "x86_64" IN_LIST ARCHITECTURE)
set(QT_VER qt-5.15.7-msvc2019_64)
else()
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
endif()
@ -191,7 +210,11 @@ if (ENABLE_QT)
set(QT_PREFIX_HINT)
endif()
find_package(Qt5 REQUIRED COMPONENTS Widgets Multimedia ${QT_PREFIX_HINT})
find_package(Qt5 REQUIRED COMPONENTS Widgets Multimedia Concurrent ${QT_PREFIX_HINT})
if (UNIX AND NOT APPLE)
find_package(Qt5 REQUIRED COMPONENTS DBus ${QT_PREFIX_HINT})
endif()
if (ENABLE_QT_TRANSLATION)
find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
@ -211,7 +234,7 @@ endif()
if (ENABLE_FFMPEG)
if (CITRA_USE_BUNDLED_FFMPEG)
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND "x86_64" IN_LIST ARCHITECTURE)
set(FFmpeg_VER "ffmpeg-4.1-win64")
else()
message(FATAL_ERROR "No bundled FFmpeg binaries for your toolchain. Disable CITRA_USE_BUNDLED_FFMPEG and provide your own.")
@ -295,13 +318,15 @@ if (CLANG_FORMAT)
set(SRCS ${PROJECT_SOURCE_DIR}/src)
set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
if (WIN32)
add_custom_target(clang-format
COMMAND powershell.exe -Command "Get-ChildItem '${SRCS}/*' -Include *.cpp,*.h,*.mm -Recurse | Foreach {&'${CLANG_FORMAT}' -i $_.fullname}"
COMMENT ${CCOMMENT})
elseif(MINGW)
add_custom_target(clang-format
COMMAND find `cygpath -u ${SRCS}` -iname *.h -o -iname *.cpp -o -iname *.mm | xargs `cygpath -u ${CLANG_FORMAT}` -i
COMMENT ${CCOMMENT})
if(MINGW)
add_custom_target(clang-format
COMMAND find `cygpath -u ${SRCS}` -iname *.h -o -iname *.cpp -o -iname *.mm | xargs `cygpath -u ${CLANG_FORMAT}` -i
COMMENT ${CCOMMENT})
else()
add_custom_target(clang-format
COMMAND powershell.exe -Command "Get-ChildItem '${SRCS}/*' -Include *.cpp,*.h,*.mm -Recurse | Foreach {&'${CLANG_FORMAT}' -i $_.fullname}"
COMMENT ${CCOMMENT})
endif()
else()
add_custom_target(clang-format
COMMAND find ${SRCS} -iname *.h -o -iname *.cpp -o -iname *.mm | xargs ${CLANG_FORMAT} -i
@ -359,12 +384,18 @@ endif()
enable_testing()
add_subdirectory(externals)
# See externals/CMakeLists.txt
foreach(def ${CRYPTOPP_COMPILE_DEFINITIONS})
add_definitions(-D${def})
endforeach()
# Boost
if (USE_SYSTEM_BOOST)
find_package(Boost 1.70.0 COMPONENTS serialization REQUIRED)
find_package(Boost 1.70.0 COMPONENTS serialization iostreams REQUIRED)
else()
add_library(Boost::boost ALIAS boost)
add_library(Boost::serialization ALIAS boost_serialization)
add_library(Boost::iostreams ALIAS boost_iostreams)
endif()
# SDL2

View File

@ -17,6 +17,7 @@ function(copy_citra_Qt5_deps target_dir)
Qt5Core$<$<CONFIG:Debug>:d>.*
Qt5Gui$<$<CONFIG:Debug>:d>.*
Qt5Widgets$<$<CONFIG:Debug>:d>.*
Qt5Concurrent$<$<CONFIG:Debug>:d>.*
Qt5Multimedia$<$<CONFIG:Debug>:d>.*
Qt5Network$<$<CONFIG:Debug>:d>.*
)

View File

@ -1,24 +1,49 @@
**BEFORE FILING AN ISSUE, READ THE RELEVANT SECTION IN THE [CONTRIBUTING](https://github.com/citra-emu/citra/wiki/Contributing#reporting-issues) FILE!!!**
<h1 align="center">
<br>
<a href="https://citra-emu.org/"><img src="https://raw.githubusercontent.com/citra-emu/citra-assets/master/Main/citra_logo.svg" alt="Citra" width="200"></a>
<br>
<b>Citra</b>
<br>
</h1>
# Citra
<h4 align="center"><b>Citra</b> is the world's most popular, open-source, Nintendo 3DS emulator.
<br>
It is written in C++ with portability in mind and builds are actively maintained for Windows, Linux, Android and macOS.
</h4>
[![GitHub Actions Build Status](https://github.com/citra-emu/citra/workflows/citra-ci/badge.svg)](https://github.com/citra-emu/citra/actions)
[![Bitrise CI Build Status](https://app.bitrise.io/app/4ccd8e5720f0d13b/status.svg?token=H32TmbCwxb3OQ-M66KbAyw&branch=master)](https://app.bitrise.io/app/4ccd8e5720f0d13b)
[![Discord](https://img.shields.io/discord/220740965957107713?color=%237289DA&label=Citra&logo=discord&logoColor=white)](https://discord.gg/FAXfZV9)
<p align="center">
<a href="https://github.com/citra-emu/citra/actions/">
<img src="https://github.com/citra-emu/citra/workflows/citra-ci/badge.svg"
alt="GitHub Actions Build Status">
</a>
<a href="https://discord.gg/FAXfZV9">
<img src="https://img.shields.io/discord/220740965957107713?color=%237289DA&label=Citra&logo=discord&logoColor=white"
alt="Discord">
</a>
</p>
Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C++. It is written with portability in mind, with builds actively maintained for Windows, Linux and macOS.
<p align="center">
<a href="#compatibility">Compatibility</a> |
<a href="#releases">Releases</a> |
<a href="#development">Development</a> |
<a href="#building">Building</a> |
<a href="#support">Support</a> |
<a href="#license">License</a>
</p>
Citra emulates a subset of 3DS hardware and therefore is useful for running/debugging homebrew applications, and it is also able to run many commercial games! Some of these do not run at a playable state, but we are working every day to advance the project forward. (Playable here means compatibility of at least "Okay" on our [game compatibility list](https://citra-emu.org/game).)
Citra is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. Please read the [FAQ](https://citra-emu.org/wiki/faq/) before getting started with the project.
## Compatibility
Check out our [website](https://citra-emu.org/)!
The emulator is capable of running most commercial games at full speed, provided you meet the necessary hardware requirements.
For a full list of games Citra supports, please visit our [Compatibility page](https://citra-emu.org/game/)
Check out our [website](https://citra-emu.org/) for the latest news on exciting features, progress reports, and more!
Please read the [FAQ](https://citra-emu.org/wiki/faq/) before getting started with the project.
Need help? Check out our [asking for help](https://citra-emu.org/help/reference/asking/) guide.
For development discussion, please join us on our [Discord server](https://citra-emu.org/discord/) or at #citra-dev on libera.
### Releases
## Releases
Citra has two main release channels: Nightly and Canary.
@ -28,30 +53,46 @@ The [Canary](https://github.com/citra-emu/citra-canary) build is based on the ma
Both builds can be installed with the installer provided on the [website](https://citra-emu.org/download/), but those looking for specific versions or standalone releases can find them in the release tabs of the [Nightly](https://github.com/citra-emu/citra-nightly/releases) and [Canary](https://github.com/citra-emu/citra-canary/releases) repositories.
Currently, development and releases of the Android version are in [a separate repository](https://github.com/citra-emu/citra-android).
Android builds can be downloaded from the Google Play Store.
A Flatpak for Citra is available on [Flathub](https://flathub.org/apps/details/org.citra_emu.citra). Details on the build process can be found in [our Flathub repository](https://github.com/flathub/org.citra_emu.citra).
### Development
## Development
Most of the development happens on GitHub. It's also where [our central repository](https://github.com/citra-emu/citra) is hosted.
For development discussion, please join us on our [Discord server](https://citra-emu.org/discord/) or at #citra-dev on libera.
If you want to contribute please take a look at the [Contributor's Guide](https://github.com/citra-emu/citra/wiki/Contributing) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information). You should also contact any of the developers in the forum in order to know about the current state of the emulator because the [TODO list](https://docs.google.com/document/d/1SWIop0uBI9IW8VGg97TAtoT_CHNoP42FzYmvG1F4QDA) isn't maintained anymore.
If you want to contribute please take a look at the [Contributor's Guide](https://github.com/citra-emu/citra/wiki/Contributing) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information). You can also contact any of the developers on Discord in order to know about the current state of the emulator.
If you want to contribute to the user interface translation, please check out the [citra project on transifex](https://www.transifex.com/citra/citra). We centralize the translation work there, and periodically upstream translations.
If you want to contribute to the user interface translation, please check out the [Citra project on transifex](https://www.transifex.com/citra/citra). We centralize the translation work there, and periodically upstream translations.
### Building
## Building
* __Windows__: [Windows Build](https://github.com/citra-emu/citra/wiki/Building-For-Windows)
* __Linux__: [Linux Build](https://github.com/citra-emu/citra/wiki/Building-For-Linux)
* __macOS__: [macOS Build](https://github.com/citra-emu/citra/wiki/Building-for-macOS)
* __Android__: [Android Build](https://github.com/citra-emu/citra/wiki/Building-for-Android)
### Support
We happily accept monetary donations or donated games and hardware. Please see our [donations page](https://citra-emu.org/donate/) for more information on how you can contribute to Citra. Any donations received will go towards things like:
## Support
If you enjoy the project and want to support us financially, check out our Patreon!
<a href="https://www.patreon.com/citraemu">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
</a>
We also happily accept donated games and hardware.
Please see our [donations page](https://citra-emu.org/donate/) for more information on how you can contribute to Citra.
Any donations received will go towards things like:
* 3DS consoles for developers to explore the hardware
* 3DS games for testing
* Any equipment required for homebrew
* Infrastructure setup
We also more than gladly accept used 3DS consoles! If you would like to give yours away, don't hesitate to join our [Discord server](https://citra-emu.org/discord/) and talk to bunnei.
## License
Citra is licensed under the GPLv2 (or any later version). Refer to the [LICENSE.txt](https://github.com/citra-emu/citra/blob/master/license.txt) file.

View File

@ -1,9 +1,9 @@
[main]
host = https://www.transifex.com
[citra.emulator]
file_filter = <lang>.ts
source_file = en.ts
source_lang = en
type = QT
[main]
host = https://www.transifex.com
[o:citra:p:citra:r:emulator]
file_filter = <lang>.ts
source_file = en.ts
source_lang = en
type = QT

View File

@ -10,4 +10,19 @@ QPushButton#GraphicsAPIStatusBarButton {
QPushButton#GraphicsAPIStatusBarButton:hover {
border: 1px solid #76797C;
}
}
QPushButton#3DOptionStatusBarButton {
color: #A5A5A5;
font-weight: bold;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
min-width: 60px;
min-height: 20px;
}
QPushButton#3DOptionStatusBarButton:hover {
border: 1px solid #76797C;
}

View File

@ -1249,4 +1249,19 @@ QPushButton#GraphicsAPIStatusBarButton {
QPushButton#GraphicsAPIStatusBarButton:hover {
border: 1px solid #76797C;
}
}
QPushButton#3DOptionStatusBarButton {
color: #A5A5A5;
font-weight: bold;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
min-width: 60px;
min-height: 20px;
}
QPushButton#3DOptionStatusBarButton:hover {
border: 1px solid #76797C;
}

View File

@ -21,6 +21,15 @@ file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/seri
add_library(boost_serialization STATIC ${boost_serialization_SRC})
target_link_libraries(boost_serialization PUBLIC boost)
# Boost::iostreams
add_library(
boost_iostreams
STATIC
${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/file_descriptor.cpp
${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/mapped_file.cpp
)
target_link_libraries(boost_iostreams PUBLIC boost)
# Add additional boost libs here; remember to ALIAS them in the root CMakeLists!
# Catch2
@ -29,25 +38,45 @@ set(CATCH_INSTALL_EXTRAS OFF)
add_subdirectory(catch2)
# Crypto++
add_subdirectory(cryptopp)
set(CRYPTOPP_BUILD_DOCUMENTATION OFF)
set(CRYPTOPP_BUILD_TESTING OFF)
set(CRYPTOPP_INSTALL OFF)
set(CRYPTOPP_SOURCES "${CMAKE_SOURCE_DIR}/externals/cryptopp")
add_subdirectory(cryptopp-cmake)
# HACK: Mismatch between compilation of CryptoPP and headers used in Citra can cause runtime issues.
# Pull out the compile definitions from CryptoPP and apply them to Citra as well to fix this.
# See: https://github.com/weidai11/cryptopp/issues/1191
get_source_file_property(CRYPTOPP_COMPILE_DEFINITIONS ${CRYPTOPP_SOURCES}/cryptlib.cpp TARGET_DIRECTORY cryptopp COMPILE_DEFINITIONS)
set(CRYPTOPP_COMPILE_DEFINITIONS ${CRYPTOPP_COMPILE_DEFINITIONS} PARENT_SCOPE)
# HACK: The logic to set up the base include directory for CryptoPP does not work with Android SDK CMake 3.22.1.
# Until there is a fixed version available, this code will detect and add in the proper include if it does not exist.
if(ANDROID)
message(STATUS "Applying CryptoPP include fix.")
get_target_property(CRYPTOPP_INCLUDES cryptopp INTERFACE_INCLUDE_DIRECTORIES)
foreach(CRYPTOPP_INCLUDE ${CRYPTOPP_INCLUDES})
if("${CRYPTOPP_INCLUDE}" MATCHES "\\$<BUILD_INTERFACE:(.*)/cryptopp>")
message(STATUS "Fixed include path: ${CMAKE_MATCH_1}")
target_include_directories(cryptopp PUBLIC $<BUILD_INTERFACE:${CMAKE_MATCH_1}>)
break()
endif()
endforeach()
endif()
# fmt and Xbyak need to be added before dynarmic
# libfmt
option(FMT_INSTALL "" ON)
add_subdirectory(fmt)
# Xbyak
if (ARCHITECTURE_x86_64)
add_library(xbyak INTERFACE)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/xbyak/xbyak DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include)
target_include_directories(xbyak SYSTEM INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include)
target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
if ("x86_64" IN_LIST ARCHITECTURE)
add_subdirectory(xbyak)
endif()
# Dynarmic
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
if ("x86_64" IN_LIST ARCHITECTURE OR "arm64" IN_LIST ARCHITECTURE)
set(DYNARMIC_TESTS OFF)
set(DYNARMIC_NO_BUNDLED_FMT ON)
set(DYNARMIC_FRONTENDS "A32")
add_subdirectory(dynarmic)
endif()
@ -67,6 +96,9 @@ set(ENABLE_SPVREMAPPER OFF)
set(ENABLE_CTEST OFF)
add_subdirectory(glslang)
# Sirit
add_subdirectory(sirit)
# glm
add_subdirectory(glm)
@ -97,6 +129,9 @@ if (ENABLE_SDL2 AND NOT USE_SYSTEM_SDL2)
add_subdirectory(sdl2)
endif()
# Zlib
add_subdirectory(zlib-ng)
# Zstandard
set(ZSTD_LEGACY_SUPPORT OFF)
set(ZSTD_BUILD_PROGRAMS OFF)
@ -155,8 +190,8 @@ if (ENABLE_WEB_SERVICE)
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
endif()
# lodepng
add_subdirectory(lodepng)
# libspng
add_subdirectory(libspng)
# (xperia64): Only use libyuv on Android b/c of build issues on Windows and mandatory JPEG
if(ANDROID)

View File

@ -22,7 +22,7 @@ function(windows_copy_files TARGET SOURCE_DIR DEST_DIR)
# cmake adds an extra check for command success which doesn't work too well with robocopy
# so trick it into thinking the command was successful with the || cmd /c "exit /b 0"
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND if not exist ${DEST_DIR} mkdir ${DEST_DIR} 2> nul
COMMAND ${CMAKE_COMMAND} -E make_directory ${DEST_DIR}
COMMAND robocopy ${SOURCE_DIR} ${DEST_DIR} ${ARGN} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0"
)
endfunction()
endfunction()

1
externals/cryptopp vendored Submodule

Submodule externals/cryptopp added at 511806c0eb

1
externals/cryptopp-cmake vendored Submodule

View File

@ -1,449 +0,0 @@
# A trimmed down version of the CMakeLists.txt from noloader/cryptopp-cmake
# The differences are:
# - removed support for legacy CMake versions
# - removed support for 32-bit
# - added prefix "CRYPTOPP_OPT_" to all option names
# - disabled testing
# - disabled installation
# - disabled documentation
# - configured to build a static library only
# - adds include directories to the library target
cmake_minimum_required(VERSION 3.1)
if (POLICY CMP0048)
cmake_policy(SET CMP0048 NEW)
endif ()
project(cryptopp VERSION 8.5.0)
if (POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif ()
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp)
include(TestBigEndian)
include(GNUInstallDirs)
include(CheckCXXCompilerFlag)
set(TEST_PROG_DIR ${SRC_DIR}/TestPrograms)
set(TEST_CXX_FILE ${TEST_PROG_DIR}/test_cxx.cxx)
#============================================================================
# Settable options
#============================================================================
option(CRYPTOPP_OPT_DISABLE_ASM "Disable ASM" OFF)
option(CRYPTOPP_OPT_DISABLE_SSSE3 "Disable SSSE3" OFF)
option(CRYPTOPP_OPT_DISABLE_SSE4 "Disable SSE4" OFF)
option(CRYPTOPP_OPT_DISABLE_AESNI "Disable AES-NI" OFF)
option(CRYPTOPP_OPT_DISABLE_SHA "Disable SHA" OFF)
option(CRYPTOPP_OPT_DISABLE_AVX "Disable AVX" OFF)
option(CRYPTOPP_OPT_DISABLE_AVX2 "Disable AVX2" OFF)
#============================================================================
# Compiler options
#============================================================================
# Only set when cross-compiling, http://www.vtk.org/Wiki/CMake_Cross_Compiling
if (NOT (CMAKE_SYSTEM_VERSION AND CMAKE_SYSTEM_PROCESSOR))
set(CRYPTOPP_CROSS_COMPILE 1)
else()
set(CRYPTOPP_CROSS_COMPILE 0)
endif()
set(CRYPTOPP_COMPILE_DEFINITIONS)
set(CRYPTOPP_COMPILE_OPTIONS)
# Don't use RPATH's. The resulting binary could fail a security audit.
set(CMAKE_MACOSX_RPATH 0)
if(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
list(APPEND CRYPTOPP_COMPILE_OPTIONS -wd68 -wd186 -wd279 -wd327 -wd161 -wd3180)
endif()
if(MSVC)
# Disable C4390: empty controlled statement found: is this the intent?
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4390")
endif()
# Endianness
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if(IS_BIG_ENDIAN)
add_definitions(-DIS_BIG_ENDIAN)
endif()
if (CRYPTOPP_OPT_DISABLE_ASM)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_ASM)
endif ()
if (CRYPTOPP_OPT_DISABLE_SSSE3)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_SSSE3)
endif ()
if (CRYPTOPP_OPT_DISABLE_SSE4)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_SSSE4)
endif ()
if (CRYPTOPP_OPT_DISABLE_CLMUL)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_CLMUL)
endif ()
if (CRYPTOPP_OPT_DISABLE_AESNI)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_AESNI)
endif ()
if (CRYPTOPP_OPT_DISABLE_RDRAND)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_RDRAND)
endif ()
if (CRYPTOPP_OPT_DISABLE_RDSEED)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_RDSEED)
endif ()
if (CRYPTOPP_OPT_DISABLE_AVX)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_AVX)
endif ()
if (CRYPTOPP_OPT_DISABLE_AVX2)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_AVX2)
endif ()
if (CRYPTOPP_OPT_DISABLE_SHA)
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_SHA)
endif ()
# We need the output 'uname -s' for Unix and Linux system detection
if (NOT CRYPTOPP_CROSS_COMPILE)
set (UNAME_CMD "uname")
set (UNAME_ARG "-s")
execute_process(COMMAND ${UNAME_CMD} ${UNAME_ARG}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE UNAME_RESULT
OUTPUT_VARIABLE UNAME_SYSTEM)
string(REGEX REPLACE "\n$" "" UNAME_SYSTEM "${UNAME_SYSTEM}")
endif()
# We need the output 'uname -m' for Unix and Linux platform detection
if (NOT CRYPTOPP_CROSS_COMPILE)
set (UNAME_CMD "uname")
set (UNAME_ARG "-m")
execute_process(COMMAND ${UNAME_CMD} ${UNAME_ARG}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE UNAME_RESULT
OUTPUT_VARIABLE UNAME_MACHINE)
string(REGEX REPLACE "\n$" "" UNAME_MACHINE "${UNAME_MACHINE}")
endif()
###############################################################################
# Try to find a Posix compatible grep and sed. Solaris, Digital Unix,
# Tru64, HP-UX and a few others need tweaking
if (EXISTS /usr/xpg4/bin/grep)
set(GREP_CMD /usr/xpg4/bin/grep)
elseif (EXISTS /usr/gnu/bin/grep)
set(GREP_CMD /usr/gnu/bin/grep)
elseif (EXISTS /usr/linux/bin/grep)
set(GREP_CMD /usr/linux/bin/grep)
else ()
set(GREP_CMD grep)
endif ()
if (EXISTS /usr/xpg4/bin/sed)
set(SED_CMD /usr/xpg4/bin/sed)
elseif (EXISTS /usr/gnu/bin/sed)
set(SED_CMD /usr/gnu/bin/sed)
elseif (EXISTS /usr/linux/bin/sed)
set(SED_CMD /usr/linux/bin/sed)
else ()
set(SED_CMD sed)
endif ()
###############################################################################
function(CheckCompileOption opt var)
CHECK_CXX_COMPILER_FLAG(${opt} ${var})
endfunction(CheckCompileOption)
function(CheckCompileLinkOption opt var prog)
if (MSVC)
# TODO: improve this...
CHECK_CXX_COMPILER_FLAG(${opt} ${var})
elseif (APPLE)
message(STATUS "Performing Test ${var}")
try_compile(COMMAND_SUCCESS ${CMAKE_BINARY_DIR} ${prog} COMPILE_DEFINITIONS ${opt})
if (COMMAND_SUCCESS)
set(${var} 1 PARENT_SCOPE)
message(STATUS "Performing Test ${var} - Success")
else ()
set(${var} 0 PARENT_SCOPE)
message(STATUS "Performing Test ${var} - Failed")
endif ()
else ()
message(STATUS "Performing Test ${var}")
try_compile(COMMAND_SUCCESS ${CMAKE_BINARY_DIR} ${prog} COMPILE_DEFINITIONS ${opt})
if (COMMAND_SUCCESS)
set(${var} 1 PARENT_SCOPE)
message(STATUS "Performing Test ${var} - Success")
else ()
set(${var} 0 PARENT_SCOPE)
message(STATUS "Performing Test ${var} - Failed")
endif ()
endif ()
endfunction(CheckCompileLinkOption)
function(AddCompileOption opt)
if ("${COMMAND_OUTPUT}" NOT STREQUAL "")
list(APPEND CRYPTOPP_COMPILE_OPTIONS "${opt}")
endif ()
endfunction(AddCompileOption)
###############################################################################
function(DumpMachine output pattern)
if (MSVC)
# CMake does not provide a generic shell/terminal mechanism
# and Microsoft environments don't know what 'sh' is.
set(${output} 0 PARENT_SCOPE)
else ()
if(CMAKE_SYSTEM_PROCESSOR MATCHES ${pattern})
set(${output} TRUE PARENT_SCOPE)
endif()
endif()
endfunction(DumpMachine)
# Thansk to Anonimal for MinGW; see http://github.com/weidai11/cryptopp/issues/466
DumpMachine(CRYPTOPP_AMD64 "(x86_64|AMD64|amd64)")
DumpMachine(CRYPTOPP_I386 "(i.86)")
DumpMachine(CRYPTOPP_MINGW64 "(w64-mingw32)|(mingw64)")
DumpMachine(CRYPTOPP_ARMV8 "(armv8|aarch64)")
###############################################################################
if(MSVC)
if(CMAKE_SYSTEM_VERSION MATCHES "10\\.0.*")
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS "_WIN32_WINNT=0x0A00")
endif()
list(APPEND CRYPTOPP_COMPILE_OPTIONS /FI winapifamily.h)
endif()
# Enable PIC for all targets except Windows and 32-bit x86.
# Avoid on 32-bit x86 due to register pressures.
if ((NOT CRYPTOPP_CROSS_COMPILE) AND (NOT (WINDOWS OR WINDOWS_STORE OR WINDOWS_PHONE)))
# Use Regex; match i386, i486, i586 and i686
if (NOT (${UNAME_MACHINE} MATCHES "i.86"))
SET(CMAKE_POSITION_INDEPENDENT_CODE 1)
endif()
endif()
# Link is driven through the compiler, but CXXFLAGS are not used. Also see
# http://public.kitware.com/pipermail/cmake/2003-June/003967.html
if (NOT (WINDOWS OR WINDOWS_STORE OR WINDOWS_PHONE))
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_FLAGS}")
endif()
#============================================================================
# Sources & headers
#============================================================================
# Library headers
file(GLOB cryptopp_HEADERS ${SRC_DIR}/*.h)
# Remove headers used to build test suite
list(REMOVE_ITEM cryptopp_HEADERS
${SRC_DIR}/bench.h
${SRC_DIR}/validate.h
)
# Library sources.
# These have been trimmed to include only things Citra uses. This speeds up
# compiles and reduces the amount of compilation breakage.
set(cryptopp_SOURCES
# The Crypto++ readme says you should put these 3 object files first,
# to avoid "problems associated with C++ static initialization order",
# but doesn't actually tell what could go wrong. Better safe than sorry
# I guess...
${SRC_DIR}/cryptlib.cpp
${SRC_DIR}/cpu.cpp
${SRC_DIR}/integer.cpp
${SRC_DIR}/algparam.cpp
${SRC_DIR}/allocate.cpp
${SRC_DIR}/asn.cpp
${SRC_DIR}/authenc.cpp
${SRC_DIR}/base64.cpp
${SRC_DIR}/basecode.cpp
${SRC_DIR}/ccm.cpp
${SRC_DIR}/crc_simd.cpp
${SRC_DIR}/des.cpp
${SRC_DIR}/dessp.cpp
${SRC_DIR}/dll.cpp
${SRC_DIR}/ec2n.cpp
${SRC_DIR}/ecp.cpp
${SRC_DIR}/filters.cpp
${SRC_DIR}/fips140.cpp
${SRC_DIR}/gcm_simd.cpp
${SRC_DIR}/gf2n_simd.cpp
${SRC_DIR}/gf2n.cpp
${SRC_DIR}/gfpcrypt.cpp
${SRC_DIR}/hex.cpp
${SRC_DIR}/hmac.cpp
${SRC_DIR}/hrtimer.cpp
${SRC_DIR}/iterhash.cpp
${SRC_DIR}/md5.cpp
${SRC_DIR}/misc.cpp
${SRC_DIR}/modes.cpp
${SRC_DIR}/mqueue.cpp
${SRC_DIR}/nbtheory.cpp
${SRC_DIR}/neon_simd.cpp
${SRC_DIR}/oaep.cpp
${SRC_DIR}/osrng.cpp
${SRC_DIR}/ppc_power7.cpp
${SRC_DIR}/ppc_power8.cpp
${SRC_DIR}/ppc_power9.cpp
${SRC_DIR}/ppc_simd.cpp
${SRC_DIR}/pubkey.cpp
${SRC_DIR}/queue.cpp
${SRC_DIR}/randpool.cpp
${SRC_DIR}/rdtables.cpp
${SRC_DIR}/rijndael_simd.cpp
${SRC_DIR}/rijndael.cpp
${SRC_DIR}/rng.cpp
${SRC_DIR}/sha_simd.cpp
${SRC_DIR}/sha.cpp
${SRC_DIR}/sse_simd.cpp
)
if(ANDROID)
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
list(APPEND cryptopp_SOURCES ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
endif()
set(cryptopp_SOURCES_ASM)
if (MSVC AND NOT DISABLE_ASM)
if (${CMAKE_GENERATOR} MATCHES ".*ARM")
message(STATUS "Disabling ASM because ARM is specified as target platform.")
else ()
enable_language(ASM_MASM)
list(APPEND cryptopp_SOURCES_ASM
${SRC_DIR}/rdrand.asm
${SRC_DIR}/rdseed.asm
)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
list(APPEND cryptopp_SOURCES_ASM
${SRC_DIR}/x64dll.asm
${SRC_DIR}/x64masm.asm
)
set_source_files_properties(${cryptopp_SOURCES_ASM} PROPERTIES COMPILE_DEFINITIONS "_M_X64")
else ()
set_source_files_properties(${cryptopp_SOURCES_ASM} PROPERTIES COMPILE_DEFINITIONS "_M_X86" COMPILE_FLAGS "/safeseh")
endif ()
set_source_files_properties(${cryptopp_SOURCES_ASM} PROPERTIES LANGUAGE ASM_MASM)
endif ()
endif ()
#============================================================================
# Architecture flags
#============================================================================
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Intel" OR CMAKE_CXX_COMPILER MATCHES "xlC")
if (CRYPTOPP_AMD64 OR CRYPTOPP_I386)
CheckCompileLinkOption("-msse2" CRYPTOPP_IA32_SSE2
"${TEST_PROG_DIR}/test_x86_sse2.cxx")
CheckCompileLinkOption("-mssse3" CRYPTOPP_IA32_SSSE3
"${TEST_PROG_DIR}/test_x86_ssse3.cxx")
CheckCompileLinkOption("-msse4.1" CRYPTOPP_IA32_SSE41
"${TEST_PROG_DIR}/test_x86_sse41.cxx")
CheckCompileLinkOption("-msse4.2" CRYPTOPP_IA32_SSE42
"${TEST_PROG_DIR}/test_x86_sse42.cxx")
CheckCompileLinkOption("-mssse3 -mpclmul" CRYPTOPP_IA32_CLMUL
"${TEST_PROG_DIR}/test_x86_clmul.cxx")
CheckCompileLinkOption("-msse4.1 -maes" CRYPTOPP_IA32_AES
"${TEST_PROG_DIR}/test_x86_aes.cxx")
CheckCompileLinkOption("-mavx" CRYPTOPP_IA32_AVX
"${TEST_PROG_DIR}/test_x86_avx.cxx")
CheckCompileLinkOption("-mavx2" CRYPTOPP_IA32_AVX2
"${TEST_PROG_DIR}/test_x86_avx2.cxx")
CheckCompileLinkOption("-msse4.2 -msha" CRYPTOPP_IA32_SHA
"${TEST_PROG_DIR}/test_x86_sha.cxx")
if (EXISTS "${TEST_PROG_DIR}/test_asm_mixed.cxx")
CheckCompileLinkOption("" CRYPTOPP_MIXED_ASM
"${TEST_PROG_DIR}/test_asm_mixed.cxx")
else ()
CheckCompileLinkOption("" CRYPTOPP_MIXED_ASM
"${TEST_PROG_DIR}/test_mixed_asm.cxx")
endif ()
if (NOT CRYPTOPP_MIXED_ASM)
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_MIXED_ASM")
endif ()
if (NOT CRYPTOPP_IA32_SSE2 AND NOT CRYPTOPP_DISABLE_ASM)
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ASM")
elseif (CRYPTOPP_IA32_SSE2 AND NOT CRYPTOPP_DISABLE_ASM)
set_source_files_properties(${SRC_DIR}/sse_simd.cpp PROPERTIES COMPILE_FLAGS "-msse2")
endif ()
if (NOT CRYPTOPP_IA32_SSSE3 AND NOT CRYPTOPP_DISABLE_SSSE3)
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SSSE3")
elseif (CRYPTOPP_IA32_SSSE3 AND NOT CRYPTOPP_DISABLE_SSSE3)
if (NOT CRYPTOPP_IA32_SSE41 AND NOT CRYPTOPP_DISABLE_SSE4)
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SSE4")
endif ()
if (NOT CRYPTOPP_IA32_SSE42 AND NOT CRYPTOPP_DISABLE_SSE4)
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SSE4")
elseif (CRYPTOPP_IA32_SSE42 AND NOT CRYPTOPP_DISABLE_SSE4)
set_source_files_properties(${SRC_DIR}/crc_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.2")
if (NOT CRYPTOPP_IA32_CLMUL AND NOT CRYPTOPP_DISABLE_CLMUL)
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_CLMUL")
elseif (CRYPTOPP_IA32_CLMUL AND NOT CRYPTOPP_DISABLE_CLMUL)
set_source_files_properties(${SRC_DIR}/gcm_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3 -mpclmul")
set_source_files_properties(${SRC_DIR}/gf2n_simd.cpp PROPERTIES COMPILE_FLAGS "-mpclmul")
endif ()
if (NOT CRYPTOPP_IA32_AES AND NOT CRYPTOPP_DISABLE_AES)
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_AESNI")
elseif (CRYPTOPP_IA32_AES AND NOT CRYPTOPP_DISABLE_AES)
set_source_files_properties(${SRC_DIR}/rijndael_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.1 -maes")
endif ()
if (NOT CRYPTOPP_IA32_AVX2 AND NOT CRYPTOPP_DISABLE_AVX2)
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_AVX2")
endif ()
if (NOT CRYPTOPP_IA32_SHA AND NOT CRYPTOPP_DISABLE_SHA)
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SHANI")
elseif (CRYPTOPP_IA32_SHA AND NOT CRYPTOPP_DISABLE_SHA)
set_source_files_properties(${SRC_DIR}/sha_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.2 -msha")
endif ()
endif ()
endif ()
endif ()
endif ()
#============================================================================
# Compile targets
#============================================================================
set(cryptopp_LIBRARY_SOURCES ${cryptopp_SOURCES_ASM})
list(APPEND cryptopp_LIBRARY_SOURCES ${cryptopp_SOURCES})
add_library(cryptopp STATIC ${cryptopp_LIBRARY_SOURCES})
target_compile_definitions(cryptopp PUBLIC ${CRYPTOPP_COMPILE_DEFINITIONS})
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
target_include_directories(cryptopp INTERFACE .)
#============================================================================
# Third-party libraries
#============================================================================
find_package(Threads)
target_link_libraries(cryptopp PRIVATE ${CMAKE_THREAD_LIBS_INIT})
if(ANDROID)
include(AndroidNdkModules)
android_ndk_import_module_cpufeatures()
target_link_libraries(cryptopp PRIVATE cpufeatures)
endif()

View File

@ -1,25 +1,27 @@
/*
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Fri Sep 9 09:22:43 2022.
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Tue Feb 21 16:13:52 2023.
Language/Generator: C/C++
Specification: gl
APIs: gl=4.4, gles2=3.2
APIs: gl=4.6, gles2=3.2
Profile: core
Extensions:
GL_ARB_buffer_storage,
GL_ARB_direct_state_access,
GL_ARB_texture_compression_bptc,
GL_EXT_buffer_storage,
GL_EXT_clip_cull_distance
GL_EXT_clip_cull_distance,
GL_EXT_texture_compression_s3tc
Loader: True
Local files: False
Omit khrplatform: False
Reproducible: False
Commandline:
--profile="core" --api="gl=4.4,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_direct_state_access,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance"
--profile="core" --api="gl=4.6,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_direct_state_access,GL_ARB_texture_compression_bptc,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_texture_compression_s3tc"
Online:
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.4&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_direct_state_access&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_direct_state_access&extensions=GL_ARB_texture_compression_bptc&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance&extensions=GL_EXT_texture_compression_s3tc
*/
@ -1472,6 +1474,62 @@ typedef void (APIENTRY *GLVULKANPROCNV)(void);
#define GL_QUERY_BUFFER_BINDING 0x9193
#define GL_QUERY_RESULT_NO_WAIT 0x9194
#define GL_MIRROR_CLAMP_TO_EDGE 0x8743
#define GL_CONTEXT_LOST 0x0507
#define GL_NEGATIVE_ONE_TO_ONE 0x935E
#define GL_ZERO_TO_ONE 0x935F
#define GL_CLIP_ORIGIN 0x935C
#define GL_CLIP_DEPTH_MODE 0x935D
#define GL_QUERY_WAIT_INVERTED 0x8E17
#define GL_QUERY_NO_WAIT_INVERTED 0x8E18
#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19
#define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A
#define GL_MAX_CULL_DISTANCES 0x82F9
#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA
#define GL_TEXTURE_TARGET 0x1006
#define GL_QUERY_TARGET 0x82EA
#define GL_GUILTY_CONTEXT_RESET 0x8253
#define GL_INNOCENT_CONTEXT_RESET 0x8254
#define GL_UNKNOWN_CONTEXT_RESET 0x8255
#define GL_RESET_NOTIFICATION_STRATEGY 0x8256
#define GL_LOSE_CONTEXT_ON_RESET 0x8252
#define GL_NO_RESET_NOTIFICATION 0x8261
#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004
#define GL_COLOR_TABLE 0x80D0
#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1
#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2
#define GL_PROXY_COLOR_TABLE 0x80D3
#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4
#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
#define GL_CONVOLUTION_1D 0x8010
#define GL_CONVOLUTION_2D 0x8011
#define GL_SEPARABLE_2D 0x8012
#define GL_HISTOGRAM 0x8024
#define GL_PROXY_HISTOGRAM 0x8025
#define GL_MINMAX 0x802E
#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB
#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC
#define GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551
#define GL_SPIR_V_BINARY 0x9552
#define GL_PARAMETER_BUFFER 0x80EE
#define GL_PARAMETER_BUFFER_BINDING 0x80EF
#define GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008
#define GL_VERTICES_SUBMITTED 0x82EE
#define GL_PRIMITIVES_SUBMITTED 0x82EF
#define GL_VERTEX_SHADER_INVOCATIONS 0x82F0
#define GL_TESS_CONTROL_SHADER_PATCHES 0x82F1
#define GL_TESS_EVALUATION_SHADER_INVOCATIONS 0x82F2
#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED 0x82F3
#define GL_FRAGMENT_SHADER_INVOCATIONS 0x82F4
#define GL_COMPUTE_SHADER_INVOCATIONS 0x82F5
#define GL_CLIPPING_INPUT_PRIMITIVES 0x82F6
#define GL_CLIPPING_OUTPUT_PRIMITIVES 0x82F7
#define GL_POLYGON_OFFSET_CLAMP 0x8E1B
#define GL_SPIR_V_EXTENSIONS 0x9553
#define GL_NUM_SPIR_V_EXTENSIONS 0x9554
#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE
#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF
#define GL_TRANSFORM_FEEDBACK_OVERFLOW 0x82EC
#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW 0x82ED
#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
#define GL_RED_BITS 0x0D52
#define GL_GREEN_BITS 0x0D53
@ -1501,14 +1559,6 @@ typedef void (APIENTRY *GLVULKANPROCNV)(void);
#define GL_HSL_COLOR 0x92AF
#define GL_HSL_LUMINOSITY 0x92B0
#define GL_PRIMITIVE_BOUNDING_BOX 0x92BE
#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004
#define GL_LOSE_CONTEXT_ON_RESET 0x8252
#define GL_GUILTY_CONTEXT_RESET 0x8253
#define GL_INNOCENT_CONTEXT_RESET 0x8254
#define GL_UNKNOWN_CONTEXT_RESET 0x8255
#define GL_RESET_NOTIFICATION_STRATEGY 0x8256
#define GL_NO_RESET_NOTIFICATION 0x8261
#define GL_CONTEXT_LOST 0x0507
#define GL_COMPRESSED_RGBA_ASTC_4x4 0x93B0
#define GL_COMPRESSED_RGBA_ASTC_5x4 0x93B1
#define GL_COMPRESSED_RGBA_ASTC_5x5 0x93B2
@ -3324,73 +3374,12 @@ typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC)(GLuint first, GLsizei count,
GLAPI PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers;
#define glBindVertexBuffers glad_glBindVertexBuffers
#endif
#ifndef GL_ES_VERSION_2_0
#define GL_ES_VERSION_2_0 1
GLAPI int GLAD_GL_ES_VERSION_2_0;
#endif
#ifndef GL_ES_VERSION_3_0
#define GL_ES_VERSION_3_0 1
GLAPI int GLAD_GL_ES_VERSION_3_0;
#endif
#ifndef GL_ES_VERSION_3_1
#define GL_ES_VERSION_3_1 1
GLAPI int GLAD_GL_ES_VERSION_3_1;
typedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC)(GLbitfield barriers);
GLAPI PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion;
#define glMemoryBarrierByRegion glad_glMemoryBarrierByRegion
#endif
#ifndef GL_ES_VERSION_3_2
#define GL_ES_VERSION_3_2 1
GLAPI int GLAD_GL_ES_VERSION_3_2;
typedef void (APIENTRYP PFNGLBLENDBARRIERPROC)(void);
GLAPI PFNGLBLENDBARRIERPROC glad_glBlendBarrier;
#define glBlendBarrier glad_glBlendBarrier
typedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
GLAPI PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox;
#define glPrimitiveBoundingBox glad_glPrimitiveBoundingBox
typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC)(void);
GLAPI PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus;
#define glGetGraphicsResetStatus glad_glGetGraphicsResetStatus
typedef void (APIENTRYP PFNGLREADNPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
GLAPI PFNGLREADNPIXELSPROC glad_glReadnPixels;
#define glReadnPixels glad_glReadnPixels
typedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
GLAPI PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv;
#define glGetnUniformfv glad_glGetnUniformfv
typedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLint *params);
GLAPI PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv;
#define glGetnUniformiv glad_glGetnUniformiv
typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint *params);
GLAPI PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;
#define glGetnUniformuiv glad_glGetnUniformuiv
#endif
#define GL_TEXTURE_TARGET 0x1006
#define GL_QUERY_TARGET 0x82EA
#define GL_MAP_PERSISTENT_BIT_EXT 0x0040
#define GL_MAP_COHERENT_BIT_EXT 0x0080
#define GL_DYNAMIC_STORAGE_BIT_EXT 0x0100
#define GL_CLIENT_STORAGE_BIT_EXT 0x0200
#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT 0x00004000
#define GL_BUFFER_IMMUTABLE_STORAGE_EXT 0x821F
#define GL_BUFFER_STORAGE_FLAGS_EXT 0x8220
#define GL_MAX_CLIP_DISTANCES_EXT 0x0D32
#define GL_MAX_CULL_DISTANCES_EXT 0x82F9
#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT 0x82FA
#define GL_CLIP_DISTANCE0_EXT 0x3000
#define GL_CLIP_DISTANCE1_EXT 0x3001
#define GL_CLIP_DISTANCE2_EXT 0x3002
#define GL_CLIP_DISTANCE3_EXT 0x3003
#define GL_CLIP_DISTANCE4_EXT 0x3004
#define GL_CLIP_DISTANCE5_EXT 0x3005
#define GL_CLIP_DISTANCE6_EXT 0x3006
#define GL_CLIP_DISTANCE7_EXT 0x3007
#ifndef GL_ARB_buffer_storage
#define GL_ARB_buffer_storage 1
GLAPI int GLAD_GL_ARB_buffer_storage;
#endif
#ifndef GL_ARB_direct_state_access
#define GL_ARB_direct_state_access 1
GLAPI int GLAD_GL_ARB_direct_state_access;
#ifndef GL_VERSION_4_5
#define GL_VERSION_4_5 1
GLAPI int GLAD_GL_VERSION_4_5;
typedef void (APIENTRYP PFNGLCLIPCONTROLPROC)(GLenum origin, GLenum depth);
GLAPI PFNGLCLIPCONTROLPROC glad_glClipControl;
#define glClipControl glad_glClipControl
typedef void (APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint *ids);
GLAPI PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks;
#define glCreateTransformFeedbacks glad_glCreateTransformFeedbacks
@ -3682,6 +3671,158 @@ GLAPI PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v;
typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUIVPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset);
GLAPI PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv;
#define glGetQueryBufferObjectuiv glad_glGetQueryBufferObjectuiv
typedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC)(GLbitfield barriers);
GLAPI PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion;
#define glMemoryBarrierByRegion glad_glMemoryBarrierByRegion
typedef void (APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
GLAPI PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage;
#define glGetTextureSubImage glad_glGetTextureSubImage
typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels);
GLAPI PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage;
#define glGetCompressedTextureSubImage glad_glGetCompressedTextureSubImage
typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC)(void);
GLAPI PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus;
#define glGetGraphicsResetStatus glad_glGetGraphicsResetStatus
typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint lod, GLsizei bufSize, void *pixels);
GLAPI PFNGLGETNCOMPRESSEDTEXIMAGEPROC glad_glGetnCompressedTexImage;
#define glGetnCompressedTexImage glad_glGetnCompressedTexImage
typedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
GLAPI PFNGLGETNTEXIMAGEPROC glad_glGetnTexImage;
#define glGetnTexImage glad_glGetnTexImage
typedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
GLAPI PFNGLGETNUNIFORMDVPROC glad_glGetnUniformdv;
#define glGetnUniformdv glad_glGetnUniformdv
typedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
GLAPI PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv;
#define glGetnUniformfv glad_glGetnUniformfv
typedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLint *params);
GLAPI PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv;
#define glGetnUniformiv glad_glGetnUniformiv
typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint *params);
GLAPI PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;
#define glGetnUniformuiv glad_glGetnUniformuiv
typedef void (APIENTRYP PFNGLREADNPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
GLAPI PFNGLREADNPIXELSPROC glad_glReadnPixels;
#define glReadnPixels glad_glReadnPixels
typedef void (APIENTRYP PFNGLGETNMAPDVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
GLAPI PFNGLGETNMAPDVPROC glad_glGetnMapdv;
#define glGetnMapdv glad_glGetnMapdv
typedef void (APIENTRYP PFNGLGETNMAPFVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
GLAPI PFNGLGETNMAPFVPROC glad_glGetnMapfv;
#define glGetnMapfv glad_glGetnMapfv
typedef void (APIENTRYP PFNGLGETNMAPIVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLint *v);
GLAPI PFNGLGETNMAPIVPROC glad_glGetnMapiv;
#define glGetnMapiv glad_glGetnMapiv
typedef void (APIENTRYP PFNGLGETNPIXELMAPFVPROC)(GLenum map, GLsizei bufSize, GLfloat *values);
GLAPI PFNGLGETNPIXELMAPFVPROC glad_glGetnPixelMapfv;
#define glGetnPixelMapfv glad_glGetnPixelMapfv
typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVPROC)(GLenum map, GLsizei bufSize, GLuint *values);
GLAPI PFNGLGETNPIXELMAPUIVPROC glad_glGetnPixelMapuiv;
#define glGetnPixelMapuiv glad_glGetnPixelMapuiv
typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVPROC)(GLenum map, GLsizei bufSize, GLushort *values);
GLAPI PFNGLGETNPIXELMAPUSVPROC glad_glGetnPixelMapusv;
#define glGetnPixelMapusv glad_glGetnPixelMapusv
typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEPROC)(GLsizei bufSize, GLubyte *pattern);
GLAPI PFNGLGETNPOLYGONSTIPPLEPROC glad_glGetnPolygonStipple;
#define glGetnPolygonStipple glad_glGetnPolygonStipple
typedef void (APIENTRYP PFNGLGETNCOLORTABLEPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
GLAPI PFNGLGETNCOLORTABLEPROC glad_glGetnColorTable;
#define glGetnColorTable glad_glGetnColorTable
typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
GLAPI PFNGLGETNCONVOLUTIONFILTERPROC glad_glGetnConvolutionFilter;
#define glGetnConvolutionFilter glad_glGetnConvolutionFilter
typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERPROC)(GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
GLAPI PFNGLGETNSEPARABLEFILTERPROC glad_glGetnSeparableFilter;
#define glGetnSeparableFilter glad_glGetnSeparableFilter
typedef void (APIENTRYP PFNGLGETNHISTOGRAMPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
GLAPI PFNGLGETNHISTOGRAMPROC glad_glGetnHistogram;
#define glGetnHistogram glad_glGetnHistogram
typedef void (APIENTRYP PFNGLGETNMINMAXPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
GLAPI PFNGLGETNMINMAXPROC glad_glGetnMinmax;
#define glGetnMinmax glad_glGetnMinmax
typedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC)(void);
GLAPI PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier;
#define glTextureBarrier glad_glTextureBarrier
#endif
#ifndef GL_VERSION_4_6
#define GL_VERSION_4_6 1
GLAPI int GLAD_GL_VERSION_4_6;
typedef void (APIENTRYP PFNGLSPECIALIZESHADERPROC)(GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);
GLAPI PFNGLSPECIALIZESHADERPROC glad_glSpecializeShader;
#define glSpecializeShader glad_glSpecializeShader
typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)(GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
GLAPI PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glad_glMultiDrawArraysIndirectCount;
#define glMultiDrawArraysIndirectCount glad_glMultiDrawArraysIndirectCount
typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)(GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
GLAPI PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glad_glMultiDrawElementsIndirectCount;
#define glMultiDrawElementsIndirectCount glad_glMultiDrawElementsIndirectCount
typedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPPROC)(GLfloat factor, GLfloat units, GLfloat clamp);
GLAPI PFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp;
#define glPolygonOffsetClamp glad_glPolygonOffsetClamp
#endif
#ifndef GL_ES_VERSION_2_0
#define GL_ES_VERSION_2_0 1
GLAPI int GLAD_GL_ES_VERSION_2_0;
#endif
#ifndef GL_ES_VERSION_3_0
#define GL_ES_VERSION_3_0 1
GLAPI int GLAD_GL_ES_VERSION_3_0;
#endif
#ifndef GL_ES_VERSION_3_1
#define GL_ES_VERSION_3_1 1
GLAPI int GLAD_GL_ES_VERSION_3_1;
#endif
#ifndef GL_ES_VERSION_3_2
#define GL_ES_VERSION_3_2 1
GLAPI int GLAD_GL_ES_VERSION_3_2;
typedef void (APIENTRYP PFNGLBLENDBARRIERPROC)(void);
GLAPI PFNGLBLENDBARRIERPROC glad_glBlendBarrier;
#define glBlendBarrier glad_glBlendBarrier
typedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
GLAPI PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox;
#define glPrimitiveBoundingBox glad_glPrimitiveBoundingBox
#endif
#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#define GL_MAP_PERSISTENT_BIT_EXT 0x0040
#define GL_MAP_COHERENT_BIT_EXT 0x0080
#define GL_DYNAMIC_STORAGE_BIT_EXT 0x0100
#define GL_CLIENT_STORAGE_BIT_EXT 0x0200
#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT 0x00004000
#define GL_BUFFER_IMMUTABLE_STORAGE_EXT 0x821F
#define GL_BUFFER_STORAGE_FLAGS_EXT 0x8220
#define GL_MAX_CLIP_DISTANCES_EXT 0x0D32
#define GL_MAX_CULL_DISTANCES_EXT 0x82F9
#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT 0x82FA
#define GL_CLIP_DISTANCE0_EXT 0x3000
#define GL_CLIP_DISTANCE1_EXT 0x3001
#define GL_CLIP_DISTANCE2_EXT 0x3002
#define GL_CLIP_DISTANCE3_EXT 0x3003
#define GL_CLIP_DISTANCE4_EXT 0x3004
#define GL_CLIP_DISTANCE5_EXT 0x3005
#define GL_CLIP_DISTANCE6_EXT 0x3006
#define GL_CLIP_DISTANCE7_EXT 0x3007
#ifndef GL_ARB_buffer_storage
#define GL_ARB_buffer_storage 1
GLAPI int GLAD_GL_ARB_buffer_storage;
#endif
#ifndef GL_ARB_direct_state_access
#define GL_ARB_direct_state_access 1
GLAPI int GLAD_GL_ARB_direct_state_access;
#endif
#ifndef GL_ARB_texture_compression_bptc
#define GL_ARB_texture_compression_bptc 1
GLAPI int GLAD_GL_ARB_texture_compression_bptc;
#endif
#ifndef GL_EXT_texture_compression_s3tc
#define GL_EXT_texture_compression_s3tc 1
GLAPI int GLAD_GL_EXT_texture_compression_s3tc;
#endif
#ifndef GL_EXT_buffer_storage
#define GL_EXT_buffer_storage 1
@ -3694,6 +3835,10 @@ GLAPI PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT;
#define GL_EXT_clip_cull_distance 1
GLAPI int GLAD_GL_EXT_clip_cull_distance;
#endif
#ifndef GL_EXT_texture_compression_s3tc
#define GL_EXT_texture_compression_s3tc 1
GLAPI int GLAD_GL_EXT_texture_compression_s3tc;
#endif
#ifdef __cplusplus
}

View File

@ -1,25 +1,27 @@
/*
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Fri Sep 9 09:22:43 2022.
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Tue Feb 21 16:13:52 2023.
Language/Generator: C/C++
Specification: gl
APIs: gl=4.4, gles2=3.2
APIs: gl=4.6, gles2=3.2
Profile: core
Extensions:
GL_ARB_buffer_storage,
GL_ARB_direct_state_access,
GL_ARB_texture_compression_bptc,
GL_EXT_buffer_storage,
GL_EXT_clip_cull_distance
GL_EXT_clip_cull_distance,
GL_EXT_texture_compression_s3tc
Loader: True
Local files: False
Omit khrplatform: False
Reproducible: False
Commandline:
--profile="core" --api="gl=4.4,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_direct_state_access,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance"
--profile="core" --api="gl=4.6,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_direct_state_access,GL_ARB_texture_compression_bptc,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_texture_compression_s3tc"
Online:
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.4&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_direct_state_access&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_direct_state_access&extensions=GL_ARB_texture_compression_bptc&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance&extensions=GL_EXT_texture_compression_s3tc
*/
#include <stdio.h>
@ -275,6 +277,8 @@ int GLAD_GL_VERSION_4_1 = 0;
int GLAD_GL_VERSION_4_2 = 0;
int GLAD_GL_VERSION_4_3 = 0;
int GLAD_GL_VERSION_4_4 = 0;
int GLAD_GL_VERSION_4_5 = 0;
int GLAD_GL_VERSION_4_6 = 0;
int GLAD_GL_ES_VERSION_2_0 = 0;
int GLAD_GL_ES_VERSION_3_0 = 0;
int GLAD_GL_ES_VERSION_3_1 = 0;
@ -302,6 +306,7 @@ PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
PFNGLBINDSAMPLERSPROC glad_glBindSamplers = NULL;
PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit = NULL;
PFNGLBINDTEXTURESPROC glad_glBindTextures = NULL;
PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;
PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
@ -318,10 +323,12 @@ PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL;
PFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL;
PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer = NULL;
PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL;
PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus = NULL;
PFNGLCLAMPCOLORPROC glad_glClampColor = NULL;
PFNGLCLEARPROC glad_glClear = NULL;
PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData = NULL;
@ -333,10 +340,17 @@ PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData = NULL;
PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData = NULL;
PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi = NULL;
PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv = NULL;
PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv = NULL;
PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv = NULL;
PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL;
PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL;
PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
PFNGLCLIPCONTROLPROC glad_glClipControl = NULL;
PFNGLCOLORMASKPROC glad_glColorMask = NULL;
PFNGLCOLORMASKIPROC glad_glColorMaski = NULL;
PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL;
@ -350,16 +364,32 @@ PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;
PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D = NULL;
PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D = NULL;
PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D = NULL;
PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL;
PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData = NULL;
PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;
PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;
PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D = NULL;
PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D = NULL;
PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D = NULL;
PFNGLCREATEBUFFERSPROC glad_glCreateBuffers = NULL;
PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers = NULL;
PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines = NULL;
PFNGLCREATEQUERIESPROC glad_glCreateQueries = NULL;
PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers = NULL;
PFNGLCREATESAMPLERSPROC glad_glCreateSamplers = NULL;
PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL;
PFNGLCREATETEXTURESPROC glad_glCreateTextures = NULL;
PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks = NULL;
PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays = NULL;
PFNGLCULLFACEPROC glad_glCullFace = NULL;
PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL;
PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL;
@ -384,6 +414,7 @@ PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL;
PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
PFNGLDISABLEPROC glad_glDisable = NULL;
PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib = NULL;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
PFNGLDISABLEIPROC glad_glDisablei = NULL;
PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL;
@ -408,6 +439,7 @@ PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced =
PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL;
PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced = NULL;
PFNGLENABLEPROC glad_glEnable = NULL;
PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib = NULL;
PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
PFNGLENABLEIPROC glad_glEnablei = NULL;
PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;
@ -418,6 +450,7 @@ PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
PFNGLFINISHPROC glad_glFinish = NULL;
PFNGLFLUSHPROC glad_glFlush = NULL;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange = NULL;
PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = NULL;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
@ -436,6 +469,7 @@ PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;
PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap = NULL;
PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv = NULL;
PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL;
@ -455,6 +489,8 @@ PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;
PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage = NULL;
PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage = NULL;
PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL;
PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL;
PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;
@ -473,6 +509,13 @@ PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v = NULL;
PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL;
PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v = NULL;
PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv = NULL;
PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv = NULL;
PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData = NULL;
PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv = NULL;
PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv = NULL;
PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv = NULL;
PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL;
PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL;
PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;
@ -488,6 +531,10 @@ PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL;
PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL;
PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL;
PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v = NULL;
PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv = NULL;
PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v = NULL;
PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv = NULL;
PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL;
PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
@ -515,7 +562,18 @@ PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;
PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage = NULL;
PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv = NULL;
PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv = NULL;
PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv = NULL;
PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv = NULL;
PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv = NULL;
PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv = NULL;
PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage = NULL;
PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v = NULL;
PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v = NULL;
PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv = NULL;
PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
@ -524,6 +582,9 @@ PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL;
PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv = NULL;
PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv = NULL;
PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv = NULL;
PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL;
@ -531,6 +592,21 @@ PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;
PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
PFNGLGETNCOLORTABLEPROC glad_glGetnColorTable = NULL;
PFNGLGETNCOMPRESSEDTEXIMAGEPROC glad_glGetnCompressedTexImage = NULL;
PFNGLGETNCONVOLUTIONFILTERPROC glad_glGetnConvolutionFilter = NULL;
PFNGLGETNHISTOGRAMPROC glad_glGetnHistogram = NULL;
PFNGLGETNMAPDVPROC glad_glGetnMapdv = NULL;
PFNGLGETNMAPFVPROC glad_glGetnMapfv = NULL;
PFNGLGETNMAPIVPROC glad_glGetnMapiv = NULL;
PFNGLGETNMINMAXPROC glad_glGetnMinmax = NULL;
PFNGLGETNPIXELMAPFVPROC glad_glGetnPixelMapfv = NULL;
PFNGLGETNPIXELMAPUIVPROC glad_glGetnPixelMapuiv = NULL;
PFNGLGETNPIXELMAPUSVPROC glad_glGetnPixelMapusv = NULL;
PFNGLGETNPOLYGONSTIPPLEPROC glad_glGetnPolygonStipple = NULL;
PFNGLGETNSEPARABLEFILTERPROC glad_glGetnSeparableFilter = NULL;
PFNGLGETNTEXIMAGEPROC glad_glGetnTexImage = NULL;
PFNGLGETNUNIFORMDVPROC glad_glGetnUniformdv = NULL;
PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv = NULL;
PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv = NULL;
PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv = NULL;
@ -538,6 +614,8 @@ PFNGLHINTPROC glad_glHint = NULL;
PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData = NULL;
PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData = NULL;
PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL;
PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData = NULL;
PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData = NULL;
PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL;
PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage = NULL;
PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage = NULL;
@ -560,14 +638,18 @@ PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
PFNGLLOGICOPPROC glad_glLogicOp = NULL;
PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;
PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer = NULL;
PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange = NULL;
PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL;
PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion = NULL;
PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL;
PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect = NULL;
PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glad_glMultiDrawArraysIndirectCount = NULL;
PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;
PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;
PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect = NULL;
PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glad_glMultiDrawElementsIndirectCount = NULL;
PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL;
PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL;
PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL;
@ -576,6 +658,18 @@ PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL;
PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL;
PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL;
PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL;
PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData = NULL;
PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage = NULL;
PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData = NULL;
PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer = NULL;
PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers = NULL;
PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri = NULL;
PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer = NULL;
PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer = NULL;
PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture = NULL;
PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer = NULL;
PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage = NULL;
PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample = NULL;
PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL;
PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL;
PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL;
@ -592,6 +686,7 @@ PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;
PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
PFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp = NULL;
PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL;
PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox = NULL;
PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;
@ -674,6 +769,7 @@ PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL;
PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;
PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding = NULL;
PFNGLSPECIALIZESHADERPROC glad_glSpecializeShader = NULL;
PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
@ -709,7 +805,26 @@ PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL;
PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;
PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier = NULL;
PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer = NULL;
PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange = NULL;
PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv = NULL;
PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv = NULL;
PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf = NULL;
PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv = NULL;
PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri = NULL;
PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv = NULL;
PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D = NULL;
PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D = NULL;
PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample = NULL;
PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D = NULL;
PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample = NULL;
PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D = NULL;
PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D = NULL;
PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D = NULL;
PFNGLTEXTUREVIEWPROC glad_glTextureView = NULL;
PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase = NULL;
PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange = NULL;
PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
PFNGLUNIFORM1DPROC glad_glUniform1d = NULL;
PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL;
@ -764,10 +879,19 @@ PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL;
PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL;
PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer = NULL;
PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL;
PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL;
PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding = NULL;
PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat = NULL;
PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat = NULL;
PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat = NULL;
PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor = NULL;
PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer = NULL;
PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer = NULL;
PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers = NULL;
PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;
PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
@ -862,105 +986,10 @@ PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
int GLAD_GL_ARB_buffer_storage = 0;
int GLAD_GL_ARB_direct_state_access = 0;
int GLAD_GL_ARB_texture_compression_bptc = 0;
int GLAD_GL_EXT_buffer_storage = 0;
int GLAD_GL_EXT_clip_cull_distance = 0;
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;
int GLAD_GL_EXT_texture_compression_s3tc = 0;
PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT = NULL;
static void load_GL_VERSION_1_0(GLADloadproc load) {
if(!GLAD_GL_VERSION_1_0) return;
@ -1590,6 +1619,138 @@ static void load_GL_VERSION_4_4(GLADloadproc load) {
glad_glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC)load("glBindImageTextures");
glad_glBindVertexBuffers = (PFNGLBINDVERTEXBUFFERSPROC)load("glBindVertexBuffers");
}
static void load_GL_VERSION_4_5(GLADloadproc load) {
if(!GLAD_GL_VERSION_4_5) return;
glad_glClipControl = (PFNGLCLIPCONTROLPROC)load("glClipControl");
glad_glCreateTransformFeedbacks = (PFNGLCREATETRANSFORMFEEDBACKSPROC)load("glCreateTransformFeedbacks");
glad_glTransformFeedbackBufferBase = (PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)load("glTransformFeedbackBufferBase");
glad_glTransformFeedbackBufferRange = (PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)load("glTransformFeedbackBufferRange");
glad_glGetTransformFeedbackiv = (PFNGLGETTRANSFORMFEEDBACKIVPROC)load("glGetTransformFeedbackiv");
glad_glGetTransformFeedbacki_v = (PFNGLGETTRANSFORMFEEDBACKI_VPROC)load("glGetTransformFeedbacki_v");
glad_glGetTransformFeedbacki64_v = (PFNGLGETTRANSFORMFEEDBACKI64_VPROC)load("glGetTransformFeedbacki64_v");
glad_glCreateBuffers = (PFNGLCREATEBUFFERSPROC)load("glCreateBuffers");
glad_glNamedBufferStorage = (PFNGLNAMEDBUFFERSTORAGEPROC)load("glNamedBufferStorage");
glad_glNamedBufferData = (PFNGLNAMEDBUFFERDATAPROC)load("glNamedBufferData");
glad_glNamedBufferSubData = (PFNGLNAMEDBUFFERSUBDATAPROC)load("glNamedBufferSubData");
glad_glCopyNamedBufferSubData = (PFNGLCOPYNAMEDBUFFERSUBDATAPROC)load("glCopyNamedBufferSubData");
glad_glClearNamedBufferData = (PFNGLCLEARNAMEDBUFFERDATAPROC)load("glClearNamedBufferData");
glad_glClearNamedBufferSubData = (PFNGLCLEARNAMEDBUFFERSUBDATAPROC)load("glClearNamedBufferSubData");
glad_glMapNamedBuffer = (PFNGLMAPNAMEDBUFFERPROC)load("glMapNamedBuffer");
glad_glMapNamedBufferRange = (PFNGLMAPNAMEDBUFFERRANGEPROC)load("glMapNamedBufferRange");
glad_glUnmapNamedBuffer = (PFNGLUNMAPNAMEDBUFFERPROC)load("glUnmapNamedBuffer");
glad_glFlushMappedNamedBufferRange = (PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)load("glFlushMappedNamedBufferRange");
glad_glGetNamedBufferParameteriv = (PFNGLGETNAMEDBUFFERPARAMETERIVPROC)load("glGetNamedBufferParameteriv");
glad_glGetNamedBufferParameteri64v = (PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)load("glGetNamedBufferParameteri64v");
glad_glGetNamedBufferPointerv = (PFNGLGETNAMEDBUFFERPOINTERVPROC)load("glGetNamedBufferPointerv");
glad_glGetNamedBufferSubData = (PFNGLGETNAMEDBUFFERSUBDATAPROC)load("glGetNamedBufferSubData");
glad_glCreateFramebuffers = (PFNGLCREATEFRAMEBUFFERSPROC)load("glCreateFramebuffers");
glad_glNamedFramebufferRenderbuffer = (PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)load("glNamedFramebufferRenderbuffer");
glad_glNamedFramebufferParameteri = (PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)load("glNamedFramebufferParameteri");
glad_glNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)load("glNamedFramebufferTexture");
glad_glNamedFramebufferTextureLayer = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)load("glNamedFramebufferTextureLayer");
glad_glNamedFramebufferDrawBuffer = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)load("glNamedFramebufferDrawBuffer");
glad_glNamedFramebufferDrawBuffers = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)load("glNamedFramebufferDrawBuffers");
glad_glNamedFramebufferReadBuffer = (PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)load("glNamedFramebufferReadBuffer");
glad_glInvalidateNamedFramebufferData = (PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)load("glInvalidateNamedFramebufferData");
glad_glInvalidateNamedFramebufferSubData = (PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)load("glInvalidateNamedFramebufferSubData");
glad_glClearNamedFramebufferiv = (PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)load("glClearNamedFramebufferiv");
glad_glClearNamedFramebufferuiv = (PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)load("glClearNamedFramebufferuiv");
glad_glClearNamedFramebufferfv = (PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)load("glClearNamedFramebufferfv");
glad_glClearNamedFramebufferfi = (PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)load("glClearNamedFramebufferfi");
glad_glBlitNamedFramebuffer = (PFNGLBLITNAMEDFRAMEBUFFERPROC)load("glBlitNamedFramebuffer");
glad_glCheckNamedFramebufferStatus = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)load("glCheckNamedFramebufferStatus");
glad_glGetNamedFramebufferParameteriv = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)load("glGetNamedFramebufferParameteriv");
glad_glGetNamedFramebufferAttachmentParameteriv = (PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetNamedFramebufferAttachmentParameteriv");
glad_glCreateRenderbuffers = (PFNGLCREATERENDERBUFFERSPROC)load("glCreateRenderbuffers");
glad_glNamedRenderbufferStorage = (PFNGLNAMEDRENDERBUFFERSTORAGEPROC)load("glNamedRenderbufferStorage");
glad_glNamedRenderbufferStorageMultisample = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glNamedRenderbufferStorageMultisample");
glad_glGetNamedRenderbufferParameteriv = (PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)load("glGetNamedRenderbufferParameteriv");
glad_glCreateTextures = (PFNGLCREATETEXTURESPROC)load("glCreateTextures");
glad_glTextureBuffer = (PFNGLTEXTUREBUFFERPROC)load("glTextureBuffer");
glad_glTextureBufferRange = (PFNGLTEXTUREBUFFERRANGEPROC)load("glTextureBufferRange");
glad_glTextureStorage1D = (PFNGLTEXTURESTORAGE1DPROC)load("glTextureStorage1D");
glad_glTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC)load("glTextureStorage2D");
glad_glTextureStorage3D = (PFNGLTEXTURESTORAGE3DPROC)load("glTextureStorage3D");
glad_glTextureStorage2DMultisample = (PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)load("glTextureStorage2DMultisample");
glad_glTextureStorage3DMultisample = (PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)load("glTextureStorage3DMultisample");
glad_glTextureSubImage1D = (PFNGLTEXTURESUBIMAGE1DPROC)load("glTextureSubImage1D");
glad_glTextureSubImage2D = (PFNGLTEXTURESUBIMAGE2DPROC)load("glTextureSubImage2D");
glad_glTextureSubImage3D = (PFNGLTEXTURESUBIMAGE3DPROC)load("glTextureSubImage3D");
glad_glCompressedTextureSubImage1D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)load("glCompressedTextureSubImage1D");
glad_glCompressedTextureSubImage2D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)load("glCompressedTextureSubImage2D");
glad_glCompressedTextureSubImage3D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)load("glCompressedTextureSubImage3D");
glad_glCopyTextureSubImage1D = (PFNGLCOPYTEXTURESUBIMAGE1DPROC)load("glCopyTextureSubImage1D");
glad_glCopyTextureSubImage2D = (PFNGLCOPYTEXTURESUBIMAGE2DPROC)load("glCopyTextureSubImage2D");
glad_glCopyTextureSubImage3D = (PFNGLCOPYTEXTURESUBIMAGE3DPROC)load("glCopyTextureSubImage3D");
glad_glTextureParameterf = (PFNGLTEXTUREPARAMETERFPROC)load("glTextureParameterf");
glad_glTextureParameterfv = (PFNGLTEXTUREPARAMETERFVPROC)load("glTextureParameterfv");
glad_glTextureParameteri = (PFNGLTEXTUREPARAMETERIPROC)load("glTextureParameteri");
glad_glTextureParameterIiv = (PFNGLTEXTUREPARAMETERIIVPROC)load("glTextureParameterIiv");
glad_glTextureParameterIuiv = (PFNGLTEXTUREPARAMETERIUIVPROC)load("glTextureParameterIuiv");
glad_glTextureParameteriv = (PFNGLTEXTUREPARAMETERIVPROC)load("glTextureParameteriv");
glad_glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC)load("glGenerateTextureMipmap");
glad_glBindTextureUnit = (PFNGLBINDTEXTUREUNITPROC)load("glBindTextureUnit");
glad_glGetTextureImage = (PFNGLGETTEXTUREIMAGEPROC)load("glGetTextureImage");
glad_glGetCompressedTextureImage = (PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)load("glGetCompressedTextureImage");
glad_glGetTextureLevelParameterfv = (PFNGLGETTEXTURELEVELPARAMETERFVPROC)load("glGetTextureLevelParameterfv");
glad_glGetTextureLevelParameteriv = (PFNGLGETTEXTURELEVELPARAMETERIVPROC)load("glGetTextureLevelParameteriv");
glad_glGetTextureParameterfv = (PFNGLGETTEXTUREPARAMETERFVPROC)load("glGetTextureParameterfv");
glad_glGetTextureParameterIiv = (PFNGLGETTEXTUREPARAMETERIIVPROC)load("glGetTextureParameterIiv");
glad_glGetTextureParameterIuiv = (PFNGLGETTEXTUREPARAMETERIUIVPROC)load("glGetTextureParameterIuiv");
glad_glGetTextureParameteriv = (PFNGLGETTEXTUREPARAMETERIVPROC)load("glGetTextureParameteriv");
glad_glCreateVertexArrays = (PFNGLCREATEVERTEXARRAYSPROC)load("glCreateVertexArrays");
glad_glDisableVertexArrayAttrib = (PFNGLDISABLEVERTEXARRAYATTRIBPROC)load("glDisableVertexArrayAttrib");
glad_glEnableVertexArrayAttrib = (PFNGLENABLEVERTEXARRAYATTRIBPROC)load("glEnableVertexArrayAttrib");
glad_glVertexArrayElementBuffer = (PFNGLVERTEXARRAYELEMENTBUFFERPROC)load("glVertexArrayElementBuffer");
glad_glVertexArrayVertexBuffer = (PFNGLVERTEXARRAYVERTEXBUFFERPROC)load("glVertexArrayVertexBuffer");
glad_glVertexArrayVertexBuffers = (PFNGLVERTEXARRAYVERTEXBUFFERSPROC)load("glVertexArrayVertexBuffers");
glad_glVertexArrayAttribBinding = (PFNGLVERTEXARRAYATTRIBBINDINGPROC)load("glVertexArrayAttribBinding");
glad_glVertexArrayAttribFormat = (PFNGLVERTEXARRAYATTRIBFORMATPROC)load("glVertexArrayAttribFormat");
glad_glVertexArrayAttribIFormat = (PFNGLVERTEXARRAYATTRIBIFORMATPROC)load("glVertexArrayAttribIFormat");
glad_glVertexArrayAttribLFormat = (PFNGLVERTEXARRAYATTRIBLFORMATPROC)load("glVertexArrayAttribLFormat");
glad_glVertexArrayBindingDivisor = (PFNGLVERTEXARRAYBINDINGDIVISORPROC)load("glVertexArrayBindingDivisor");
glad_glGetVertexArrayiv = (PFNGLGETVERTEXARRAYIVPROC)load("glGetVertexArrayiv");
glad_glGetVertexArrayIndexediv = (PFNGLGETVERTEXARRAYINDEXEDIVPROC)load("glGetVertexArrayIndexediv");
glad_glGetVertexArrayIndexed64iv = (PFNGLGETVERTEXARRAYINDEXED64IVPROC)load("glGetVertexArrayIndexed64iv");
glad_glCreateSamplers = (PFNGLCREATESAMPLERSPROC)load("glCreateSamplers");
glad_glCreateProgramPipelines = (PFNGLCREATEPROGRAMPIPELINESPROC)load("glCreateProgramPipelines");
glad_glCreateQueries = (PFNGLCREATEQUERIESPROC)load("glCreateQueries");
glad_glGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECTI64VPROC)load("glGetQueryBufferObjecti64v");
glad_glGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECTIVPROC)load("glGetQueryBufferObjectiv");
glad_glGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECTUI64VPROC)load("glGetQueryBufferObjectui64v");
glad_glGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECTUIVPROC)load("glGetQueryBufferObjectuiv");
glad_glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC)load("glMemoryBarrierByRegion");
glad_glGetTextureSubImage = (PFNGLGETTEXTURESUBIMAGEPROC)load("glGetTextureSubImage");
glad_glGetCompressedTextureSubImage = (PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)load("glGetCompressedTextureSubImage");
glad_glGetGraphicsResetStatus = (PFNGLGETGRAPHICSRESETSTATUSPROC)load("glGetGraphicsResetStatus");
glad_glGetnCompressedTexImage = (PFNGLGETNCOMPRESSEDTEXIMAGEPROC)load("glGetnCompressedTexImage");
glad_glGetnTexImage = (PFNGLGETNTEXIMAGEPROC)load("glGetnTexImage");
glad_glGetnUniformdv = (PFNGLGETNUNIFORMDVPROC)load("glGetnUniformdv");
glad_glGetnUniformfv = (PFNGLGETNUNIFORMFVPROC)load("glGetnUniformfv");
glad_glGetnUniformiv = (PFNGLGETNUNIFORMIVPROC)load("glGetnUniformiv");
glad_glGetnUniformuiv = (PFNGLGETNUNIFORMUIVPROC)load("glGetnUniformuiv");
glad_glReadnPixels = (PFNGLREADNPIXELSPROC)load("glReadnPixels");
glad_glGetnMapdv = (PFNGLGETNMAPDVPROC)load("glGetnMapdv");
glad_glGetnMapfv = (PFNGLGETNMAPFVPROC)load("glGetnMapfv");
glad_glGetnMapiv = (PFNGLGETNMAPIVPROC)load("glGetnMapiv");
glad_glGetnPixelMapfv = (PFNGLGETNPIXELMAPFVPROC)load("glGetnPixelMapfv");
glad_glGetnPixelMapuiv = (PFNGLGETNPIXELMAPUIVPROC)load("glGetnPixelMapuiv");
glad_glGetnPixelMapusv = (PFNGLGETNPIXELMAPUSVPROC)load("glGetnPixelMapusv");
glad_glGetnPolygonStipple = (PFNGLGETNPOLYGONSTIPPLEPROC)load("glGetnPolygonStipple");
glad_glGetnColorTable = (PFNGLGETNCOLORTABLEPROC)load("glGetnColorTable");
glad_glGetnConvolutionFilter = (PFNGLGETNCONVOLUTIONFILTERPROC)load("glGetnConvolutionFilter");
glad_glGetnSeparableFilter = (PFNGLGETNSEPARABLEFILTERPROC)load("glGetnSeparableFilter");
glad_glGetnHistogram = (PFNGLGETNHISTOGRAMPROC)load("glGetnHistogram");
glad_glGetnMinmax = (PFNGLGETNMINMAXPROC)load("glGetnMinmax");
glad_glTextureBarrier = (PFNGLTEXTUREBARRIERPROC)load("glTextureBarrier");
}
static void load_GL_VERSION_4_6(GLADloadproc load) {
if(!GLAD_GL_VERSION_4_6) return;
glad_glSpecializeShader = (PFNGLSPECIALIZESHADERPROC)load("glSpecializeShader");
glad_glMultiDrawArraysIndirectCount = (PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)load("glMultiDrawArraysIndirectCount");
glad_glMultiDrawElementsIndirectCount = (PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)load("glMultiDrawElementsIndirectCount");
glad_glPolygonOffsetClamp = (PFNGLPOLYGONOFFSETCLAMPPROC)load("glPolygonOffsetClamp");
}
static void load_GL_ARB_buffer_storage(GLADloadproc load) {
if(!GLAD_GL_ARB_buffer_storage) return;
glad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC)load("glBufferStorage");
@ -1698,6 +1859,8 @@ static int find_extensionsGL(void) {
if (!get_exts()) return 0;
GLAD_GL_ARB_buffer_storage = has_ext("GL_ARB_buffer_storage");
GLAD_GL_ARB_direct_state_access = has_ext("GL_ARB_direct_state_access");
GLAD_GL_ARB_texture_compression_bptc = has_ext("GL_ARB_texture_compression_bptc");
GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc");
free_exts();
return 1;
}
@ -1755,9 +1918,11 @@ static void find_coreGL(void) {
GLAD_GL_VERSION_4_2 = (major == 4 && minor >= 2) || major > 4;
GLAD_GL_VERSION_4_3 = (major == 4 && minor >= 3) || major > 4;
GLAD_GL_VERSION_4_4 = (major == 4 && minor >= 4) || major > 4;
if (GLVersion.major > 4 || (GLVersion.major >= 4 && GLVersion.minor >= 4)) {
GLAD_GL_VERSION_4_5 = (major == 4 && minor >= 5) || major > 4;
GLAD_GL_VERSION_4_6 = (major == 4 && minor >= 6) || major > 4;
if (GLVersion.major > 4 || (GLVersion.major >= 4 && GLVersion.minor >= 6)) {
max_loaded_major = 4;
max_loaded_minor = 4;
max_loaded_minor = 6;
}
}
@ -1784,6 +1949,8 @@ int gladLoadGLLoader(GLADloadproc load) {
load_GL_VERSION_4_2(load);
load_GL_VERSION_4_3(load);
load_GL_VERSION_4_4(load);
load_GL_VERSION_4_5(load);
load_GL_VERSION_4_6(load);
if (!find_extensionsGL()) return 0;
load_GL_ARB_buffer_storage(load);
@ -2169,6 +2336,7 @@ static int find_extensionsGLES2(void) {
if (!get_exts()) return 0;
GLAD_GL_EXT_buffer_storage = has_ext("GL_EXT_buffer_storage");
GLAD_GL_EXT_clip_cull_distance = has_ext("GL_EXT_clip_cull_distance");
GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc");
free_exts();
return 1;
}

14
externals/libspng/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,14 @@
add_library(spng STATIC spng.h spng.c)
target_compile_definitions(spng PUBLIC SPNG_STATIC)
target_include_directories(spng PUBLIC ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(spng PRIVATE ZLIB::ZLIB)
# Enable SSE4.1 on x64
if ("x86_64" IN_LIST ARCHITECTURE)
target_compile_definitions(spng PRIVATE SPNG_SSE=4)
if (NOT MSVC)
target_compile_options(spng PRIVATE -msse4.1)
endif()
endif()
add_library(spng::spng ALIAS spng)

6979
externals/libspng/spng.c vendored Normal file

File diff suppressed because it is too large Load Diff

537
externals/libspng/spng.h vendored Normal file
View File

@ -0,0 +1,537 @@
/* SPDX-License-Identifier: BSD-2-Clause */
#ifndef SPNG_H
#define SPNG_H
#ifdef __cplusplus
extern "C" {
#endif
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(SPNG_STATIC)
#if defined(SPNG__BUILD)
#define SPNG_API __declspec(dllexport)
#else
#define SPNG_API __declspec(dllimport)
#endif
#else
#define SPNG_API
#endif
#if defined(_MSC_VER)
#define SPNG_CDECL __cdecl
#else
#define SPNG_CDECL
#endif
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#define SPNG_VERSION_MAJOR 0
#define SPNG_VERSION_MINOR 7
#define SPNG_VERSION_PATCH 3
enum spng_errno
{
SPNG_IO_ERROR = -2,
SPNG_IO_EOF = -1,
SPNG_OK = 0,
SPNG_EINVAL,
SPNG_EMEM,
SPNG_EOVERFLOW,
SPNG_ESIGNATURE,
SPNG_EWIDTH,
SPNG_EHEIGHT,
SPNG_EUSER_WIDTH,
SPNG_EUSER_HEIGHT,
SPNG_EBIT_DEPTH,
SPNG_ECOLOR_TYPE,
SPNG_ECOMPRESSION_METHOD,
SPNG_EFILTER_METHOD,
SPNG_EINTERLACE_METHOD,
SPNG_EIHDR_SIZE,
SPNG_ENOIHDR,
SPNG_ECHUNK_POS,
SPNG_ECHUNK_SIZE,
SPNG_ECHUNK_CRC,
SPNG_ECHUNK_TYPE,
SPNG_ECHUNK_UNKNOWN_CRITICAL,
SPNG_EDUP_PLTE,
SPNG_EDUP_CHRM,
SPNG_EDUP_GAMA,
SPNG_EDUP_ICCP,
SPNG_EDUP_SBIT,
SPNG_EDUP_SRGB,
SPNG_EDUP_BKGD,
SPNG_EDUP_HIST,
SPNG_EDUP_TRNS,
SPNG_EDUP_PHYS,
SPNG_EDUP_TIME,
SPNG_EDUP_OFFS,
SPNG_EDUP_EXIF,
SPNG_ECHRM,
SPNG_EPLTE_IDX,
SPNG_ETRNS_COLOR_TYPE,
SPNG_ETRNS_NO_PLTE,
SPNG_EGAMA,
SPNG_EICCP_NAME,
SPNG_EICCP_COMPRESSION_METHOD,
SPNG_ESBIT,
SPNG_ESRGB,
SPNG_ETEXT,
SPNG_ETEXT_KEYWORD,
SPNG_EZTXT,
SPNG_EZTXT_COMPRESSION_METHOD,
SPNG_EITXT,
SPNG_EITXT_COMPRESSION_FLAG,
SPNG_EITXT_COMPRESSION_METHOD,
SPNG_EITXT_LANG_TAG,
SPNG_EITXT_TRANSLATED_KEY,
SPNG_EBKGD_NO_PLTE,
SPNG_EBKGD_PLTE_IDX,
SPNG_EHIST_NO_PLTE,
SPNG_EPHYS,
SPNG_ESPLT_NAME,
SPNG_ESPLT_DUP_NAME,
SPNG_ESPLT_DEPTH,
SPNG_ETIME,
SPNG_EOFFS,
SPNG_EEXIF,
SPNG_EIDAT_TOO_SHORT,
SPNG_EIDAT_STREAM,
SPNG_EZLIB,
SPNG_EFILTER,
SPNG_EBUFSIZ,
SPNG_EIO,
SPNG_EOF,
SPNG_EBUF_SET,
SPNG_EBADSTATE,
SPNG_EFMT,
SPNG_EFLAGS,
SPNG_ECHUNKAVAIL,
SPNG_ENCODE_ONLY,
SPNG_EOI,
SPNG_ENOPLTE,
SPNG_ECHUNK_LIMITS,
SPNG_EZLIB_INIT,
SPNG_ECHUNK_STDLEN,
SPNG_EINTERNAL,
SPNG_ECTXTYPE,
SPNG_ENOSRC,
SPNG_ENODST,
SPNG_EOPSTATE,
SPNG_ENOTFINAL,
};
enum spng_text_type
{
SPNG_TEXT = 1,
SPNG_ZTXT = 2,
SPNG_ITXT = 3
};
enum spng_color_type
{
SPNG_COLOR_TYPE_GRAYSCALE = 0,
SPNG_COLOR_TYPE_TRUECOLOR = 2,
SPNG_COLOR_TYPE_INDEXED = 3,
SPNG_COLOR_TYPE_GRAYSCALE_ALPHA = 4,
SPNG_COLOR_TYPE_TRUECOLOR_ALPHA = 6
};
enum spng_filter
{
SPNG_FILTER_NONE = 0,
SPNG_FILTER_SUB = 1,
SPNG_FILTER_UP = 2,
SPNG_FILTER_AVERAGE = 3,
SPNG_FILTER_PAETH = 4
};
enum spng_filter_choice
{
SPNG_DISABLE_FILTERING = 0,
SPNG_FILTER_CHOICE_NONE = 8,
SPNG_FILTER_CHOICE_SUB = 16,
SPNG_FILTER_CHOICE_UP = 32,
SPNG_FILTER_CHOICE_AVG = 64,
SPNG_FILTER_CHOICE_PAETH = 128,
SPNG_FILTER_CHOICE_ALL = (8|16|32|64|128)
};
enum spng_interlace_method
{
SPNG_INTERLACE_NONE = 0,
SPNG_INTERLACE_ADAM7 = 1
};
/* Channels are always in byte-order */
enum spng_format
{
SPNG_FMT_RGBA8 = 1,
SPNG_FMT_RGBA16 = 2,
SPNG_FMT_RGB8 = 4,
/* Partially implemented, see documentation */
SPNG_FMT_GA8 = 16,
SPNG_FMT_GA16 = 32,
SPNG_FMT_G8 = 64,
/* No conversion or scaling */
SPNG_FMT_PNG = 256,
SPNG_FMT_RAW = 512 /* big-endian (everything else is host-endian) */
};
enum spng_ctx_flags
{
SPNG_CTX_IGNORE_ADLER32 = 1, /* Ignore checksum in DEFLATE streams */
SPNG_CTX_ENCODER = 2 /* Create an encoder context */
};
enum spng_decode_flags
{
SPNG_DECODE_USE_TRNS = 1, /* Deprecated */
SPNG_DECODE_USE_GAMA = 2, /* Deprecated */
SPNG_DECODE_USE_SBIT = 8, /* Undocumented */
SPNG_DECODE_TRNS = 1, /* Apply transparency */
SPNG_DECODE_GAMMA = 2, /* Apply gamma correction */
SPNG_DECODE_PROGRESSIVE = 256 /* Initialize for progressive reads */
};
enum spng_crc_action
{
/* Default for critical chunks */
SPNG_CRC_ERROR = 0,
/* Discard chunk, invalid for critical chunks.
Since v0.6.2: default for ancillary chunks */
SPNG_CRC_DISCARD = 1,
/* Ignore and don't calculate checksum.
Since v0.6.2: also ignores checksums in DEFLATE streams */
SPNG_CRC_USE = 2
};
enum spng_encode_flags
{
SPNG_ENCODE_PROGRESSIVE = 1, /* Initialize for progressive writes */
SPNG_ENCODE_FINALIZE = 2, /* Finalize PNG after encoding image */
};
struct spng_ihdr
{
uint32_t width;
uint32_t height;
uint8_t bit_depth;
uint8_t color_type;
uint8_t compression_method;
uint8_t filter_method;
uint8_t interlace_method;
};
struct spng_plte_entry
{
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha; /* Reserved for internal use */
};
struct spng_plte
{
uint32_t n_entries;
struct spng_plte_entry entries[256];
};
struct spng_trns
{
uint16_t gray;
uint16_t red;
uint16_t green;
uint16_t blue;
uint32_t n_type3_entries;
uint8_t type3_alpha[256];
};
struct spng_chrm_int
{
uint32_t white_point_x;
uint32_t white_point_y;
uint32_t red_x;
uint32_t red_y;
uint32_t green_x;
uint32_t green_y;
uint32_t blue_x;
uint32_t blue_y;
};
struct spng_chrm
{
double white_point_x;
double white_point_y;
double red_x;
double red_y;
double green_x;
double green_y;
double blue_x;
double blue_y;
};
struct spng_iccp
{
char profile_name[80];
size_t profile_len;
char *profile;
};
struct spng_sbit
{
uint8_t grayscale_bits;
uint8_t red_bits;
uint8_t green_bits;
uint8_t blue_bits;
uint8_t alpha_bits;
};
struct spng_text
{
char keyword[80];
int type;
size_t length;
char *text;
uint8_t compression_flag; /* iTXt only */
uint8_t compression_method; /* iTXt, ztXt only */
char *language_tag; /* iTXt only */
char *translated_keyword; /* iTXt only */
};
struct spng_bkgd
{
uint16_t gray; /* Only for gray/gray alpha */
uint16_t red;
uint16_t green;
uint16_t blue;
uint16_t plte_index; /* Only for indexed color */
};
struct spng_hist
{
uint16_t frequency[256];
};
struct spng_phys
{
uint32_t ppu_x, ppu_y;
uint8_t unit_specifier;
};
struct spng_splt_entry
{
uint16_t red;
uint16_t green;
uint16_t blue;
uint16_t alpha;
uint16_t frequency;
};
struct spng_splt
{
char name[80];
uint8_t sample_depth;
uint32_t n_entries;
struct spng_splt_entry *entries;
};
struct spng_time
{
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
};
struct spng_offs
{
int32_t x, y;
uint8_t unit_specifier;
};
struct spng_exif
{
size_t length;
char *data;
};
struct spng_chunk
{
size_t offset;
uint32_t length;
uint8_t type[4];
uint32_t crc;
};
enum spng_location
{
SPNG_AFTER_IHDR = 1,
SPNG_AFTER_PLTE = 2,
SPNG_AFTER_IDAT = 8,
};
struct spng_unknown_chunk
{
uint8_t type[4];
size_t length;
void *data;
enum spng_location location;
};
enum spng_option
{
SPNG_KEEP_UNKNOWN_CHUNKS = 1,
SPNG_IMG_COMPRESSION_LEVEL,
SPNG_IMG_WINDOW_BITS,
SPNG_IMG_MEM_LEVEL,
SPNG_IMG_COMPRESSION_STRATEGY,
SPNG_TEXT_COMPRESSION_LEVEL,
SPNG_TEXT_WINDOW_BITS,
SPNG_TEXT_MEM_LEVEL,
SPNG_TEXT_COMPRESSION_STRATEGY,
SPNG_FILTER_CHOICE,
SPNG_CHUNK_COUNT_LIMIT,
SPNG_ENCODE_TO_BUFFER,
};
typedef void* SPNG_CDECL spng_malloc_fn(size_t size);
typedef void* SPNG_CDECL spng_realloc_fn(void* ptr, size_t size);
typedef void* SPNG_CDECL spng_calloc_fn(size_t count, size_t size);
typedef void SPNG_CDECL spng_free_fn(void* ptr);
struct spng_alloc
{
spng_malloc_fn *malloc_fn;
spng_realloc_fn *realloc_fn;
spng_calloc_fn *calloc_fn;
spng_free_fn *free_fn;
};
struct spng_row_info
{
uint32_t scanline_idx;
uint32_t row_num; /* deinterlaced row index */
int pass;
uint8_t filter;
};
typedef struct spng_ctx spng_ctx;
typedef int spng_read_fn(spng_ctx *ctx, void *user, void *dest, size_t length);
typedef int spng_write_fn(spng_ctx *ctx, void *user, void *src, size_t length);
typedef int spng_rw_fn(spng_ctx *ctx, void *user, void *dst_src, size_t length);
SPNG_API spng_ctx *spng_ctx_new(int flags);
SPNG_API spng_ctx *spng_ctx_new2(struct spng_alloc *alloc, int flags);
SPNG_API void spng_ctx_free(spng_ctx *ctx);
SPNG_API int spng_set_png_buffer(spng_ctx *ctx, const void *buf, size_t size);
SPNG_API int spng_set_png_stream(spng_ctx *ctx, spng_rw_fn *rw_func, void *user);
SPNG_API int spng_set_png_file(spng_ctx *ctx, FILE *file);
SPNG_API void *spng_get_png_buffer(spng_ctx *ctx, size_t *len, int *error);
SPNG_API int spng_set_image_limits(spng_ctx *ctx, uint32_t width, uint32_t height);
SPNG_API int spng_get_image_limits(spng_ctx *ctx, uint32_t *width, uint32_t *height);
SPNG_API int spng_set_chunk_limits(spng_ctx *ctx, size_t chunk_size, size_t cache_size);
SPNG_API int spng_get_chunk_limits(spng_ctx *ctx, size_t *chunk_size, size_t *cache_size);
SPNG_API int spng_set_crc_action(spng_ctx *ctx, int critical, int ancillary);
SPNG_API int spng_set_option(spng_ctx *ctx, enum spng_option option, int value);
SPNG_API int spng_get_option(spng_ctx *ctx, enum spng_option option, int *value);
SPNG_API int spng_decoded_image_size(spng_ctx *ctx, int fmt, size_t *len);
/* Decode */
SPNG_API int spng_decode_image(spng_ctx *ctx, void *out, size_t len, int fmt, int flags);
/* Progressive decode */
SPNG_API int spng_decode_scanline(spng_ctx *ctx, void *out, size_t len);
SPNG_API int spng_decode_row(spng_ctx *ctx, void *out, size_t len);
SPNG_API int spng_decode_chunks(spng_ctx *ctx);
/* Encode/decode */
SPNG_API int spng_get_row_info(spng_ctx *ctx, struct spng_row_info *row_info);
/* Encode */
SPNG_API int spng_encode_image(spng_ctx *ctx, const void *img, size_t len, int fmt, int flags);
/* Progressive encode */
SPNG_API int spng_encode_scanline(spng_ctx *ctx, const void *scanline, size_t len);
SPNG_API int spng_encode_row(spng_ctx *ctx, const void *row, size_t len);
SPNG_API int spng_encode_chunks(spng_ctx *ctx);
SPNG_API int spng_get_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr);
SPNG_API int spng_get_plte(spng_ctx *ctx, struct spng_plte *plte);
SPNG_API int spng_get_trns(spng_ctx *ctx, struct spng_trns *trns);
SPNG_API int spng_get_chrm(spng_ctx *ctx, struct spng_chrm *chrm);
SPNG_API int spng_get_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int);
SPNG_API int spng_get_gama(spng_ctx *ctx, double *gamma);
SPNG_API int spng_get_gama_int(spng_ctx *ctx, uint32_t *gama_int);
SPNG_API int spng_get_iccp(spng_ctx *ctx, struct spng_iccp *iccp);
SPNG_API int spng_get_sbit(spng_ctx *ctx, struct spng_sbit *sbit);
SPNG_API int spng_get_srgb(spng_ctx *ctx, uint8_t *rendering_intent);
SPNG_API int spng_get_text(spng_ctx *ctx, struct spng_text *text, uint32_t *n_text);
SPNG_API int spng_get_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd);
SPNG_API int spng_get_hist(spng_ctx *ctx, struct spng_hist *hist);
SPNG_API int spng_get_phys(spng_ctx *ctx, struct spng_phys *phys);
SPNG_API int spng_get_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t *n_splt);
SPNG_API int spng_get_time(spng_ctx *ctx, struct spng_time *time);
SPNG_API int spng_get_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t *n_chunks);
/* Official extensions */
SPNG_API int spng_get_offs(spng_ctx *ctx, struct spng_offs *offs);
SPNG_API int spng_get_exif(spng_ctx *ctx, struct spng_exif *exif);
SPNG_API int spng_set_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr);
SPNG_API int spng_set_plte(spng_ctx *ctx, struct spng_plte *plte);
SPNG_API int spng_set_trns(spng_ctx *ctx, struct spng_trns *trns);
SPNG_API int spng_set_chrm(spng_ctx *ctx, struct spng_chrm *chrm);
SPNG_API int spng_set_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int);
SPNG_API int spng_set_gama(spng_ctx *ctx, double gamma);
SPNG_API int spng_set_gama_int(spng_ctx *ctx, uint32_t gamma);
SPNG_API int spng_set_iccp(spng_ctx *ctx, struct spng_iccp *iccp);
SPNG_API int spng_set_sbit(spng_ctx *ctx, struct spng_sbit *sbit);
SPNG_API int spng_set_srgb(spng_ctx *ctx, uint8_t rendering_intent);
SPNG_API int spng_set_text(spng_ctx *ctx, struct spng_text *text, uint32_t n_text);
SPNG_API int spng_set_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd);
SPNG_API int spng_set_hist(spng_ctx *ctx, struct spng_hist *hist);
SPNG_API int spng_set_phys(spng_ctx *ctx, struct spng_phys *phys);
SPNG_API int spng_set_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t n_splt);
SPNG_API int spng_set_time(spng_ctx *ctx, struct spng_time *time);
SPNG_API int spng_set_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t n_chunks);
/* Official extensions */
SPNG_API int spng_set_offs(spng_ctx *ctx, struct spng_offs *offs);
SPNG_API int spng_set_exif(spng_ctx *ctx, struct spng_exif *exif);
SPNG_API const char *spng_strerror(int err);
SPNG_API const char *spng_version_string(void);
#ifdef __cplusplus
}
#endif
#endif /* SPNG_H */

View File

@ -1,7 +0,0 @@
add_library(lodepng
lodepng/lodepng.cpp
lodepng/lodepng.h
)
create_target_directory_groups(lodepng)
target_include_directories(lodepng INTERFACE lodepng)

View File

@ -834,7 +834,7 @@ struct MicroProfile
inline int MicroProfileLogType(MicroProfileLogEntry Index)
{
return ((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3;
return (int)(((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3ULL);
}
inline uint64_t MicroProfileLogTimerIndex(MicroProfileLogEntry Index)
@ -881,12 +881,12 @@ T MicroProfileMax(T a, T b)
inline int64_t MicroProfileMsToTick(float fMs, int64_t nTicksPerSecond)
{
return (int64_t)(fMs*0.001f*nTicksPerSecond);
return (int64_t)(fMs*0.001f*(float)nTicksPerSecond);
}
inline float MicroProfileTickToMsMultiplier(int64_t nTicksPerSecond)
{
return 1000.f / nTicksPerSecond;
return 1000.f / (float)nTicksPerSecond;
}
inline uint16_t MicroProfileGetGroupIndex(MicroProfileToken t)
@ -902,8 +902,10 @@ inline uint16_t MicroProfileGetGroupIndex(MicroProfileToken t)
#include <windows.h>
#define snprintf _snprintf
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4244)
#endif
int64_t MicroProfileTicksPerSecondCpu()
{
static int64_t nTicksPerSecond = 0;
@ -929,14 +931,14 @@ typedef void* (*MicroProfileThreadFunc)(void*);
#ifndef _WIN32
typedef pthread_t MicroProfileThread;
void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
{
pthread_attr_t Attr;
int r = pthread_attr_init(&Attr);
MP_ASSERT(r == 0);
pthread_create(pThread, &Attr, Func, 0);
}
void MicroProfileThreadJoin(MicroProfileThread* pThread)
inline void MicroProfileThreadJoin(MicroProfileThread* pThread)
{
int r = pthread_join(*pThread, 0);
MP_ASSERT(r == 0);
@ -953,11 +955,11 @@ DWORD _stdcall ThreadTrampoline(void* pFunc)
return static_cast<DWORD>(reinterpret_cast<uint64_t>(F(0)));
}
void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
{
*pThread = CreateThread(0, 0, ThreadTrampoline, Func, 0, 0);
}
void MicroProfileThreadJoin(MicroProfileThread* pThread)
inline void MicroProfileThreadJoin(MicroProfileThread* pThread)
{
WaitForSingleObject(*pThread, INFINITE);
CloseHandle(*pThread);
@ -1154,7 +1156,7 @@ inline void MicroProfileSetThreadLog(MicroProfileThreadLog* pLog)
pthread_setspecific(g_MicroProfileThreadLogKey, pLog);
}
#else
MicroProfileThreadLog* MicroProfileGetThreadLog()
inline MicroProfileThreadLog* MicroProfileGetThreadLog()
{
return g_MicroProfileThreadLog;
}
@ -1270,7 +1272,7 @@ MicroProfileToken MicroProfileFindToken(const char* pGroup, const char* pName)
return MICROPROFILE_INVALID_TOKEN;
}
uint16_t MicroProfileGetGroup(const char* pGroup, MicroProfileTokenType Type)
inline uint16_t MicroProfileGetGroup(const char* pGroup, MicroProfileTokenType Type)
{
for(uint32_t i = 0; i < S.nGroupCount; ++i)
{
@ -1299,7 +1301,7 @@ uint16_t MicroProfileGetGroup(const char* pGroup, MicroProfileTokenType Type)
return nGroupIndex;
}
void MicroProfileRegisterGroup(const char* pGroup, const char* pCategory, uint32_t nColor)
inline void MicroProfileRegisterGroup(const char* pGroup, const char* pCategory, uint32_t nColor)
{
int nCategoryIndex = -1;
for(uint32_t i = 0; i < S.nCategoryCount; ++i)
@ -1465,7 +1467,7 @@ void MicroProfileGpuLeave(MicroProfileToken nToken_, uint64_t nTickStart)
}
}
void MicroProfileContextSwitchPut(MicroProfileContextSwitch* pContextSwitch)
inline void MicroProfileContextSwitchPut(MicroProfileContextSwitch* pContextSwitch)
{
if(S.nRunning || pContextSwitch->nTicks <= S.nPauseTicks)
{
@ -1746,10 +1748,10 @@ void MicroProfileFlip()
}
}
}
for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
{
pLog->nGroupTicks[i] += nGroupTicks[i];
pFrameGroup[i] += nGroupTicks[i];
pLog->nGroupTicks[j] += nGroupTicks[j];
pFrameGroup[j] += nGroupTicks[j];
}
pLog->nStackPos = nStackPos;
}
@ -1917,7 +1919,7 @@ void MicroProfileSetEnableAllGroups(bool bEnableAllGroups)
S.nAllGroupsWanted = bEnableAllGroups ? 1 : 0;
}
void MicroProfileEnableCategory(const char* pCategory, bool bEnabled)
inline void MicroProfileEnableCategory(const char* pCategory, bool bEnabled)
{
int nCategoryIndex = -1;
for(uint32_t i = 0; i < S.nCategoryCount; ++i)
@ -2027,7 +2029,7 @@ void MicroProfileForceDisableGroup(const char* pGroup, MicroProfileTokenType Typ
}
void MicroProfileCalcAllTimers(float* pTimers, float* pAverage, float* pMax, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, float* pTotal, uint32_t nSize)
inline void MicroProfileCalcAllTimers(float* pTimers, float* pAverage, float* pMax, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, float* pTotal, uint32_t nSize)
{
for(uint32_t i = 0; i < S.nTotalTimers && i < nSize; ++i)
{
@ -3332,7 +3334,7 @@ bool MicroProfileIsLocalThread(uint32_t nThreadId)
#endif
#else
bool MicroProfileIsLocalThread(uint32_t nThreadId){return false;}
bool MicroProfileIsLocalThread([[maybe_unused]] uint32_t nThreadId) { return false; }
void MicroProfileStopContextSwitchTrace(){}
void MicroProfileStartContextSwitchTrace(){}
@ -3580,7 +3582,7 @@ int MicroProfileGetGpuTickReference(int64_t* pOutCpu, int64_t* pOutGpu)
#undef S
#ifdef _WIN32
#ifdef _MSC_VER
#pragma warning(pop)
#endif

1
externals/sirit vendored Submodule

Submodule externals/sirit added at f0b6bbe55b

17
externals/zlib-ng/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,17 @@
set(ZLIB_ENABLE_TESTS OFF)
set(ZLIBNG_ENABLE_TESTS OFF)
set(WITH_GZFILEOP OFF)
set(WITH_GTEST OFF)
set(ZLIB_COMPAT ON)
set(SKIP_INSTALL_ALL ON)
option(BUILD_SHARED_LIBS "Build shared library" OFF)
add_subdirectory(zlib-ng)
# Set ZLIB variables for find_package used by other projects
set(ZLIB_INCLUDE_DIR ${CMAKE_BINARY_DIR}/zlib-ng CACHE STRING "Path to zlib include directory")
set(ZLIB_LIBRARY ZLIB::ZLIB CACHE STRING "Path to zlib library")
# Setup zlib alias project so FindZLIB doesn't recreate it
add_library(ZLIB::ZLIB ALIAS zlib)

1
externals/zlib-ng/zlib-ng vendored Submodule

View File

@ -46,11 +46,21 @@ if (MSVC)
# Warnings
/W3
/we4062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled
/we4101 # 'identifier': unreferenced local variable
/we4265 # 'class': class has virtual functions, but destructor is not virtual
/we4267 # 'var': conversion from 'size_t' to 'type', possible loss of data
/we4388 # signed/unsigned mismatch
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
/we4555 # Expression has no effect; expected expression with side-effect
/we4834 # Discarding return value of function with 'nodiscard' attribute
/we5038 # data member 'member1' will be initialized after data member 'member2'
)
else()
add_compile_options(
/MP
/Zo
/permissive-
/EHsc
/volatile:iso
@ -64,17 +74,26 @@ if (MSVC)
# Warnings
/W3
/we4062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled
/we4101 # 'identifier': unreferenced local variable
/we4265 # 'class': class has virtual functions, but destructor is not virtual
/we4267 # 'var': conversion from 'size_t' to 'type', possible loss of data
/we4388 # signed/unsigned mismatch
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
/we4555 # Expression has no effect; expected expression with side-effect
/we4834 # Discarding return value of function with 'nodiscard' attribute
/we5038 # data member 'member1' will be initialized after data member 'member2'
)
endif()
# Since MSVC's debugging information is not very deterministic, so we have to disable it
# when using ccache or other caching tools
if (NOT CITRA_USE_CCACHE)
add_compile_options(
/Zi
/Zo
)
if (CITRA_USE_CCACHE OR CITRA_USE_PRECOMPILED_HEADERS)
# Precompiled headers are deleted if not using /Z7. See https://github.com/nanoant/CMakePCHCompiler/issues/21
add_compile_options(/Z7)
else()
add_compile_options(/Zi)
endif()
# /GS- - No stack buffer overflow checks

View File

@ -18,21 +18,12 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
// This is important as it will run lint but not abort on error
// Lint has some overly obnoxious "errors" that should really be warnings
abortOnError false
//Uncomment disable lines for test builds...
//disable 'MissingTranslation'bin
//disable 'ExtraTranslation'
}
defaultConfig {
// TODO If this is ever modified, change application_id in strings.xml
applicationId "org.citra.citra_emu"
minSdkVersion 28
targetSdkVersion 29
targetSdkVersion 31
versionCode autoVersion
versionName getVersion()
ndk.abiFilters abiFilter
@ -96,10 +87,14 @@ android {
externalNativeBuild {
cmake {
version "3.18.1"
version "3.22.1"
path "../../../CMakeLists.txt"
}
}
lint {
abortOnError false
}
namespace 'org.citra.citra_emu'
defaultConfig {
externalNativeBuild {
@ -107,7 +102,8 @@ android {
arguments "-DENABLE_QT=0", // Don't use QT
"-DENABLE_SDL2=0", // Don't use SDL
"-DENABLE_WEB_SERVICE=0", // Don't use telemetry
"-DANDROID_ARM_NEON=true" // cryptopp requires Neon to work
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
"-DBUNDLE_SPEEX=ON"
abiFilters abiFilter
}
@ -116,22 +112,25 @@ android {
}
dependencies {
implementation "androidx.activity:activity:1.5.1"
implementation "androidx.fragment:fragment:1.5.5"
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.exifinterface:exifinterface:1.3.4'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "androidx.documentfile:documentfile:1.0.1"
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.5.1'
implementation 'androidx.fragment:fragment:1.5.3'
implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0"
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.core:core-splashscreen:1.0.0'
// For loading huge screenshots from the disk.
implementation 'com.squareup.picasso:picasso:2.71828'
// Allows FRP-style asynchronous operations in Android.
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.nononsenseapps:filepicker:4.2.1'
implementation 'org.ini4j:ini4j:0.5.4'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
@ -139,6 +138,10 @@ dependencies {
// Please don't upgrade the billing library as the newer version is not GPL-compatible
implementation 'com.android.billingclient:billing:2.0.3'
// To use the androidx.test.core APIs
androidTestImplementation "androidx.test:core:1.5.0"
androidTestImplementation "androidx.test.ext:junit:1.1.5"
}
def getVersion() {

View File

@ -1,8 +1,8 @@
package org.citra.citra_emu;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -19,7 +19,7 @@ public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
Context appContext = ApplicationProvider.getApplicationContext();
assertEquals("org.citra.citra_emu", appContext.getPackageName());
}

View File

@ -1,27 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.citra.citra_emu">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false"/>
<uses-feature
android:name="android.hardware.gamepad"
android:required="false"/>
<uses-feature android:glEsVersion="0x00030002" android:required="true" />
<uses-feature android:name="android.hardware.opengles.aep" android:required="true" />
<uses-feature
android:name="android.hardware.microphone"
android:required="false"/>
<uses-feature
android:name="android.hardware.camera"
android:required="false"/>
<uses-feature
android:name="android.hardware.camera.any"
android:required="false" />
android:required="false"/>
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false"/>
<uses-feature
android:name="android.software.leanback"
android:required="false"/>
<uses-feature android:glEsVersion="0x00030002" android:required="true" />
<uses-feature android:name="android.hardware.opengles.aep" android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name="org.citra.citra_emu.CitraApplication"
android:label="@string/app_name"
@ -30,52 +38,43 @@
android:supportsRtl="true"
android:isGame="true"
android:banner="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true">
android:requestLegacyExternalStorage="true"
android:debuggable="true">
<activity
android:name="org.citra.citra_emu.ui.main.MainActivity"
android:theme="@style/CitraBase"
android:theme="@style/Theme.Citra.Splash.Main"
android:exported="true"
android:resizeableActivity="false">
<!-- This intentfilter marks this Activity as the one that gets launched from Home screen. -->
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name="org.citra.citra_emu.features.settings.ui.SettingsActivity"
android:configChanges="orientation|screenSize|uiMode"
android:theme="@style/CitraSettingsBase"
android:theme="@style/Theme.Citra.Main"
android:label="@string/preferences_settings"/>
<activity
android:name="org.citra.citra_emu.activities.EmulationActivity"
android:resizeableActivity="false"
android:theme="@style/CitraEmulationBase"
android:theme="@style/Theme.Citra.Main"
android:launchMode="singleTop"/>
<service android:name="org.citra.citra_emu.utils.ForegroundService"/>
<activity
android:name="org.citra.citra_emu.activities.CustomFilePickerActivity"
android:label="@string/app_name"
android:theme="@style/FilePickerTheme">
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="org.citra.citra_emu.features.cheats.ui.CheatsActivity"
android:exported="false"
android:theme="@style/CitraSettingsBase"
android:theme="@style/Theme.Citra.Main"
android:label="@string/cheats"/>
<service android:name="org.citra.citra_emu.utils.DirectoryInitialization"/>
<provider
android:name="org.citra.citra_emu.model.GameProvider"
@ -83,16 +82,6 @@
android:enabled="true"
android:exported="false">
</provider>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.filesprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/nnf_provider_paths" />
</provider>
</application>
</manifest>

View File

@ -12,10 +12,12 @@ import android.os.Build;
import org.citra.citra_emu.model.GameDatabase;
import org.citra.citra_emu.utils.DirectoryInitialization;
import org.citra.citra_emu.utils.DocumentsTree;
import org.citra.citra_emu.utils.PermissionsHandler;
public class CitraApplication extends Application {
public static GameDatabase databaseHelper;
public static DocumentsTree documentsTree;
private static CitraApplication application;
private void createNotificationChannel() {
@ -39,6 +41,7 @@ public class CitraApplication extends Application {
public void onCreate() {
super.onCreate();
application = this;
documentsTree = new DocumentsTree();
if (PermissionsHandler.hasWriteAccess(getApplicationContext())) {
DirectoryInitialization.start(getApplicationContext());

View File

@ -28,6 +28,7 @@ import androidx.fragment.app.DialogFragment;
import org.citra.citra_emu.activities.EmulationActivity;
import org.citra.citra_emu.applets.SoftwareKeyboard;
import org.citra.citra_emu.utils.EmulationMenuSettings;
import org.citra.citra_emu.utils.FileUtil;
import org.citra.citra_emu.utils.Log;
import org.citra.citra_emu.utils.PermissionsHandler;
@ -38,6 +39,8 @@ import java.util.Objects;
import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.RECORD_AUDIO;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
/**
* Class which contains methods that interact
* with the native side of the Citra code.
@ -162,6 +165,10 @@ public final class NativeLibrary {
// Create the config.ini file.
public static native void CreateConfigFile();
public static native void CreateLogFile();
public static native void LogUserDirectory(String directory);
public static native int DefaultCPUCore();
/**
@ -245,7 +252,7 @@ public final class NativeLibrary {
final String title = Objects.requireNonNull(Objects.requireNonNull(getArguments()).getString("title"));
final String message = Objects.requireNonNull(Objects.requireNonNull(getArguments()).getString("message"));
return new AlertDialog.Builder(emulationActivity)
return new MaterialAlertDialogBuilder(emulationActivity)
.setTitle(title)
.setMessage(message)
.setPositiveButton(R.string.continue_button, (dialog, which) -> {
@ -260,11 +267,11 @@ public final class NativeLibrary {
coreErrorAlertLock.notify();
}
}).setOnDismissListener(dialog -> {
coreErrorAlertResult = true;
synchronized (coreErrorAlertLock) {
coreErrorAlertLock.notify();
}
}).create();
coreErrorAlertResult = true;
synchronized (coreErrorAlertLock) {
coreErrorAlertLock.notify();
}
}).create();
}
}
@ -345,7 +352,7 @@ public final class NativeLibrary {
} else {
// Create object used for waiting.
final Object lock = new Object();
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity)
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(emulationActivity)
.setTitle(caption)
.setMessage(text);
@ -427,7 +434,7 @@ public final class NativeLibrary {
return alertPromptResult;
}
public static AlertDialog.Builder displayAlertPromptImpl(String caption, String text, int buttonConfig) {
public static MaterialAlertDialogBuilder displayAlertPromptImpl(String caption, String text, int buttonConfig) {
final EmulationActivity emulationActivity = sEmulationActivity.get();
alertPromptResult = "";
alertPromptButton = 0;
@ -444,7 +451,7 @@ public final class NativeLibrary {
FrameLayout container = new FrameLayout(emulationActivity);
container.addView(alertPromptEditText);
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity)
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(emulationActivity)
.setTitle(caption)
.setView(container)
.setPositiveButton(android.R.string.ok, (dialogInterface, i) ->
@ -506,7 +513,7 @@ public final class NativeLibrary {
captionId = R.string.loader_error_encrypted;
}
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity)
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(emulationActivity)
.setTitle(captionId)
.setMessage(Html.fromHtml("Please follow the guides to redump your <a href=\"https://citra-emu.org/wiki/dumping-game-cartridges/\">game cartidges</a> or <a href=\"https://citra-emu.org/wiki/dumping-installed-titles/\">installed titles</a>.", Html.FROM_HTML_MODE_LEGACY))
.setPositiveButton(android.R.string.ok, (dialog, whichButton) -> emulationActivity.finish())
@ -663,4 +670,73 @@ public final class NativeLibrary {
public static final int RELEASED = 0;
public static final int PRESSED = 1;
}
public static boolean createFile(String directory, String filename) {
if (FileUtil.isNativePath(directory)) {
return CitraApplication.documentsTree.createFile(directory, filename);
}
return FileUtil.createFile(CitraApplication.getAppContext(), directory, filename) != null;
}
public static boolean createDir(String directory, String directoryName) {
if (FileUtil.isNativePath(directory)) {
return CitraApplication.documentsTree.createDir(directory, directoryName);
}
return FileUtil.createDir(CitraApplication.getAppContext(), directory, directoryName) != null;
}
public static int openContentUri(String path, String openMode) {
if (FileUtil.isNativePath(path)) {
return CitraApplication.documentsTree.openContentUri(path, openMode);
}
return FileUtil.openContentUri(CitraApplication.getAppContext(), path, openMode);
}
public static String[] getFilesName(String path) {
if (FileUtil.isNativePath(path)) {
return CitraApplication.documentsTree.getFilesName(path);
}
return FileUtil.getFilesName(CitraApplication.getAppContext(), path);
}
public static long getSize(String path) {
if (FileUtil.isNativePath(path)) {
return CitraApplication.documentsTree.getFileSize(path);
}
return FileUtil.getFileSize(CitraApplication.getAppContext(), path);
}
public static boolean fileExists(String path) {
if (FileUtil.isNativePath(path)) {
return CitraApplication.documentsTree.Exists(path);
}
return FileUtil.Exists(CitraApplication.getAppContext(), path);
}
public static boolean isDirectory(String path) {
if (FileUtil.isNativePath(path)) {
return CitraApplication.documentsTree.isDirectory(path);
}
return FileUtil.isDirectory(CitraApplication.getAppContext(), path);
}
public static boolean copyFile(String sourcePath, String destinationParentPath, String destinationFilename) {
if (FileUtil.isNativePath(sourcePath) && FileUtil.isNativePath(destinationParentPath)) {
return CitraApplication.documentsTree.copyFile(sourcePath, destinationParentPath, destinationFilename);
}
return FileUtil.copyFile(CitraApplication.getAppContext(), sourcePath, destinationParentPath, destinationFilename);
}
public static boolean renameFile(String path, String destinationFilename) {
if (FileUtil.isNativePath(path)) {
return CitraApplication.documentsTree.renameFile(path, destinationFilename);
}
return FileUtil.renameFile(CitraApplication.getAppContext(), path, destinationFilename);
}
public static boolean deleteDocument(String path) {
if (FileUtil.isNativePath(path)) {
return CitraApplication.documentsTree.deleteDocument(path);
}
return FileUtil.deleteDocument(CitraApplication.getAppContext(), path);
}
}

View File

@ -1,38 +0,0 @@
package org.citra.citra_emu.activities;
import android.content.Intent;
import android.os.Environment;
import androidx.annotation.Nullable;
import com.nononsenseapps.filepicker.AbstractFilePickerFragment;
import com.nononsenseapps.filepicker.FilePickerActivity;
import org.citra.citra_emu.fragments.CustomFilePickerFragment;
import java.io.File;
public class CustomFilePickerActivity extends FilePickerActivity {
public static final String EXTRA_TITLE = "filepicker.intent.TITLE";
public static final String EXTRA_EXTENSIONS = "filepicker.intent.EXTENSIONS";
@Override
protected AbstractFilePickerFragment<File> getFragment(
@Nullable final String startPath, final int mode, final boolean allowMultiple,
final boolean allowCreateDir, final boolean allowExistingFile,
final boolean singleClick) {
CustomFilePickerFragment fragment = new CustomFilePickerFragment();
// startPath is allowed to be null. In that case, default folder should be SD-card and not "/"
fragment.setArgs(
startPath != null ? startPath : Environment.getExternalStorageDirectory().getPath(),
mode, allowMultiple, allowCreateDir, allowExistingFile, singleClick);
Intent intent = getIntent();
int title = intent == null ? 0 : intent.getIntExtra(EXTRA_TITLE, 0);
fragment.setTitle(title);
String allowedExtensions = intent == null ? "*" : intent.getStringExtra(EXTRA_EXTENSIONS);
fragment.setAllowedExtensions(allowedExtensions);
return fragment;
}
}

View File

@ -5,31 +5,35 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Pair;
import android.util.SparseIntArray;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.PopupMenu;
import androidx.core.app.NotificationManagerCompat;
import androidx.fragment.app.FragmentActivity;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.R;
import org.citra.citra_emu.contracts.OpenFileResultContract;
import org.citra.citra_emu.features.cheats.ui.CheatsActivity;
import org.citra.citra_emu.features.settings.model.view.InputBindingSetting;
import org.citra.citra_emu.features.settings.ui.SettingsActivity;
@ -42,6 +46,7 @@ import org.citra.citra_emu.utils.EmulationMenuSettings;
import org.citra.citra_emu.utils.FileBrowserHelper;
import org.citra.citra_emu.utils.FileUtil;
import org.citra.citra_emu.utils.ForegroundService;
import org.citra.citra_emu.utils.ThemeUtil;
import java.io.File;
import java.io.IOException;
@ -53,6 +58,9 @@ import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.RECORD_AUDIO;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.slider.Slider;
public final class EmulationActivity extends AppCompatActivity {
public static final String EXTRA_SELECTED_GAME = "SelectedGame";
public static final String EXTRA_SELECTED_TITLE = "SelectedTitle";
@ -74,11 +82,24 @@ public final class EmulationActivity extends AppCompatActivity {
public static final int MENU_ACTION_JOYSTICK_REL_CENTER = 15;
public static final int MENU_ACTION_DPAD_SLIDE_ENABLE = 16;
public static final int MENU_ACTION_OPEN_CHEATS = 17;
public static final int MENU_ACTION_CLOSE_GAME = 18;
public static final int REQUEST_SELECT_AMIIBO = 2;
private static final int EMULATION_RUNNING_NOTIFICATION = 0x1000;
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
private final ActivityResultLauncher<Boolean> mOpenFileLauncher =
registerForActivityResult(new OpenFileResultContract(), result -> {
if (result == null)
return;
String[] selectedFiles = FileBrowserHelper.getSelectedFiles(
result, getApplicationContext(), Collections.singletonList("bin"));
if (selectedFiles == null)
return;
onAmiiboSelected(selectedFiles[0]);
});
static {
buttonsActionsMap.append(R.id.menu_emulation_edit_layout,
EmulationActivity.MENU_ACTION_EDIT_CONTROLS_PLACEMENT);
@ -114,9 +135,10 @@ public final class EmulationActivity extends AppCompatActivity {
EmulationActivity.MENU_ACTION_DPAD_SLIDE_ENABLE);
buttonsActionsMap
.append(R.id.menu_emulation_open_cheats, EmulationActivity.MENU_ACTION_OPEN_CHEATS);
buttonsActionsMap
.append(R.id.menu_emulation_close_game, EmulationActivity.MENU_ACTION_CLOSE_GAME);
}
private View mDecorView;
private EmulationFragment mEmulationFragment;
private SharedPreferences mPreferences;
private ControllerMappingHelper mControllerMappingHelper;
@ -145,6 +167,8 @@ public final class EmulationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
ThemeUtil.applyTheme(this);
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
@ -160,21 +184,9 @@ public final class EmulationActivity extends AppCompatActivity {
mControllerMappingHelper = new ControllerMappingHelper();
// Get a handle to the Window containing the UI.
mDecorView = getWindow().getDecorView();
mDecorView.setOnSystemUiVisibilityChangeListener(visibility ->
{
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// Go back to immersive fullscreen mode in 3s
Handler handler = new Handler(getMainLooper());
handler.postDelayed(this::enableFullscreenImmersive, 3000 /* 3s */);
}
});
// Set these options now so that the SurfaceView the game renders into is the right size.
enableFullscreenImmersive();
setTheme(R.style.CitraEmulationBase);
setContentView(R.layout.activity_emulation);
// Find or create the EmulationFragment
@ -223,21 +235,12 @@ public final class EmulationActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
NativeLibrary.PauseEmulation();
new AlertDialog.Builder(this)
.setTitle(R.string.emulation_close_game)
.setMessage(R.string.emulation_close_game_message)
.setPositiveButton(android.R.string.yes, (dialogInterface, i) ->
{
mEmulationFragment.stopEmulation();
finish();
})
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) ->
NativeLibrary.UnPauseEmulation())
.setOnCancelListener(dialogInterface ->
NativeLibrary.UnPauseEmulation())
.create()
.show();
View anchor = findViewById(R.id.menu_anchor);
PopupMenu popupMenu = new PopupMenu(this, anchor);
onCreateOptionsMenu(popupMenu.getMenu(), popupMenu.getMenuInflater());
updateSavestateMenuOptions(popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(this::onOptionsItemSelected);
popupMenu.show();
}
@Override
@ -246,7 +249,7 @@ public final class EmulationActivity extends AppCompatActivity {
case NativeLibrary.REQUEST_CODE_NATIVE_CAMERA:
if (grantResults[0] != PackageManager.PERMISSION_GRANTED &&
shouldShowRequestPermissionRationale(CAMERA)) {
new AlertDialog.Builder(this)
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.camera)
.setMessage(R.string.camera_permission_needed)
.setPositiveButton(android.R.string.ok, null)
@ -257,7 +260,7 @@ public final class EmulationActivity extends AppCompatActivity {
case NativeLibrary.REQUEST_CODE_NATIVE_MIC:
if (grantResults[0] != PackageManager.PERMISSION_GRANTED &&
shouldShowRequestPermissionRationale(RECORD_AUDIO)) {
new AlertDialog.Builder(this)
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.microphone)
.setMessage(R.string.microphone_permission_needed)
.setPositiveButton(android.R.string.ok, null)
@ -271,21 +274,30 @@ public final class EmulationActivity extends AppCompatActivity {
}
}
public void onEmulationStarted() {
Toast.makeText(this, getString(R.string.emulation_menu_help), Toast.LENGTH_LONG).show();
}
private void enableFullscreenImmersive() {
// It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar.
mDecorView.setSystemUiVisibility(
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_IMMERSIVE);
View.SYSTEM_UI_FLAG_IMMERSIVE |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_emulation, menu);
onCreateOptionsMenu(menu, getMenuInflater());
return true;
}
private void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_emulation, menu);
int layoutOptionMenuItem = R.id.menu_screen_layout_landscape;
switch (EmulationMenuSettings.getLandscapeScreenLayout()) {
@ -306,8 +318,6 @@ public final class EmulationActivity extends AppCompatActivity {
menu.findItem(R.id.menu_emulation_show_fps).setChecked(EmulationMenuSettings.getShowFps());
menu.findItem(R.id.menu_emulation_swap_screens).setChecked(EmulationMenuSettings.getSwapScreens());
menu.findItem(R.id.menu_emulation_show_overlay).setChecked(EmulationMenuSettings.getShowOverlay());
return true;
}
private void DisplaySavestateWarning() {
@ -320,7 +330,7 @@ public final class EmulationActivity extends AppCompatActivity {
View view = inflater.inflate(R.layout.dialog_checkbox, null);
CheckBox checkBox = view.findViewById(R.id.checkBox);
new AlertDialog.Builder(this)
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.savestate_warning_title)
.setMessage(R.string.savestate_warning_message)
.setView(view)
@ -333,12 +343,16 @@ public final class EmulationActivity extends AppCompatActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
updateSavestateMenuOptions(menu);
return true;
}
private void updateSavestateMenuOptions(Menu menu) {
final NativeLibrary.SavestateInfo[] savestates = NativeLibrary.GetSavestateInfo();
if (savestates == null) {
menu.findItem(R.id.menu_emulation_save_state).setVisible(false);
menu.findItem(R.id.menu_emulation_load_state).setVisible(false);
return true;
return;
}
menu.findItem(R.id.menu_emulation_save_state).setVisible(true);
menu.findItem(R.id.menu_emulation_load_state).setVisible(true);
@ -367,7 +381,6 @@ public final class EmulationActivity extends AppCompatActivity {
saveStateMenu.getItem(info.slot - 1).setTitle(text);
loadStateMenu.getItem(info.slot - 1).setTitle(text).setEnabled(true);
}
return true;
}
@SuppressWarnings("WrongConstant")
@ -456,9 +469,7 @@ public final class EmulationActivity extends AppCompatActivity {
break;
case MENU_ACTION_LOAD_AMIIBO:
FileBrowserHelper.openFilePicker(this, REQUEST_SELECT_AMIIBO,
R.string.select_amiibo,
Collections.singletonList("bin"), false);
mOpenFileLauncher.launch(false);
break;
case MENU_ACTION_REMOVE_AMIIBO:
@ -480,6 +491,21 @@ public final class EmulationActivity extends AppCompatActivity {
case MENU_ACTION_OPEN_CHEATS:
CheatsActivity.launch(this);
break;
case MENU_ACTION_CLOSE_GAME:
NativeLibrary.PauseEmulation();
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.emulation_close_game)
.setMessage(R.string.emulation_close_game_message)
.setPositiveButton(android.R.string.yes, (dialogInterface, i) ->
{
mEmulationFragment.stopEmulation();
finish();
})
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> NativeLibrary.UnPauseEmulation())
.setOnCancelListener(dialogInterface -> NativeLibrary.UnPauseEmulation())
.show();
break;
}
return true;
@ -536,20 +562,8 @@ public final class EmulationActivity extends AppCompatActivity {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) {
super.onActivityResult(requestCode, resultCode, result);
switch (requestCode) {
case StillImageCameraHelper.REQUEST_CAMERA_FILE_PICKER:
StillImageCameraHelper.OnFilePickerResult(resultCode == RESULT_OK ? result : null);
break;
case REQUEST_SELECT_AMIIBO:
// If the user picked a file, as opposed to just backing out.
if (resultCode == MainActivity.RESULT_OK) {
String[] selectedFiles = FileBrowserHelper.getSelectedFiles(result);
if (selectedFiles == null)
return;
onAmiiboSelected(selectedFiles[0]);
}
break;
if (requestCode == StillImageCameraHelper.REQUEST_CAMERA_FILE_PICKER) {
StillImageCameraHelper.OnFilePickerResult(resultCode == RESULT_OK ? result : null);
}
}
@ -564,11 +578,10 @@ public final class EmulationActivity extends AppCompatActivity {
}
if (!success) {
new AlertDialog.Builder(this)
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.amiibo_load_error)
.setMessage(R.string.amiibo_load_error_message)
.setPositiveButton(android.R.string.ok, null)
.create()
.show();
}
}
@ -580,8 +593,6 @@ public final class EmulationActivity extends AppCompatActivity {
private void toggleControls() {
final SharedPreferences.Editor editor = mPreferences.edit();
boolean[] enabledButtons = new boolean[14];
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.emulation_toggle_controls);
for (int i = 0; i < enabledButtons.length; i++) {
// Buttons that are disabled by default
@ -596,63 +607,47 @@ public final class EmulationActivity extends AppCompatActivity {
enabledButtons[i] = mPreferences.getBoolean("buttonToggle" + i, defaultValue);
}
builder.setMultiChoiceItems(R.array.n3dsButtons, enabledButtons,
(dialog, indexSelected, isChecked) -> editor
.putBoolean("buttonToggle" + indexSelected, isChecked));
builder.setPositiveButton(android.R.string.ok, (dialogInterface, i) ->
{
editor.apply();
mEmulationFragment.refreshInputOverlay();
});
AlertDialog alertDialog = builder.create();
alertDialog.show();
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.emulation_toggle_controls)
.setMultiChoiceItems(R.array.n3dsButtons, enabledButtons,
(dialog, indexSelected, isChecked) -> editor
.putBoolean("buttonToggle" + indexSelected, isChecked))
.setPositiveButton(android.R.string.ok, (dialogInterface, i) ->
{
editor.apply();
mEmulationFragment.refreshInputOverlay();
})
.show();
}
private void adjustScale() {
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.dialog_seekbar, null);
View view = inflater.inflate(R.layout.dialog_slider, null);
final SeekBar seekbar = view.findViewById(R.id.seekbar);
final TextView value = view.findViewById(R.id.text_value);
final Slider slider = view.findViewById(R.id.slider);
final TextView textValue = view.findViewById(R.id.text_value);
final TextView units = view.findViewById(R.id.text_units);
seekbar.setMax(150);
seekbar.setProgress(mPreferences.getInt("controlScale", 50));
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
value.setText(String.valueOf(progress + 50));
}
public void onStopTrackingTouch(SeekBar seekBar) {
setControlScale(seekbar.getProgress());
}
slider.setValueTo(150);
slider.setValue(mPreferences.getInt("controlScale", 50));
slider.addOnChangeListener((slider1, progress, fromUser) -> {
textValue.setText(String.valueOf((int) progress + 50));
setControlScale((int) slider1.getValue());
});
value.setText(String.valueOf(seekbar.getProgress() + 50));
textValue.setText(String.valueOf((int) slider.getValue() + 50));
units.setText("%");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.emulation_control_scale);
builder.setView(view);
final int previousProgress = seekbar.getProgress();
builder.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> {
setControlScale(previousProgress);
});
builder.setPositiveButton(android.R.string.ok, (dialogInterface, i) ->
{
setControlScale(seekbar.getProgress());
});
builder.setNeutralButton(R.string.slider_default, (dialogInterface, i) -> {
setControlScale(50);
});
final int previousProgress = (int) slider.getValue();
AlertDialog alertDialog = builder.create();
alertDialog.show();
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.emulation_control_scale)
.setView(view)
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> setControlScale(previousProgress))
.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> setControlScale((int) slider.getValue()))
.setNeutralButton(R.string.slider_default, (dialogInterface, i) -> setControlScale(50))
.show();
}
private void setControlScale(int scale) {
@ -663,12 +658,10 @@ public final class EmulationActivity extends AppCompatActivity {
}
private void resetOverlay() {
new AlertDialog.Builder(this)
new MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.emulation_touch_overlay_reset))
.setPositiveButton(android.R.string.yes, (dialogInterface, i) -> mEmulationFragment.resetInputOverlay())
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> {
})
.create()
.setNegativeButton(android.R.string.cancel, null)
.show();
}

View File

@ -2,8 +2,6 @@ package org.citra.citra_emu.adapters;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.SystemClock;
import android.view.LayoutInflater;
@ -12,20 +10,20 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.color.MaterialColors;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.R;
import org.citra.citra_emu.activities.EmulationActivity;
import org.citra.citra_emu.model.GameDatabase;
import org.citra.citra_emu.ui.DividerItemDecoration;
import org.citra.citra_emu.utils.FileUtil;
import org.citra.citra_emu.utils.Log;
import org.citra.citra_emu.utils.PicassoUtils;
import org.citra.citra_emu.viewholders.GameViewHolder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
/**
@ -88,8 +86,14 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
holder.textGameTitle.setText(mCursor.getString(GameDatabase.GAME_COLUMN_TITLE).replaceAll("[\\t\\n\\r]+", " "));
holder.textCompany.setText(mCursor.getString(GameDatabase.GAME_COLUMN_COMPANY));
final Path gamePath = Paths.get(mCursor.getString(GameDatabase.GAME_COLUMN_PATH));
holder.textFileName.setText(gamePath.getFileName().toString());
String filepath = mCursor.getString(GameDatabase.GAME_COLUMN_PATH);
String filename;
if (FileUtil.isNativePath(filepath)) {
filename = CitraApplication.documentsTree.getFilename(filepath);
} else {
filename = FileUtil.getFilename(CitraApplication.getAppContext(), filepath);
}
holder.textFileName.setText(filename);
// TODO These shouldn't be necessary once the move to a DB-based model is complete.
holder.gameId = mCursor.getString(GameDatabase.GAME_COLUMN_GAME_ID);
@ -99,9 +103,9 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
holder.regions = mCursor.getString(GameDatabase.GAME_COLUMN_REGIONS);
holder.company = mCursor.getString(GameDatabase.GAME_COLUMN_COMPANY);
final int backgroundColorId = isValidGame(holder.path) ? R.color.card_view_background : R.color.card_view_disabled;
final int backgroundColorId = isValidGame(holder.path) ? R.attr.colorSurface : R.attr.colorErrorContainer;
View itemView = holder.getItemView();
itemView.setBackgroundColor(ContextCompat.getColor(itemView.getContext(), backgroundColorId));
itemView.setBackgroundColor(MaterialColors.getColor(itemView, backgroundColorId));
} else {
Log.error("[GameAdapter] Can't bind view; Cursor is not valid.");
}
@ -204,24 +208,6 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
EmulationActivity.launch((FragmentActivity) view.getContext(), holder.path, holder.title);
}
public static class SpacesItemDecoration extends DividerItemDecoration {
private int space;
public SpacesItemDecoration(Drawable divider, int space) {
super(divider);
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, @NonNull View view, @NonNull RecyclerView parent,
@NonNull RecyclerView.State state) {
outRect.left = 0;
outRect.right = 0;
outRect.bottom = space;
outRect.top = 0;
}
}
private boolean isValidGame(String path) {
return Stream.of(
".rar", ".zip", ".7z", ".torrent", ".tar", ".gz").noneMatch(suffix -> path.toLowerCase().endsWith(suffix));

View File

@ -22,6 +22,8 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
public final class MiiSelector {
public static class MiiSelectorConfig implements java.io.Serializable {
public boolean enable_cancel_button;
@ -69,8 +71,8 @@ public final class MiiSelector {
? (int) config.initially_selected_mii_index
: 0;
data.index = initialIndex;
AlertDialog.Builder builder =
new AlertDialog.Builder(emulationActivity)
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(emulationActivity)
.setTitle(config.title.isEmpty()
? emulationActivity.getString(R.string.mii_selector)
: config.title)

View File

@ -19,6 +19,8 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.R;
@ -124,7 +126,7 @@ public final class SoftwareKeyboard {
FrameLayout container = new FrameLayout(emulationActivity);
container.addView(editText);
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity)
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(emulationActivity)
.setTitle(R.string.software_keyboard)
.setView(container);
setCancelable(false);
@ -227,7 +229,7 @@ public final class SoftwareKeyboard {
break;
}
new AlertDialog.Builder(emulationActivity)
new MaterialAlertDialogBuilder(emulationActivity)
.setTitle(R.string.software_keyboard)
.setMessage(message)
.setPositiveButton(android.R.string.ok, null)

View File

@ -0,0 +1,24 @@
package org.citra.citra_emu.contracts;
import android.content.Context;
import android.content.Intent;
import android.util.Pair;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class OpenFileResultContract extends ActivityResultContract<Boolean, Intent> {
@NonNull
@Override
public Intent createIntent(@NonNull Context context, Boolean allowMultiple) {
return new Intent(Intent.ACTION_OPEN_DOCUMENT)
.setType("application/octet-stream")
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultiple);
}
@Override
public Intent parseResult(int i, @Nullable Intent intent) {
return intent;
}
}

View File

@ -0,0 +1,91 @@
package org.citra.citra_emu.dialogs;
import android.app.Dialog;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Objects;
import org.citra.citra_emu.R;
import org.citra.citra_emu.utils.FileUtil;
import org.citra.citra_emu.utils.PermissionsHandler;
public class CitraDirectoryDialog extends DialogFragment {
public static final String TAG = "citra_directory_dialog_fragment";
private static final String MOVE_DATE_ENABLE = "IS_MODE_DATA_ENABLE";
TextView pathView;
TextView spaceView;
CheckBox checkBox;
AlertDialog dialog;
Listener listener;
public interface Listener {
void onPressPositiveButton(boolean moveData, Uri path);
}
public static CitraDirectoryDialog newInstance(String path, Listener listener) {
CitraDirectoryDialog frag = new CitraDirectoryDialog();
frag.listener = listener;
Bundle args = new Bundle();
args.putString("path", path);
frag.setArguments(args);
return frag;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final FragmentActivity activity = requireActivity();
final Uri path = Uri.parse(Objects.requireNonNull(requireArguments().getString("path")));
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
String freeSpaceText =
getResources().getString(R.string.free_space, FileUtil.getFreeSpace(activity, path));
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.dialog_citra_directory, null);
checkBox = view.findViewById(R.id.checkBox);
pathView = view.findViewById(R.id.path);
spaceView = view.findViewById(R.id.space);
checkBox.setChecked(mPreferences.getBoolean(MOVE_DATE_ENABLE, true));
if (!PermissionsHandler.hasWriteAccess(activity)) {
checkBox.setVisibility(View.GONE);
}
checkBox.setOnCheckedChangeListener(
(v, isChecked)
// record move data selection with SharedPreferences
-> mPreferences.edit().putBoolean(MOVE_DATE_ENABLE, checkBox.isChecked()).apply());
pathView.setText(path.getPath());
spaceView.setText(freeSpaceText);
setCancelable(false);
dialog = new MaterialAlertDialogBuilder(activity)
.setView(view)
.setIcon(R.mipmap.ic_launcher)
.setTitle(R.string.app_name)
.setPositiveButton(
android.R.string.ok,
(d, v) -> listener.onPressPositiveButton(checkBox.isChecked(), path))
.setNegativeButton(android.R.string.cancel, null)
.create();
return dialog;
}
}

View File

@ -0,0 +1,61 @@
package org.citra.citra_emu.dialogs;
import android.app.Dialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.citra.citra_emu.R;
public class CopyDirProgressDialog extends DialogFragment {
public static final String TAG = "copy_dir_progress_dialog";
ProgressBar progressBar;
TextView progressText;
AlertDialog dialog;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final FragmentActivity activity = requireActivity();
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.dialog_progress_bar, null);
progressBar = view.findViewById(R.id.progress_bar);
progressText = view.findViewById(R.id.progress_text);
progressText.setText("");
setCancelable(false);
dialog = new MaterialAlertDialogBuilder(activity)
.setView(view)
.setIcon(R.mipmap.ic_launcher)
.setTitle(R.string.move_data)
.setMessage("")
.create();
return dialog;
}
public void onUpdateSearchProgress(String msg) {
requireActivity().runOnUiThread(() -> {
dialog.setMessage(getResources().getString(R.string.searching_direcotry, msg));
});
}
public void onUpdateCopyProgress(String msg, int progress, int max) {
requireActivity().runOnUiThread(() -> {
progressBar.setProgress(progress);
progressBar.setMax(max);
progressText.setText(String.format("%d/%d", progress, max));
dialog.setMessage(getResources().getString(R.string.copy_file_name, msg));
});
}
}

View File

@ -6,9 +6,7 @@ package org.citra.citra_emu.disk_shader_cache;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
@ -18,6 +16,8 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.R;
import org.citra.citra_emu.activities.EmulationActivity;
@ -55,10 +55,10 @@ public class DiskShaderCacheProgress {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity emulationActivity = Objects.requireNonNull(getActivity());
final Activity emulationActivity = requireActivity();
final String title = Objects.requireNonNull(Objects.requireNonNull(getArguments()).getString("title"));
final String message = Objects.requireNonNull(Objects.requireNonNull(getArguments()).getString("message"));
final String title = Objects.requireNonNull(requireArguments().getString("title"));
final String message = Objects.requireNonNull(requireArguments().getString("message"));
LayoutInflater inflater = LayoutInflater.from(emulationActivity);
View view = inflater.inflate(R.layout.dialog_progress_bar, null);
@ -70,26 +70,21 @@ public class DiskShaderCacheProgress {
setCancelable(false);
setRetainInstance(true);
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity);
builder.setTitle(title);
builder.setMessage(message);
builder.setView(view);
builder.setNegativeButton(android.R.string.cancel, null);
dialog = builder.create();
dialog.create();
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener((v) -> emulationActivity.onBackPressed());
synchronized (finishLock) {
finishLock.notifyAll();
}
dialog = new MaterialAlertDialogBuilder(emulationActivity)
.setView(view)
.setTitle(title)
.setMessage(message)
.setNegativeButton(android.R.string.cancel, (dialog, which) -> emulationActivity.onBackPressed())
.create();
return dialog;
}
private void onUpdateProgress(String msg, int progress, int max) {
Objects.requireNonNull(getActivity()).runOnUiThread(() -> {
requireActivity().runOnUiThread(() -> {
progressBar.setProgress(progress);
progressBar.setMax(max);
progressText.setText(String.format("%d/%d", progress, max));
@ -133,6 +128,8 @@ public class DiskShaderCacheProgress {
case Complete:
// Workaround for when dialog is dismissed when the app is in the background
fragment.dismissAllowingStateLoss();
emulationActivity.runOnUiThread(emulationActivity::onEmulationStarted);
break;
}
}

View File

@ -11,10 +11,11 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.citra.citra_emu.R;
import org.citra.citra_emu.features.cheats.model.Cheat;
import org.citra.citra_emu.features.cheats.model.CheatsViewModel;
@ -80,12 +81,12 @@ public class CheatDetailsFragment extends Fragment {
private void onDeleteClicked(View view) {
String name = mEditName.getText().toString();
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setMessage(getString(R.string.cheats_delete_confirmation, name));
builder.setPositiveButton(android.R.string.yes,
(dialog, i) -> mViewModel.deleteSelectedCheat());
builder.setNegativeButton(android.R.string.no, null);
builder.show();
new MaterialAlertDialogBuilder(requireContext())
.setMessage(getString(R.string.cheats_delete_confirmation, name))
.setPositiveButton(android.R.string.yes,
(dialog, i) -> mViewModel.deleteSelectedCheat())
.setNegativeButton(android.R.string.no, null)
.show();
}
private void onEditClicked(View view) {

View File

@ -7,6 +7,9 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -19,6 +22,9 @@ import org.citra.citra_emu.features.cheats.model.CheatsViewModel;
import org.citra.citra_emu.ui.DividerItemDecoration;
public class CheatListFragment extends Fragment {
private RecyclerView mRecyclerView;
private FloatingActionButton mFab;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@ -28,19 +34,38 @@ public class CheatListFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
RecyclerView recyclerView = view.findViewById(R.id.cheat_list);
FloatingActionButton fab = view.findViewById(R.id.fab);
mRecyclerView = view.findViewById(R.id.cheat_list);
mFab = view.findViewById(R.id.fab);
CheatsActivity activity = (CheatsActivity) requireActivity();
CheatsViewModel viewModel = new ViewModelProvider(activity).get(CheatsViewModel.class);
recyclerView.setAdapter(new CheatsAdapter(activity, viewModel));
recyclerView.setLayoutManager(new LinearLayoutManager(activity));
recyclerView.addItemDecoration(new DividerItemDecoration(activity, null));
mRecyclerView.setAdapter(new CheatsAdapter(activity, viewModel));
mRecyclerView.setLayoutManager(new LinearLayoutManager(activity));
mRecyclerView.addItemDecoration(new DividerItemDecoration(activity, null));
fab.setOnClickListener(v -> {
mFab.setOnClickListener(v -> {
viewModel.startAddingCheat();
viewModel.openDetailsView();
});
setInsets();
}
private void setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(mRecyclerView, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(0, 0, 0, insets.bottom + getResources().getDimensionPixelSize(R.dimen.spacing_fab_list));
ViewGroup.MarginLayoutParams mlpFab =
(ViewGroup.MarginLayoutParams) mFab.getLayoutParams();
int fabPadding = getResources().getDimensionPixelSize(R.dimen.spacing_large);
mlpFab.leftMargin = insets.left + fabPadding;
mlpFab.bottomMargin = insets.bottom + fabPadding;
mlpFab.rightMargin = insets.right + fabPadding;
mFab.setLayoutParams(mlpFab);
return windowInsets;
});
}
}

View File

@ -10,14 +10,25 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsAnimationCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.slidingpanelayout.widget.SlidingPaneLayout;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.MaterialToolbar;
import org.citra.citra_emu.R;
import org.citra.citra_emu.features.cheats.model.Cheat;
import org.citra.citra_emu.features.cheats.model.CheatsViewModel;
import org.citra.citra_emu.ui.TwoPaneOnBackPressedCallback;
import org.citra.citra_emu.utils.InsetsHelper;
import org.citra.citra_emu.utils.ThemeUtil;
import java.util.List;
public class CheatsActivity extends AppCompatActivity
implements SlidingPaneLayout.PanelSlideListener {
@ -37,16 +48,20 @@ public class CheatsActivity extends AppCompatActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
ThemeUtil.applyTheme(this);
super.onCreate(savedInstanceState);
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
mViewModel = new ViewModelProvider(this).get(CheatsViewModel.class);
mViewModel.load();
setContentView(R.layout.activity_cheats);
mSlidingPaneLayout = findViewById(R.id.sliding_pane_layout);
mCheatList = findViewById(R.id.cheat_list);
mCheatDetails = findViewById(R.id.cheat_details);
mCheatList = findViewById(R.id.cheat_list_container);
mCheatDetails = findViewById(R.id.cheat_details_container);
mCheatListLastFocus = mCheatList;
mCheatDetailsLastFocus = mCheatDetails;
@ -63,7 +78,11 @@ public class CheatsActivity extends AppCompatActivity
mViewModel.getOpenDetailsViewEvent().observe(this, this::openDetailsView);
// Show "Up" button in the action bar for navigation
MaterialToolbar toolbar = findViewById(R.id.toolbar_cheats);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setInsets();
}
@Override
@ -146,8 +165,7 @@ public class CheatsActivity extends AppCompatActivity
}
}
public static void setOnFocusChangeListenerRecursively(@NonNull View view,
View.OnFocusChangeListener listener) {
public static void setOnFocusChangeListenerRecursively(@NonNull View view, View.OnFocusChangeListener listener) {
view.setOnFocusChangeListener(listener);
if (view instanceof ViewGroup) {
@ -158,4 +176,56 @@ public class CheatsActivity extends AppCompatActivity
}
}
}
private void setInsets() {
AppBarLayout appBarLayout = findViewById(R.id.appbar_cheats);
ViewCompat.setOnApplyWindowInsetsListener(mSlidingPaneLayout, (v, windowInsets) -> {
Insets barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
Insets keyboardInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime());
InsetsHelper.insetAppBar(barInsets, appBarLayout);
mSlidingPaneLayout.setPadding(barInsets.left, 0, barInsets.right, 0);
// Set keyboard insets if the system supports smooth keyboard animations
ViewGroup.MarginLayoutParams mlpDetails =
(ViewGroup.MarginLayoutParams) mCheatDetails.getLayoutParams();
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R) {
if (keyboardInsets.bottom > 0) {
mlpDetails.bottomMargin = keyboardInsets.bottom;
} else {
mlpDetails.bottomMargin = barInsets.bottom;
}
} else {
if (mlpDetails.bottomMargin == 0) {
mlpDetails.bottomMargin = barInsets.bottom;
}
}
mCheatDetails.setLayoutParams(mlpDetails);
return windowInsets;
});
// Update the layout for every frame that the keyboard animates in
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
ViewCompat.setWindowInsetsAnimationCallback(mCheatDetails,
new WindowInsetsAnimationCompat.Callback(
WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STOP) {
int keyboardInsets = 0;
int barInsets = 0;
@NonNull
@Override
public WindowInsetsCompat onProgress(@NonNull WindowInsetsCompat insets,
@NonNull List<WindowInsetsAnimationCompat> runningAnimations) {
ViewGroup.MarginLayoutParams mlpDetails =
(ViewGroup.MarginLayoutParams) mCheatDetails.getLayoutParams();
keyboardInsets = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;
barInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom;
mlpDetails.bottomMargin = Math.max(keyboardInsets, barInsets);
mCheatDetails.setLayoutParams(mlpDetails);
return insets;
}
});
}
}
}

View File

@ -8,18 +8,28 @@ import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuInflater;
import android.widget.FrameLayout;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.FragmentTransaction;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.MaterialToolbar;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.R;
import org.citra.citra_emu.utils.DirectoryInitialization;
import org.citra.citra_emu.utils.DirectoryStateReceiver;
import org.citra.citra_emu.utils.EmulationMenuSettings;
import org.citra.citra_emu.utils.InsetsHelper;
import org.citra.citra_emu.utils.ThemeUtil;
public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView {
private static final String ARG_MENU_TAG = "menu_tag";
@ -38,10 +48,13 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeUtil.applyTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
Intent launcher = getIntent();
String gameID = launcher.getStringExtra(ARG_GAME_ID);
String menuTag = launcher.getStringExtra(ARG_MENU_TAG);
@ -49,7 +62,11 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
mPresenter.onCreate(savedInstanceState, menuTag, gameID);
// Show "Back" button in the action bar for navigation
MaterialToolbar toolbar = findViewById(R.id.toolbar_settings);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setInsets();
}
@Override
@ -107,10 +124,10 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
if (addToStack) {
if (areSystemAnimationsEnabled()) {
transaction.setCustomAnimations(
R.animator.settings_enter,
R.animator.settings_exit,
R.animator.settings_pop_enter,
R.animator.setttings_pop_exit);
R.anim.anim_settings_fragment_in,
R.anim.anim_settings_fragment_out,
0,
R.anim.anim_pop_settings_fragment_out);
}
transaction.addToBackStack(null);
@ -212,4 +229,14 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
private SettingsFragment getFragment() {
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
}
private void setInsets() {
AppBarLayout appBar = findViewById(R.id.appbar_settings);
FrameLayout frame = findViewById(R.id.frame_content);
ViewCompat.setOnApplyWindowInsetsListener(frame, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
InsetsHelper.insetAppBar(insets, appBar);
return windowInsets;
});
}
}

View File

@ -3,7 +3,9 @@ package org.citra.citra_emu.features.settings.ui;
import android.content.IntentFilter;
import android.os.Bundle;
import android.text.TextUtils;
import androidx.appcompat.app.AppCompatActivity;
import androidx.documentfile.provider.DocumentFile;
import java.io.File;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.features.settings.model.Settings;
import org.citra.citra_emu.features.settings.utils.SettingsFile;
@ -13,8 +15,6 @@ import org.citra.citra_emu.utils.DirectoryStateReceiver;
import org.citra.citra_emu.utils.Log;
import org.citra.citra_emu.utils.ThemeUtil;
import java.io.File;
public final class SettingsActivityPresenter {
private static final String KEY_SHOULD_SAVE = "should_save";
@ -60,8 +60,8 @@ public final class SettingsActivityPresenter {
}
private void prepareCitraDirectoriesIfNeeded() {
File configFile = new File(DirectoryInitialization.getUserDirectory() + "/config/" + SettingsFile.FILE_NAME_CONFIG + ".ini");
if (!configFile.exists()) {
DocumentFile configFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG);
if (configFile == null || !configFile.exists()) {
Log.error("Citra config file could not be found!");
}
if (DirectoryInitialization.areCitraDirectoriesReady()) {
@ -109,8 +109,6 @@ public final class SettingsActivityPresenter {
mSettings.saveSettings(mView);
}
ThemeUtil.applyTheme();
NativeLibrary.ReloadSettings();
}

View File

@ -6,13 +6,16 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.DatePicker;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.TimePicker;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.slider.Slider;
import org.citra.citra_emu.R;
import org.citra.citra_emu.dialogs.MotionAlertDialog;
import org.citra.citra_emu.features.settings.model.FloatSetting;
@ -41,15 +44,14 @@ import org.citra.citra_emu.utils.Log;
import java.util.ArrayList;
public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder>
implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener {
public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder> implements DialogInterface.OnClickListener, Slider.OnChangeListener {
private SettingsFragmentView mView;
private Context mContext;
private ArrayList<SettingsItem> mSettings;
private SettingsItem mClickedItem;
private int mClickedPosition;
private int mSeekbarProgress;
private int mSliderProgress;
private AlertDialog mDialog;
private TextView mTextSliderValue;
@ -149,11 +151,9 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
int value = getSelectionForSingleChoiceValue(item);
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
builder.setTitle(item.getNameId());
builder.setSingleChoiceItems(item.getChoicesId(), value, this);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getNameId())
.setSingleChoiceItems(item.getChoicesId(), value, this);
mDialog = builder.show();
}
@ -162,11 +162,9 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
int value = getSelectionForSingleChoiceValue(item);
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
builder.setTitle(item.getNameId());
builder.setSingleChoiceItems(item.getChoicesId(), value, this);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getNameId())
.setSingleChoiceItems(item.getChoicesId(), value, this);
mDialog = builder.show();
}
@ -199,11 +197,9 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
public void onStringSingleChoiceClick(StringSingleChoiceSetting item) {
mClickedItem = item;
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
builder.setTitle(item.getNameId());
builder.setSingleChoiceItems(item.getChoicesId(), item.getSelectValueIndex(), this);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getNameId())
.setSingleChoiceItems(item.getChoicesId(), item.getSelectValueIndex(), this);
mDialog = builder.show();
}
@ -226,8 +222,6 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
mClickedItem = item;
mClickedPosition = position;
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
View view = inflater.inflate(R.layout.sysclock_datetime_picker, null);
@ -265,44 +259,45 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
closeDialog();
};
builder.setView(view);
builder.setPositiveButton(android.R.string.ok, ok);
builder.setNegativeButton(android.R.string.cancel, defaultCancelListener);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mView.getActivity())
.setView(view)
.setPositiveButton(android.R.string.ok, ok)
.setNegativeButton(android.R.string.cancel, defaultCancelListener);
mDialog = builder.show();
}
public void onSliderClick(SliderSetting item, int position) {
mClickedItem = item;
mClickedPosition = position;
mSeekbarProgress = item.getSelectedValue();
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
mSliderProgress = item.getSelectedValue();
LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
View view = inflater.inflate(R.layout.dialog_seekbar, null);
View view = inflater.inflate(R.layout.dialog_slider, null);
SeekBar seekbar = view.findViewById(R.id.seekbar);
Slider slider = view.findViewById(R.id.slider);
builder.setTitle(item.getNameId());
builder.setView(view);
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, defaultCancelListener);
builder.setNeutralButton(R.string.slider_default, (DialogInterface dialog, int which) -> {
seekbar.setProgress(item.getDefaultValue());
onClick(dialog, which);
});
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getNameId())
.setView(view)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
.setNeutralButton(R.string.slider_default, (DialogInterface dialog, int which) -> {
slider.setValue(item.getDefaultValue());
onClick(dialog, which);
});
mDialog = builder.show();
mTextSliderValue = view.findViewById(R.id.text_value);
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
mTextSliderValue.setText(String.valueOf(mSliderProgress));
TextView units = view.findViewById(R.id.text_units);
units.setText(item.getUnits());
seekbar.setMin(item.getMin());
seekbar.setMax(item.getMax());
seekbar.setProgress(mSeekbarProgress);
slider.setValueFrom(item.getMin());
slider.setValueTo(item.getMax());
slider.setValue(mSliderProgress);
seekbar.setOnSeekBarChangeListener(this);
slider.addOnChangeListener(this);
}
public void onSubmenuClick(SubmenuSetting item) {
@ -375,19 +370,19 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
closeDialog();
} else if (mClickedItem instanceof SliderSetting) {
SliderSetting sliderSetting = (SliderSetting) mClickedItem;
if (sliderSetting.getSelectedValue() != mSeekbarProgress) {
if (sliderSetting.getSelectedValue() != mSliderProgress) {
mView.onSettingChanged();
}
if (sliderSetting.getSetting() instanceof FloatSetting) {
float value = (float) mSeekbarProgress;
float value = (float) mSliderProgress;
FloatSetting setting = sliderSetting.setSelectedValue(value);
if (setting != null) {
mView.putSetting(setting);
}
} else {
IntSetting setting = sliderSetting.setSelectedValue(mSeekbarProgress);
IntSetting setting = sliderSetting.setSelectedValue(mSliderProgress);
if (setting != null) {
mView.putSetting(setting);
}
@ -397,7 +392,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
}
mClickedItem = null;
mSeekbarProgress = -1;
mSliderProgress = -1;
}
public void closeDialog() {
@ -411,20 +406,6 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mSeekbarProgress = progress;
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
private int getValueForSingleChoiceSelection(SingleChoiceSetting item, int which) {
int valuesId = item.getValuesId();
@ -484,4 +465,10 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
return -1;
}
@Override
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
mSliderProgress = (int) value;
mTextSliderValue.setText(String.valueOf(mSliderProgress));
}
}

View File

@ -8,6 +8,9 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -29,6 +32,8 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
private SettingsAdapter mAdapter;
private RecyclerView mRecyclerView;
public static Fragment newInstance(String menuTag, String gameId) {
SettingsFragment fragment = new SettingsFragment();
@ -71,15 +76,17 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
RecyclerView recyclerView = view.findViewById(R.id.list_settings);
mRecyclerView = view.findViewById(R.id.list_settings);
recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(manager);
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(manager);
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
SettingsActivityView activity = (SettingsActivityView) getActivity();
mPresenter.onViewCreated(activity.getSettings());
setInsets();
}
@Override
@ -133,4 +140,12 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
public void onSettingChanged() {
mActivity.onSettingChanged();
}
private void setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(mRecyclerView, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(insets.left, 0, insets.right, insets.bottom);
return windowInsets;
});
}
}

View File

@ -192,11 +192,15 @@ public final class SettingsFragmentPresenter {
Setting language = systemSection.getSetting(SettingsFile.KEY_LANGUAGE);
Setting systemClock = systemSection.getSetting(SettingsFile.KEY_INIT_CLOCK);
Setting dateTime = systemSection.getSetting(SettingsFile.KEY_INIT_TIME);
Setting pluginLoader = systemSection.getSetting(SettingsFile.KEY_PLUGIN_LOADER);
Setting allowPluginLoader = systemSection.getSetting(SettingsFile.KEY_ALLOW_PLUGIN_LOADER);
sl.add(new SingleChoiceSetting(SettingsFile.KEY_REGION_VALUE, Settings.SECTION_SYSTEM, R.string.emulated_region, 0, R.array.regionNames, R.array.regionValues, -1, region));
sl.add(new SingleChoiceSetting(SettingsFile.KEY_LANGUAGE, Settings.SECTION_SYSTEM, R.string.emulated_language, 0, R.array.languageNames, R.array.languageValues, 1, language));
sl.add(new SingleChoiceSetting(SettingsFile.KEY_INIT_CLOCK, Settings.SECTION_SYSTEM, R.string.init_clock, R.string.init_clock_description, R.array.systemClockNames, R.array.systemClockValues, 0, systemClock));
sl.add(new DateTimeSetting(SettingsFile.KEY_INIT_TIME, Settings.SECTION_SYSTEM, R.string.init_time, R.string.init_time_description, "2000-01-01 00:00:01", dateTime));
sl.add(new CheckBoxSetting(SettingsFile.KEY_PLUGIN_LOADER, Settings.SECTION_SYSTEM, R.string.plugin_loader, R.string.plugin_loader_description, false, pluginLoader));
sl.add(new CheckBoxSetting(SettingsFile.KEY_ALLOW_PLUGIN_LOADER, Settings.SECTION_SYSTEM, R.string.allow_plugin_loader, R.string.allow_plugin_loader_description, true, allowPluginLoader));
}
private void addCameraSettings(ArrayList<SettingsItem> sl) {
@ -351,6 +355,9 @@ public final class SettingsFragmentPresenter {
mView.getActivity().setTitle(R.string.preferences_graphics);
SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER);
Setting graphicsApi = rendererSection.getSetting(SettingsFile.KEY_GRAPHICS_API);
Setting spvShaderGen = rendererSection.getSetting(SettingsFile.KEY_SPIRV_SHADER_GEN);
Setting asyncShaders = rendererSection.getSetting(SettingsFile.KEY_ASYNC_SHADERS);
Setting resolutionFactor = rendererSection.getSetting(SettingsFile.KEY_RESOLUTION_FACTOR);
Setting filterMode = rendererSection.getSetting(SettingsFile.KEY_FILTER_MODE);
Setting shadersAccurateMul = rendererSection.getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL);
@ -367,6 +374,9 @@ public final class SettingsFragmentPresenter {
//Setting preloadTextures = utilitySection.getSetting(SettingsFile.KEY_PRELOAD_TEXTURES);
sl.add(new HeaderSetting(null, null, R.string.renderer, 0));
sl.add(new SingleChoiceSetting(SettingsFile.KEY_GRAPHICS_API, Settings.SECTION_RENDERER, R.string.graphics_api, 0, R.array.graphicsApiNames, R.array.graphicsApiValues, 2, graphicsApi));
sl.add(new CheckBoxSetting(SettingsFile.KEY_SPIRV_SHADER_GEN, Settings.SECTION_RENDERER, R.string.spirv_shader_gen, R.string.spirv_shader_gen_description, true, spvShaderGen));
sl.add(new CheckBoxSetting(SettingsFile.KEY_ASYNC_SHADERS, Settings.SECTION_RENDERER, R.string.async_shaders, R.string.async_shaders_description, false, asyncShaders));
sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, Settings.SECTION_RENDERER, R.string.internal_resolution, R.string.internal_resolution_description, 1, 4, "x", 1, resolutionFactor));
sl.add(new CheckBoxSetting(SettingsFile.KEY_FILTER_MODE, Settings.SECTION_RENDERER, R.string.linear_filtering, R.string.linear_filtering_description, true, filterMode));
sl.add(new CheckBoxSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL, Settings.SECTION_RENDERER, R.string.shaders_accurate_mul, R.string.shaders_accurate_mul_description, false, shadersAccurateMul));
@ -408,11 +418,13 @@ public final class SettingsFragmentPresenter {
Setting hardwareRenderer = rendererSection.getSetting(SettingsFile.KEY_HW_RENDERER);
Setting hardwareShader = rendererSection.getSetting(SettingsFile.KEY_HW_SHADER);
Setting vsyncEnable = rendererSection.getSetting(SettingsFile.KEY_USE_VSYNC);
Setting rendererDebug = rendererSection.getSetting(SettingsFile.KEY_RENDERER_DEBUG);
sl.add(new HeaderSetting(null, null, R.string.debug_warning, 0));
sl.add(new CheckBoxSetting(SettingsFile.KEY_CPU_JIT, Settings.SECTION_CORE, R.string.cpu_jit, R.string.cpu_jit_description, true, useCpuJit, true, mView));
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_RENDERER, Settings.SECTION_RENDERER, R.string.hw_renderer, R.string.hw_renderer_description, true, hardwareRenderer, true, mView));
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_SHADER, Settings.SECTION_RENDERER, R.string.hw_shaders, R.string.hw_shaders_description, true, hardwareShader, true, mView));
sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_VSYNC, Settings.SECTION_RENDERER, R.string.vsync, R.string.vsync_description, true, vsyncEnable));
sl.add(new CheckBoxSetting(SettingsFile.KEY_RENDERER_DEBUG, Settings.SECTION_RENDERER, R.string.renderer_debug, R.string.renderer_debug_description, false, rendererDebug));
}
}

View File

@ -1,48 +0,0 @@
package org.citra.citra_emu.features.settings.ui;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* FrameLayout subclass with few Properties added to simplify animations.
* Don't remove the methods appearing as unused, in order not to break the menu animations
*/
public final class SettingsFrameLayout extends FrameLayout {
private float mVisibleness = 1.0f;
public SettingsFrameLayout(Context context) {
super(context);
}
public SettingsFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public float getYFraction() {
return getY() / getHeight();
}
public void setYFraction(float yFraction) {
final int height = getHeight();
setY((height > 0) ? (yFraction * height) : -9999);
}
public float getVisibleness() {
return mVisibleness;
}
public void setVisibleness(float visibleness) {
setScaleX(visibleness);
setScaleY(visibleness);
setAlpha(visibleness);
}
}

View File

@ -1,6 +1,10 @@
package org.citra.citra_emu.features.settings.utils;
import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.documentfile.provider.DocumentFile;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.NativeLibrary;
@ -18,10 +22,11 @@ import org.citra.citra_emu.utils.Log;
import org.ini4j.Wini;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeMap;
@ -39,6 +44,10 @@ public final class SettingsFile {
public static final String KEY_PREMIUM = "premium";
public static final String KEY_GRAPHICS_API = "graphics_api";
public static final String KEY_SPIRV_SHADER_GEN = "spirv_shader_gen";
public static final String KEY_RENDERER_DEBUG = "renderer_debug";
public static final String KEY_ASYNC_SHADERS = "async_shader_compilation";
public static final String KEY_HW_RENDERER = "use_hw_renderer";
public static final String KEY_HW_SHADER = "use_hw_shader";
public static final String KEY_SHADERS_ACCURATE_MUL = "shaders_accurate_mul";
@ -78,6 +87,8 @@ public final class SettingsFile {
public static final String KEY_IS_NEW_3DS = "is_new_3ds";
public static final String KEY_REGION_VALUE = "region_value";
public static final String KEY_LANGUAGE = "language";
public static final String KEY_PLUGIN_LOADER = "plugin_loader";
public static final String KEY_ALLOW_PLUGIN_LOADER = "allow_plugin_loader";
public static final String KEY_INIT_CLOCK = "init_clock";
public static final String KEY_INIT_TIME = "init_time";
@ -143,13 +154,15 @@ public final class SettingsFile {
* @param view The current view.
* @return An Observable that emits a HashMap of the file's contents, then completes.
*/
static HashMap<String, SettingSection> readFile(final File ini, boolean isCustomGame, SettingsActivityView view) {
static HashMap<String, SettingSection> readFile(final DocumentFile ini, boolean isCustomGame, SettingsActivityView view) {
HashMap<String, SettingSection> sections = new Settings.SettingsSectionMap();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(ini));
Context context = CitraApplication.getAppContext();
InputStream inputStream = context.getContentResolver().openInputStream(ini.getUri());
reader = new BufferedReader(new InputStreamReader(inputStream));
SettingSection current = null;
for (String line; (line = reader.readLine()) != null; ) {
@ -164,11 +177,11 @@ public final class SettingsFile {
}
}
} catch (FileNotFoundException e) {
Log.error("[SettingsFile] File not found: " + ini.getAbsolutePath() + e.getMessage());
Log.error("[SettingsFile] File not found: " + ini.getUri() + e.getMessage());
if (view != null)
view.onSettingsFileNotFound();
} catch (IOException e) {
Log.error("[SettingsFile] Error reading from: " + ini.getAbsolutePath() + e.getMessage());
Log.error("[SettingsFile] Error reading from: " + ini.getUri() + e.getMessage());
if (view != null)
view.onSettingsFileNotFound();
} finally {
@ -176,7 +189,7 @@ public final class SettingsFile {
try {
reader.close();
} catch (IOException e) {
Log.error("[SettingsFile] Error closing: " + ini.getAbsolutePath() + e.getMessage());
Log.error("[SettingsFile] Error closing: " + ini.getUri() + e.getMessage());
}
}
}
@ -210,17 +223,23 @@ public final class SettingsFile {
*/
public static void saveFile(final String fileName, TreeMap<String, SettingSection> sections,
SettingsActivityView view) {
File ini = getSettingsFile(fileName);
DocumentFile ini = getSettingsFile(fileName);
try {
Wini writer = new Wini(ini);
Context context = CitraApplication.getAppContext();
InputStream inputStream = context.getContentResolver().openInputStream(ini.getUri());
Wini writer = new Wini(inputStream);
Set<String> keySet = sections.keySet();
for (String key : keySet) {
SettingSection section = sections.get(key);
writeSection(writer, section);
}
writer.store();
inputStream.close();
OutputStream outputStream = context.getContentResolver().openOutputStream(ini.getUri());
writer.store(outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
view.showToastMessage(CitraApplication.getAppContext().getString(R.string.error_saving, fileName, e.getMessage()), false);
@ -260,14 +279,16 @@ public final class SettingsFile {
return generalSectionName;
}
@NonNull
private static File getSettingsFile(String fileName) {
return new File(
DirectoryInitialization.getUserDirectory() + "/config/" + fileName + ".ini");
public static DocumentFile getSettingsFile(String fileName) {
DocumentFile root = DocumentFile.fromTreeUri(CitraApplication.getAppContext(), Uri.parse(DirectoryInitialization.getUserDirectory()));
DocumentFile configDirectory = root.findFile("config");
return configDirectory.findFile(fileName + ".ini");
}
private static File getCustomGameSettingsFile(String gameId) {
return new File(DirectoryInitialization.getUserDirectory() + "/GameSettings/" + gameId + ".ini");
private static DocumentFile getCustomGameSettingsFile(String gameId) {
DocumentFile root = DocumentFile.fromTreeUri(CitraApplication.getAppContext(), Uri.parse(DirectoryInitialization.getUserDirectory()));
DocumentFile configDirectory = root.findFile("GameSettings");
return configDirectory.findFile(gameId + ".ini");
}
private static SettingSection sectionFromLine(String line, boolean isCustomGame) {

View File

@ -1,120 +0,0 @@
package org.citra.citra_emu.fragments;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.FileProvider;
import com.nononsenseapps.filepicker.FilePickerFragment;
import org.citra.citra_emu.R;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CustomFilePickerFragment extends FilePickerFragment {
private static String ALL_FILES = "*";
private int mTitle;
private static List<String> extensions = Collections.singletonList(ALL_FILES);
@NonNull
@Override
public Uri toUri(@NonNull final File file) {
return FileProvider
.getUriForFile(getContext(),
getContext().getApplicationContext().getPackageName() + ".filesprovider",
file);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mode == MODE_DIR) {
TextView ok = getActivity().findViewById(R.id.nnf_button_ok);
ok.setText(R.string.select_dir);
TextView cancel = getActivity().findViewById(R.id.nnf_button_cancel);
cancel.setVisibility(View.GONE);
}
}
@Override
protected View inflateRootView(LayoutInflater inflater, ViewGroup container) {
View view = super.inflateRootView(inflater, container);
if (mTitle != 0) {
Toolbar toolbar = view.findViewById(com.nononsenseapps.filepicker.R.id.nnf_picker_toolbar);
ViewGroup parent = (ViewGroup) toolbar.getParent();
int index = parent.indexOfChild(toolbar);
View newToolbar = inflater.inflate(R.layout.filepicker_toolbar, toolbar, false);
TextView title = newToolbar.findViewById(R.id.filepicker_title);
title.setText(mTitle);
parent.removeView(toolbar);
parent.addView(newToolbar, index);
}
return view;
}
public void setTitle(int title) {
mTitle = title;
}
public void setAllowedExtensions(String allowedExtensions) {
if (allowedExtensions == null)
return;
extensions = Arrays.asList(allowedExtensions.split(","));
}
@Override
protected boolean isItemVisible(@NonNull final File file) {
// Some users jump to the conclusion that Dolphin isn't able to detect their
// files if the files don't show up in the file picker when mode == MODE_DIR.
// To avoid this, show files even when the user needs to select a directory.
return (showHiddenItems || !file.isHidden()) &&
(file.isDirectory() || extensions.contains(ALL_FILES) ||
extensions.contains(fileExtension(file.getName()).toLowerCase()));
}
@Override
public boolean isCheckable(@NonNull final File file) {
// We need to make a small correction to the isCheckable logic due to
// overriding isItemVisible to show files when mode == MODE_DIR.
// AbstractFilePickerFragment always treats files as checkable when
// allowExistingFile == true, but we don't want files to be checkable when mode == MODE_DIR.
return super.isCheckable(file) && !(mode == MODE_DIR && file.isFile());
}
@Override
public void goUp() {
if (Environment.getExternalStorageDirectory().getPath().equals(mCurrentPath.getPath())) {
goToDir(new File("/storage/"));
return;
}
if (mCurrentPath.equals(new File("/storage/"))){
return;
}
super.goUp();
}
@Override
public void onClickDir(@NonNull View view, @NonNull DirViewHolder viewHolder) {
if(viewHolder.file.equals(new File("/storage/emulated/")))
viewHolder.file = new File("/storage/emulated/0/");
super.onClickDir(view, viewHolder);
}
private static String fileExtension(@NonNull String filename) {
int i = filename.lastIndexOf('.');
return i < 0 ? "" : filename.substring(i + 1);
}
}

View File

@ -0,0 +1,36 @@
package org.citra.citra_emu.model;
import android.net.Uri;
import android.provider.DocumentsContract;
/**
* A struct that is much more "cheaper" than DocumentFile.
* Only contains the information we needed.
*/
public class CheapDocument {
private final String filename;
private final Uri uri;
private final String mimeType;
public CheapDocument(String filename, String mimeType, Uri uri) {
this.filename = filename;
this.mimeType = mimeType;
this.uri = uri;
}
public String getFilename() {
return filename;
}
public Uri getUri() {
return uri;
}
public String getMimeType() {
return mimeType;
}
public boolean isDirectory() {
return mimeType.equals(DocumentsContract.Document.MIME_TYPE_DIR);
}
}

View File

@ -5,8 +5,10 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.utils.FileUtil;
import org.citra.citra_emu.utils.Log;
import java.io.File;
@ -64,10 +66,12 @@ public final class GameDatabase extends SQLiteOpenHelper {
private static final String SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS " + TABLE_NAME_FOLDERS;
private static final String SQL_DELETE_GAMES = "DROP TABLE IF EXISTS " + TABLE_NAME_GAMES;
private final Context mContext;
public GameDatabase(Context context) {
// Superclass constructor builds a database or uses an existing one.
super(context, "games.db", null, DB_VERSION);
mContext = context;
}
@Override
@ -151,9 +155,10 @@ public final class GameDatabase extends SQLiteOpenHelper {
while (folderCursor.moveToNext()) {
String folderPath = folderCursor.getString(FOLDER_COLUMN_PATH);
File folder = new File(folderPath);
Uri folder = Uri.parse(folderPath);
// If the folder is empty because it no longer exists, remove it from the library.
if (!folder.exists()) {
CheapDocument[] files = FileUtil.listFiles(mContext, folder);
if (files.length == 0) {
Log.error(
"[GameDatabase] Folder no longer exists. Removing from the library: " + folderPath);
database.delete(TABLE_NAME_FOLDERS,
@ -161,7 +166,7 @@ public final class GameDatabase extends SQLiteOpenHelper {
new String[]{Long.toString(folderCursor.getLong(COLUMN_DB_ID))});
}
addGamesRecursive(database, folder, allowedExtensions, 3);
addGamesRecursive(database, files, allowedExtensions, 3);
}
fileCursor.close();
@ -173,33 +178,28 @@ public final class GameDatabase extends SQLiteOpenHelper {
database.close();
}
private static void addGamesRecursive(SQLiteDatabase database, File parent, Set<String> allowedExtensions, int depth) {
private void addGamesRecursive(SQLiteDatabase database, CheapDocument[] files,
Set<String> allowedExtensions, int depth) {
if (depth <= 0) {
return;
}
File[] children = parent.listFiles();
if (children != null) {
for (File file : children) {
if (file.isHidden()) {
continue;
}
for (CheapDocument file : files) {
if (file.isDirectory()) {
Set<String> newExtensions = new HashSet<>(Arrays.asList(
".3ds", ".3dsx", ".elf", ".axf", ".cci", ".cxi", ".app"));
CheapDocument[] children = FileUtil.listFiles(mContext, file.getUri());
this.addGamesRecursive(database, children, newExtensions, depth - 1);
} else {
String filename = file.getUri().toString();
if (file.isDirectory()) {
Set<String> newExtensions = new HashSet<>(Arrays.asList(
".3ds", ".3dsx", ".elf", ".axf", ".cci", ".cxi", ".app"));
addGamesRecursive(database, file, newExtensions, depth - 1);
} else {
String filePath = file.getPath();
int extensionStart = filename.lastIndexOf('.');
if (extensionStart > 0) {
String fileExtension = filename.substring(extensionStart);
int extensionStart = filePath.lastIndexOf('.');
if (extensionStart > 0) {
String fileExtension = filePath.substring(extensionStart);
// Check that the file has an extension we care about before trying to read out of it.
if (allowedExtensions.contains(fileExtension.toLowerCase())) {
attemptToAddGame(database, filePath);
}
// Check that the file has an extension we care about before trying to read out of it.
if (allowedExtensions.contains(fileExtension.toLowerCase())) {
attemptToAddGame(database, filename);
}
}
}

View File

@ -1,6 +1,8 @@
package org.citra.citra_emu.ui;
import android.content.Context;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
@ -32,6 +34,13 @@ public class TwoPaneOnBackPressedCallback extends OnBackPressedCallback
@Override
public void onPanelClosed(@NonNull View panel) {
closeKeyboard();
setEnabled(false);
}
private void closeKeyboard() {
InputMethodManager manager = (InputMethodManager) mSlidingPaneLayout.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
manager.hideSoftInputFromWindow(mSlidingPaneLayout.getRootView().getWindowToken(), 0);
}
}

View File

@ -1,35 +1,46 @@
package org.citra.citra_emu.ui.main;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.FrameLayout;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.splashscreen.SplashScreen;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Collections;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import com.google.android.material.appbar.AppBarLayout;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.R;
import org.citra.citra_emu.activities.EmulationActivity;
import org.citra.citra_emu.contracts.OpenFileResultContract;
import org.citra.citra_emu.features.settings.ui.SettingsActivity;
import org.citra.citra_emu.model.GameProvider;
import org.citra.citra_emu.ui.platform.PlatformGamesFragment;
import org.citra.citra_emu.utils.AddDirectoryHelper;
import org.citra.citra_emu.utils.BillingManager;
import org.citra.citra_emu.utils.CitraDirectoryHelper;
import org.citra.citra_emu.utils.DirectoryInitialization;
import org.citra.citra_emu.utils.FileBrowserHelper;
import org.citra.citra_emu.utils.InsetsHelper;
import org.citra.citra_emu.utils.PermissionsHandler;
import org.citra.citra_emu.utils.PicassoUtils;
import org.citra.citra_emu.utils.StartupHandler;
import org.citra.citra_emu.utils.ThemeUtil;
import java.util.Arrays;
import java.util.Collections;
/**
* The main Activity of the Lollipop style UI. Manages several PlatformGamesFragments, which
* individually display a grid of available games for each Fragment, in a tabbed layout.
@ -46,13 +57,72 @@ public final class MainActivity extends AppCompatActivity implements MainView {
private static MenuItem mPremiumButton;
private final CitraDirectoryHelper citraDirectoryHelper = new CitraDirectoryHelper(this, () -> {
// If mPlatformGamesFragment is null means game directory have not been set yet.
if (mPlatformGamesFragment == null) {
mPlatformGamesFragment = new PlatformGamesFragment();
getSupportFragmentManager()
.beginTransaction()
.add(mFrameLayoutId, mPlatformGamesFragment)
.commit();
showGameInstallDialog();
}
});
private final ActivityResultLauncher<Uri> mOpenCitraDirectory =
registerForActivityResult(new ActivityResultContracts.OpenDocumentTree(), result -> {
if (result == null)
return;
citraDirectoryHelper.showCitraDirectoryDialog(result);
});
private final ActivityResultLauncher<Uri> mOpenGameListLauncher =
registerForActivityResult(new ActivityResultContracts.OpenDocumentTree(), result -> {
if (result == null)
return;
int takeFlags =
(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(result, takeFlags);
// When a new directory is picked, we currently will reset the existing games
// database. This effectively means that only one game directory is supported.
// TODO(bunnei): Consider fixing this in the future, or removing code for this.
getContentResolver().insert(GameProvider.URI_RESET, null);
// Add the new directory
mPresenter.onDirectorySelected(result.toString());
});
private final ActivityResultLauncher<Boolean> mOpenFileLauncher =
registerForActivityResult(new OpenFileResultContract(), result -> {
if (result == null)
return;
String[] selectedFiles = FileBrowserHelper.getSelectedFiles(
result, getApplicationContext(), Collections.singletonList("cia"));
if (selectedFiles == null) {
Toast
.makeText(getApplicationContext(), R.string.cia_file_not_found,
Toast.LENGTH_LONG)
.show();
return;
}
NativeLibrary.InstallCIAS(selectedFiles);
mPresenter.refreshGameList();
});
@Override
protected void onCreate(Bundle savedInstanceState) {
ThemeUtil.applyTheme();
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
splashScreen.setKeepOnScreenCondition(
()
-> (PermissionsHandler.hasWriteAccess(this) &&
!DirectoryInitialization.areCitraDirectoriesReady()));
ThemeUtil.applyTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
findViews();
setSupportActionBar(mToolbar);
@ -61,7 +131,7 @@ public final class MainActivity extends AppCompatActivity implements MainView {
mPresenter.onCreate();
if (savedInstanceState == null) {
StartupHandler.HandleInit(this);
StartupHandler.HandleInit(this, mOpenCitraDirectory);
if (PermissionsHandler.hasWriteAccess(this)) {
mPlatformGamesFragment = new PlatformGamesFragment();
getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment)
@ -77,6 +147,8 @@ public final class MainActivity extends AppCompatActivity implements MainView {
// Dismiss previous notifications (should not happen unless a crash occurred)
EmulationActivity.tryDismissRunningNotification(this);
setInsets();
}
@Override
@ -144,7 +216,7 @@ public final class MainActivity extends AppCompatActivity implements MainView {
if (PermissionsHandler.hasWriteAccess(this)) {
SettingsActivity.launch(this, menuTag, "");
} else {
PermissionsHandler.checkWritePermission(this);
PermissionsHandler.checkWritePermission(this, mOpenCitraDirectory);
}
}
@ -152,79 +224,18 @@ public final class MainActivity extends AppCompatActivity implements MainView {
public void launchFileListActivity(int request) {
if (PermissionsHandler.hasWriteAccess(this)) {
switch (request) {
case MainPresenter.REQUEST_SELECT_CITRA_DIRECTORY:
mOpenCitraDirectory.launch(null);
break;
case MainPresenter.REQUEST_ADD_DIRECTORY:
FileBrowserHelper.openDirectoryPicker(this,
MainPresenter.REQUEST_ADD_DIRECTORY,
R.string.select_game_folder,
Arrays.asList("elf", "axf", "cci", "3ds",
"cxi", "app", "3dsx", "cia",
"rar", "zip", "7z", "torrent",
"tar", "gz"));
break;
mOpenGameListLauncher.launch(null);
break;
case MainPresenter.REQUEST_INSTALL_CIA:
FileBrowserHelper.openFilePicker(this, MainPresenter.REQUEST_INSTALL_CIA,
R.string.install_cia_title,
Collections.singletonList("cia"), true);
break;
mOpenFileLauncher.launch(true);
break;
}
} else {
PermissionsHandler.checkWritePermission(this);
}
}
/**
* @param requestCode An int describing whether the Activity that is returning did so successfully.
* @param resultCode An int describing what Activity is giving us this callback.
* @param result The information the returning Activity is providing us.
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) {
super.onActivityResult(requestCode, resultCode, result);
switch (requestCode) {
case MainPresenter.REQUEST_ADD_DIRECTORY:
// If the user picked a file, as opposed to just backing out.
if (resultCode == MainActivity.RESULT_OK) {
// When a new directory is picked, we currently will reset the existing games
// database. This effectively means that only one game directory is supported.
// TODO(bunnei): Consider fixing this in the future, or removing code for this.
getContentResolver().insert(GameProvider.URI_RESET, null);
// Add the new directory
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
}
break;
case MainPresenter.REQUEST_INSTALL_CIA:
// If the user picked a file, as opposed to just backing out.
if (resultCode == MainActivity.RESULT_OK) {
NativeLibrary.InstallCIAS(FileBrowserHelper.getSelectedFiles(result));
mPresenter.refeshGameList();
}
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
DirectoryInitialization.start(this);
mPlatformGamesFragment = new PlatformGamesFragment();
getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment)
.commit();
// Immediately prompt user to select a game directory on first boot
if (mPresenter != null) {
mPresenter.launchFileListActivity(MainPresenter.REQUEST_ADD_DIRECTORY);
}
} else {
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
PermissionsHandler.checkWritePermission(this, mOpenCitraDirectory);
}
}
@ -245,6 +256,18 @@ public final class MainActivity extends AppCompatActivity implements MainView {
}
}
private void showGameInstallDialog() {
new MaterialAlertDialogBuilder(this)
.setIcon(R.mipmap.ic_launcher)
.setTitle(R.string.app_name)
.setMessage(R.string.app_game_install_description)
.setCancelable(false)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok,
(d, v) -> mOpenGameListLauncher.launch(null))
.show();
}
@Override
protected void onDestroy() {
EmulationActivity.tryDismissRunningNotification(this);
@ -266,4 +289,15 @@ public final class MainActivity extends AppCompatActivity implements MainView {
public static void invokePremiumBilling(Runnable callback) {
mBillingManager.invokePremiumBilling(callback);
}
private void setInsets() {
AppBarLayout appBar = findViewById(R.id.appbar);
FrameLayout frame = findViewById(R.id.games_platform_frame);
ViewCompat.setOnApplyWindowInsetsListener(frame, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
InsetsHelper.insetAppBar(insets, appBar);
frame.setPadding(insets.left, 0, insets.right, 0);
return windowInsets;
});
}
}

View File

@ -1,5 +1,6 @@
package org.citra.citra_emu.ui.main;
import android.content.Context;
import android.os.SystemClock;
import org.citra.citra_emu.BuildConfig;
@ -9,10 +10,12 @@ import org.citra.citra_emu.features.settings.model.Settings;
import org.citra.citra_emu.features.settings.utils.SettingsFile;
import org.citra.citra_emu.model.GameDatabase;
import org.citra.citra_emu.utils.AddDirectoryHelper;
import org.citra.citra_emu.utils.PermissionsHandler;
public final class MainPresenter {
public static final int REQUEST_ADD_DIRECTORY = 1;
public static final int REQUEST_INSTALL_CIA = 2;
public static final int REQUEST_SELECT_CITRA_DIRECTORY = 3;
private final MainView mView;
private String mDirToAdd;
@ -25,7 +28,7 @@ public final class MainPresenter {
public void onCreate() {
String versionName = BuildConfig.VERSION_NAME;
mView.setVersionString(versionName);
refeshGameList();
refreshGameList();
}
public void launchFileListActivity(int request) {
@ -46,6 +49,10 @@ public final class MainPresenter {
mView.launchSettingsActivity(SettingsFile.FILE_NAME_CONFIG);
return true;
case R.id.button_select_root:
mView.launchFileListActivity(REQUEST_SELECT_CITRA_DIRECTORY);
return true;
case R.id.button_add_directory:
launchFileListActivity(REQUEST_ADD_DIRECTORY);
return true;
@ -74,9 +81,12 @@ public final class MainPresenter {
mDirToAdd = dir;
}
public void refeshGameList() {
GameDatabase databaseHelper = CitraApplication.databaseHelper;
databaseHelper.scanLibrary(databaseHelper.getWritableDatabase());
mView.refresh();
public void refreshGameList() {
Context context = CitraApplication.getAppContext();
if (PermissionsHandler.hasWriteAccess(context)) {
GameDatabase databaseHelper = CitraApplication.databaseHelper;
databaseHelper.scanLibrary(databaseHelper.getWritableDatabase());
mView.refresh();
}
}
}

View File

@ -7,12 +7,18 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.divider.MaterialDividerItemDecoration;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.R;
import org.citra.citra_emu.adapters.GameAdapter;
@ -49,7 +55,9 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(ContextCompat.getDrawable(getActivity(), R.drawable.gamelist_divider), 1));
MaterialDividerItemDecoration divider = new MaterialDividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL);
divider.setLastItemDecorated(false);
mRecyclerView.addItemDecoration(divider);
// Add swipe down to refresh gesture
final SwipeRefreshLayout pullToRefresh = view.findViewById(R.id.refresh_grid_games);
@ -59,6 +67,11 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
refresh();
pullToRefresh.setRefreshing(false);
});
pullToRefresh.setProgressBackgroundColorSchemeColor(MaterialColors.getColor(pullToRefresh, R.attr.colorPrimary));
pullToRefresh.setColorSchemeColors(MaterialColors.getColor(pullToRefresh, R.attr.colorOnPrimary));
setInsets();
}
@Override
@ -83,4 +96,12 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
mRecyclerView = root.findViewById(R.id.grid_games);
mTextView = root.findViewById(R.id.gamelist_empty_text);
}
private void setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(mRecyclerView, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(0, 0, 0, insets.bottom);
return windowInsets;
});
}
}

View File

@ -0,0 +1,87 @@
package org.citra.citra_emu.utils;
import android.content.Intent;
import android.net.Uri;
import androidx.fragment.app.FragmentActivity;
import java.util.concurrent.Executors;
import org.citra.citra_emu.dialogs.CitraDirectoryDialog;
import org.citra.citra_emu.dialogs.CopyDirProgressDialog;
/**
* Citra directory initialization ui flow controller.
*/
public class CitraDirectoryHelper {
public interface Listener {
void onDirectoryInitialized();
}
private final FragmentActivity mFragmentActivity;
private final Listener mListener;
public CitraDirectoryHelper(FragmentActivity mFragmentActivity, Listener mListener) {
this.mFragmentActivity = mFragmentActivity;
this.mListener = mListener;
}
public void showCitraDirectoryDialog(Uri result) {
CitraDirectoryDialog citraDirectoryDialog = CitraDirectoryDialog.newInstance(
result.toString(), ((moveData, path) -> {
Uri previous = PermissionsHandler.getCitraDirectory();
// Do noting if user select the previous path.
if (path.equals(previous)) {
return;
}
int takeFlags = (Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);
mFragmentActivity.getContentResolver().takePersistableUriPermission(path,
takeFlags);
if (!moveData || previous == null) {
initializeCitraDirectory(path);
mListener.onDirectoryInitialized();
return;
}
// If user check move data, show copy progress dialog.
showCopyDialog(previous, path);
}));
citraDirectoryDialog.show(mFragmentActivity.getSupportFragmentManager(),
CitraDirectoryDialog.TAG);
}
private void showCopyDialog(Uri previous, Uri path) {
CopyDirProgressDialog copyDirProgressDialog = new CopyDirProgressDialog();
copyDirProgressDialog.showNow(mFragmentActivity.getSupportFragmentManager(),
CopyDirProgressDialog.TAG);
// Run copy dir in background
Executors.newSingleThreadExecutor().execute(() -> {
FileUtil.copyDir(
mFragmentActivity, previous.toString(), path.toString(),
new FileUtil.CopyDirListener() {
@Override
public void onSearchProgress(String directoryName) {
copyDirProgressDialog.onUpdateSearchProgress(directoryName);
}
@Override
public void onCopyProgress(String filename, int progress, int max) {
copyDirProgressDialog.onUpdateCopyProgress(filename, progress, max);
}
@Override
public void onComplete() {
initializeCitraDirectory(path);
copyDirProgressDialog.dismissAllowingStateLoss();
mListener.onDirectoryInitialized();
}
});
});
}
private void initializeCitraDirectory(Uri path) {
if (!PermissionsHandler.setCitraDirectory(path.toString()))
return;
DirectoryInitialization.resetCitraDirectoryState();
DirectoryInitialization.start(mFragmentActivity);
}
}

View File

@ -9,19 +9,18 @@ package org.citra.citra_emu.utils;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Environment;
import android.preference.PreferenceManager;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.citra.citra_emu.NativeLibrary;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.atomic.AtomicBoolean;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.NativeLibrary;
/**
* A service that spawns its own thread in order to copy several binary and shader files
@ -49,6 +48,9 @@ public final class DirectoryInitialization {
if (PermissionsHandler.hasWriteAccess(context)) {
if (setCitraUserDirectory()) {
initializeInternalStorage(context);
CitraApplication.documentsTree.setRoot(Uri.parse(userPath));
NativeLibrary.CreateLogFile();
NativeLibrary.LogUserDirectory(userPath);
NativeLibrary.CreateConfigFile();
directoryState = DirectoryInitializationState.CITRA_DIRECTORIES_INITIALIZED;
} else {
@ -75,6 +77,11 @@ public final class DirectoryInitialization {
return directoryState == DirectoryInitializationState.CITRA_DIRECTORIES_INITIALIZED;
}
public static void resetCitraDirectoryState() {
directoryState = null;
isCitraDirectoryInitializationRunning.compareAndSet(true, false);
}
public static String getUserDirectory() {
if (directoryState == null) {
throw new IllegalStateException("DirectoryInitialization has to run at least once!");
@ -88,15 +95,11 @@ public final class DirectoryInitialization {
private static native void SetSysDirectory(String path);
private static boolean setCitraUserDirectory() {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
File externalPath = Environment.getExternalStorageDirectory();
if (externalPath != null) {
userPath = externalPath.getAbsolutePath() + "/citra-emu";
Log.debug("[DirectoryInitialization] User Dir: " + userPath);
// NativeLibrary.SetUserDirectory(userPath);
return true;
}
Uri dataPath = PermissionsHandler.getCitraDirectory();
if (dataPath != null) {
userPath = dataPath.toString();
Log.debug("[DirectoryInitialization] User Dir: " + userPath);
return true;
}
return false;

View File

@ -0,0 +1,271 @@
package org.citra.citra_emu.utils;
import android.content.Context;
import android.net.Uri;
import android.provider.DocumentsContract;
import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.model.CheapDocument;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
/**
* A cached document tree for citra user directory.
* For every filepath which is not startsWith "content://" will need to use this class to traverse.
* For example:
* C++ citra log file directory will be /log/citra_log.txt.
* After DocumentsTree.resolvePath() it will become content URI.
*/
public class DocumentsTree {
private DocumentsNode root;
private final Context context;
public static final String DELIMITER = "/";
public DocumentsTree() {
context = CitraApplication.getAppContext();
}
public void setRoot(Uri rootUri) {
root = null;
root = new DocumentsNode();
root.uri = rootUri;
root.isDirectory = true;
}
public boolean createFile(String filepath, String name) {
DocumentsNode node = resolvePath(filepath);
if (node == null) return false;
if (!node.isDirectory) return false;
if (!node.loaded) structTree(node);
Uri mUri = node.uri;
try {
String filename = URLDecoder.decode(name, FileUtil.DECODE_METHOD);
if (node.children.get(filename) != null) return true;
DocumentFile createdFile = FileUtil.createFile(context, mUri.toString(), name);
if (createdFile == null) return false;
DocumentsNode document = new DocumentsNode(createdFile, false);
document.parent = node;
node.children.put(document.key, document);
return true;
} catch (Exception e) {
Log.error("[DocumentsTree]: Cannot create file, error: " + e.getMessage());
}
return false;
}
public boolean createDir(String filepath, String name) {
DocumentsNode node = resolvePath(filepath);
if (node == null) return false;
if (!node.isDirectory) return false;
if (!node.loaded) structTree(node);
Uri mUri = node.uri;
try {
String filename = URLDecoder.decode(name, FileUtil.DECODE_METHOD);
if (node.children.get(filename) != null) return true;
DocumentFile createdDirectory = FileUtil.createDir(context, mUri.toString(), name);
if (createdDirectory == null) return false;
DocumentsNode document = new DocumentsNode(createdDirectory, true);
document.parent = node;
node.children.put(document.key, document);
return true;
} catch (Exception e) {
Log.error("[DocumentsTree]: Cannot create file, error: " + e.getMessage());
}
return false;
}
public int openContentUri(String filepath, String openmode) {
DocumentsNode node = resolvePath(filepath);
if (node == null) {
return -1;
}
return FileUtil.openContentUri(context, node.uri.toString(), openmode);
}
public String getFilename(String filepath) {
DocumentsNode node = resolvePath(filepath);
if (node == null) {
return "";
}
return node.name;
}
public String[] getFilesName(String filepath) {
DocumentsNode node = resolvePath(filepath);
if (node == null || !node.isDirectory) {
return new String[0];
}
// If this directory have not been iterate struct it.
if (!node.loaded) structTree(node);
return node.children.keySet().toArray(new String[0]);
}
public long getFileSize(String filepath) {
DocumentsNode node = resolvePath(filepath);
if (node == null || node.isDirectory) {
return 0;
}
return FileUtil.getFileSize(context, node.uri.toString());
}
public boolean isDirectory(String filepath) {
DocumentsNode node = resolvePath(filepath);
if (node == null) return false;
return node.isDirectory;
}
public boolean Exists(String filepath) {
return resolvePath(filepath) != null;
}
public boolean copyFile(String sourcePath, String destinationParentPath, String destinationFilename) {
DocumentsNode sourceNode = resolvePath(sourcePath);
if (sourceNode == null) return false;
DocumentsNode destinationNode = resolvePath(destinationParentPath);
if (destinationNode == null) return false;
try {
DocumentFile destinationParent = DocumentFile.fromTreeUri(context, destinationNode.uri);
if (destinationParent == null) return false;
String filename = URLDecoder.decode(destinationFilename, "UTF-8");
DocumentFile destination = destinationParent.createFile("application/octet-stream", filename);
if (destination == null) return false;
DocumentsNode document = new DocumentsNode();
document.uri = destination.getUri();
document.parent = destinationNode;
document.name = destination.getName();
document.isDirectory = destination.isDirectory();
document.loaded = true;
InputStream input = context.getContentResolver().openInputStream(sourceNode.uri);
OutputStream output = context.getContentResolver().openOutputStream(destination.getUri());
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) != -1) {
output.write(buffer, 0, len);
}
input.close();
output.flush();
output.close();
destinationNode.children.put(document.key, document);
return true;
} catch (Exception e) {
Log.error("[DocumentsTree]: Cannot copy file, error: " + e.getMessage());
}
return false;
}
public boolean renameFile(String filepath, String destinationFilename) {
DocumentsNode node = resolvePath(filepath);
if (node == null) return false;
try {
Uri mUri = node.uri;
String filename = URLDecoder.decode(destinationFilename, FileUtil.DECODE_METHOD);
DocumentsContract.renameDocument(context.getContentResolver(), mUri, filename);
node.rename(filename);
return true;
} catch (Exception e) {
Log.error("[DocumentsTree]: Cannot rename file, error: " + e.getMessage());
}
return false;
}
public boolean deleteDocument(String filepath) {
DocumentsNode node = resolvePath(filepath);
if (node == null) return false;
try {
Uri mUri = node.uri;
if (!DocumentsContract.deleteDocument(context.getContentResolver(), mUri)) {
return false;
}
if (node.parent != null) {
node.parent.children.remove(node.key);
}
return true;
} catch (Exception e) {
Log.error("[DocumentsTree]: Cannot rename file, error: " + e.getMessage());
}
return false;
}
@Nullable
private DocumentsNode resolvePath(String filepath) {
if (root == null)
return null;
StringTokenizer tokens = new StringTokenizer(filepath, DELIMITER, false);
DocumentsNode iterator = root;
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
if (token.isEmpty()) continue;
iterator = find(iterator, token);
if (iterator == null) return null;
}
return iterator;
}
@Nullable
private DocumentsNode find(DocumentsNode parent, String filename) {
if (parent.isDirectory && !parent.loaded) {
structTree(parent);
}
return parent.children.get(filename);
}
/**
* Construct current level directory tree
*
* @param parent parent node of this level
*/
private void structTree(DocumentsNode parent) {
CheapDocument[] documents = FileUtil.listFiles(context, parent.uri);
for (CheapDocument document : documents) {
DocumentsNode node = new DocumentsNode(document);
node.parent = parent;
parent.children.put(node.key, node);
}
parent.loaded = true;
}
private static class DocumentsNode {
private DocumentsNode parent;
private final Map<String, DocumentsNode> children = new HashMap<>();
private String key;
private String name;
private Uri uri;
private boolean loaded = false;
private boolean isDirectory = false;
private DocumentsNode() {}
private DocumentsNode(CheapDocument document) {
name = document.getFilename();
uri = document.getUri();
key = FileUtil.getFilenameWithExtensions(uri);
isDirectory = document.isDirectory();
loaded = !isDirectory;
}
private DocumentsNode(DocumentFile document, boolean isCreateDir) {
name = document.getName();
uri = document.getUri();
key = FileUtil.getFilenameWithExtensions(uri);
isDirectory = isCreateDir;
loaded = true;
}
private void rename(String key) {
if (parent == null) {
return;
}
parent.children.remove(this.key);
this.name = key;
parent.children.put(key, this);
}
}
}

View File

@ -8,7 +8,7 @@ import org.citra.citra_emu.CitraApplication;
public class EmulationMenuSettings {
private static SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
// These must match what is defined in src/core/settings.h
// These must match what is defined in src/common/settings.h
public static final int LayoutOption_Default = 0;
public static final int LayoutOption_SingleScreen = 1;
public static final int LayoutOption_LargeScreen = 2;

View File

@ -1,71 +1,48 @@
package org.citra.citra_emu.utils;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import androidx.documentfile.provider.DocumentFile;
import com.nononsenseapps.filepicker.FilePickerActivity;
import com.nononsenseapps.filepicker.Utils;
import org.citra.citra_emu.activities.CustomFilePickerActivity;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public final class FileBrowserHelper {
public static void openDirectoryPicker(FragmentActivity activity, int requestCode, int title, List<String> extensions) {
Intent i = new Intent(activity, CustomFilePickerActivity.class);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
Environment.getExternalStorageDirectory().getPath());
i.putExtra(CustomFilePickerActivity.EXTRA_TITLE, title);
i.putExtra(CustomFilePickerActivity.EXTRA_EXTENSIONS, String.join(",", extensions));
activity.startActivityForResult(i, requestCode);
}
public static void openFilePicker(FragmentActivity activity, int requestCode, int title,
List<String> extensions, boolean allowMultiple) {
Intent i = new Intent(activity, CustomFilePickerActivity.class);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, allowMultiple);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_FILE);
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
Environment.getExternalStorageDirectory().getPath());
i.putExtra(CustomFilePickerActivity.EXTRA_TITLE, title);
i.putExtra(CustomFilePickerActivity.EXTRA_EXTENSIONS, String.join(",", extensions));
activity.startActivityForResult(i, requestCode);
}
@Nullable
public static String getSelectedDirectory(Intent result) {
// Use the provided utility method to parse the result
List<Uri> files = Utils.getSelectedFilesFromResult(result);
if (!files.isEmpty()) {
File file = Utils.getFileForUri(files.get(0));
return file.getAbsolutePath();
public static String[] getSelectedFiles(Intent result, Context context, List<String> extension) {
ClipData clipData = result.getClipData();
List<DocumentFile> files = new ArrayList<>();
if (clipData == null) {
files.add(DocumentFile.fromSingleUri(context, result.getData()));
} else {
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
Uri uri = item.getUri();
files.add(DocumentFile.fromSingleUri(context, uri));
}
}
return null;
}
@Nullable
public static String[] getSelectedFiles(Intent result) {
// Use the provided utility method to parse the result
List<Uri> files = Utils.getSelectedFilesFromResult(result);
if (!files.isEmpty()) {
String[] paths = new String[files.size()];
for (int i = 0; i < files.size(); i++)
paths[i] = Utils.getFileForUri(files.get(i)).getAbsolutePath();
return paths;
List<String> filePaths = new ArrayList<>();
for (int i = 0; i < files.size(); i++) {
DocumentFile file = files.get(i);
String filename = file.getName();
int extensionStart = filename.lastIndexOf('.');
if (extensionStart > 0) {
String fileExtension = filename.substring(extensionStart + 1);
if (extension.contains(fileExtension)) {
filePaths.add(file.getUri().toString());
}
}
}
if (filePaths.isEmpty()) {
return null;
}
return filePaths.toArray(new String[0]);
}
return null;

View File

@ -1,11 +1,385 @@
package org.citra.citra_emu.utils;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.system.Os;
import android.system.StructStatVfs;
import android.util.Pair;
import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import org.citra.citra_emu.model.CheapDocument;
public class FileUtil {
static final String PATH_TREE = "tree";
static final String DECODE_METHOD = "UTF-8";
static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
static final String TEXT_PLAIN = "text/plain";
public interface CopyDirListener {
void onSearchProgress(String directoryName);
void onCopyProgress(String filename, int progress, int max);
void onComplete();
}
/**
* Create a file from directory with filename.
*
* @param context Application context
* @param directory parent path for file.
* @param filename file display name.
* @return boolean
*/
@Nullable
public static DocumentFile createFile(Context context, String directory, String filename) {
try {
Uri directoryUri = Uri.parse(directory);
DocumentFile parent;
parent = DocumentFile.fromTreeUri(context, directoryUri);
if (parent == null) return null;
filename = URLDecoder.decode(filename, DECODE_METHOD);
int extensionPosition = filename.lastIndexOf('.');
String extension = "";
if (extensionPosition > 0) {
extension = filename.substring(extensionPosition);
}
String mimeType = APPLICATION_OCTET_STREAM;
if (extension.equals(".txt")) {
mimeType = TEXT_PLAIN;
}
DocumentFile isExist = parent.findFile(filename);
if (isExist != null) return isExist;
return parent.createFile(mimeType, filename);
} catch (Exception e) {
Log.error("[FileUtil]: Cannot create file, error: " + e.getMessage());
}
return null;
}
/**
* Create a directory from directory with filename.
*
* @param context Application context
* @param directory parent path for directory.
* @param directoryName directory display name.
* @return boolean
*/
@Nullable
public static DocumentFile createDir(Context context, String directory, String directoryName) {
try {
Uri directoryUri = Uri.parse(directory);
DocumentFile parent;
parent = DocumentFile.fromTreeUri(context, directoryUri);
if (parent == null) return null;
directoryName = URLDecoder.decode(directoryName, DECODE_METHOD);
DocumentFile isExist = parent.findFile(directoryName);
if (isExist != null) return isExist;
return parent.createDirectory(directoryName);
} catch (Exception e) {
Log.error("[FileUtil]: Cannot create file, error: " + e.getMessage());
}
return null;
}
/**
* Open content uri and return file descriptor to JNI.
*
* @param context Application context
* @param path Native content uri path
* @param openmode will be one of "r", "r", "rw", "wa", "rwa"
* @return file descriptor
*/
public static int openContentUri(Context context, String path, String openmode) {
try (ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(Uri.parse(path), openmode)) {
if (parcelFileDescriptor == null) {
Log.error("[FileUtil]: Cannot get the file descriptor from uri: " + path);
return -1;
}
return parcelFileDescriptor.detachFd();
} catch (Exception e) {
Log.error("[FileUtil]: Cannot open content uri, error: " + e.getMessage());
}
return -1;
}
/**
* Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow
* This function will be faster than DocumentFile.listFiles
*
* @param context Application context
* @param uri Directory uri.
* @return CheapDocument lists.
*/
public static CheapDocument[] listFiles(Context context, Uri uri) {
final ContentResolver resolver = context.getContentResolver();
final String[] columns = new String[]{
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
DocumentsContract.Document.COLUMN_DISPLAY_NAME,
DocumentsContract.Document.COLUMN_MIME_TYPE,
};
Cursor c = null;
final List<CheapDocument> results = new ArrayList<>();
try {
String docId;
if (isRootTreeUri(uri)) {
docId = DocumentsContract.getTreeDocumentId(uri);
} else {
docId = DocumentsContract.getDocumentId(uri);
}
final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, docId);
c = resolver.query(childrenUri, columns, null, null, null);
while (c.moveToNext()) {
final String documentId = c.getString(0);
final String documentName = c.getString(1);
final String documentMimeType = c.getString(2);
final Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(uri, documentId);
CheapDocument document = new CheapDocument(documentName, documentMimeType, documentUri);
results.add(document);
}
} catch (Exception e) {
Log.error("[FileUtil]: Cannot list file error: " + e.getMessage());
} finally {
closeQuietly(c);
}
return results.toArray(new CheapDocument[0]);
}
/**
* Check whether given path exists.
*
* @param path Native content uri path
* @return bool
*/
public static boolean Exists(Context context, String path) {
Cursor c = null;
try {
Uri mUri = Uri.parse(path);
final String[] columns = new String[] {DocumentsContract.Document.COLUMN_DOCUMENT_ID};
c = context.getContentResolver().query(mUri, columns, null, null, null);
return c.getCount() > 0;
} catch (Exception e) {
Log.info("[FileUtil] Cannot find file from given path, error: " + e.getMessage());
} finally {
closeQuietly(c);
}
return false;
}
/**
* Check whether given path is a directory
*
* @param path content uri path
* @return bool
*/
public static boolean isDirectory(Context context, String path) {
final ContentResolver resolver = context.getContentResolver();
final String[] columns = new String[] {DocumentsContract.Document.COLUMN_MIME_TYPE};
boolean isDirectory = false;
Cursor c = null;
try {
Uri mUri = Uri.parse(path);
c = resolver.query(mUri, columns, null, null, null);
c.moveToNext();
final String mimeType = c.getString(0);
isDirectory = mimeType.equals(DocumentsContract.Document.MIME_TYPE_DIR);
} catch (Exception e) {
Log.error("[FileUtil]: Cannot list files, error: " + e.getMessage());
} finally {
closeQuietly(c);
}
return isDirectory;
}
/**
* Get file display name from given path
*
* @param path content uri path
* @return String display name
*/
public static String getFilename(Context context, String path) {
final ContentResolver resolver = context.getContentResolver();
final String[] columns = new String[] {DocumentsContract.Document.COLUMN_DISPLAY_NAME};
String filename = "";
Cursor c = null;
try {
Uri mUri = Uri.parse(path);
c = resolver.query(mUri, columns, null, null, null);
c.moveToNext();
filename = c.getString(0);
} catch (Exception e) {
Log.error("[FileUtil]: Cannot get file size, error: " + e.getMessage());
} finally {
closeQuietly(c);
}
return filename;
}
public static String[] getFilesName(Context context, String path) {
Uri uri = Uri.parse(path);
List<String> files = new ArrayList<>();
for (CheapDocument file : FileUtil.listFiles(context, uri)) {
files.add(file.getFilename());
}
return files.toArray(new String[0]);
}
/**
* Get file size from given path.
*
* @param path content uri path
* @return long file size
*/
public static long getFileSize(Context context, String path) {
final ContentResolver resolver = context.getContentResolver();
final String[] columns = new String[] {DocumentsContract.Document.COLUMN_SIZE};
long size = 0;
Cursor c = null;
try {
Uri mUri = Uri.parse(path);
c = resolver.query(mUri, columns, null, null, null);
c.moveToNext();
size = c.getLong(0);
} catch (Exception e) {
Log.error("[FileUtil]: Cannot get file size, error: " + e.getMessage());
} finally {
closeQuietly(c);
}
return size;
}
public static boolean copyFile(Context context, String sourcePath, String destinationParentPath, String destinationFilename) {
try {
Uri sourceUri = Uri.parse(sourcePath);
Uri destinationUri = Uri.parse(destinationParentPath);
DocumentFile destinationParent = DocumentFile.fromTreeUri(context, destinationUri);
if (destinationParent == null) return false;
String filename = URLDecoder.decode(destinationFilename, "UTF-8");
DocumentFile destination = destinationParent.findFile(filename);
if (destination == null) {
destination = destinationParent.createFile("application/octet-stream", filename);
}
if (destination == null) return false;
InputStream input = context.getContentResolver().openInputStream(sourceUri);
OutputStream output = context.getContentResolver().openOutputStream(destination.getUri());
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) != -1) {
output.write(buffer, 0, len);
}
input.close();
output.flush();
output.close();
return true;
} catch (Exception e) {
Log.error("[FileUtil]: Cannot copy file, error: " + e.getMessage());
}
return false;
}
public static void copyDir(Context context, String sourcePath, String destinationPath,
CopyDirListener listener) {
try {
Uri sourceUri = Uri.parse(sourcePath);
Uri destinationUri = Uri.parse(destinationPath);
final List<Pair<CheapDocument, DocumentFile>> files = new ArrayList<>();
final List<Pair<Uri, Uri>> dirs = new ArrayList<>();
dirs.add(new Pair<>(sourceUri, destinationUri));
// Searching all files which need to be copied and struct the directory in destination.
while (!dirs.isEmpty()) {
DocumentFile fromDir = DocumentFile.fromTreeUri(context, dirs.get(0).first);
DocumentFile toDir = DocumentFile.fromTreeUri(context, dirs.get(0).second);
if (fromDir == null || toDir == null)
continue;
Uri fromUri = fromDir.getUri();
if (listener != null) {
listener.onSearchProgress(fromUri.getPath());
}
CheapDocument[] documents = FileUtil.listFiles(context, fromUri);
for (CheapDocument document : documents) {
String filename = document.getFilename();
if (document.isDirectory()) {
DocumentFile target = toDir.findFile(filename);
if (target == null || !target.exists()) {
target = toDir.createDirectory(filename);
}
if (target == null)
continue;
dirs.add(new Pair<>(document.getUri(), target.getUri()));
} else {
DocumentFile target = toDir.findFile(filename);
if (target == null || !target.exists()) {
target =
toDir.createFile(document.getMimeType(), document.getFilename());
}
if (target == null)
continue;
files.add(new Pair<>(document, target));
}
}
dirs.remove(0);
}
int total = files.size();
int progress = 0;
for (Pair<CheapDocument, DocumentFile> file : files) {
DocumentFile to = file.second;
Uri toUri = to.getUri();
String filename = getFilenameWithExtensions(toUri);
String toPath = toUri.getPath();
DocumentFile toParent = to.getParentFile();
if (toParent == null)
continue;
FileUtil.copyFile(context, file.first.getUri().toString(),
toParent.getUri().toString(), filename);
progress++;
if (listener != null) {
listener.onCopyProgress(toPath, progress, total);
}
}
if (listener != null) {
listener.onComplete();
}
} catch (Exception e) {
Log.error("[FileUtil]: Cannot copy directory, error: " + e.getMessage());
}
}
public static boolean renameFile(Context context, String path, String destinationFilename) {
try {
Uri uri = Uri.parse(path);
DocumentsContract.renameDocument(context.getContentResolver(), uri, destinationFilename);
return true;
} catch (Exception e) {
Log.error("[FileUtil]: Cannot rename file, error: " + e.getMessage());
}
return false;
}
public static boolean deleteDocument(Context context, String path) {
try {
Uri uri = Uri.parse(path);
DocumentsContract.deleteDocument(context.getContentResolver(), uri);
return true;
} catch (Exception e) {
Log.error("[FileUtil]: Cannot delete document, error: " + e.getMessage());
}
return false;
}
public static byte[] getBytesFromFile(File file) throws IOException {
final long length = file.length();
@ -21,8 +395,8 @@ public class FileUtil {
int numRead;
try (InputStream is = new FileInputStream(file)) {
while (offset < bytes.length
&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
while (offset < bytes.length &&
(numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
}
@ -34,4 +408,53 @@ public class FileUtil {
return bytes;
}
public static boolean isRootTreeUri(Uri uri) {
final List<String> paths = uri.getPathSegments();
return paths.size() == 2 && PATH_TREE.equals(paths.get(0));
}
public static boolean isNativePath(String path) {
try {
return path.charAt(0) == '/';
} catch (StringIndexOutOfBoundsException e) {
Log.error("[FileUtil] Cannot determine the string is native path or not.");
}
return false;
}
public static String getFilenameWithExtensions(Uri uri) {
final String path = uri.getPath();
final int index = path.lastIndexOf('/');
return path.substring(index + 1);
}
public static double getFreeSpace(Context context, Uri uri) {
try {
Uri docTreeUri = DocumentsContract.buildDocumentUriUsingTree(
uri, DocumentsContract.getTreeDocumentId(uri));
ParcelFileDescriptor pfd =
context.getContentResolver().openFileDescriptor(docTreeUri, "r");
assert pfd != null;
StructStatVfs stats = Os.fstatvfs(pfd.getFileDescriptor());
double spaceInGigaBytes = stats.f_bavail * stats.f_bsize / 1024.0 / 1024 / 1024;
pfd.close();
return spaceInGigaBytes;
} catch (Exception e) {
Log.error("[FileUtil] Cannot get storage size.");
}
return 0;
}
public static void closeQuietly(AutoCloseable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (RuntimeException rethrown) {
throw rethrown;
} catch (Exception ignored) {
}
}
}
}

View File

@ -27,7 +27,7 @@ public class ForegroundService extends Service {
private void showRunningNotification() {
// Intent is used to resume emulation if the notification is clicked
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, EmulationActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
new Intent(this, EmulationActivity.class), PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.app_notification_channel_id))
.setSmallIcon(R.drawable.ic_stat_notification_logo)

View File

@ -13,12 +13,12 @@ import java.nio.IntBuffer;
public class GameIconRequestHandler extends RequestHandler {
@Override
public boolean canHandleRequest(Request data) {
return "iso".equals(data.uri.getScheme());
return "content".equals(data.uri.getScheme()) || data.uri.getScheme() == null;
}
@Override
public Result load(Request request, int networkPolicy) {
String url = request.uri.getHost() + request.uri.getPath();
String url = request.uri.toString();
int[] vector = NativeLibrary.GetIcon(url);
Bitmap bitmap = Bitmap.createBitmap(48, 48, Bitmap.Config.RGB_565);
bitmap.copyPixelsFromBuffer(IntBuffer.wrap(vector));

View File

@ -0,0 +1,33 @@
package org.citra.citra_emu.utils;
import android.content.Context;
import android.content.res.Resources;
import android.view.ViewGroup;
import androidx.core.graphics.Insets;
import com.google.android.material.appbar.AppBarLayout;
public class InsetsHelper {
public static final int THREE_BUTTON_NAVIGATION = 0;
public static final int TWO_BUTTON_NAVIGATION = 1;
public static final int GESTURE_NAVIGATION = 2;
public static void insetAppBar(Insets insets, AppBarLayout appBarLayout)
{
ViewGroup.MarginLayoutParams mlpAppBar =
(ViewGroup.MarginLayoutParams) appBarLayout.getLayoutParams();
mlpAppBar.leftMargin = insets.left;
mlpAppBar.rightMargin = insets.right;
appBarLayout.setLayoutParams(mlpAppBar);
}
public static int getSystemGestureType(Context context) {
Resources resources = context.getResources();
int resourceId = resources.getIdentifier("config_navBarInteractionMode", "integer", "android");
if (resourceId != 0) {
return resources.getInteger(resourceId);
}
return 0;
}
}

View File

@ -1,28 +1,32 @@
package org.citra.citra_emu.utils;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import androidx.core.content.ContextCompat;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.FragmentActivity;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.R;
public class PermissionsHandler {
public static final int REQUEST_CODE_WRITE_PERMISSION = 500;
public static final String CITRA_DIRECTORY = "CITRA_DIRECTORY";
public static final SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
// We use permissions acceptance as an indicator if this is a first boot for the user.
public static boolean isFirstBoot(final FragmentActivity activity) {
return ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
public static boolean isFirstBoot(FragmentActivity activity) {
return !hasWriteAccess(activity.getApplicationContext());
}
@TargetApi(Build.VERSION_CODES.M)
public static boolean checkWritePermission(final FragmentActivity activity) {
public static boolean checkWritePermission(FragmentActivity activity,
ActivityResultLauncher<Uri> launcher) {
if (isFirstBoot(activity)) {
activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_WRITE_PERMISSION);
launcher.launch(null);
return false;
}
@ -30,6 +34,31 @@ public class PermissionsHandler {
}
public static boolean hasWriteAccess(Context context) {
return ContextCompat.checkSelfPermission(context, WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
try {
Uri uri = getCitraDirectory();
if (uri == null)
return false;
int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
context.getContentResolver().takePersistableUriPermission(uri, takeFlags);
DocumentFile root = DocumentFile.fromTreeUri(context, uri);
if (root != null && root.exists()) return true;
context.getContentResolver().releasePersistableUriPermission(uri, takeFlags);
} catch (Exception e) {
Log.error("[PermissionsHandler]: Cannot check citra data directory permission, error: " + e.getMessage());
}
return false;
}
@Nullable
public static Uri getCitraDirectory() {
String directoryString = mPreferences.getString(CITRA_DIRECTORY, "");
if (directoryString.isEmpty()) {
return null;
}
return Uri.parse(directoryString);
}
public static boolean setCitraDirectory(String uriString) {
return mPreferences.edit().putString(CITRA_DIRECTORY, uriString).commit();
}
}

View File

@ -31,7 +31,7 @@ public class PicassoUtils {
public static void loadGameIcon(ImageView imageView, String gamePath) {
Picasso
.get()
.load(Uri.parse("iso:/" + gamePath))
.load(Uri.parse(gamePath))
.fit()
.centerInside()
.config(Bitmap.Config.RGB_565)

View File

@ -1,19 +1,23 @@
package org.citra.citra_emu.utils;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.widget.TextView;
import androidx.activity.result.ActivityResultLauncher;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.citra.citra_emu.R;
import org.citra.citra_emu.activities.EmulationActivity;
public final class StartupHandler {
private static void handlePermissionsCheck(FragmentActivity parent) {
private static void handlePermissionsCheck(FragmentActivity parent,
ActivityResultLauncher<Uri> launcher) {
// Ask the user to grant write permission if it's not already granted
PermissionsHandler.checkWritePermission(parent);
PermissionsHandler.checkWritePermission(parent, launcher);
String start_file = "";
Bundle extras = parent.getIntent().getExtras();
@ -30,16 +34,23 @@ public final class StartupHandler {
}
}
public static void HandleInit(FragmentActivity parent) {
public static void HandleInit(FragmentActivity parent, ActivityResultLauncher<Uri> launcher) {
if (PermissionsHandler.isFirstBoot(parent)) {
// Prompt user with standard first boot disclaimer
new AlertDialog.Builder(parent)
AlertDialog dialog =
new MaterialAlertDialogBuilder(parent)
.setTitle(R.string.app_name)
.setIcon(R.mipmap.ic_launcher)
.setMessage(parent.getResources().getString(R.string.app_disclaimer))
.setMessage(R.string.app_disclaimer)
.setPositiveButton(android.R.string.ok, null)
.setOnDismissListener(dialogInterface -> handlePermissionsCheck(parent))
.setCancelable(false)
.setOnDismissListener(
dialogInterface -> handlePermissionsCheck(parent, launcher))
.show();
TextView textView = dialog.findViewById(android.R.id.message);
if (textView == null)
return;
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}

View File

@ -1,18 +1,32 @@
package org.citra.citra_emu.utils;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.preference.PreferenceManager;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import com.google.android.material.color.MaterialColors;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.R;
import org.citra.citra_emu.features.settings.utils.SettingsFile;
public class ThemeUtil {
private static SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
private static void applyTheme(int designValue) {
public static final float NAV_BAR_ALPHA = 0.9f;
private static void applyTheme(int designValue, AppCompatActivity activity) {
switch (designValue) {
case 0:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
@ -26,9 +40,44 @@ public class ThemeUtil {
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
break;
}
int systemReportedThemeMode = activity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
WindowInsetsControllerCompat windowController = WindowCompat.getInsetsController(activity.getWindow(), activity.getWindow().getDecorView());
windowController.setAppearanceLightStatusBars(systemReportedThemeMode == Configuration.UI_MODE_NIGHT_NO);
windowController.setAppearanceLightNavigationBars(systemReportedThemeMode == Configuration.UI_MODE_NIGHT_NO);
setNavigationBarColor(activity, MaterialColors.getColor(activity.getWindow().getDecorView(), R.attr.colorSurface));
}
public static void applyTheme() {
applyTheme(mPreferences.getInt(SettingsFile.KEY_DESIGN, 0));
public static void applyTheme(AppCompatActivity activity) {
applyTheme(mPreferences.getInt(SettingsFile.KEY_DESIGN, 0), activity);
}
public static void setNavigationBarColor(@NonNull Activity activity, @ColorInt int color) {
int gestureType = InsetsHelper.getSystemGestureType(activity.getApplicationContext());
int orientation = activity.getResources().getConfiguration().orientation;
// Use a solid color when the navigation bar is on the left/right edge of the screen
if ((gestureType == InsetsHelper.THREE_BUTTON_NAVIGATION ||
gestureType == InsetsHelper.TWO_BUTTON_NAVIGATION) &&
orientation == Configuration.ORIENTATION_LANDSCAPE) {
activity.getWindow().setNavigationBarColor(color);
} else if (gestureType == InsetsHelper.THREE_BUTTON_NAVIGATION ||
gestureType == InsetsHelper.TWO_BUTTON_NAVIGATION) {
// Use semi-transparent color when in portrait mode with three/two button navigation to
// partially see list items behind the navigation bar
activity.getWindow().setNavigationBarColor(ThemeUtil.getColorWithOpacity(color, NAV_BAR_ALPHA));
} else {
// Use transparent color when using gesture navigation
activity.getWindow().setNavigationBarColor(
ContextCompat.getColor(activity.getApplicationContext(),
android.R.color.transparent));
}
}
@ColorInt
public static int getColorWithOpacity(@ColorInt int color, float alphaFactor) {
return Color.argb(Math.round(alphaFactor * Color.alpha(color)), Color.red(color),
Color.green(color), Color.blue(color));
}
}

View File

@ -19,14 +19,16 @@ add_library(citra-android SHARED
default_ini.h
emu_window/emu_window.cpp
emu_window/emu_window.h
emu_window/emu_window_gl.cpp
emu_window/emu_window_gl.h
emu_window/emu_window_vk.cpp
emu_window/emu_window_vk.h
game_info.cpp
game_info.h
game_settings.cpp
game_settings.h
id_cache.cpp
id_cache.h
lodepng_image_interface.cpp
lodepng_image_interface.h
mic.cpp
mic.h
native.cpp
@ -36,6 +38,6 @@ add_library(citra-android SHARED
)
target_link_libraries(citra-android PRIVATE audio_core common core input_common network)
target_link_libraries(citra-android PRIVATE android camera2ndk EGL glad inih jnigraphics lodepng log mediandk yuv)
target_link_libraries(citra-android PRIVATE android camera2ndk EGL glad inih jnigraphics log mediandk yuv)
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android)

View File

@ -11,10 +11,10 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/param_package.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/service.h"
#include "core/settings.h"
#include "input_common/main.h"
#include "input_common/udp/client.h"
#include "jni/camera/ndk_camera.h"
@ -25,8 +25,12 @@
Config::Config() {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
sdl2_config_loc = Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) + "config.ini";
sdl2_config = std::make_unique<INIReader>(sdl2_config_loc);
sdl2_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "config.ini";
std::string ini_buffer;
FileUtil::ReadFileToString(true, sdl2_config_loc, ini_buffer);
if (!ini_buffer.empty()) {
sdl2_config = std::make_unique<INIReader>(ini_buffer.c_str(), ini_buffer.size());
}
Reload();
}
@ -35,12 +39,15 @@ Config::~Config() = default;
bool Config::LoadINI(const std::string& default_contents, bool retry) {
const std::string& location = this->sdl2_config_loc;
if (sdl2_config->ParseError() < 0) {
if (sdl2_config == nullptr || sdl2_config->ParseError() < 0) {
if (retry) {
LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location);
Common::FS::CreateFullPath(location);
Common::FS::WriteStringToFile(true, location, default_contents);
sdl2_config = std::make_unique<INIReader>(location); // Reopen file
FileUtil::CreateFullPath(location);
FileUtil::WriteStringToFile(true, location, default_contents);
std::string ini_buffer;
FileUtil::ReadFileToString(true, location, ini_buffer);
sdl2_config =
std::make_unique<INIReader>(ini_buffer.c_str(), ini_buffer.size()); // Reopen file
return LoadINI(default_contents, false);
}
@ -114,7 +121,13 @@ void Config::ReadValues() {
sdl2_config->GetString("Premium", "texture_filter_name", "none");
// Renderer
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", true);
Settings::values.graphics_api =
static_cast<Settings::GraphicsAPI>(sdl2_config->GetInteger("Renderer", "graphics_api", 2));
Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "renderer_debug", false);
Settings::values.async_shader_compilation =
sdl2_config->GetBoolean("Renderer", "async_shader_compilation", true);
Settings::values.spirv_shader_gen =
sdl2_config->GetBoolean("Renderer", "spirv_shader_gen", true);
Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true);
Settings::values.use_hw_shader = sdl2_config->GetBoolean("Renderer", "use_hw_shader", true);
Settings::values.shaders_accurate_mul =
@ -139,9 +152,9 @@ void Config::ReadValues() {
Settings::values.factor_3d =
static_cast<u8>(sdl2_config->GetInteger("Renderer", "factor_3d", 0));
std::string default_shader = "none (builtin)";
if (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph)
if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Anaglyph)
default_shader = "dubois (builtin)";
else if (Settings::values.render_3d == Settings::StereoRenderOption::Interlaced)
else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Interlaced)
default_shader = "horizontal (builtin)";
Settings::values.pp_shader_name =
sdl2_config->GetString("Renderer", "pp_shader_name", default_shader);
@ -186,9 +199,9 @@ void Config::ReadValues() {
sdl2_config->GetBoolean("Utility", "preload_textures", false);
// Audio
Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false);
Settings::values.enable_dsp_lle_multithread =
sdl2_config->GetBoolean("Audio", "enable_dsp_lle_multithread", false);
Settings::values.audio_emulation =
static_cast<Settings::AudioEmulation>(sdl2_config->GetInteger(
"Audio", "audio_emulation", static_cast<int>(Settings::AudioEmulation::HLE)));
Settings::values.sink_id = sdl2_config->GetString("Audio", "output_engine", "auto");
Settings::values.enable_audio_stretching =
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
@ -229,6 +242,10 @@ void Config::ReadValues() {
std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch())
.count();
}
Settings::values.plugin_loader_enabled =
sdl2_config->GetBoolean("System", "plugin_loader", false);
Settings::values.allow_plugin_loader =
sdl2_config->GetBoolean("System", "allow_plugin_loader", true);
// Camera
using namespace Service::CAM;

View File

@ -98,9 +98,21 @@ use_cpu_jit =
cpu_clock_percentage =
[Renderer]
# Whether to render using GLES or OpenGL
# 0: OpenGL, 1 (default): GLES
use_gles =
# Whether to render using OpenGL or Vulkan
# 1: OpenGL, 2 (default): Vulkan
graphics_api =
# Whether to emit PICA fragment shader using SPIRV or GLSL
# 1: SPIR-V (default), 0: GLSL
spirv_shader_gen =
# Whether to use a worker thread for vulkan command buffer recording
# 1: On (default), 0: Off
async_command_recording =
# Whether to enable additional debugging information during emulation
# 1: On, 0 (default): Off
renderer_debug =
# Whether to use software or hardware rendering.
# 0: Software, 1 (default): Hardware
@ -168,9 +180,12 @@ factor_3d =
# The name of the post processing shader to apply.
# Loaded from shaders if render_3d is off or side by side.
# Loaded from shaders/anaglyph if render_3d is anaglyph
pp_shader_name =
# The name of the shader to apply when render_3d is anaglyph.
# Loaded from shaders/anaglyph
anaglyph_shader_name =
# Whether to enable linear filtering or not
# This is required for some shaders to work correctly
# 0: Nearest, 1 (default): Linear
@ -281,6 +296,11 @@ init_clock =
# Note: 3DS can only handle times later then Jan 1 2000
init_time =
# Plugin loader state, if enabled plugins will be loaded from the SD card.
# You can also set if homebrew apps are allowed to enable the plugin loader
plugin_loader =
allow_plugin_loader =
[Camera]
# Which camera engine to use for the right outer camera
# blank: a dummy camera that always returns black image

View File

@ -6,12 +6,9 @@
#include <array>
#include <cstdlib>
#include <string>
#include <android/native_window_jni.h>
#include <glad/glad.h>
#include "common/logging/log.h"
#include "core/settings.h"
#include "common/settings.h"
#include "input_common/main.h"
#include "jni/emu_window/emu_window.h"
#include "jni/id_cache.h"
@ -20,52 +17,6 @@
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
static constexpr std::array<EGLint, 15> egl_attribs{EGL_SURFACE_TYPE,
EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES3_BIT_KHR,
EGL_BLUE_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_RED_SIZE,
8,
EGL_DEPTH_SIZE,
0,
EGL_STENCIL_SIZE,
0,
EGL_NONE};
static constexpr std::array<EGLint, 5> egl_empty_attribs{EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
static constexpr std::array<EGLint, 4> egl_context_attribs{EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
SharedContext_Android::SharedContext_Android(EGLDisplay egl_display, EGLConfig egl_config,
EGLContext egl_share_context)
: egl_display{egl_display}, egl_surface{eglCreatePbufferSurface(egl_display, egl_config,
egl_empty_attribs.data())},
egl_context{eglCreateContext(egl_display, egl_config, egl_share_context,
egl_context_attribs.data())} {
ASSERT_MSG(egl_surface, "eglCreatePbufferSurface() failed!");
ASSERT_MSG(egl_context, "eglCreateContext() failed!");
}
SharedContext_Android::~SharedContext_Android() {
if (!eglDestroySurface(egl_display, egl_surface)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
if (!eglDestroyContext(egl_display, egl_context)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
}
void SharedContext_Android::MakeCurrent() {
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
}
void SharedContext_Android::DoneCurrent() {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
static bool IsPortraitMode() {
return JNI_FALSE != IDCache::GetEnvForThread()->CallStaticBooleanMethod(
IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode());
@ -79,6 +30,10 @@ static void UpdateLandscapeScreenLayout() {
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
render_window = surface;
window_info.type = Frontend::WindowSystemType::Android;
window_info.render_surface = surface;
StopPresenting();
}
@ -98,6 +53,7 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) {
void EmuWindow_Android::OnFramebufferSizeChanged() {
UpdateLandscapeScreenLayout();
const bool is_portrait_mode{IsPortraitMode()};
const int bigger{window_width > window_height ? window_width : window_height};
const int smaller{window_width < window_height ? window_width : window_height};
if (is_portrait_mode) {
@ -107,7 +63,7 @@ void EmuWindow_Android::OnFramebufferSizeChanged() {
}
}
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) {
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) : host_window{surface} {
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android");
if (!surface) {
@ -115,108 +71,10 @@ EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) {
return;
}
window_width = ANativeWindow_getWidth(surface);
window_height = ANativeWindow_getHeight(surface);
Network::Init();
host_window = surface;
if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) {
LOG_CRITICAL(Frontend, "eglGetDisplay() failed");
return;
}
if (eglInitialize(egl_display, 0, 0) != EGL_TRUE) {
LOG_CRITICAL(Frontend, "eglInitialize() failed");
return;
}
if (EGLint egl_num_configs{}; eglChooseConfig(egl_display, egl_attribs.data(), &egl_config, 1,
&egl_num_configs) != EGL_TRUE) {
LOG_CRITICAL(Frontend, "eglChooseConfig() failed");
return;
}
CreateWindowSurface();
if (eglQuerySurface(egl_display, egl_surface, EGL_WIDTH, &window_width) != EGL_TRUE) {
return;
}
if (eglQuerySurface(egl_display, egl_surface, EGL_HEIGHT, &window_height) != EGL_TRUE) {
return;
}
if (egl_context = eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data());
egl_context == EGL_NO_CONTEXT) {
LOG_CRITICAL(Frontend, "eglCreateContext() failed");
return;
}
if (eglSurfaceAttrib(egl_display, egl_surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) !=
EGL_TRUE) {
LOG_CRITICAL(Frontend, "eglSurfaceAttrib() failed");
return;
}
if (core_context = CreateSharedContext(); !core_context) {
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
return;
}
if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) != EGL_TRUE) {
LOG_CRITICAL(Frontend, "eglMakeCurrent() failed");
return;
}
if (!gladLoadGLES2Loader((GLADloadproc)eglGetProcAddress)) {
LOG_CRITICAL(Frontend, "gladLoadGLES2Loader() failed");
return;
}
if (!eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0)) {
LOG_CRITICAL(Frontend, "eglSwapInterval() failed");
return;
}
OnFramebufferSizeChanged();
}
bool EmuWindow_Android::CreateWindowSurface() {
if (!host_window) {
return true;
}
EGLint format{};
eglGetConfigAttrib(egl_display, egl_config, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(host_window, 0, 0, format);
if (egl_surface = eglCreateWindowSurface(egl_display, egl_config, host_window, 0);
egl_surface == EGL_NO_SURFACE) {
return {};
}
return !!egl_surface;
}
void EmuWindow_Android::DestroyWindowSurface() {
if (!egl_surface) {
return;
}
if (eglGetCurrentSurface(EGL_DRAW) == egl_surface) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
if (!eglDestroySurface(egl_display, egl_surface)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
egl_surface = EGL_NO_SURFACE;
}
void EmuWindow_Android::DestroyContext() {
if (!egl_context) {
return;
}
if (eglGetCurrentContext() == egl_context) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
if (!eglDestroyContext(egl_display, egl_context)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
if (!eglTerminate(egl_display)) {
LOG_CRITICAL(Frontend, "eglTerminate() failed");
}
egl_context = EGL_NO_CONTEXT;
egl_display = EGL_NO_DISPLAY;
}
EmuWindow_Android::~EmuWindow_Android() {
@ -224,34 +82,6 @@ EmuWindow_Android::~EmuWindow_Android() {
DestroyContext();
}
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android::CreateSharedContext() const {
return std::make_unique<SharedContext_Android>(egl_display, egl_config, egl_context);
}
void EmuWindow_Android::StopPresenting() {
if (presenting_state == PresentingState::Running) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
presenting_state = PresentingState::Stopped;
}
void EmuWindow_Android::TryPresenting() {
if (presenting_state != PresentingState::Running) {
if (presenting_state == PresentingState::Initial) {
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
presenting_state = PresentingState::Running;
} else {
return;
}
}
eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
if (VideoCore::g_renderer) {
VideoCore::g_renderer->TryPresent(0);
eglSwapBuffers(egl_display, egl_surface);
}
}
void EmuWindow_Android::PollEvents() {
if (!render_window) {
return;

View File

@ -1,42 +1,17 @@
// Copyright 2019 Citra Emulator Project
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "core/frontend/emu_window.h"
struct ANativeWindow;
class SharedContext_Android : public Frontend::GraphicsContext {
public:
SharedContext_Android(EGLDisplay egl_display, EGLConfig egl_config,
EGLContext egl_share_context);
~SharedContext_Android() override;
void MakeCurrent() override;
void DoneCurrent() override;
private:
EGLDisplay egl_display{};
EGLSurface egl_surface{};
EGLContext egl_context{};
};
class EmuWindow_Android : public Frontend::EmuWindow {
public:
EmuWindow_Android(ANativeWindow* surface);
~EmuWindow_Android();
void Present();
/// Called by the onSurfaceChanges() method to change the surface
void OnSurfaceChanged(ANativeWindow* surface);
@ -47,31 +22,34 @@ public:
void OnTouchMoved(int x, int y);
void PollEvents() override;
void MakeCurrent() override;
void DoneCurrent() override;
void TryPresenting();
void StopPresenting();
virtual void TryPresenting() = 0;
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
virtual void StopPresenting() = 0;
private:
protected:
void OnFramebufferSizeChanged();
bool CreateWindowSurface();
void DestroyWindowSurface();
void DestroyContext();
/// Creates the API specific window surface
virtual bool CreateWindowSurface() {}
/// Destroys the API specific window surface
virtual void DestroyWindowSurface() {}
/// Destroys the graphics context
virtual void DestroyContext() {}
protected:
ANativeWindow* render_window{};
ANativeWindow* host_window{};
int window_width{};
int window_height{};
EGLConfig egl_config;
EGLSurface egl_surface{};
EGLContext egl_context{};
EGLDisplay egl_display{};
std::unique_ptr<Frontend::GraphicsContext> core_context;
enum class PresentingState {

View File

@ -0,0 +1,205 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cstdlib>
#include <string>
#include <android/native_window_jni.h>
#include <glad/glad.h>
#include "common/logging/log.h"
#include "common/settings.h"
#include "input_common/main.h"
#include "jni/emu_window/emu_window_gl.h"
#include "jni/id_cache.h"
#include "jni/input_manager.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
static constexpr std::array<EGLint, 15> egl_attribs{EGL_SURFACE_TYPE,
EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES3_BIT_KHR,
EGL_BLUE_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_RED_SIZE,
8,
EGL_DEPTH_SIZE,
0,
EGL_STENCIL_SIZE,
0,
EGL_NONE};
static constexpr std::array<EGLint, 5> egl_empty_attribs{EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
static constexpr std::array<EGLint, 4> egl_context_attribs{EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
class SharedContext_Android : public Frontend::GraphicsContext {
public:
SharedContext_Android(EGLDisplay egl_display, EGLConfig egl_config,
EGLContext egl_share_context)
: egl_display{egl_display}, egl_surface{eglCreatePbufferSurface(egl_display, egl_config,
egl_empty_attribs.data())},
egl_context{eglCreateContext(egl_display, egl_config, egl_share_context,
egl_context_attribs.data())} {
ASSERT_MSG(egl_surface, "eglCreatePbufferSurface() failed!");
ASSERT_MSG(egl_context, "eglCreateContext() failed!");
}
~SharedContext_Android() override {
if (!eglDestroySurface(egl_display, egl_surface)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
if (!eglDestroyContext(egl_display, egl_context)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
}
void MakeCurrent() {
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
}
void DoneCurrent() {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
private:
EGLDisplay egl_display{};
EGLSurface egl_surface{};
EGLContext egl_context{};
};
EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(ANativeWindow* surface)
: EmuWindow_Android{surface} {
if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) {
LOG_CRITICAL(Frontend, "eglGetDisplay() failed");
return;
}
if (eglInitialize(egl_display, 0, 0) != EGL_TRUE) {
LOG_CRITICAL(Frontend, "eglInitialize() failed");
return;
}
if (EGLint egl_num_configs{}; eglChooseConfig(egl_display, egl_attribs.data(), &egl_config, 1,
&egl_num_configs) != EGL_TRUE) {
LOG_CRITICAL(Frontend, "eglChooseConfig() failed");
return;
}
CreateWindowSurface();
if (eglQuerySurface(egl_display, egl_surface, EGL_WIDTH, &window_width) != EGL_TRUE) {
return;
}
if (eglQuerySurface(egl_display, egl_surface, EGL_HEIGHT, &window_height) != EGL_TRUE) {
return;
}
if (egl_context = eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data());
egl_context == EGL_NO_CONTEXT) {
LOG_CRITICAL(Frontend, "eglCreateContext() failed");
return;
}
if (eglSurfaceAttrib(egl_display, egl_surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) !=
EGL_TRUE) {
LOG_CRITICAL(Frontend, "eglSurfaceAttrib() failed");
return;
}
if (core_context = CreateSharedContext(); !core_context) {
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
return;
}
if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) != EGL_TRUE) {
LOG_CRITICAL(Frontend, "eglMakeCurrent() failed");
return;
}
if (!gladLoadGLES2Loader((GLADloadproc)eglGetProcAddress)) {
LOG_CRITICAL(Frontend, "gladLoadGLES2Loader() failed");
return;
}
if (!eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0)) {
LOG_CRITICAL(Frontend, "eglSwapInterval() failed");
return;
}
OnFramebufferSizeChanged();
}
bool EmuWindow_Android_OpenGL::CreateWindowSurface() {
if (!host_window) {
return true;
}
EGLint format{};
eglGetConfigAttrib(egl_display, egl_config, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(host_window, 0, 0, format);
if (egl_surface = eglCreateWindowSurface(egl_display, egl_config, host_window, 0);
egl_surface == EGL_NO_SURFACE) {
return {};
}
return !!egl_surface;
}
void EmuWindow_Android_OpenGL::DestroyWindowSurface() {
if (!egl_surface) {
return;
}
if (eglGetCurrentSurface(EGL_DRAW) == egl_surface) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
if (!eglDestroySurface(egl_display, egl_surface)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
egl_surface = EGL_NO_SURFACE;
}
void EmuWindow_Android_OpenGL::DestroyContext() {
if (!egl_context) {
return;
}
if (eglGetCurrentContext() == egl_context) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
if (!eglDestroyContext(egl_display, egl_context)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
if (!eglTerminate(egl_display)) {
LOG_CRITICAL(Frontend, "eglTerminate() failed");
}
egl_context = EGL_NO_CONTEXT;
egl_display = EGL_NO_DISPLAY;
}
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android_OpenGL::CreateSharedContext() const {
return std::make_unique<SharedContext_Android>(egl_display, egl_config, egl_context);
}
void EmuWindow_Android_OpenGL::StopPresenting() {
if (presenting_state == PresentingState::Running) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
presenting_state = PresentingState::Stopped;
}
void EmuWindow_Android_OpenGL::TryPresenting() {
if (presenting_state != PresentingState::Running) {
if (presenting_state == PresentingState::Initial) {
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
presenting_state = PresentingState::Running;
} else {
return;
}
}
eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
if (VideoCore::g_renderer) {
VideoCore::g_renderer->TryPresent(0);
eglSwapBuffers(egl_display, egl_surface);
}
}

View File

@ -0,0 +1,36 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "jni/emu_window/emu_window.h"
struct ANativeWindow;
class EmuWindow_Android_OpenGL : public EmuWindow_Android {
public:
EmuWindow_Android_OpenGL(ANativeWindow* surface);
~EmuWindow_Android_OpenGL() override = default;
void TryPresenting() override;
void StopPresenting() override;
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
private:
bool CreateWindowSurface() override;
void DestroyWindowSurface() override;
void DestroyContext() override;
private:
EGLConfig egl_config;
EGLSurface egl_surface{};
EGLContext egl_context{};
EGLDisplay egl_display{};
};

View File

@ -0,0 +1,65 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cstdlib>
#include <string>
#include <android/native_window_jni.h>
#include "common/logging/log.h"
#include "common/settings.h"
#include "input_common/main.h"
#include "jni/emu_window/emu_window_vk.h"
#include "jni/id_cache.h"
#include "jni/input_manager.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
class SharedContext_Android : public Frontend::GraphicsContext {};
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(ANativeWindow* surface)
: EmuWindow_Android{surface} {
CreateWindowSurface();
if (core_context = CreateSharedContext(); !core_context) {
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
return;
}
OnFramebufferSizeChanged();
}
bool EmuWindow_Android_Vulkan::CreateWindowSurface() {
if (!host_window) {
return true;
}
window_info.type = Frontend::WindowSystemType::Android;
window_info.render_surface = host_window;
return true;
}
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android_Vulkan::CreateSharedContext() const {
return std::make_unique<SharedContext_Android>();
}
void EmuWindow_Android_Vulkan::StopPresenting() {
presenting_state = PresentingState::Stopped;
}
void EmuWindow_Android_Vulkan::TryPresenting() {
if (presenting_state != PresentingState::Running) {
if (presenting_state == PresentingState::Initial) {
presenting_state = PresentingState::Running;
} else {
return;
}
}
if (VideoCore::g_renderer) {
VideoCore::g_renderer->TryPresent(0);
}
}

View File

@ -0,0 +1,23 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "jni/emu_window/emu_window.h"
struct ANativeWindow;
class EmuWindow_Android_Vulkan : public EmuWindow_Android {
public:
EmuWindow_Android_Vulkan(ANativeWindow* surface);
~EmuWindow_Android_Vulkan() override = default;
void TryPresenting() override;
void StopPresenting() override;
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
private:
bool CreateWindowSurface() override;
};

View File

@ -35,7 +35,7 @@ std::vector<u8> GetSMDHData(std::string physical_name) {
std::string update_path = Service::AM::GetTitleContentPath(
Service::FS::MediaType::SDMC, program_id + 0x0000000E'00000000);
if (!Common::FS::Exists(update_path))
if (!FileUtil::Exists(update_path))
return original_smdh;
std::unique_ptr<Loader::AppLoader> update_loader = Loader::GetLoader(update_path);

View File

@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/settings.h"
#include "common/settings.h"
namespace GameSettings {

View File

@ -2,11 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/android_storage.h"
#include "common/common_paths.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"
#include "core/settings.h"
#include "common/settings.h"
#include "jni/applets/mii_selector.h"
#include "jni/applets/swkbd.h"
#include "jni/camera/still_image_camera.h"
@ -156,13 +157,9 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
// Initialize Logger
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter);
log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
Log::SetGlobalFilter(log_filter);
Log::AddBackend(std::make_unique<Log::LogcatBackend>());
Common::FS::CreateFullPath(Common::FS::GetUserPath(Common::FS::UserPath::LogDir));
Log::AddBackend(std::make_unique<Log::FileBackend>(
Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + LOG_FILE));
LOG_INFO(Frontend, "Logging backend initialised");
// Initialize misc classes
s_savestate_info_class = reinterpret_cast<jclass>(
@ -230,6 +227,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
MiiSelector::InitJNI(env);
SoftwareKeyboard::InitJNI(env);
Camera::StillImage::InitJNI(env);
AndroidStorage::InitJNI(env, s_native_library_class);
return JNI_VERSION;
}
@ -254,6 +252,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
MiiSelector::CleanupJNI(env);
SoftwareKeyboard::CleanupJNI(env);
Camera::StillImage::CleanupJNI(env);
AndroidStorage::CleanupJNI();
}
#ifdef __cplusplus

View File

@ -1,29 +0,0 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <lodepng.h>
#include "common/logging/log.h"
#include "jni/lodepng_image_interface.h"
bool LodePNGImageInterface::DecodePNG(std::vector<u8>& dst, u32& width, u32& height,
const std::string& path) {
u32 lodepng_ret = lodepng::decode(dst, width, height, path);
if (lodepng_ret) {
LOG_CRITICAL(Frontend, "Failed to decode {} because {}", path,
lodepng_error_text(lodepng_ret));
return false;
}
return true;
}
bool LodePNGImageInterface::EncodePNG(const std::string& path, const std::vector<u8>& src,
u32 width, u32 height) {
u32 lodepng_ret = lodepng::encode(path, src, width, height);
if (lodepng_ret) {
LOG_CRITICAL(Frontend, "Failed to encode {} because {}", path,
lodepng_error_text(lodepng_ret));
return false;
}
return true;
}

View File

@ -1,14 +0,0 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/frontend/image_interface.h"
class LodePNGImageInterface final : public Frontend::ImageInterface {
public:
bool DecodePNG(std::vector<u8>& dst, u32& width, u32& height, const std::string& path) override;
bool EncodePNG(const std::string& path, const std::vector<u8>& src, u32 width,
u32 height) override;
};

Some files were not shown because too many files have changed in this diff Show More