Compare commits

...

188 Commits

Author SHA1 Message Date
Zangetsu38 8340bcb07a hack bleach 2017-11-27 22:45:19 +01:00
Zangetsu38 ea84a6588b Update Project to Visual Studio 2017. 2017-11-27 22:45:19 +01:00
Zangetsu38 babaf8b91e Update LLVM 5.0 2017-11-27 22:37:52 +01:00
Zion Nimchuk 3fbc60f7d4 Initial LLVM 5 port 2017-11-27 22:36:32 +01:00
Megamouse 662fe8cc95 [Qt/Input] Improve pad_settings_dialog a bit (#3611)
* Input: further work on remapping Xinput and begin work on remapping DS4

* Input: Improve pad_settings_dialog a bit and begin Remapping for XInput

* Input: begin evdev remapping and change all handlers to use cfg::string

* Input: finish work on remapping evdev

and some more crap

* Input: finish work on remapping Xinput and DS4

* Input: add DS4 Colors to DS4 config

* Input: Improve DS4 deadzone scaling

Jarves made some mistakes, so I'll fix them in the follow up commit

* Input: fix Jarves fixes on DS4 deadzone

and remove unnecessary usage of toUtf8

* Input: add primitive batterychecks to XInput and DS4

* Input: add mmjoystick remapping

* Input: Fix evdev and some Vibration issues

* Input: adjust capabilities to fix stick input for games like LoS 2

also fix threshold slider minimum
also add ps button to all the handlers

* Input: Further evdev work

based on danilaml code review and own debugging:
Fixed path issue, <= 0 issue, some captures, const, axis with same codes.
Adds a map to each device that differentiates negative and positive axis mappings.
adjusted rest of the file to tabs (ListDevices and beginning of threadProc)

* Input: use 20ms vibration update time for xbox one elite controllers.

* Input: Fix return type of Clamp()

* Input: Evdev Fix

* Input: Evdev Optional GetNextButtonPress

presumably better than the other

* Input: review changes

* Input: evdev: fix wrong index in axis handling

move bindpadtodevice down to keep consistency between handlers and not get crazy

* Input: evdev: fix expensive add_device in GetNextButtonPress

* cleanup

* Input: mmjoy: fix type

* Input: evdev: final fixes

* Input: evdev: exclude unnecessary buttons while mapping Xbox 360 or DS4

* Input: add deadzone preview by passing necessary values in callback

use 0.5 of max value for threshold in pad dialog

* Input: get rid of all-uppercase variables
2017-11-28 01:31:15 +04:00
Nekotekina 695b4c1f06 Change sys_usbd_receive_event 2017-11-27 23:15:28 +03:00
Nekotekina d366823949 RSX: fix fix (406E semaphore release) 2017-11-27 23:15:28 +03:00
Nekotekina 33aa2f0b62 Fix log limit 2017-11-27 23:15:28 +03:00
Unknown 917ee472d4 Qt: implement progress_dialog 2017-11-27 23:16:46 +04:00
Unknown 2f7d621fc8 Qt: remove some warnings 2017-11-27 23:16:46 +04:00
VelocityRa 754cdea435 Avoid recreating SwsContext every frame
* Applies to video decoding(`libvdec`) and post-processing(`libvpost`).
2017-11-27 22:35:40 +04:00
scribam 5f07f78c23 CMake minor improvements (#3783)
* cmake: simplify GLEW integration

* cmake: simplify ZLIB integration

* cmake: simplify ALSA detection

* cmake: check C++ compiler and flags instead of C ones

* cmake: bring consistency in Qt packages detection and remove unnecessary related "include_directories"

* cmake: harmonize coding style

* cmake: set CMAKE_INCLUDE_CURRENT_DIR to ON only when necessary
2017-11-27 22:04:55 +04:00
Unknown b22f3d7a55 Qt: change settingsdialog to horizontal layout 2017-11-27 21:35:59 +04:00
Nekotekina 1344f15efd RSX: improve nv406e::semaphore_release 2017-11-26 09:02:37 +03:00
Nekotekina f7803927d9 Fix exitspawn (autoexit option)
Fix other situations affected by this options
2017-11-26 09:02:37 +03:00
Nekotekina 2ac773385f Clamp utime range (Wnd) 2017-11-26 09:02:37 +03:00
scribam 477c6fdedd Update Fedora packages in the README file 2017-11-26 00:11:37 +00:00
scribam 78101a9e57 cmake: remove unused link to ffmpeg libswresample 2017-11-25 14:07:11 +00:00
scribam d05071221e cmake: check if ffmpeg libswscale is present 2017-11-25 14:07:11 +00:00
Nekotekina 7d3a528871 Use Qt for error reports 2017-11-23 20:36:21 +03:00
Nekotekina cc4bc41cf4 Fix free space check (Wnd) 2017-11-23 18:38:05 +03:00
Nekotekina 5fffef74a2 PKG installer update for DLC
Also:
1) Don't ask for overwriting. It's outdated feature.
2) Limit cancellation capabilities.
2017-11-23 18:38:05 +03:00
Nekotekina ddbcbd0f1c Add libpulse-dev to README.md 2017-11-23 18:38:05 +03:00
Nekotekina b60d3a3dae Log: minor improvements 2017-11-23 18:38:05 +03:00
Nekotekina 74c248150b Log sys_fs_utime values 2017-11-23 18:38:05 +03:00
Nekotekina e77d5cf970 Revert ERROR_INVALID_PARAMETERS
I don't want to ignore serious problems in light of easy workarounds.
2017-11-23 18:38:05 +03:00
Nekotekina d32a30bbeb Restore log compression 2017-11-23 18:38:05 +03:00
Nekotekina 868180eacd New logging strategy 2017-11-23 18:38:05 +03:00
Nekotekina c247ebad0c Log: improve messages for multiple RPCS3 instances 2017-11-23 18:38:05 +03:00
Nekotekina 6a5ce475b8 Implement fs::unshare (linux) 2017-11-23 18:38:05 +03:00
Ofek 3628a8593f Fix cellGameBootCheck for disc games (#3771)
Don't return dirName
2017-11-23 16:27:44 +04:00
Ofek 58c42ad9c0 Check sys_spu_thread_group_create's nsize (#3742)
* Check sys_spu_thread_group_create's nsize

* cellSearch callback correction
2017-11-23 02:02:23 +04:00
Megamouse fb52cbb8b2 Trophy: Save dialog state (#3729)
* Trophy: Save dialog state and add show type settings

* SaveDataManager: Save Dialog State

* SaveDataList: Minor Optimization

* Qt: Save icon size on mouseevent resizes

it's a bit slower than using the slider because it saves every single resize. But better than not saving at all for now

* SaveData: Optimize saving to settings a bit

No Saving needed there

* Qt: get rid of all-uppercase enums and namespaces

* Qt/Linux: adjust remaining DX12 tooltip

* Qt: prevent dockwidget contextmenu
2017-11-22 15:11:59 +04:00
Unknown de465cb941 Fix "Exit RPCS3 when process finishes" command line crash
Added force_boot to force boot on cmdline boot.
Load() caused a Stop() that exited the application with "Exit RPCS3 when process finishes" enabled. Now Stop is only called if the emu is not stopped
2017-11-21 03:02:47 +04:00
Jan Beich dd5791a2cc Fixes from FreeBSD package (#3765)
* Thread: unbreak on BSDs after dbc9bdfe02

Utilities/Thread.cpp:1920:2: error: unknown type name 'cpu_set_t'; did you mean 'cpusetid_t'?
        cpu_set_t cs;
        ^~~~~~~~~
        cpusetid_t
/usr/include/sys/types.h:84:22: note: 'cpusetid_t' declared here
typedef __cpusetid_t    cpusetid_t;
                        ^
Utilities/Thread.cpp:1921:2: error: use of undeclared identifier 'CPU_ZERO'
        CPU_ZERO(&cs);
        ^
Utilities/Thread.cpp:1922:2: error: use of undeclared identifier 'CPU_SET'
        CPU_SET(core, &cs);
        ^
Utilities/Thread.cpp:1923:48: error: unknown type name 'cpu_set_t'; did you mean 'cpusetid_t'?
        pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cs);
                                                      ^~~~~~~~~
                                                      cpusetid_t

* JIT: use MAP_32BIT on Linux and FreeBSD

Unless RLIMIT_DATA is low enough FreeBSD by default reserves lower 2Gb
for brk(2) style heap, ignoring mmap(2) address hint requested by RPCS3.
Passing MAP_32BIT fixes the following crash

Assertion failed: ((Type == ELF::R_X86_64_32 && (Value <= UINT32_MAX)) || (Type == ELF::R_X86_64_32S && ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))), function resolveX86_64Relocation, file /usr/ports/devel/llvm40/work/llvm-4.0.1.src/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp, line 287.

* build: unbreak -DVULKAN_PREBUILT with system glslang on Unix

rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:4:10: fatal error: '../../../../Vulkan/glslang/SPIRV/GlslangToSpv.h' file not found
 #include "../../../../Vulkan/glslang/SPIRV/GlslangToSpv.h"
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/VK/VKCommonDecompiler.cpp.o: In function `vk::compile_glsl_to_spv(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, glsl::program_domain, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&)':
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x50e): undefined reference to `glslang::TProgram::TProgram()'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x51d): undefined reference to `glslang::TShader::TShader(EShLanguage)'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x542): undefined reference to `glslang::TShader::setStrings(char const* const*, int)'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x581): undefined reference to `glslang::TShader::parse(TBuiltInResource const*, int, EProfile, bool, bool, EShMessages, glslang::TShader::Includer&)'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x5d6): undefined reference to `glslang::TProgram::link(EShMessages)'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x5f1): undefined reference to `glslang::GlslangToSpv(glslang::TIntermediate const&, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, glslang::SpvOptions*)'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x5ff): undefined reference to `glslang::TShader::getInfoLog()'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x61a): undefined reference to `glslang::TShader::getInfoDebugLog()'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x630): undefined reference to `glslang::TShader::~TShader()'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x63c): undefined reference to `glslang::TProgram::~TProgram()'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x6d2): undefined reference to `glslang::TShader::~TShader()'
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x6de): undefined reference to `glslang::TProgram::~TProgram()'
rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/VK/VKCommonDecompiler.cpp.o: In function `vk::initialize_compiler_context()':
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x6f5): undefined reference to `glslang::InitializeProcess()'
rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/VK/VKCommonDecompiler.cpp.o: In function `vk::finalize_compiler_context()':
rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp:(.text+0x856): undefined reference to `glslang::FinalizeProcess()'

* build/msvc: add missing glslang include directory after 6bb3f1b4d7

"c:\projects\rpcs3\rpcs3\VKGSRender.vcxproj" (default target) (15) ->
(ClCompile target) ->
  Emu\RSX\VK\VKCommonDecompiler.cpp(4): fatal error C1083: Cannot open include file: 'SPIRV/GlslangToSpv.h': No such file or directory [c:\projects\rpcs3\rpcs3\VKGSRender.vcxproj]
2017-11-21 01:56:25 +04:00
Unknown 380f90b097 Handle Win32 error 87 ERROR_INVALID_PARAMETER with fs::error::inval 2017-11-20 17:55:41 +03:00
clienthax 86a34fbb45 Fix regressions caused by network code. (#3702)
* Stub SOCK_DGRAM_P2P to allow some games to load again.

* Add 'support' for unspec sockets
(Have only seen the youtube app using these so far)
2017-11-20 16:42:16 +03:00
kd-11 5d87ef86b5 vk: Reset renderer status whenever a window geometry event is processed 2017-11-20 15:18:57 +03:00
kd-11 df7d52b177 rsx/fp: Give abs higher prio as it invalidates any precision checks 2017-11-20 15:18:57 +03:00
kd-11 f5addbf751 rsx/fp: improve SRC modifier order
- Neg modifier is applied after clamping. Abs has not been tested/proven so precision clamp goes first now, not last
2017-11-20 15:18:57 +03:00
kd-11 a8c0dd649e rsx/fp: RE work on precision modifier bits
- Testing DS2 has revealed clamping bits in SRC1 that were not respected and left negative values reaching the framebuffer
2017-11-20 15:18:57 +03:00
kd-11 bbb3bdf008 rsx: Abort all drawing commands if no swapchain exists
- Should keep nvidia from consuming all device memory when minimized
2017-11-20 15:18:57 +03:00
kd-11 6d2dcbd164 rsx: Enable hw blit engine for local->main memory blit operations as well 2017-11-20 15:18:57 +03:00
kd-11 be6b5922dd rsx: research native texel byte order on cpu readback (WCB) [WIP] 2017-11-20 15:18:57 +03:00
Unknown 59be9dc36e Qt: move "Disable Vertex Cache" option back to gpu tab 2017-11-20 13:36:13 +03:00
Tahir Akhlaq bd0d87ecaf Updates ReadMe for Windows (#3713)
- Includes prebuilt libraries in instructions
2017-11-20 01:10:27 +00:00
Unknown 61ca9df45c Qt: Use global Appicon instead of setting it in every Dialog 2017-11-20 00:34:29 +00:00
scribam 222c0e0fc5 Fix set thread affinity on OS X (#3757) 2017-11-20 02:02:35 +04:00
Zion Nimchuk 12ecba7d49 Initial work on sys_usbd syscalls 2017-11-19 23:11:13 +03:00
scribam 214ea1e0f6 AppVeyor Qt fix 2017-11-19 18:25:13 +00:00
scribam 0870862898 Use zeux/pugixml instead of RPCS3/pugixml 2017-11-19 01:36:12 +04:00
Nekotekina c58738807e Fix cond_variable timeout
Thanks @Farseer2 for debugging
2017-11-18 10:24:17 +03:00
scribam 223f17ac7e Bump CMake requirement 2017-11-16 01:41:51 +04:00
Nekotekina c435b328c7 Implement savedata delete op 2017-11-15 21:00:02 +03:00
Nekotekina 3792a85084 Fix fs::dir (const begin/end) 2017-11-15 21:00:02 +03:00
Nekotekina 0d1cb8c878 Fix cellMsgDialog 2017-11-15 21:00:02 +03:00
Nekotekina 16d7023a92 cellSaveData fixes 2017-11-15 21:00:02 +03:00
Nekotekina 358afc045d Minor fix (cellGame) 2017-11-15 21:00:02 +03:00
Nekotekina 0fbb8b9a18 Implement _sys_prx_load_module_by_fd
Implement _sys_prx_load_module_on_memcontainer_by_fd
2017-11-15 21:00:02 +03:00
Nekotekina 9ef00b4a12 RSX: Rewrite frame limit 2017-11-15 21:00:02 +03:00
Nekotekina 916851bd4a Optimize cpuid 2017-11-15 21:00:02 +03:00
Nekotekina 9bc0ec586a Fix command line args 2017-11-15 21:00:02 +03:00
Nekotekina f4eab09557 Add supporters 2017-11-15 21:00:02 +03:00
Nekotekina f2980d57a1 ALSA audio backend fixes 2017-11-15 21:00:02 +03:00
Nekotekina dbc9bdfe02 Implement set_ideal_processor_core (linux) 2017-11-15 21:00:02 +03:00
clienthax 9e0b881b2b Fire callback in cellSearchInitialize
Allows BLJS10131 to get ingame ;)
2017-11-15 02:26:36 +04:00
clienthax 946ba3be29 Fix bug in sys_spu_thread_group_create (#3734) 2017-11-14 22:24:55 +04:00
Ani 0064976c43 Bump version to 0.0.4 2017-11-12 18:13:22 +00:00
Ani 4bdb6674eb GUI: Style fix for Kuroi (Dark)
Small style fix for Kuroi (Dark) Theme
2017-11-12 18:13:22 +00:00
Ani c7f7d7ef5b Fixes commit count on GIT-VERSION
AppVeyor: Fetches commit count from unshallowed upstream instead of fetching from HEAD (will always be 3 since we clone with depth of 3)
2017-11-12 18:13:22 +00:00
Robbie 2c19fdf092 Fix off by one error in trophies (#3715) 2017-11-12 17:36:13 +00:00
Ofek 8fc9862614 Fix cellGameGet(Set)Param (#3690)
* Fix cellGameGet(Set)Param
2017-11-11 22:22:38 +00:00
Talkashie 55d84414ee Stub sceNpSnsFbCheckConfig (#3720) 2017-11-11 22:18:32 +04:00
Talkashie 8c0bdd71d9 Correct two typos and a couple of other nitpicky things (#3721)
Correct two typos and a couple of other nitpicky things
2017-11-11 12:56:59 +00:00
kd-11 3c9126d91f rsx: Ignore FENCE instruction as it seems like its ignored on realhw
- This is likely a compiler hint for performance reasons and not a mandate
2017-11-09 14:39:50 +03:00
kd-11 8b4836a12f rsx: Fix shader cache version check 2017-11-09 14:39:50 +03:00
kd-11 b2a7eee1ec rsx: Bump shader cache ver and fix blit engine crash
- Disables blit operations if the target will have a size of 0 in any dimension
- Bumps shader cache ver to 1.1
2017-11-09 14:39:50 +03:00
kd-11 ed21bb309f rsx: Minor fixups
- Fix texture cache blit behaviour when src has AA enabled and dst is a blit dst texture with or without AA
-- This requires handling AA resolve by removing a half downscale on multisampled axes

- Return all ones when a vertex attribute is disabled.
-- Some games forget to enable vertex attributes actually needed by the fs
2017-11-08 13:15:34 +03:00
kd-11 7b3e4f5e3d vk: Hotfix
- facepalm: Do not enable depth comparison mode if masquerading as RGBA color!
2017-11-08 13:15:34 +03:00
kd-11 30b3af0d12 vk: Cleanup, simplify renderpass management 2017-11-08 13:15:34 +03:00
kd-11 541cb4062b vk: Fix shader logging
- Do not overwrite logged programs
2017-11-08 13:15:34 +03:00
kd-11 4e9160104a rsx/vk/gl: Cleanup and refector glsl::getFunctionImpl
- Both backends now generate very similar code
2017-11-08 13:15:34 +03:00
kd-11 86fa379c78 rsx/vk: Fix unnormalized converted textures 2017-11-08 13:15:34 +03:00
kd-11 8733505d0a rsx: Minor fixes
- texture_cache: Fix internal size calculation for subresources
- vk: Delay dynamic state updates until just about to draw to ensure no flush has discarded the cb state
2017-11-08 13:15:34 +03:00
kd-11 242611aa46 gl/qt: Catch segfaults in wglDeleteContext with SEH (AMD windows driver)
- In rare cases the driver derefs a nullptr and dies, taking the emulator with it
- From testing, it seems the vram is indeed freed when this happens so its "safe" to continue
2017-11-08 13:15:34 +03:00
kd-11 baa5a261a5 rsx: Rewrite invalidate_range_impl_base in a way that makes sense. Fixes wcb hanging 2017-11-08 13:15:34 +03:00
kd-11 3730b9d1da rsx: More fixes
- Support for raster offsets in surface descriptors (looks to be unused)
- Do not tag disabled render targets when using MRT (pitch = 64)
- Add missing notify_surface_changed() call for openGL
2017-11-08 13:15:34 +03:00
kd-11 0d35363ea0 rsx: Minor optimization - dont update sampler state if texture state registers have not changed 2017-11-08 13:15:34 +03:00
kd-11 75504b3f5e rsx: Rework context handling and stop leaking the GL ccontext
- GL contexts are external handles that require manual lifecycle management
2017-11-08 13:15:34 +03:00
kd-11 4ca98e53a6 rsx: Fix for unnormalized texture access 2017-11-08 13:15:34 +03:00
kd-11 300a36d3d6 rsx: Fixes for cubemap reconstruction
- Do not abort generation if sides are missing, replace with blank surfaces instead
- Make cubemaps scale with res scaling
2017-11-08 13:15:34 +03:00
kd-11 60c7a508a7 rsx: Refactor create_subresource_view(deferred_subresource&) and implement a subresource cache
- This limits the number of times an image is copied and improves performance
2017-11-08 13:15:34 +03:00
kd-11 1fa18757fc rsx: Implement render-to-cubemap; Also simplify unnormalized samplers [WIP, DELETE SHADER CACHE, VERY SLOW]
- Enables real-time cubemap reflections
- TODO: Vulkan is broke; rsx is very slow with this feature
2017-11-08 13:15:34 +03:00
kd-11 fbb7186e66 rsx/gl: Addendum - Fix fragment shader to consume texture scale parameters 2017-11-08 13:15:34 +03:00
kd-11 0961a43997 rsx: Implement 1D<->2D image type casts 2017-11-08 13:15:34 +03:00
kd-11 7037504dcf rsx: Workaround for missing AA flags on some surfaces
- This just doesnt work right yet. It looks like AA is being used dynamically? (RDR)
- TODO: Try to locate flags to set AA if AA mode is not changed
2017-11-08 13:15:34 +03:00
kd-11 2385029eab gl: Shift code around to increase work done after memory transfer operations
- The current code is slower because memory operations are too close to their draw calls
-- This is mainly an issue with proprietary AMD drivers
2017-11-08 13:15:34 +03:00
kd-11 eed55a446c rsx: Minor optimization
- Defer resolving image copy operations to the binding step
2017-11-08 13:15:34 +03:00
kd-11 bbcb6b6851 rsx: Fbo fixes 2
- Use AA mode to predict surface compression. Compression mode is useless without AA activated
- Rewrites most image subresource fetch routines to use the new heuristic
- Fix rsx::thread::find_tile. FEED000(X) can be substituted for (X) in the code
-- Fixes alot of failures when looking for tiled regions

rsx: Fix antialiased unnormalized coords
- scaling factors are inverse to allow proper coordinates to be computed in fs
2017-11-08 13:15:34 +03:00
kd-11 b95630d84a rsx: Minor fixups
- Optimize framebuffer memory invalidate conditions
- Fix texture sampling of AA textures (wider by 2x surfaces)
2017-11-08 13:15:34 +03:00
kd-11 af1d3c2aa6 rsx: Improve surface store resource management
- vk: Use frame testing to determine invalidated resources that can be safely deleted
2017-11-08 13:15:34 +03:00
kd-11 ec3e5c547f rsx: More fixes
- Tag surface store to help determine when contents have been invalidated
- Crop framebuffer textures if they are not the requested dimensions!
2017-11-08 13:15:34 +03:00
kd-11 963a87fed5 rsx: Critical fixes
- Remove generic throws from the rsx pipeline. Stops the rsx thread from silently dying leaving the emulator in a hung state
- Hackplement add_signed and reverse_subtract_signed blend modes
2017-11-08 13:15:34 +03:00
kd-11 173d05b54f rsx: Optimizations
- Reimplement fragment program fetch and rewrite texture upload mechanism
-- All of these steps should only be done at most once per draw call
-- Eliminates continously checking the surface store for overlapping addresses as well

addenda - critical fixes
- gl: Bind TIU before starting texture operations as they will affect the currently bound texture
- vk: Reuse sampler objects if possible
- rsx: Support for depth resampling for depth textures obtained via blit engine

vk/rsx: Minor fixes
- Fix accidental imageview dereference when using WCB if texture memory occupies FB memory
- Invalidate dirty framebuffers (strict mode only)
- Normalize line endings because VS is dumb
2017-11-08 13:15:34 +03:00
Zion Nimchuk 865bb47462 HEAD or master will no longer show up in the titlebar 2017-11-08 12:49:22 +04:00
scribam 3e7ed8a831 PPUTranslator minor changes 2017-11-08 08:34:00 +04:00
Zion 3a49a77c07 Fix git-branch in title... again (#3704)
Fix git-branch in title... again
2017-11-08 01:22:41 +00:00
Zion Nimchuk 6782b22637 Make cellMouseGetDataList return CELL_MOUSE_ERROR_NO_DEVICE if mouse handler is set to null 2017-11-04 19:55:32 +00:00
scribam 4600094829 [RSX] Fix uninitialized value before usage 2017-11-04 01:28:53 +03:00
kd-11 daaa83b9ca rsx: Fix for framebuffer validation 2017-11-04 00:08:30 +03:00
Robbie 3288050680 Have trophy manager reject games that have invalid usr data rather than dying. 2017-11-03 21:15:43 +03:00
Robbie b8c29ae957 Make it so that TROPUSR doesn't crash on "bad" imput. 2017-11-03 21:15:43 +03:00
Robbie 47bacc0ef0 Make trophy dialog smarter and not need the silly file. Can load all games by default now. 2017-11-03 21:15:43 +03:00
Tahir Akhlaq 3d0dced4bd change CryptAcquireContextW to try CRYPT_NEWKEYSET flag if key container doesnt exist already < https://msdn.microsoft.com/en-us/library/windows/desktop/aa379886(v=vs.85).aspx > 2017-11-03 14:17:37 +03:00
kd-11 30bba09fed disable fb testing for partial framebuffer resources 2017-11-02 14:35:19 +03:00
kd-11 31b07f2c5c rsx: Tweaks
- Optimize get_surface_subresource
- Add check_program_status time to draw call setup statistics. It can slow down games significantly
2017-11-02 14:35:19 +03:00
kd-11 f7063bb57b vk: Improved handling of swap_bytes behaviour when using WCB 2017-11-02 14:35:19 +03:00
kd-11 e4ef85b6e0 rsx: Experimental; Try to calculate pixel offset using nv3062 pitch register since we know the target block is defined with 3062 registers 2017-11-02 14:35:19 +03:00
Nekotekina b7c2088489 Add supporters 2017-11-01 05:07:12 +03:00
Nekotekina 59cd0a9c7f Implement set_native_priority (posix) 2017-11-01 05:07:12 +03:00
Nekotekina af107df0b4 Fix NPDRM exitspawn 2017-11-01 05:07:12 +03:00
Nekotekina 0e7e40f2cb Fix /dev_bdvd/ for exitspawn 2017-11-01 05:07:11 +03:00
Nekotekina 0b788f5b43 Add Delete LLVM Cache option 2017-11-01 05:07:11 +03:00
scribam db5c2500c2 Update PPA urls to the latest version of Qt 2017-10-31 09:29:12 +00:00
scribam a1496eb1f1 Revert Qt requirements to version 5.7 for Linux 2017-10-31 09:29:12 +00:00
Robbie 4aa89132d7 Implement Trophy Manager. 2017-10-29 18:48:33 +03:00
Ani 9b8eb089b1 Handle device not ready in fs::error. Solves #3592 2017-10-29 16:52:12 +03:00
MRG95 c1f08ce58d Added breakpoint list
Added a list widget that displays all the currently active breakpoints. You can rename each one for convenience, delete them in bulk, or double click to jump to that address.
2017-10-29 16:17:05 +03:00
MRG95 09a0d046f4 Repositioned current instruction to middle
As soon as I tried the debugger, i wanted to move it to the middle almost instantly. Checked the code and found it sitting right here but commented out. Why? This is awesome.
2017-10-29 16:17:05 +03:00
Unknown 0741698f13 Qt: Fix Save Data Dialog initial size 2017-10-29 15:52:46 +03:00
kd-11 c2ac05f734 rsx: Fix for rsx thread lockup due to nested access violations when WCB is enabled 2017-10-29 15:25:17 +03:00
kd-11 f8f5f9f418 vk: Allow swapchain create to fail with an error 2017-10-29 15:25:17 +03:00
kd-11 7e6d6b45d4 nvidia facepalm 2017-10-29 15:25:17 +03:00
kd-11 361e80f7dc rsx: Tag cache blocks returned on access violation to validate data passed
to flush_all is up to date. Should prevent recursive exceptions

Partially revert Jarves' fix to invalidate cache on tile unbind. This will
need alot more work. Fixes hangs
2017-10-29 15:25:17 +03:00
kd-11 395b4bfa45 gsframe: Break waiting is emulator is stopped suddenly
- Keeps the queue from hanging the GUI
2017-10-29 15:25:17 +03:00
kd-11 ce2b790d8f rsx/qt: GsFrame improvements
- Identify minimize/restore events as separate from regular resize and do not react to them
- Enable message queue consumption after loading the shaders cache. Also hides the frame in this step
-- This fixes the 'start fullscreen' bug when running vulkan
2017-10-29 15:25:17 +03:00
Nekotekina 1ffc1e82b0 fixup 2017-10-28 23:39:10 +03:00
Nekotekina 8520ca7ef7 Audio: add Buffer Count setting 2017-10-28 23:24:08 +03:00
Nekotekina 89fba1c385 ppu_acontext draft 2017-10-28 23:24:08 +03:00
Nekotekina 00a0d37455 Add cmdline support 2017-10-28 23:24:08 +03:00
scribam dbb2251f93 [Qt] Fix uninitialised values before usage 2017-10-28 13:56:32 +03:00
kd-11 7abf755a57 rsx: Avoid false positives by early rejection. Should keep cache thashing to a minimum 2017-10-28 13:26:16 +03:00
kd-11 055f0e2e4a rsx: Export more information about affected cache sections when handling violations
- This allows for better handling of deferred flushes.
-- There's still no guarantee that cache contents will have changed between the set acquisition and following flush operation
-- Hopefully this is rare enough that it doesnt cause serious issues for now
2017-10-28 13:26:16 +03:00
kd-11 49f4da3016 rsx: Fixes
- vk: Always reopen primary command buffers. They should only be closed in flush_command_queue
- If uploading a texture and there are collisions with protected buffers, do not rebuild the cache
- Perform writes via flush before reprotecting pages that were not trampled
- Only flush no pages once
2017-10-28 13:26:16 +03:00
kd-11 bf234dc668 rsx: Implement memory tags for strict mode to validate render target memory 2017-10-28 13:26:16 +03:00
kd-11 11bd65c2b5 vulkan: Flush queue before attempting to copy texture memory! 2017-10-28 13:26:16 +03:00
Jake e0d1ac676e rsx: invalidate surface store address when tile is unbound 2017-10-28 12:46:20 +03:00
Jake 494cbac78b spu: save and restore mfc cmd after processing 2017-10-28 12:46:20 +03:00
Jake 0d46a8e786 spu: Implement readch(mfc_cmd) 2017-10-28 12:46:20 +03:00
Jake 626b9f93c4 rsx: make dmactrl get 'readonly' 2017-10-28 12:46:20 +03:00
Zangetsu38 53f9defb07 Trophy: use system language setting 2017-10-27 14:09:50 +01:00
Robbie 4bf8d1e41f Fix off by one error. Sigh. 2017-10-26 20:31:55 +01:00
Robbie 936c817bd8 Fix focus issue in trophies. 2017-10-26 20:31:55 +01:00
kd-11 9c9495621c rsx: Fix critical bug concerning transient data layout in memory 2017-10-26 00:35:45 +03:00
kd-11 d53673c6f7 rsx: Disable draw call batching when strict mode is enabled
- Minor bugs have been observed with it always enabled
2017-10-26 00:35:45 +03:00
kd-11 882e949f80 vk: Fix for infinite hanging in the access violation handler 2017-10-24 22:59:09 +03:00
kd-11 e6849a59a2 rsx: Better detection of framebuffer memory copy operations
- Still requires texture stitching to work correctly, but matching dimensions works well for now
2017-10-24 22:59:09 +03:00
kd-11 6918e265ec rsx/vk: Be a little more frugal with texture memory to avoid running out of VRAM on 1GB cards 2017-10-24 22:59:09 +03:00
kd-11 e9f293f522 rsx: Improve separate treatment of write exceptions vs read exceptions
- Optimizes search functionality and avoids thrashing valid sections
2017-10-24 22:59:09 +03:00
kd-11 5fc36d64b6 fix build 2017-10-24 22:59:09 +03:00
kd-11 95e6d78689 rsx: Workaround for 0 pitch textures.
- Should these be ignored? Needs investigation
2017-10-24 22:59:09 +03:00
kd-11 f4a666345a rsx: Even more texture cache fixes
- Fix subresource sampling
- Invalidate memory range before uploading textures to prevent hangs
2017-10-24 22:59:09 +03:00
kd-11 7a5c88a8d1 rsx: Only transfer framebuffer contents if memory contents are compatible 2017-10-24 22:59:09 +03:00
kd-11 0de0dded53 rsx: Texture fixes continued
- Fix buffer invalidate behaviour (wcb)
- Disable auto rebuild with only framebuffer storage getting rebuilt
- Fix vulkan subresource sampling
2017-10-24 22:59:09 +03:00
kd-11 5e58cf6079 rsx: Restructuring [WIP]
- Refactor invalidate memory functions into one function
- Add cached object rebuilding functionality to avoid throwing away useful memory on an invalidate
- Added debug monitoring of texture unit VRAM usage
2017-10-24 22:59:09 +03:00
Robbie b0737d1c90 Make a basic trophy notification dialog (#3204)
* Make trophy notification dialog.

* Fix bug where trophy state doesn't persist with game reboot.
2017-10-24 18:43:05 +03:00
Robbie 779ed75a19 Save manager improvements (#3631)
* Make size of manager only 60% of screen height initially at most.

* Add ability to delete/select multiple entries.

* Add ability to open up save dir and fix how it's done in
game_list_frame.

* Make delete much cleaner.
2017-10-24 18:09:38 +03:00
Unknown dbf1573e89 Update Readme to Qt 5.8 2017-10-24 15:11:37 +01:00
kd-11 96fd8556f2 Silence annoying experimental build warning
- Compiling locally on VS defines BRANCH to "" (empty $BRANCH envvar) and defines _MSC_VER. The pdb check is useless since it will never be reached
2017-10-22 00:14:40 +03:00
kd-11 8f324dfc0a vk: Enable primitive restart workaround for polaris and vega on linux as well
- Looks like it might be a hardware erratum
2017-10-22 00:14:40 +03:00
Unknown 34a6085cc0 Qt: add "clear" option to tty log contextmenu 2017-10-19 15:13:17 +01:00
Megamouse b3efa75206 [Qt] UI improvements (#3558)
* Qt: Show tooltips in description box

* Qt: implement description subscription

* Qt: add gamelist resize for ctrl-+/-/wheel (simple zoom)

* Qt: handle strict mode in gui tab

* Qt: more highdpi stuff

* Qt: remove old tooltips from settings_dialog

* Qt: conform cpublit tooltip to new subscription model
2017-10-19 14:29:48 +03:00
toccata10 b90a7dc66a evdev: add analog to dpad option (#3551)
* evdev Analog to digital option

* rewrite conditions on axis rotation

* a bit of cleanup
2017-10-19 13:41:02 +03:00
Megamouse 200557c036 [Qt] Add syntax highlighter (#3550)
* Qt: Add syntax highlighter

* Qt: add syntax highlighter to cg_disasm

The glsl part is pretty much finished.
The asm is still missing a few rules.
Colors are not yet fully decided

* Qt: add filter for syntax highlighter
2017-10-19 12:58:39 +03:00
kd-11 472cb3b1c2 gl: Check for vendor_string ATI for AMD cards. It seems AMD is still using the ATI openGL stack 2017-10-19 12:22:52 +03:00
kd-11 d8ee6a2edb add RX 550 to AMD vulkan cards with restart bug 2017-10-19 12:22:52 +03:00
kd-11 ddcacb8258 general fixes; Force u32 return type for index_count and add RX Vega to primitive restart blacklist 2017-10-19 12:22:52 +03:00
kd-11 a8e1754fa4 rsx: Allow clear_surface command for depth-only passes. Removes invalidate cache hack 2017-10-19 12:22:52 +03:00
kd-11 5db45c3699 rsx: More fixes
- Workaround for AMD glMultiDrawArrays bug
- Disable disjoint command submission when multidraw support is disabled
2017-10-19 12:22:52 +03:00
kd-11 89dcafbe41 rsx: Reimplement index buffer generation
- Emulate primitive restart in software whenever we get the chance
- Ensure PRIMITIVE_RESTART is never active when LIST topologies are active
- Reimplement TRIANGLE_FAN, POLYGON and QUAD expansion
2017-10-19 12:22:52 +03:00
kd-11 3d05e61f7e rsx/vk: Workaround for polaris primitive restart bug 2017-10-19 12:22:52 +03:00
Zangetsu38 5146f3ec47 Fix compile VS 2017-10-16 18:42:03 +03:00
scribam 170a95f5df Add BRANCH as a preprocessor definition taken from an environment variable 2017-10-15 18:20:02 +01:00
scribam c661578906 Bump Qt version to 5.9.2 for Travis 2017-10-15 14:23:48 +01:00
scribam f20e0c2898 rpcs3.vcxproj: remove unused paths in AdditionalLibraryDirectories 2017-10-15 14:23:48 +01:00
scribam 64b2ae3cd5 appveyor.yml: use Visual Studio solution to build the project and cleanup 2017-10-15 14:23:48 +01:00
kd-11 a11d66f52d update vulkan submodules (#3600) 2017-10-15 14:37:52 +03:00
Megamouse 304a4a1b61 GUI: add some visual studio filters (#3375) 2017-10-14 19:06:20 +03:00
207 changed files with 14192 additions and 5288 deletions
+1
View File
@@ -59,6 +59,7 @@ rpcs3/git-version.h
# Visual Studio Files
.vs/*
*.ipch
*.vspx
*.psess
*.VC.*
+6 -6
View File
@@ -8,13 +8,13 @@
[submodule "llvm"]
path = llvm
url = https://github.com/llvm-mirror/llvm
branch = release_40
branch = release_50
[submodule "GSL"]
path = 3rdparty/GSL
url = https://github.com/Microsoft/GSL.git
[submodule "libpng"]
path = 3rdparty/libpng
url = https://github.com/RPCS3/libpng
url = https://github.com/Zangetsu38/libpng
ignore = dirty
[submodule "Vulkan/glslang"]
path = Vulkan/glslang
@@ -25,9 +25,6 @@
[submodule "Utilities/yaml-cpp"]
path = Utilities/yaml-cpp
url = https://github.com/RPCS3/yaml-cpp
[submodule "3rdparty/pugixml"]
path = 3rdparty/pugixml
url = https://github.com/RPCS3/pugixml
[submodule "3rdparty/cereal"]
path = 3rdparty/cereal
url = https://github.com/USCiLab/cereal.git
@@ -36,8 +33,11 @@
url = https://github.com/madler/zlib
[submodule "3rdparty/hidapi"]
path = 3rdparty/hidapi
url = https://github.com/RPCS3/hidapi
url = https://github.com/Zangetsu38/hidapi
branch = master
[submodule "3rdparty/Optional"]
path = 3rdparty/Optional
url = https://github.com/akrzemi1/Optional.git
[submodule "3rdparty/pugixml"]
path = 3rdparty/pugixml
url = https://github.com/zeux/pugixml
+8 -8
View File
@@ -54,7 +54,7 @@ before_script:
- git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Utilities/yaml-cpp 3rdparty/cereal 3rdparty/hidapi 3rdparty/Optional Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers
- mkdir build
- cd build
- export CMAKE_PREFIX_PATH=~/Qt/5.9.1/gcc_64/lib/cmake
- export CMAKE_PREFIX_PATH=~/Qt/5.9.2/gcc_64/lib/cmake
- if [ "$TRAVIS_PULL_REQUEST" = false ]; then
export CXXFLAGS="$CXXFLAGS -DBRANCH=$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH";
else
@@ -64,20 +64,20 @@ before_script:
- make -j 3
- # AppImage generation
- if [ -n "$UPLOAD_URL" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ "$CC" = "clang-4.0" ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then
export LD_LIBRARY_PATH=~/Qt/5.9.1/gcc_64/lib;
export LD_LIBRARY_PATH=~/Qt/5.9.2/gcc_64/lib;
make DESTDIR=appdir install ; find appdir/ ;
find ../bin ;
wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" ;
chmod a+x linuxdeployqt*.AppImage ;
export PATH=~/Qt/5.9.1/gcc_64/bin/:${PATH} ;
export PATH=~/Qt/5.9.2/gcc_64/bin/:${PATH} ;
./linuxdeployqt*.AppImage --appimage-extract ;
./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -bundle-non-qt-libs ;
mkdir ./appdir/usr/plugins/xcbglintegrations/ ;
mkdir ./appdir/usr/plugins/imageformats/ ;
cp ~/Qt/5.9.1/gcc_64/lib/libQt5Svg.so.5 ./appdir/usr/lib/ ;
cp ~/Qt/5.9.1/gcc_64/plugins/xcbglintegrations/* ./appdir/usr/plugins/xcbglintegrations/ ;
cp ~/Qt/5.9.1/gcc_64/plugins/imageformats/* ./appdir/usr/plugins/imageformats/ ;
cp ~/Qt/5.9.1/gcc_64/plugins/platforms/* ./appdir/usr/plugins/platforms/ ;
cp ~/Qt/5.9.2/gcc_64/lib/libQt5Svg.so.5 ./appdir/usr/lib/ ;
cp ~/Qt/5.9.2/gcc_64/plugins/xcbglintegrations/* ./appdir/usr/plugins/xcbglintegrations/ ;
cp ~/Qt/5.9.2/gcc_64/plugins/imageformats/* ./appdir/usr/plugins/imageformats/ ;
cp ~/Qt/5.9.2/gcc_64/plugins/platforms/* ./appdir/usr/plugins/platforms/ ;
export PATH=${TRAVIS_BUILD_DIR}/build/squashfs-root/usr/bin/:${PATH} ;
./squashfs-root/usr/bin/appimagetool ${TRAVIS_BUILD_DIR}/build/appdir ;
find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq ;
@@ -115,7 +115,7 @@ addons:
- libstdc++-5-dev
- lib32stdc++6
- zlib1g-dev
# We need to install qt 5.9.1 manually because the version trusty provides is too old.
# We need to install qt 5.9.2 manually because the version trusty provides is too old.
#- qtbase5-dev
- libudev-dev
- libevdev-dev
+1 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0.2)
cmake_minimum_required(VERSION 3.1)
option(WITH_GDB "WITH_GDB" OFF)
option(WITHOUT_LLVM "WITHOUT_LLVM" OFF)
+17 -9
View File
@@ -20,19 +20,19 @@ If you want to contribute please take a look at the [Coding Style](https://githu
## Dependencies
### Windows
* [Visual Studio 2015](https://www.visualstudio.com/vs/older-downloads/)
* [Visual C++ Redistributable Packages for Visual Studio 2015](http://www.microsoft.com/en-us/download/details.aspx?id=48145)
* [Visual Studio 2017](https://www.visualstudio.com/en/downloads/)
* [Visual C++ Redistributable Packages for Visual Studio 2017](https://go.microsoft.com/fwlink/?LinkId=746572)
* [Cmake 3.1.0+](https://www.cmake.org/download/) (required; add to PATH)
* [Python 3.3+](https://www.python.org/downloads/) (required; add to PATH)
* [Qt 5.7+](https://www.qt.io/download-open-source/) (required; add QTDIR `<QtInstallFolder>\5.7\msvc2015_64\` environment variable if you do not want to use the Visual Studio Qt Plugin)
* [Qt 5.9.2](https://www.qt.io/download-open-source/) (required; add QTDIR `<QtInstallFolder>\5.9.1\msvc2015_64\` environment variable if you do not want to use the Visual Studio Qt Plugin)
* [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2015) (optional; see above)
### Linux
* [Qt 5.7+](https://www.qt.io/download-open-source/)
* GCC 5.1+ or Clang 3.5.0+ ([not GCC 6.1](https://github.com/RPCS3/rpcs3/issues/1691))
* Debian & Ubuntu: `sudo apt-get install cmake build-essential libasound2-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git qt5-default`
* Debian & Ubuntu: `sudo apt-get install cmake build-essential libasound2-dev libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git qt5-default`
* Arch: `sudo pacman -S glew openal cmake llvm qt5-base`
* Fedora: `sudo dnf install cmake qt5-devel vulkan-devel glew glew-devel`
* Fedora: `sudo dnf install cmake glew glew-devel libatomic libudev-devel openal-devel qt5-devel vulkan-devel`
**If you have a NVIDIA GPU, you may need to install the libglvnd package.**
### MacOS
@@ -47,15 +47,23 @@ To initialize the repository don't forget to execute `git submodule update --ini
### Configuring Qt
*If you're using Visual Studio 2017 without Qt plugin support (or simply dont want to use it):*
1) Add `QTDIR` environment variable and set it to `<QtInstallFolder>\5.7\msvc2015_64\` </br>
1) Add `QTDIR` environment variable and set it to `<QtInstallFolder>\5.9.2\msvc2017_64\` </br>
Open `rpcs3.sln`
*If you wish to use the Visual Studio plugin for Qt:* </br>
1) Go to the Qt5 menu and edit Qt5 options. Add the path to your Qt installation with compiler e.g. `C:\Qt\5.7\msvc2015_64`. </br>
1) Go to the Qt5 menu and edit Qt5 options. Add the path to your Qt installation with compiler e.g. `C:\Qt\5.9.2\msvc2015_64`. </br>
2) While selecting the rpcs3qt project, go to Qt5->Project Setting and select the version you added.
### Building the projects
1) Build the projects in *__BUILD_BEFORE* folder: right-click on every project > *Build*. </br>
2) Press *BUILD* > *Build Solution* or *Rebuild Solution*. </br>
You may want to download precompiled [LLVM lib](https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRY2k3Q2Yya05lcm8) and extract to root rpcs3 folder (which contains `rpcs3.sln`), as well as download and extract [additional libs](https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRaHYxV3VOS2d0a0U) to `lib\%CONFIGURATION%-x64\` to speed up compilation time (unoptimised/debug libs are currently not available precompiled).
If you're not using precompiled libs, build the projects in *__BUILD_BEFORE* folder: right-click on every project > *Build*. </br></br>
`Build > Build Solution`</br>
## Building on Linux & Mac OS:
+13 -3
View File
@@ -118,7 +118,7 @@ namespace cfg
bool m_value;
public:
const bool def;
bool def;
_bool(node* owner, const std::string& name, bool def = false)
: _base(type::_bool, owner, name)
@@ -150,6 +150,11 @@ namespace cfg
return true;
}
void set(const bool& value)
{
m_value = value;
}
};
// Value node with fixed set of possible values, each maps to an enum value of type T.
@@ -217,7 +222,7 @@ namespace cfg
int_type m_value;
public:
const int_type def;
int_type def;
_int(node* owner, const std::string& name, int_type def = std::min<int_type>(Max, std::max<int_type>(Min, 0)))
: _base(type::_int, owner, name)
@@ -253,6 +258,11 @@ namespace cfg
return false;
}
void set(const s64& value)
{
m_value = static_cast<int_type>(value);
}
std::vector<std::string> to_list() const override
{
return make_int_range(Min, Max);
@@ -271,7 +281,7 @@ namespace cfg
std::string m_value;
public:
const std::string def;
std::string def;
string(node* owner, const std::string& name, const std::string& def = {})
: _base(type::string, owner, name)
+28 -3
View File
@@ -75,10 +75,25 @@ static time_t to_time(const FILETIME& ft)
static FILETIME from_time(s64 _time)
{
const ullong wtime = (_time + 11644473600ULL) * 10000000ULL;
FILETIME result;
result.dwLowDateTime = static_cast<DWORD>(wtime);
result.dwHighDateTime = static_cast<DWORD>(wtime >> 32);
if (_time <= -11644473600ll)
{
result.dwLowDateTime = 0;
result.dwHighDateTime = 0;
}
else if (_time > INT64_MAX / 10000000ll - 11644473600ll)
{
result.dwLowDateTime = 0xffffffff;
result.dwHighDateTime = 0x7fffffff;
}
else
{
const ullong wtime = (_time + 11644473600ull) * 10000000ull;
result.dwLowDateTime = static_cast<DWORD>(wtime);
result.dwHighDateTime = static_cast<DWORD>(wtime >> 32);
}
return result;
}
@@ -96,6 +111,8 @@ static fs::error to_error(DWORD e)
case ERROR_INVALID_NAME: return fs::error::inval;
case ERROR_SHARING_VIOLATION: return fs::error::acces;
case ERROR_DIR_NOT_EMPTY: return fs::error::notempty;
case ERROR_NOT_READY: return fs::error::noent;
//case ERROR_INVALID_PARAMETER: return fs::error::inval;
default: fmt::throw_exception("Unknown Win32 error: %u.", e);
}
}
@@ -106,6 +123,7 @@ static fs::error to_error(DWORD e)
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/statvfs.h>
#include <sys/file.h>
#include <dirent.h>
#include <fcntl.h>
#include <libgen.h>
@@ -937,6 +955,13 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return;
}
if (test(mode & fs::unshare) && ::flock(fd, LOCK_EX | LOCK_NB) != 0)
{
g_tls_error = errno == EWOULDBLOCK ? fs::error::acces : to_error(errno);
::close(fd);
return;
}
class unix_file final : public file_base, public get_native_handle
{
const int m_fd;
+7 -7
View File
@@ -422,7 +422,7 @@ namespace fs
class iterator
{
dir* m_parent;
const dir* m_parent;
dir_entry m_entry;
public:
@@ -432,7 +432,7 @@ namespace fs
from_current
};
iterator(dir* parent, mode mode_ = mode::from_first)
iterator(const dir* parent, mode mode_ = mode::from_first)
: m_parent(parent)
{
if (!m_parent)
@@ -458,7 +458,7 @@ namespace fs
iterator& operator++()
{
*this = { m_parent, mode::from_current };
*this = {m_parent, mode::from_current};
return *this;
}
@@ -468,14 +468,14 @@ namespace fs
}
};
iterator begin()
iterator begin() const
{
return{ m_dir ? this : nullptr };
return {m_dir ? this : nullptr};
}
iterator end()
iterator end() const
{
return{ nullptr };
return {nullptr};
}
};
+10 -2
View File
@@ -30,6 +30,8 @@
#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/mman.h>
#endif
#include "JIT.h"
@@ -47,6 +49,11 @@ static void* const s_memory = []() -> void*
llvm::InitializeNativeTargetAsmPrinter();
LLVMLinkInMCJIT();
#ifdef MAP_32BIT
auto ptr = ::mmap(nullptr, s_memory_size, PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_32BIT, -1, 0);
if (ptr != MAP_FAILED)
return ptr;
#else
for (u64 addr = 0x10000000; addr <= 0x80000000 - s_memory_size; addr += 0x1000000)
{
if (auto ptr = utils::memory_reserve(s_memory_size, (void*)addr))
@@ -54,6 +61,7 @@ static void* const s_memory = []() -> void*
return ptr;
}
}
#endif
return utils::memory_reserve(s_memory_size);
}();
@@ -258,11 +266,11 @@ struct MemoryManager : llvm::RTDyldMemoryManager
return RTDyldMemoryManager::registerEHFrames(addr, load_addr, size);
}
virtual void deregisterEHFrames(u8* addr, u64 load_addr, std::size_t size) override
virtual void deregisterEHFrames() override
{
LOG_ERROR(GENERAL, "deregisterEHFrames() called"); // Not expected
return RTDyldMemoryManager::deregisterEHFrames(addr, load_addr, size);
return RTDyldMemoryManager::deregisterEHFrames();
}
};
+219 -48
View File
@@ -4,15 +4,19 @@
#include "sema.h"
#include "Utilities/sysinfo.h"
#include "Utilities/Thread.h"
#include "rpcs3_version.h"
#include <string>
#include <unordered_map>
#include <thread>
#include <chrono>
using namespace std::literals::chrono_literals;
#ifdef _WIN32
#define NOMINMAX
#include <Windows.h>
#else
#include <chrono>
#include <sys/mman.h>
#endif
@@ -49,23 +53,32 @@ void fmt_class_string<logs::level>::format(std::string& out, u64 arg)
namespace logs
{
constexpr std::size_t s_log_size = 128 * 1024 * 1024;
constexpr std::size_t s_log_size_s = s_log_size / 2;
constexpr std::size_t s_log_size_t = s_log_size / 4 + s_log_size_s;
constexpr std::size_t s_log_size_e = s_log_size / 8 + s_log_size_t;
constexpr std::size_t s_log_size_f = s_log_size / 16 + s_log_size_e;
// Memory-mapped buffer size
constexpr u64 s_log_size = 32 * 1024 * 1024;
class file_writer
{
fs::file m_file;
std::string m_name;
std::thread m_writer;
fs::file m_fout;
fs::file m_fout2;
u64 m_max_size;
#ifdef _WIN32
::HANDLE m_fmap;
#endif
atomic_t<std::size_t> m_pos{0};
std::size_t m_size{0};
uchar* m_fptr{};
z_stream m_zs{};
semaphore<> m_m;
alignas(128) atomic_t<u64> m_buf{0}; // MSB (40 bit): push begin, LSB (24 bis): push size
alignas(128) atomic_t<u64> m_out{0}; // Amount of bytes written to file
uchar m_zout[65536];
// Write buffered logs immediately
bool flush(u64 bufv);
public:
file_writer(const std::string& name);
@@ -119,7 +132,7 @@ namespace logs
static file_listener* get_logger()
{
// Use magic static
static file_listener logger("RPCS3.log");
static file_listener logger("RPCS3");
return &logger;
}
@@ -291,13 +304,45 @@ void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, const u
logs::file_writer::file_writer(const std::string& name)
: m_name(name)
{
const std::string log_name = fs::get_config_dir() + name + ".log";
const std::string buf_name = fs::get_config_dir() + name + ".buf";
try
{
if (!m_file.open(fs::get_config_dir() + name, fs::read + fs::write + fs::create + fs::trunc + fs::unshare))
if (!m_file.open(buf_name, fs::read + fs::write + fs::create + fs::trunc + fs::unshare))
{
fmt::throw_exception("Can't create file %s (error %s)", name, fs::g_tls_error);
if (fs::g_tls_error == fs::error::acces)
{
if (fs::exists(buf_name))
{
fmt::throw_exception("Another instance of %s is running. Close it or kill its process, if necessary.", name);
}
else
{
fmt::throw_exception("Cannot create %s.log (access denied)."
#ifdef _WIN32
"\nNote that %s cannot be installed in Program Files or similar directory with limited permissions."
#else
"\nPlease, check %s permissions in '~/.config/'."
#endif
, name, name);
}
}
fmt::throw_exception("Cannot create %s.log (error %s)", name, fs::g_tls_error);
}
// Check free space
fs::device_stat stats{};
if (!fs::statfs(fs::get_config_dir(), stats) || stats.avail_free < s_log_size * 8)
{
fmt::throw_exception("Not enough free space (%f KB)", stats.avail_free / 1000000.);
}
// Limit log size to ~25% of free space
m_max_size = stats.avail_free / 4;
// Initialize memory mapped file
#ifdef _WIN32
m_fmap = CreateFileMappingW(m_file.get_handle(), 0, PAGE_READWRITE, s_log_size >> 32, s_log_size & 0xffffffff, 0);
m_fptr = m_fmap ? (uchar*)MapViewOfFile(m_fmap, FILE_MAP_WRITE, 0, 0, 0) : nullptr;
@@ -307,44 +352,94 @@ logs::file_writer::file_writer(const std::string& name)
#endif
verify(name.c_str()), m_fptr;
std::memset(m_fptr, '\n', s_log_size);
// Rotate backups (TODO)
fs::remove_file(fs::get_config_dir() + name + "1.gz");
fs::remove_file(fs::get_config_dir() + name + "1.log.gz");
fs::create_dir(fs::get_config_dir() + "old_logs");
fs::rename(fs::get_config_dir() + m_name + ".gz", fs::get_config_dir() + "old_logs/" + m_name + ".gz", true);
fs::rename(fs::get_config_dir() + m_name + ".log.gz", fs::get_config_dir() + "old_logs/" + m_name + ".log.gz", true);
// Actual log file (allowed to fail)
m_fout.open(log_name, fs::rewrite);
// Compressed log
if (!m_fout2.open(log_name + ".gz", fs::rewrite) || deflateInit2(&m_zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) != Z_OK)
{
m_fout2.close();
}
}
catch (const std::exception& e)
{
std::thread([text = std::string{e.what()}]{ report_fatal_error(text); }).detach();
return;
}
catch (...)
{
catch_all_exceptions();
std::thread([]{ report_fatal_error("Unknown error" HERE); }).detach();
return;
}
m_writer = std::thread([this]()
{
thread_ctrl::set_native_priority(-1);
while (true)
{
const u64 bufv = m_buf;
if (bufv & 0xffffff)
{
// Wait if threads are writing logs
std::this_thread::yield();
continue;
}
if (!flush(bufv))
{
if (m_out == -1)
{
break;
}
std::this_thread::sleep_for(10ms);
}
}
});
}
logs::file_writer::~file_writer()
{
if (m_size == 0)
if (!m_fptr)
{
m_size = std::min<std::size_t>(+m_pos, s_log_size);
return;
}
// Compress
z_stream zs{};
if (deflateInit2(&zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) == Z_OK)
// Stop writer thread
while (m_out << 24 < m_buf)
{
auto buf = std::make_unique<uchar[]>(s_log_size);
zs.avail_in = ::narrow<u32>(m_size);
zs.avail_out = s_log_size;
zs.next_in = m_fptr;
zs.next_out = buf.get();
std::this_thread::yield();
}
if (deflate(&zs, Z_FINISH) != Z_STREAM_ERROR)
{
fs::file(fs::get_config_dir() + m_name + ".gz", fs::rewrite).write(buf.get(), zs.total_out);
}
m_out = -1;
m_writer.join();
if (deflateEnd(&zs) != Z_OK)
if (m_fout2)
{
m_zs.avail_in = 0;
m_zs.next_in = nullptr;
do
{
m_zs.avail_out = sizeof(m_zout);
m_zs.next_out = m_zout;
if (deflate(&m_zs, Z_FINISH) == Z_STREAM_ERROR || m_fout2.write(m_zout, sizeof(m_zout) - m_zs.avail_out) != sizeof(m_zout) - m_zs.avail_out)
{
break;
}
}
while (m_zs.avail_out == 0);
deflateEnd(&m_zs);
}
#ifdef _WIN32
@@ -353,33 +448,109 @@ logs::file_writer::~file_writer()
#else
::munmap(m_fptr, s_log_size);
#endif
m_file.trunc(m_size);
}
bool logs::file_writer::flush(u64 bufv)
{
semaphore_lock lock(m_m);
const u64 st = +m_out;
const u64 end = std::min<u64>((st + s_log_size) & ~(s_log_size - 1), bufv >> 24);
if (end > st)
{
// Avoid writing too big fragments
const u64 size = std::min<u64>(end - st, sizeof(m_zout) / 2);
// Write uncompressed
if (m_fout && st < m_max_size && m_fout.write(m_fptr + st % s_log_size, size) != size)
{
m_fout.close();
}
// Write compressed
if (m_fout2 && st < m_max_size)
{
m_zs.avail_in = size;
m_zs.next_in = m_fptr + st % s_log_size;
do
{
m_zs.avail_out = sizeof(m_zout);
m_zs.next_out = m_zout;
if (deflate(&m_zs, Z_NO_FLUSH) == Z_STREAM_ERROR || m_fout2.write(m_zout, sizeof(m_zout) - m_zs.avail_out) != sizeof(m_zout) - m_zs.avail_out)
{
deflateEnd(&m_zs);
m_fout2.close();
break;
}
}
while (m_zs.avail_out == 0);
}
m_out += size;
return true;
}
return false;
}
void logs::file_writer::log(logs::level sev, const char* text, std::size_t size)
{
// Adaptive log limit
const auto lim =
sev >= logs::level::success ? s_log_size_s :
sev == logs::level::todo ? s_log_size_t :
sev == logs::level::error ? s_log_size_e : s_log_size_f;
if (m_pos >= lim)
if (!m_fptr)
{
return;
}
// Acquire memory
const auto pos = m_pos.fetch_add(size);
// TODO: write bigger fragment directly in blocking manner
while (size && size <= 0xffffff)
{
u64 bufv;
// Write if possible
if (pos + size <= s_log_size)
{
std::memcpy(m_fptr + pos, text, size);
}
else if (pos <= s_log_size)
{
m_size = pos;
const auto pos = m_buf.atomic_op([&](u64& v) -> uchar*
{
const u64 v1 = v >> 24;
const u64 v2 = v & 0xffffff;
if (UNLIKELY(v2 + size > 0xffffff || v1 + v2 + size >= m_out + s_log_size))
{
bufv = v;
return nullptr;
}
v += size;
return m_fptr + (v1 + v2) % s_log_size;
});
if (UNLIKELY(!pos))
{
if ((bufv & 0xffffff) + size > 0xffffff || bufv & 0xffffff)
{
// Concurrency limit reached
std::this_thread::yield();
}
else
{
// Queue is full, need to write out
flush(bufv);
}
continue;
}
if (pos + size > m_fptr + s_log_size)
{
const auto frag = m_fptr + s_log_size - pos;
std::memcpy(pos, text, frag);
std::memcpy(m_fptr, text + frag, size - frag);
}
else
{
std::memcpy(pos, text, size);
}
m_buf += (u64{size} << 24) - size;
break;
}
}
+37 -43
View File
@@ -16,6 +16,12 @@
#ifdef __APPLE__
#define _XOPEN_SOURCE
#define __USE_GNU
#include <mach/thread_act.h>
#include <mach/thread_policy.h>
#endif
#if defined(__DragonFly__) || defined(__FreeBSD__)
#include <pthread_np.h>
#define cpu_set_t cpuset_t
#endif
#include <errno.h>
#include <signal.h>
@@ -31,32 +37,6 @@ thread_local u64 g_tls_fault_all = 0;
thread_local u64 g_tls_fault_rsx = 0;
thread_local u64 g_tls_fault_spu = 0;
static void report_fatal_error(const std::string& msg)
{
static semaphore<> g_report_only_once;
g_report_only_once.wait();
std::string _msg = msg + "\n"
"HOW TO REPORT ERRORS: https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support\n"
"Please, don't send incorrect reports. Thanks for understanding.\n";
#ifdef _WIN32
_msg += "\nPress Yes or Enter to visit the URL above immediately.";
const std::size_t buf_size = _msg.size() + 1;
const int size = static_cast<int>(buf_size);
std::unique_ptr<wchar_t[]> buffer(new wchar_t[buf_size]);
MultiByteToWideChar(CP_UTF8, 0, _msg.c_str(), size, buffer.get(), size);
if (MessageBoxW(0, buffer.get(), L"Fatal error", MB_ICONERROR | MB_YESNO) == IDYES)
{
ShellExecuteW(0, L"open", L"https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support", 0, 0, SW_SHOWNORMAL);
}
#else
std::printf("Fatal error: \n%s", _msg.c_str());
#endif
}
[[noreturn]] void catch_all_exceptions()
{
try
@@ -71,8 +51,6 @@ static void report_fatal_error(const std::string& msg)
{
report_fatal_error("Unhandled exception (unknown)");
}
std::abort();
}
enum x64_reg_t : u32
@@ -1491,13 +1469,11 @@ const bool s_exception_handler_set = []() -> bool
if (!AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)exception_handler))
{
report_fatal_error("AddVectoredExceptionHandler() failed.");
std::abort();
}
if (!SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)exception_filter))
{
report_fatal_error("SetUnhandledExceptionFilter() failed.");
std::abort();
}
return true;
@@ -1544,7 +1520,6 @@ static void signal_handler(int sig, siginfo_t* info, void* uct)
// TODO (debugger interaction)
report_fatal_error(fmt::format("Segfault %s location %p at %p.", cause, info->si_addr, RIP(context)));
std::abort();
}
const bool s_exception_handler_set = []() -> bool
@@ -1768,7 +1743,7 @@ bool thread_ctrl::_wait_for(u64 usec)
}
}
}
while (_this->m_cond.wait(_lock, std::exchange(usec, usec == -1 ? -1 : 0)));
while (_this->m_cond.wait(_lock, std::exchange(usec, usec > cond_variable::max_timeout ? -1 : 0)));
// Timeout
return false;
@@ -1884,20 +1859,30 @@ void thread_ctrl::set_native_priority(int priority)
HANDLE _this_thread = GetCurrentThread();
INT native_priority = THREAD_PRIORITY_NORMAL;
switch (priority)
{
default:
case 0:
break;
case 1:
if (priority > 0)
native_priority = THREAD_PRIORITY_ABOVE_NORMAL;
break;
case -1:
if (priority < 0)
native_priority = THREAD_PRIORITY_BELOW_NORMAL;
break;
}
SetThreadPriority(_this_thread, native_priority);
if (!SetThreadPriority(_this_thread, native_priority))
{
LOG_ERROR(GENERAL, "SetThreadPriority() failed: 0x%x", GetLastError());
}
#else
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(), &policy, &param);
if (priority > 0)
param.sched_priority = sched_get_priority_max(policy);
if (priority < 0)
param.sched_priority = sched_get_priority_min(policy);
if (int err = pthread_setschedparam(pthread_self(), policy, &param))
{
LOG_ERROR(GENERAL, "pthraed_setschedparam() failed: %d", err);
}
#endif
}
@@ -1906,6 +1891,15 @@ void thread_ctrl::set_ideal_processor_core(int core)
#ifdef _WIN32
HANDLE _this_thread = GetCurrentThread();
SetThreadIdealProcessor(_this_thread, core);
#elif __APPLE__
thread_affinity_policy_data_t policy = { static_cast<integer_t>(core) };
thread_port_t mach_thread = pthread_mach_thread_np(pthread_self());
thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1);
#elif defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__)
cpu_set_t cs;
CPU_ZERO(&cs);
CPU_SET(core, &cs);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cs);
#endif
}
+3
View File
@@ -10,6 +10,9 @@
#include "sema.h"
#include "cond.h"
// Report error and call std::abort(), defined in main.cpp
[[noreturn]] void report_fatal_error(const std::string&);
// Will report exception and call std::abort() if put in catch(...)
[[noreturn]] void catch_all_exceptions();
+4 -3
View File
@@ -10,12 +10,13 @@
bool cond_variable::imp_wait(u32 _old, u64 _timeout) noexcept
{
verify(HERE), _old != -1; // Very unlikely: it requires 2^32 distinct threads to wait simultaneously
const bool is_inf = _timeout > max_timeout;
#ifdef _WIN32
LARGE_INTEGER timeout;
timeout.QuadPart = _timeout * -10;
if (HRESULT rc = NtWaitForKeyedEvent(nullptr, &m_value, false, _timeout == -1 ? nullptr : &timeout))
if (HRESULT rc = NtWaitForKeyedEvent(nullptr, &m_value, false, is_inf ? nullptr : &timeout))
{
verify(HERE), rc == WAIT_TIMEOUT;
@@ -37,12 +38,12 @@ bool cond_variable::imp_wait(u32 _old, u64 _timeout) noexcept
for (u32 value = _old + 1;; value = m_value)
{
const int err = futex((int*)&m_value.raw(), FUTEX_WAIT_PRIVATE, value, _timeout == -1 ? nullptr : &timeout, nullptr, 0) == 0
const int err = futex((int*)&m_value.raw(), FUTEX_WAIT_PRIVATE, value, is_inf ? nullptr : &timeout, nullptr, 0) == 0
? 0
: errno;
// Normal or timeout wakeup
if (!err || (_timeout != -1 && err == ETIMEDOUT))
if (!err || (!is_inf && err == ETIMEDOUT))
{
// Cleanup (remove waiter)
verify(HERE), m_value--;
+2
View File
@@ -47,4 +47,6 @@ public:
imp_wake(-1);
}
}
static constexpr u64 max_timeout = u64{UINT32_MAX} / 1000 * 1000000;
};
+29 -2
View File
@@ -16,6 +16,7 @@ rem // Official git repository and contact information can be found at
rem // https://github.com/RPCS3/rpcs3 and http://rpcs3.net/.
setlocal ENABLEDELAYEDEXPANSION
setlocal ENABLEEXTENSIONS
set GIT_VERSION_FILE=%~p0..\rpcs3\git-version.h
if not defined GIT (
@@ -54,9 +55,35 @@ if errorlevel 1 (
goto done
)
rem // Get commit count from HEAD by default
for /F %%I IN ('call %GIT% rev-list HEAD --count') do set GIT_VERSION=%%I
rem // If we're in AppVeyor and we're building for master: Get commit count from unshallowed upstream
if defined APPVEYOR (
if not defined APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH (
call %GIT% remote add upstream https://github.com/RPCS3/RPCS3.git
call %GIT% fetch --unshallow upstream
for /F %%I IN ('call %GIT% rev-list --count upstream/master') do set GIT_VERSION=%%I
)
)
if defined APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH (
if "%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%"=="master" (
for /f "tokens=1* delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set user=%%a
set "GIT_BRANCH=!user!/%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%"
) else (
set GIT_BRANCH=%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%
)
) else (
for /F %%I IN ('call %GIT% rev-parse --abbrev-ref HEAD') do set GIT_BRANCH=%%I
)
rem // Get last commit (shortened) and concat after commit count in GIT_VERSION
for /F %%I IN ('call %GIT% rev-parse --short HEAD') do set GIT_VERSION=%GIT_VERSION%-%%I
for /F %%I IN ('call %GIT% rev-parse --abbrev-ref HEAD') do set GIT_BRANCH=%%I
rem // Echo obtained GIT_VERSION for debug purposes if needed
echo %GIT_VERSION%
rem // Don't modify the file if it already has the current version.
if exist "%GIT_VERSION_FILE%" (
@@ -69,7 +96,7 @@ if exist "%GIT_VERSION_FILE%" (
echo // This is a generated file. > "%GIT_VERSION_FILE%"
echo. >> "%GIT_VERSION_FILE%"
echo #define RPCS3_GIT_VERSION "%GIT_VERSION%" >> "%GIT_VERSION_FILE%"
echo #define RPCS3_GIT_BRANCH "%GIT_BRANCH%" >> "%GIT_VERSION_FILE%"
echo #define RPCS3_GIT_BRANCH ^"%GIT_BRANCH%^" >> "%GIT_VERSION_FILE%"
echo. >> "%GIT_VERSION_FILE%"
echo // If you don't want this file to update/recompile, change to 1. >> "%GIT_VERSION_FILE%"
echo #define RPCS3_GIT_VERSION_NO_UPDATE 0 >> "%GIT_VERSION_FILE%"
+20 -1
View File
@@ -7,6 +7,25 @@
#include <unistd.h>
#endif
bool utils::has_ssse3()
{
static const bool g_value = get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x200;
return g_value;
}
bool utils::has_avx()
{
static const bool g_value = get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x10000000;
return g_value;
}
bool utils::has_rtm()
{
// Check RTM and MPX extensions in order to filter out TSX on Haswell CPUs
static const bool g_value = get_cpuid(0, 0)[0] >= 0x7 && (get_cpuid(7, 0)[1] & 0x4800) == 0x4800;
return g_value;
}
std::string utils::get_system_info()
{
std::string result;
@@ -49,7 +68,7 @@ std::string utils::get_system_info()
if (has_avx())
{
result += " | AVX";
result += " | AVX+";
}
if (has_rtm())
+3 -13
View File
@@ -16,21 +16,11 @@ namespace utils
return {0u+regs[0], 0u+regs[1], 0u+regs[2], 0u+regs[3]};
}
inline bool has_ssse3()
{
return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x200;
}
bool has_ssse3();
inline bool has_avx()
{
return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x10000000;
}
bool has_avx();
inline bool has_rtm()
{
// Check RTM and MPX extensions in order to filter out TSX on Haswell CPUs
return get_cpuid(0, 0)[0] >= 0x7 && (get_cpuid(7, 0)[1] & 0x4800) == 0x4800;
}
bool has_rtm();
inline bool transaction_enter()
{
+21 -1
View File
@@ -48,7 +48,7 @@
#define CONCATENATE_DETAIL(x, y) x ## y
#define CONCATENATE(x, y) CONCATENATE_DETAIL(x, y)
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE_DETAIL(x) #x ""
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define HERE "\n(in file " __FILE__ ":" STRINGIZE(__LINE__) ")"
@@ -534,6 +534,26 @@ inline u64 cntlz64(u64 arg, bool nonzero = false)
#endif
}
inline u32 cnttz32(u32 arg, bool nonzero = false)
{
#ifdef _MSC_VER
ulong res;
return _BitScanForward(&res, arg) || nonzero ? res : 32;
#else
return arg || nonzero ? __builtin_ctzll(arg) : 32;
#endif
}
inline u64 cnttz64(u64 arg, bool nonzero = false)
{
#ifdef _MSC_VER
ulong res;
return _BitScanForward64(&res, arg) || nonzero ? res : 64;
#else
return arg || nonzero ? __builtin_ctzll(arg) : 64;
#endif
}
// Helper function, used by ""_u16, ""_u32, ""_u64
constexpr u8 to_u8(char c)
{
+1 -1
View File
@@ -19,7 +19,7 @@
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+8 -8
View File
@@ -19,12 +19,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -39,20 +39,20 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m</NMakeBuildCommandLine>
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeCleanCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m</NMakeCleanCommandLine>
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeReBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m
</NMakeReBuildCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeReBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeCleanCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m</NMakeCleanCommandLine>
</PropertyGroup>
<ItemDefinitionGroup>
+8 -8
View File
@@ -19,12 +19,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -39,24 +39,24 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
<NMakeBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
<NMakeReBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
<NMakeCleanCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m</NMakeCleanCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m
</NMakeCleanCommandLine>
</PropertyGroup>
+72 -34
View File
@@ -1,44 +1,82 @@
version: '0.0.3-{build}'
#---------------------------------#
# general configuration #
#---------------------------------#
os: Visual Studio 2015
platform: x64
clone_folder: C:\rpcs3
clone_depth: 3
test: off
# version format
version: '0.0.4-{build}'
configuration:
# Release
- ReleaseLLVM
#---------------------------------#
# environment configuration #
#---------------------------------#
before_build:
- ps: $env:Date="$(git show -s --date=short --format='%ad')"
- git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp 3rdparty/cereal 3rdparty/zlib 3rdparty/hidapi 3rdparty/Optional
- 7z x zlib.7z -aos -oC:\rpcs3\ > null
- 7z x vulkan.7z -aos -oC:\rpcs3\Vulkan > null
- set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%/#%APPVEYOR_PULL_REQUEST_NUMBER%
- if "%APPVEYOR_PULL_REQUEST_NUMBER%"=="" (set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%)
- set CXXFLAGS=-DBRANCH=%BRANCH%
- if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 14 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/lib/cmake/llvm -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
# Build worker image (VM template)
image: Visual Studio 2017
build_script:
- cmake --build . --config Release -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
# clone directory
clone_folder: c:\projects\rpcs3
install:
- if not exist llvmlibs.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRY2k3Q2Yya05lcm8" -FileName llvmlibs.7z
- if not exist vulkan.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRaHYxV3VOS2d0a0U" -FileName vulkan.7z
- if not exist zlib.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B-HVE3xvheVFX05lRFdnZlh5aUU" -FileName zlib.7z
- set QTDIR=C:\Qt\5.8\msvc2015_64
- set OPENALDIR=C:\rpcs3\3rdparty\OpenAL
- set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%QTDIR%;%PATH%
- set COMMIT_SHA=%APPVEYOR_REPO_COMMIT:~0,8%
# set clone depth
clone_depth: 3 # clone entire repository history if not defined
artifacts:
- path: bin
name: 'rpcs3-v0.0.3-$(Date)-$(COMMIT_SHA)_win64'
type: zip
# environment variables
environment:
QTDIR: C:\Qt\5.9\msvc2017_64
# build cache to preserve files/folders between builds
cache:
- llvmlibs.7z -> appveyor.yml
- vulkan.7z -> appveyor.yml
- zlib.7z -> appveyor.yml
# scripts that run after cloning repository
install:
- git submodule update --init 3rdparty/cereal 3rdparty/ffmpeg 3rdparty/GSL 3rdparty/hidapi 3rdparty/libpng 3rdparty/Optional 3rdparty/pugixml 3rdparty/zlib asmjit Utilities/yaml-cpp Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers
#---------------------------------#
# build configuration #
#---------------------------------#
# build platform, i.e. x86, x64, Any CPU. This setting is optional.
platform: x64
# build Configuration, i.e. Debug, Release, etc.
configuration: Release - LLVM
build:
parallel: true # enable MSBuild parallel builds
project: rpcs3.sln # path to Visual Studio solution or project
# MSBuild verbosity level
verbosity: normal
# scripts to run before build
before_build:
- set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%/#%APPVEYOR_PULL_REQUEST_NUMBER%
- if "%APPVEYOR_PULL_REQUEST_NUMBER%"=="" (set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%)
- set PATH=%PATH%;%QTDIR%
- if not exist llvmlibs.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRY2k3Q2Yya05lcm8" -FileName llvmlibs.7z
- 7z x llvmlibs.7z -aos -o%APPVEYOR_BUILD_FOLDER% > null
- if not exist vulkan.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRaHYxV3VOS2d0a0U" -FileName vulkan.7z
- 7z x vulkan.7z -aos -o"%APPVEYOR_BUILD_FOLDER%\lib\%CONFIGURATION%-%PLATFORM%" > null
# scripts to run *after* solution is built and *before* automatic packaging occurs (web apps, NuGet packages, Azure Cloud Services)
before_package:
- rm %APPVEYOR_BUILD_FOLDER%\bin\rpcs3.exp
- rm %APPVEYOR_BUILD_FOLDER%\bin\rpcs3.lib
- rm %APPVEYOR_BUILD_FOLDER%\bin\rpcs3.pdb
- set COMMIT_DATE=%APPVEYOR_REPO_COMMIT_TIMESTAMP:~0,10%
- set COMMIT_SHA=%APPVEYOR_REPO_COMMIT:~0,8%
#---------------------------------#
# tests configuration #
#---------------------------------#
# to disable automatic tests
test: off
#---------------------------------#
# artifacts configuration #
#---------------------------------#
# pushing entire folder as a zip archive
artifacts:
- path: bin
name: 'rpcs3-v0.0.4-$(COMMIT_DATE)-$(COMMIT_SHA)_win64'
+1 -1
View File
@@ -93,7 +93,7 @@
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+41 -41
View File
@@ -40,7 +40,7 @@ QWidget {
/* Mouse tooltips */
QToolTip {
border: 1px solid #323232;
border: 0.05em solid #323232;
background-color: #323232;
color: #ecf0f1;
}
@@ -49,29 +49,29 @@ QToolTip {
QHeaderView::section {
background-color: #323232;
color: #ecf0f1;
padding-left: 4px;
border: 1px solid #323232;
padding-left: 0.2em;
border: 0.05em solid #323232;
}
/* Settings Dialog: Tabs */
QTabBar::tab {
color: #ecf0f1;
border: 1px solid #444;
border: 0.05em solid #444;
border-bottom-style: none;
background-color: #333333;
padding-left: 16px;
padding-right: 16px;
padding-top: 4px;
padding-bottom: 4px;
margin-right: -2px;
padding-left: 0.9em;
padding-right: 0.9em;
padding-top: 0.2em;
padding-bottom: 0.2em;
margin-right: -0.2em;
}
QTabBar::tab:last {
margin-right: 0px;
margin-right: 0em;
}
QTabBar::tab:!selected {
color: #b1b1b1;
border-bottom-style: solid;
margin-top: 3px;
margin-top: 0.15em;
background-color: #292929;
}
QTabBar::tab:hover {
@@ -81,11 +81,11 @@ QTabBar::tab:hover {
/* Checkboxes */
QCheckBox::indicator {
border-radius: 2px;
border: 1px solid #ecf0f1;
width: 10px;
height: 10px;
margin-top: 1px;
border-radius: 0.1em;
border: 0.05em solid #ecf0f1;
margin-top: 0.05em;
width: 0.8em;
height: 0.8em;
}
QCheckBox::indicator:checked {
background-color: #2ecc71; /* Green */
@@ -99,11 +99,11 @@ QCheckBox::indicator::disabled {
/* Radio Buttons */
QRadioButton::indicator {
border-radius: 6px;
border: 1px solid #ecf0f1;
width: 10px;
height: 10px;
margin-top: 1px;
border-radius: 0.4em;
border: 0.05em solid;
border-color: white;
width: 0.8em;
height: 0.8em;
}
QRadioButton::indicator:checked {
background-color: #2ecc71; /* Green */
@@ -119,10 +119,10 @@ QRadioButton::indicator::disabled {
QComboBox {
background-color: #404040;
color: #fff;
border: 1px solid #1e1e1e;
border-radius: 3px;
padding-bottom: 2px;
padding-left: 4px;
border: 0.05em solid #1e1e1e;
border-radius: 0.15em;
padding-bottom: 0.2em;
padding-left: 0.4em;
}
QComboBox::disabled {
background-color: #828790;
@@ -131,15 +131,15 @@ QComboBox::disabled {
/* Group Boxes (Settings Dialog) */
QGroupBox {
margin-top: 17px;
font-size: 13px;
border: 1px solid #bdc3c7;
border-radius: 4px;
margin-top: 1em;
font-size: 8pt;
border: 0.05em solid #bdc3c7;
border-radius: 0.3em;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center;
padding: 5px 10px 5px 10px;
subcontrol-position: top;
padding: 0.3em 0.5em 0.3em 0.5em;
color: #fff;
}
@@ -154,19 +154,19 @@ QPushButton::disabled {
/* Log and Debugger borders */
QTextEdit {
border: 1px solid #828790;
border: 0.05em solid #828790;
}
/* For dock buttons to be visible */
QDockWidget::close-button, QDockWidget::float-button {
background-color: #bdc3c7;
border: 1px solid #000;
border-radius: 4px;
border: 0.05em solid #000;
border-radius: 0.3em;
}
/* Disable ugly borders */
QTabWidget::pane {
border: 0px solid #828790;
border: 0em solid #828790;
}
/* Top menu bar */
@@ -174,14 +174,14 @@ QMenuBar::item:selected {
background: #444444;
}
QMenu::item {
padding-left: 20px;
padding-right: 15px;
padding-top: 4px;
padding-bottom: 4px;
padding-left: 1.5em;
padding-right: 0.75em;
padding-top: 0.25em;
padding-bottom: 0.25em;
}
QMenu::item:selected {
background: #444444;
border: 1px solid #bdc3c7;
border: 0.05em solid #bdc3c7;
}
QMenu::item:disabled {
background-color: #444444;
@@ -223,7 +223,7 @@ QLabel#color_button {
/* Seachbar on main toolbar */
QLineEdit#mw_searchbar {
margin-left:14px;
margin-left: 0.7em;
color: #ecf0f1;
}
+1 -1
Submodule llvm updated: 4423e35117...f30c918816
+8 -8
View File
@@ -18,12 +18,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -39,30 +39,30 @@
<NMakePreprocessorDefinitions>
</NMakePreprocessorDefinitions>
<NMakeBuildCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m
</NMakeCleanCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakePreprocessorDefinitions />
<NMakeBuildCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m
</NMakeCleanCommandLine>
</PropertyGroup>
+1 -1
View File
@@ -32,7 +32,7 @@ Controller.prototype.ComponentSelectionPageCallback = function() {
var widget = gui.currentPageWidget();
widget.deselectAll();
widget.selectComponent("qt.591.gcc_64");
widget.selectComponent("qt.592.gcc_64");
gui.clickButton(buttons.NextButton);
}
+2 -2
View File
@@ -20,14 +20,14 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
+5 -2
View File
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2006
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asmjit", "asmjitsrc\asmjit.vcxproj", "{AC40FF01-426E-4838-A317-66354CEFAE88}"
EndProject
@@ -243,4 +243,7 @@ Global
{FDC361C5-7734-493B-8CFB-037308B35122} = {DDF904CA-2771-441A-8629-5DF2EB922A79}
{A107C21C-418A-4697-BB10-20C3AA60E2E4} = {FA1E6C16-CA63-45F8-8D52-E21DF396BE36}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06CC7920-E085-4B81-9582-8DE8AAD42510}
EndGlobalSection
EndGlobal
+7 -8
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0.2)
cmake_minimum_required(VERSION 3.1)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake_modules")
set(RES_FILES "")
@@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 14)
include(CheckCCompilerFlag)
# Qt section
find_package(Qt5 5.7 COMPONENTS Widgets)
find_package(Qt5 5.9 COMPONENTS Widgets)
if (WIN32)
find_package(Qt5WinExtras REQUIRED)
set(RPCS3_QT_LIBS Qt5::Widgets Qt5::WinExtras)
@@ -24,13 +24,13 @@ endif()
# Let's make sure we have Qt before we continue
if (NOT Qt5Widgets_FOUND)
if (Qt5Widgets_VERSION VERSION_LESS 5.7.0)
message("Minimum supported Qt5 version is 5.7! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
if (Qt5Widgets_VERSION VERSION_LESS 5.9.0)
message("Minimum supported Qt5 version is 5.9! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
if ("${CMAKE_SYSTEM}" MATCHES "Linux")
message(FATAL_ERROR "Most distros do not provide an up-to-date version of Qt.
If you're on Ubuntu or Linux Mint, there are PPAs you can use to install an up-to-date qt5 version.
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt591-xenial
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt591-trusty
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt592-xenial
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt592-trusty
just make sure to run
source /opt/qt59/bin/qt59-env.sh
before re-running cmake")
@@ -44,7 +44,7 @@ before re-running cmake")
message("CMake was unable to find Qt5!")
if (WIN32)
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\5.8\\msvc2017_64\\)")
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\5.9\\msvc2017_64\\)")
elseif("${CMAKE_SYSTEM}" MATCHES "Linux")
message(FATAL_ERROR "Make sure to install your distro's qt5 package!")
else()
@@ -342,7 +342,6 @@ if (NOT WIN32 AND VULKAN_FOUND)
"${RPCS3_SRC_DIR}/../Vulkan/glslang/glslang/MachineIndependent/*.cpp"
"${RPCS3_SRC_DIR}/../Vulkan/glslang/glslang/OSDependent/Unix/*.cpp"
"${RPCS3_SRC_DIR}/../Vulkan/glslang/OGLCompilersDLL/*.cpp"
"${RPCS3_SRC_DIR}/../Vulkan/glslang/hlsl/*.cpp"
"${RPCS3_SRC_DIR}/../Vulkan/glslang/SPIRV/*.cpp"
)
+65 -25
View File
@@ -4,27 +4,19 @@
#include "sha1.h"
#include "key_vault.h"
#include "Utilities/StrFmt.h"
#include "Emu/System.h"
#include "Emu/VFS.h"
#include "unpkg.h"
bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>& sync, const std::string& pkg_filepath)
bool pkg_install(const std::string& path, atomic_t<double>& sync)
{
const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB
std::vector<fs::file> filelist;
u32 cur_file=0;
fs::file original_file(pkg_filepath);
original_file.seek(pkg_f.pos());
filelist.push_back(std::move(original_file));
// Save current file offset (probably zero)
const u64 start_offset = pkg_f.pos();
u64 cur_offset = start_offset;
u64 cur_file_offset = start_offset;
// Get basic PKG information
PKGHeader header;
filelist.emplace_back(fs::file{path});
u32 cur_file = 0;
u64 cur_offset = 0;
u64 cur_file_offset = 0;
auto archive_seek = [&](const s64 new_offset, const fs::seek_mode damode = fs::seek_set)
{
@@ -73,6 +65,8 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
return num_read;
};
// Get basic PKG information
PKGHeader header;
if (archive_read(&header, sizeof(header)) != sizeof(header))
{
@@ -108,18 +102,18 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
}
}
if (header.pkg_size > pkg_f.size())
if (header.pkg_size > filelist[0].size())
{
//Check if multi-files pkg
if (pkg_filepath.length() < 7 || pkg_filepath.substr(pkg_filepath.length() - 7).compare("_00.pkg") != 0)
// Check if multi-files pkg
if (path.size() < 7 || path.compare(path.size() - 7, 7, "_00.pkg", 7) != 0)
{
LOG_ERROR(LOADER, "PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size);
return false;
}
std::string name_wo_number = pkg_filepath.substr(0, pkg_filepath.length() - 7);
u64 cursize = pkg_f.size();
while (cursize != header.pkg_size)
std::string name_wo_number = path.substr(0, path.size() - 7);
u64 cursize = filelist[0].size();
while (cursize < header.pkg_size)
{
std::string archive_filename = fmt::format("%s_%02d.pkg", name_wo_number, filelist.size());
@@ -131,7 +125,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
}
cursize += archive_file.size();
filelist.push_back(std::move(archive_file));
filelist.emplace_back(std::move(archive_file));
}
}
@@ -143,6 +137,12 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
be_t<u32> drm_type{0};
be_t<u32> content_type{0};
std::string install_id;
// Read title ID and use it as an installation directory
install_id.resize(9);
archive_seek(55);
archive_read(&install_id.front(), install_id.size());
archive_seek(header.pkg_info_off);
@@ -179,18 +179,50 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
break;
}
case 0xA:
{
if (packet.size > 8)
{
// Read an actual installation directory (DLC)
install_id.resize(packet.size);
archive_read(&install_id.front(), packet.size);
install_id = install_id.c_str() + 8;
continue;
}
break;
}
}
archive_seek(packet.size, fs::seek_cur);
}
// If false, an existing directory is being overwritten: cannot cancel the operation
bool was_null = true;
// Get full path and create the directory
const std::string dir = Emu.GetHddDir() + "game/" + install_id + '/';
if (!fs::create_dir(dir))
{
if (fs::g_tls_error == fs::error::exist)
{
was_null = false;
}
else
{
LOG_ERROR(LOADER, "PKG: Could not create the installation directory %s", dir);
return false;
}
}
// Allocate buffer with BUF_SIZE size or more if required
const std::unique_ptr<u128[]> buf(new u128[std::max<u64>(BUF_SIZE, sizeof(PKGEntry) * header.file_count) / sizeof(u128)]);
// Define decryption subfunction (`psp` arg selects the key for specific block)
auto decrypt = [&](u64 offset, u64 size, const uchar* key) -> u64
{
archive_seek(start_offset + header.data_offset + offset);
archive_seek(header.data_offset + offset);
// Read the data and set available size
const u64 read = archive_read(buf.get(), size);
@@ -334,8 +366,16 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
if (sync.fetch_add((block_size + 0.0) / header.data_size) < 0.)
{
LOG_ERROR(LOADER, "Package installation cancelled: %s", dir);
return false;
if (was_null)
{
LOG_ERROR(LOADER, "Package installation cancelled: %s", dir);
out.close();
fs::remove_all(dir, true);
return false;
}
// Cannot cancel the installation
sync += 1.;
}
}
+1 -1
View File
@@ -57,4 +57,4 @@ struct PKGEntry
be_t<u32> pad; // Padding (zeros)
};
bool pkg_install(const class fs::file& pkg_f, const std::string& dir, atomic_t<double>&, const std::string& pkg_filepath);
bool pkg_install(const std::string& path, atomic_t<double>&);
+1 -1
View File
@@ -31,7 +31,7 @@
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+6 -4
View File
@@ -50,6 +50,8 @@ OpenALThread::OpenALThread()
{
m_format = g_cfg.audio.convert_to_u16 ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32;
}
m_buffers = std::make_unique<ALuint[]>(g_cfg.audio.frames);
}
OpenALThread::~OpenALThread()
@@ -83,7 +85,7 @@ void OpenALThread::Close()
if (alIsSource(m_source))
alDeleteSources(1, &m_source);
alDeleteBuffers(g_al_buffers_count, m_buffers);
alDeleteBuffers(g_cfg.audio.frames, m_buffers.get());
checkForAlError("alDeleteBuffers");
}
@@ -98,7 +100,7 @@ void OpenALThread::Open(const void* src, int size)
alGenSources(1, &m_source);
checkForAlError("alGenSources");
alGenBuffers(g_al_buffers_count, m_buffers);
alGenBuffers(g_cfg.audio.frames, m_buffers.get());
checkForAlError("alGenBuffers");
alSourcei(m_source, AL_LOOPING, AL_FALSE);
@@ -106,13 +108,13 @@ void OpenALThread::Open(const void* src, int size)
m_buffer_size = size;
for (uint i = 0; i<g_al_buffers_count; ++i)
for (int i = 0; i < g_cfg.audio.frames; ++i)
{
alBufferData(m_buffers[i], m_format, src, m_buffer_size, 48000);
checkForAlError("alBufferData");
}
alSourceQueueBuffers(m_source, g_al_buffers_count, m_buffers);
alSourceQueueBuffers(m_source, g_cfg.audio.frames, m_buffers.get());
checkForAlError("alSourceQueueBuffers");
Play();
}
+2 -3
View File
@@ -2,15 +2,14 @@
#include "Emu/Audio/AudioThread.h"
#include "3rdparty/OpenAL/include/alext.h"
#include <memory>
class OpenALThread : public AudioThread
{
private:
static const uint g_al_buffers_count = 24;
ALint m_format;
ALuint m_source;
ALuint m_buffers[g_al_buffers_count];
std::unique_ptr<ALuint[]> m_buffers;
ALsizei m_buffer_size;
public:
+70 -37
View File
@@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/GSL.h"
#include "Emu/System.h"
#include "ALSAThread.h"
@@ -9,10 +8,12 @@
#include <alsa/asoundlib.h>
static thread_local snd_pcm_t* s_tls_handle{nullptr};
static thread_local snd_pcm_hw_params_t* s_tls_hw_params{nullptr};
static thread_local snd_pcm_sw_params_t* s_tls_sw_params{nullptr};
static void error(int err, const char* reason)
{
fprintf(stderr, "ALSA: %s failed: %s\n", reason, snd_strerror(err));
LOG_ERROR(GENERAL, "ALSA: %s failed: %s\n", reason, snd_strerror(err));
}
static bool check(int err, const char* reason)
@@ -28,55 +29,86 @@ static bool check(int err, const char* reason)
ALSAThread::ALSAThread()
{
snd_pcm_hw_params_t* hw_params{nullptr};
auto at_ret = gsl::finally([&]()
{
if (hw_params)
{
snd_pcm_hw_params_free(hw_params);
}
});
if (!check(snd_pcm_open(&s_tls_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK), "snd_pcm_open"))
return;
if (!check(snd_pcm_hw_params_malloc(&hw_params), "snd_pcm_hw_params_malloc"))
if (!check(snd_pcm_hw_params_malloc(&s_tls_hw_params), "snd_pcm_hw_params_malloc"))
return;
if (!check(snd_pcm_hw_params_any(s_tls_handle, hw_params), "snd_pcm_hw_params_any"))
if (!check(snd_pcm_hw_params_any(s_tls_handle, s_tls_hw_params), "snd_pcm_hw_params_any"))
return;
if (!check(snd_pcm_hw_params_set_access(s_tls_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
if (!check(snd_pcm_hw_params_set_access(s_tls_handle, s_tls_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
return;
if (!check(snd_pcm_hw_params_set_format(s_tls_handle, hw_params, g_cfg.audio.convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
if (!check(snd_pcm_hw_params_set_format(s_tls_handle, s_tls_hw_params, g_cfg.audio.convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
return;
if (!check(snd_pcm_hw_params_set_rate(s_tls_handle, hw_params, 48000, 0), "snd_pcm_hw_params_set_rate_near"))
uint rate = 48000;
if (!check(snd_pcm_hw_params_set_rate_near(s_tls_handle, s_tls_hw_params, &rate, nullptr), "snd_pcm_hw_params_set_rate_near"))
return;
if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, hw_params, g_cfg.audio.downmix_to_2ch ? 2 : 8), "snd_pcm_hw_params_set_channels"))
if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, s_tls_hw_params, g_cfg.audio.downmix_to_2ch ? 2 : 8), "snd_pcm_hw_params_set_channels"))
return;
if (!check(snd_pcm_hw_params_set_buffer_size(s_tls_handle, hw_params, 8 * 256), "snd_pcm_hw_params_set_buffer_size"))
//uint period = 5333;
//if (!check(snd_pcm_hw_params_set_period_time_near(s_tls_handle, s_tls_hw_params, &period, nullptr), "snd_pcm_hw_params_set_period_time_near"))
// return;
//if (!check(snd_pcm_hw_params_set_periods(s_tls_handle, s_tls_hw_params, 4, 0), "snd_pcm_hw_params_set_periods"))
// return;
snd_pcm_uframes_t bufsize_frames = g_cfg.audio.frames * 256;
snd_pcm_uframes_t period_frames = 256;
if (!check(snd_pcm_hw_params_set_buffer_size_near(s_tls_handle, s_tls_hw_params, &bufsize_frames), "snd_pcm_hw_params_set_buffer_size_near"))
return;
if (!check(snd_pcm_hw_params_set_period_size(s_tls_handle, hw_params, 256, 0), "snd_pcm_hw_params_set_period_size"))
if (!check(snd_pcm_hw_params_set_period_size_near(s_tls_handle, s_tls_hw_params, &period_frames, 0), "snd_pcm_hw_params_set_period_size"))
return;
//if (!check(snd_pcm_hw_params_set_periods(s_tls_handle, hw_params, 2, 0), "snd_pcm_hw_params_set_periods"))
// return;
if (!check(snd_pcm_hw_params(s_tls_handle, s_tls_hw_params), "snd_pcm_hw_params"))
return;
if (!check(snd_pcm_hw_params(s_tls_handle, hw_params), "snd_pcm_hw_params"))
if (!check(snd_pcm_hw_params_get_buffer_size(s_tls_hw_params, &bufsize_frames), "snd_pcm_hw_params_get_buffer_size"))
return;
if (!check(snd_pcm_hw_params_get_period_size(s_tls_hw_params, &period_frames, nullptr), "snd_pcm_hw_params_get_period_size"))
return;
if (!check(snd_pcm_sw_params_malloc(&s_tls_sw_params), "snd_pcm_sw_params_malloc"))
return;
if (!check(snd_pcm_sw_params_current(s_tls_handle, s_tls_sw_params), "snd_pcm_sw_params_current"))
return;
if (!check(snd_pcm_sw_params_set_start_threshold(s_tls_handle, s_tls_sw_params, period_frames), "snd_pcm_sw_params_set_start_threshold"))
return;
if (!check(snd_pcm_sw_params_set_stop_threshold(s_tls_handle, s_tls_sw_params, bufsize_frames), "snd_pcm_sw_params_set_stop_threshold"))
return;
if (!check(snd_pcm_sw_params(s_tls_handle, s_tls_sw_params), "snd_pcm_sw_params"))
return;
if (!check(snd_pcm_prepare(s_tls_handle), "snd_pcm_prepare"))
return;
LOG_NOTICE(GENERAL, "ALSA: bufsize_frames=%u, period_frames=%u", bufsize_frames, period_frames);
}
ALSAThread::~ALSAThread()
{
if (s_tls_sw_params)
{
snd_pcm_sw_params_free(s_tls_sw_params);
}
if (s_tls_hw_params)
{
snd_pcm_hw_params_free(s_tls_hw_params);
}
if (s_tls_handle)
{
snd_pcm_close(s_tls_handle);
@@ -105,29 +137,30 @@ void ALSAThread::AddData(const void* src, int size)
size /= g_cfg.audio.convert_to_u16 ? 2 : 4;
size /= g_cfg.audio.downmix_to_2ch ? 2 : 8;
int res;
int res = snd_pcm_writei(s_tls_handle, src, size);
while (true)
if (res == -EAGAIN)
{
res = snd_pcm_writei(s_tls_handle, src, size);
LOG_WARNING(GENERAL, "ALSA: EAGAIN");
return;
}
if (res == -EAGAIN)
if (res < 0)
{
res = snd_pcm_recover(s_tls_handle, res, 0);
if (res < 0)
{
continue;
}
else if (res == -EPIPE)
{
snd_pcm_prepare(s_tls_handle);
}
else
{
break;
LOG_WARNING(GENERAL, "ALSA: failed to recover (%d)", res);
return;
}
res = snd_pcm_writei(s_tls_handle, src, size);
}
if (res != size)
{
error(res, "snd_pcm_writei");
LOG_WARNING(GENERAL, "ALSA: error (%d)", res);
}
}
-1
View File
@@ -8,7 +8,6 @@ extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
}
#include "cellPamf.h"
+4 -2
View File
@@ -57,6 +57,8 @@ void audio_config::on_init(const std::shared_ptr<void>& _this)
void audio_config::on_task()
{
thread_ctrl::set_native_priority(1);
AudioDumper m_dump(g_cfg.audio.dump_to_file ? 2 : 0); // Init AudioDumper for 2 channels if enabled
float buf2ch[2 * BUFFER_SIZE]{}; // intermediate buffer for 2 channels
@@ -337,8 +339,8 @@ void audio_config::on_task()
case 8: m_dump.WriteData(&buf8ch, sizeof(buf8ch)); break; // write file data (8 ch)
}
cellAudio.trace("Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)",
time_pos, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);
cellAudio.trace("Audio perf: (access=%d, AddData=%d, events=%d, dump=%d)",
stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);
}
}
+1 -1
View File
@@ -554,7 +554,7 @@ s32 cellFontExtend(u32 a1, u32 a2, u32 a3)
//Something happens
}
//Something happens?
return CELL_OK;
return -1;
}
s32 cellFontRenderCharGlyphImageVertical()
+12 -2
View File
@@ -94,7 +94,7 @@ struct content_permission final
{
try
{
if (!temp.empty())
if (temp.size() > 1)
{
fs::remove_all(temp);
}
@@ -255,7 +255,7 @@ error_code cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr
{
*type = CELL_GAME_GAMETYPE_DISC;
*attributes = 0; // TODO
if (dirName) strcpy_trunc(*dirName, ""); // ???
// TODO: dirName might be a read only string when BootCheck is called on a disc game. (e.g. Ben 10 Ultimate Alien: Cosmic Destruction)
if (!fxm::make<content_permission>("", std::move(sfo)))
{
@@ -659,6 +659,11 @@ error_code cellGameGetParamString(s32 id, vm::ptr<char> buf, u32 bufsize)
{
cellGame.warning("cellGameGetParamString(id=%d, buf=*0x%x, bufsize=%d)", id, buf, bufsize);
if (!buf || bufsize == 0)
{
return CELL_GAME_ERROR_PARAM;
}
const auto prm = fxm::get<content_permission>();
if (!prm)
@@ -685,6 +690,11 @@ error_code cellGameSetParamString(s32 id, vm::cptr<char> buf)
{
cellGame.warning("cellGameSetParamString(id=%d, buf=*0x%x)", id, buf);
if (!buf)
{
return CELL_GAME_ERROR_PARAM;
}
const auto prm = fxm::get<content_permission>();
if (!prm)
+13 -8
View File
@@ -74,7 +74,7 @@ s32 cellMouseGetInfo(vm::ptr<CellMouseInfo> info)
for (u32 i=0; i<CELL_MAX_MICE; i++) info->vendor_id[i] = current_info.vendor_id[i];
for (u32 i=0; i<CELL_MAX_MICE; i++) info->product_id[i] = current_info.product_id[i];
for (u32 i=0; i<CELL_MAX_MICE; i++) info->status[i] = current_info.status[i];
return CELL_OK;
}
@@ -96,7 +96,7 @@ s32 cellMouseInfoTabletMode(u32 port_no, vm::ptr<CellMouseInfoTablet> info)
info->is_supported = 0; // Unimplemented: (0=Tablet mode is not supported)
info->mode = 1; // Unimplemented: (1=Mouse mode)
return CELL_OK;
}
@@ -115,7 +115,7 @@ s32 cellMouseGetData(u32 port_no, vm::ptr<CellMouseData> data)
{
return CELL_MOUSE_ERROR_NO_DEVICE;
}
MouseData& current_data = handler->GetData(port_no);
data->update = current_data.update;
data->buttons = current_data.buttons;
@@ -134,22 +134,27 @@ s32 cellMouseGetData(u32 port_no, vm::ptr<CellMouseData> data)
s32 cellMouseGetDataList(u32 port_no, vm::ptr<CellMouseDataList> data)
{
UNIMPLEMENTED_FUNC(sys_io);
return CELL_OK;
sys_io.todo("cellMouseGetDataList(port_no=%d, data=0x%x", port_no, data);
if (g_cfg.io.mouse == mouse_handler::null)
return CELL_MOUSE_ERROR_NO_DEVICE;
else
{
data->list_num = 0;
return CELL_OK;
}
}
s32 cellMouseSetTabletMode(u32 port_no, u32 mode)
{
UNIMPLEMENTED_FUNC(sys_io);
return CELL_OK;
}
s32 cellMouseGetTabletDataList(u32 port_no, u32 data_addr)
{
UNIMPLEMENTED_FUNC(sys_io);
return CELL_OK;
}
+1 -1
View File
@@ -23,7 +23,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
return CELL_MSGDIALOG_ERROR_PARAM;
}
const MsgDialogType _type = { type };
const MsgDialogType _type = {type ^ CELL_MSGDIALOG_TYPE_BG_INVISIBLE};
switch (_type.button_type.unshifted())
{
+108 -49
View File
@@ -37,7 +37,8 @@ enum : u32
SAVEDATA_OP_FIXED_SAVE = 6,
SAVEDATA_OP_FIXED_LOAD = 7,
SAVEDATA_OP_FIXED_DELETE = 14,
SAVEDATA_OP_LIST_DELETE = 13,
SAVEDATA_OP_FIXED_DELETE = 14,
};
namespace
@@ -52,6 +53,7 @@ namespace
CellSaveDataStatSet statSet;
CellSaveDataFileGet fileGet;
CellSaveDataFileSet fileSet;
CellSaveDataDoneGet doneGet;
};
}
@@ -81,11 +83,12 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
vm::ptr<CellSaveDataStatSet> statSet = g_savedata_context.ptr(&savedata_context::statSet);
vm::ptr<CellSaveDataFileGet> fileGet = g_savedata_context.ptr(&savedata_context::fileGet);
vm::ptr<CellSaveDataFileSet> fileSet = g_savedata_context.ptr(&savedata_context::fileSet);
vm::ptr<CellSaveDataDoneGet> doneGet = g_savedata_context.ptr(&savedata_context::doneGet);
//TODO: get current user ID
// userId(0) = CELL_SYSUTIL_USERID_CURRENT
// path of the specified user (00000001 by default)
const std::string& base_dir = vfs::get(fmt::format("/dev_hdd0/home/%08u/savedata/", userId ? userId : 1u));
const std::string base_dir = vfs::get(fmt::format("/dev_hdd0/home/%08u/savedata/", userId ? userId : 1u));
result->userdata = userdata; // probably should be assigned only once (allows the callback to change it)
@@ -98,9 +101,9 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
listGet->dirNum = 0;
listGet->dirListNum = 0;
listGet->dirList.set(setBuf->buf.addr());
memset(listGet->reserved, 0, sizeof(listGet->reserved));
std::memset(listGet->reserved, 0, sizeof(listGet->reserved));
const auto prefix_list = fmt::split(setList->dirNamePrefix.get_ptr(), { "|" });
const auto prefix_list = fmt::split(setList->dirNamePrefix.get_ptr(), {"|"});
// get the saves matching the supplied prefix
for (auto&& entry : fs::dir(base_dir))
@@ -204,10 +207,11 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
auto& dir = *dir_list++;
strcpy_trunc(dir.dirName, entry.dirName);
strcpy_trunc(dir.listParam, entry.listParam);
memset(dir.reserved, 0, sizeof(dir.reserved));
std::memset(dir.reserved, 0, sizeof(dir.reserved));
}
s32 selected = -1;
s32 focused = -1;
if (funcList)
{
@@ -217,14 +221,14 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
if (result->result < 0)
{
//TODO: display dialog
cellSaveData.warning("savedata_op(): funcList returned < 0.");
cellSaveData.warning("savedata_op(): funcList returned result=%d.", result->result);
return CELL_SAVEDATA_ERROR_CBRESULT;
}
// if the callback has returned ok, lets return OK.
// typically used at game launch when no list is actually required.
// CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM is only valid for funcFile and funcDone
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST)
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)
{
return CELL_OK;
}
@@ -243,19 +247,6 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
return true;
}), save_entries.end());
// Add any new data (not currently supported by the UI)
//if (listSet->newData)
//{
// SaveDataEntry *_saveDataEntry = new SaveDataEntry();
// _saveDataEntry->dirName = listSet->newData->dirName.get_ptr();
// save_entry.dirName = listSet->newData->dirName.get_ptr();
// save_entries.emplace_back(*_saveDataEntry);
//}
// Focus save data
s32 focused = -1;
switch (const u32 pos_type = listSet->focusPosition)
{
case CELL_SAVEDATA_FOCUSPOS_DIRNAME:
@@ -323,14 +314,52 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
return CELL_SAVEDATA_ERROR_PARAM;
}
}
}
// Display Save Data List but do so asynchronously in the GUI thread.
bool hasNewData = (bool)listSet->newData; // newData
auto delete_save = [&](const std::string& del_path)
{
strcpy_trunc(doneGet->dirName, save_entries[selected].dirName);
doneGet->hddFreeSizeKB = 40 * 1024 * 1024; // 40 GB
doneGet->sizeKB = 0;
doneGet->excResult = CELL_OK;
std::memset(doneGet->reserved, 0, sizeof(doneGet->reserved));
const fs::dir _dir{del_path};
for (auto&& file : _dir)
{
if (!file.is_directory)
{
doneGet->sizeKB += ::align(file.size, 4096);
if (!fs::remove_file(del_path + file.name))
{
doneGet->excResult = CELL_SAVEDATA_ERROR_FAILURE;
}
}
}
if (!_dir)
{
doneGet->excResult = CELL_SAVEDATA_ERROR_NODATA;
}
if (!doneGet->excResult && !fs::remove_dir(del_path))
{
doneGet->excResult = CELL_SAVEDATA_ERROR_FAILURE;
}
funcDone(ppu, result, doneGet);
};
while (funcList)
{
// Display Save Data List asynchronously in the GUI thread.
atomic_t<bool> dlg_result(false);
Emu.CallAfter([&]()
{
selected = Emu.GetCallbacks().get_save_dialog()->ShowSaveDataList(save_entries, focused, hasNewData, listSet);
selected = Emu.GetCallbacks().get_save_dialog()->ShowSaveDataList(save_entries, focused, operation, listSet);
dlg_result = true;
});
@@ -351,6 +380,29 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
return CELL_CANCEL;
}
if (operation == SAVEDATA_OP_LIST_DELETE)
{
delete_save(base_dir + save_entries[selected].dirName + '/');
if (result->result < 0)
{
cellSaveData.warning("savedata_op(): funcDone returned result=%d.", result->result);
return CELL_SAVEDATA_ERROR_CBRESULT;
}
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)
{
return CELL_OK;
}
// CELL_SAVEDATA_CBRESULT_OK_NEXT expected
save_entries.erase(save_entries.cbegin() + selected);
focused = save_entries.empty() ? -1 : selected;
selected = -1;
continue;
}
break;
}
if (funcFixed)
@@ -359,7 +411,7 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
funcFixed(ppu, result, listGet, fixedSet);
// skip all following steps if OK_LAST
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST)
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)
{
return CELL_OK;
}
@@ -370,8 +422,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
// depends on fixedSet->option
// 0 = none
// 1 = skip confirmation dialog
cellSaveData.warning("savedata_op(): funcFixed returned < 0.");
cellSaveData.warning("savedata_op(): funcFixed returned result=%d.", result->result);
return CELL_SAVEDATA_ERROR_CBRESULT;
}
@@ -394,6 +446,18 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
save_entry.dirName = fixedSet->dirName.get_ptr();
}
if (operation == SAVEDATA_OP_FIXED_DELETE)
{
delete_save(base_dir + save_entries[selected].dirName + '/');
if (result->result < 0)
{
cellSaveData.warning("savedata_op(): funcDone_ returned result=%d.", result->result);
return CELL_SAVEDATA_ERROR_CBRESULT;
}
return CELL_OK;
}
}
if (selected >= 0)
@@ -504,15 +568,15 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
if (result->result < 0)
{
cellSaveData.warning("savedata_op(): funcStat returned 0x%x", result->result);
cellSaveData.warning("savedata_op(): funcStat returned result=%d.", result->result);
return CELL_SAVEDATA_ERROR_CBRESULT;
}
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST)
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)
{
return CELL_OK;
}
if (statSet->setParam)
{
// Update PARAM.SFO
@@ -544,7 +608,7 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
case CELL_SAVEDATA_RECREATE_NO:
{
//CELL_SAVEDATA_RECREATE_NO = overwrite and let the user know, not data is corrupt.
//cellSaveData.error("Savedata %s considered broken", save_entry.dirName);
//cellSaveData.error("Savedata %s considered broken", save_entry.dirName);
//TODO: if this is a save, and it's not auto, then show a dialog
// fallthrough
}
@@ -591,7 +655,7 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
// Create save directory if necessary
if (psf.size() && save_entry.isNew && !fs::create_dir(dir_path))
{
{
cellSaveData.warning("savedata_op(): failed to create %s", dir_path);
return CELL_SAVEDATA_ERROR_ACCESS_ERROR;
}
@@ -607,7 +671,7 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
if (result->result < 0)
{
cellSaveData.warning("savedata_op(): funcFile returned < 0.");
cellSaveData.warning("savedata_op(): funcFile returned result=%d.", result->result);
return CELL_SAVEDATA_ERROR_CBRESULT;
}
@@ -720,9 +784,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
return CELL_OK;
}
s32 static NEVER_INLINE save_op_get_list_item(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB, u32 userId)
static NEVER_INLINE s32 savedata_get_list_item(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB, u32 userId)
{
//TODO: accurately get the current user
if (userId == 0)
{
@@ -806,7 +869,6 @@ s32 cellSaveDataListLoad(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf
version, setList, setBuf, funcList, funcStat, funcFile, container);
return savedata_op(ppu, SAVEDATA_OP_LIST_LOAD, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null);
}
s32 cellSaveDataFixedSave2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
@@ -834,7 +896,6 @@ s32 cellSaveDataFixedSave(ppu_thread& ppu, u32 version, PSetList setList, PSetBu
version, setList, setBuf, funcFixed, funcStat, funcFile, container);
return savedata_op(ppu, SAVEDATA_OP_FIXED_SAVE, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, vm::null, 0, vm::null);
}
s32 cellSaveDataFixedLoad(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
@@ -914,10 +975,10 @@ s32 cellSaveDataDelete(u32 container)
s32 cellSaveDataFixedDelete(ppu_thread& ppu, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataFixedDelete(setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)",
cellSaveData.warning("cellSaveDataFixedDelete(setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)",
setList, setBuf, funcFixed, funcDone, container, userdata);
return CELL_OK;
return savedata_op(ppu, SAVEDATA_OP_FIXED_DELETE, 0, vm::null, 1, setList, setBuf, vm::null, funcFixed, vm::null, vm::null, container, 2, userdata, 0, funcDone);
}
s32 cellSaveDataUserListSave(ppu_thread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
@@ -986,26 +1047,24 @@ s32 cellSaveDataUserListAutoLoad(ppu_thread& ppu, u32 version, u32 userId, u32 e
s32 cellSaveDataUserFixedDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataUserFixedDelete(userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)",
cellSaveData.error("cellSaveDataUserFixedDelete(userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)",
userId, setList, setBuf, funcFixed, funcDone, container, userdata);
return CELL_OK;
return savedata_op(ppu, SAVEDATA_OP_FIXED_DELETE, 0, vm::null, 1, setList, setBuf, vm::null, funcFixed, vm::null, vm::null, container, 6, userdata, userId, funcDone);
}
void cellSaveDataEnableOverlay(s32 enable)
{
cellSaveData.error("cellSaveDataEnableOverlay(enable=%d)", enable);
return;
}
// Functions (Extensions)
s32 cellSaveDataListDelete(ppu_thread& ppu, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
UNIMPLEMENTED_FUNC(cellSaveData);
cellSaveData.warning("cellSaveDataListDelete(setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", setList, setBuf, funcList, funcDone, container, userdata);
return CELL_OK;
return savedata_op(ppu, SAVEDATA_OP_LIST_DELETE, 0, vm::null, 0, setList, setBuf, funcList, vm::null, vm::null, vm::null, container, 0x40, userdata, 0, funcDone);
}
s32 cellSaveDataListImport(ppu_thread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
@@ -1039,15 +1098,15 @@ s32 cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr<char> dirName, u32 maxSize
s32 cellSaveDataGetListItem(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB)
{
cellSaveData.warning("cellSavaDataGetListItem(dirName=%s, dir=*0x%x, sysFileParam=*0x%x, bind=*0x%x, sizeKB=*0x%x)", dirName, dir, sysFileParam, bind, sizeKB);
return save_op_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, 0);
return savedata_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, 0);
}
s32 cellSaveDataUserListDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
UNIMPLEMENTED_FUNC(cellSaveData);
cellSaveData.error("cellSaveDataUserListDelete(userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, setList, setBuf, funcList, funcDone, container, userdata);
return CELL_OK;
return savedata_op(ppu, SAVEDATA_OP_LIST_DELETE, 0, vm::null, 0, setList, setBuf, funcList, vm::null, vm::null, vm::null, container, 0x40, userdata, userId, funcDone);
}
s32 cellSaveDataUserListImport(ppu_thread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
@@ -1082,7 +1141,7 @@ s32 cellSaveDataUserGetListItem(u32 userId, vm::cptr<char> dirName, vm::ptr<Cell
{
cellSaveData.warning("cellSavaDataGetListItem(dirName=%s, dir=*0x%x, sysFileParam=*0x%x, bind=*0x%x, sizeKB=*0x%x, userID=*0x%x)", dirName, dir, sysFileParam, bind, sizeKB, userId);
return save_op_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, userId);
return savedata_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, userId);
}
void cellSysutil_SaveData_init()
+1 -1
View File
@@ -291,5 +291,5 @@ class SaveDialogBase
public:
virtual ~SaveDialogBase();
virtual s32 ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, bool isSaving, vm::ptr<CellSaveDataListSet> listSet) = 0;
virtual s32 ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet) = 0;
};
+9 -1
View File
@@ -3,14 +3,22 @@
#include "Emu/Cell/PPUModule.h"
#include "cellSearch.h"
#include "cellSysutil.h"
logs::channel cellSearch("cellSearch");
s32 cellSearchInitialize(CellSearchMode mode, u32 container, vm::ptr<CellSearchSystemCallback> func, vm::ptr<u32> userData)
s32 cellSearchInitialize(ppu_thread& ppu, CellSearchMode mode, u32 container, vm::ptr<CellSearchSystemCallback> func, vm::ptr<u32> userData)
{
cellSearch.warning("cellSearchInitialize()");
// TODO: Store the arguments somewhere so we can use them later.
//inform callback that search is alive
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
func(ppu, CELL_SEARCH_EVENT_INITIALIZE_RESULT, CELL_OK, vm::null, userData);
return CELL_OK;
});
return CELL_OK;
}
+9 -7
View File
@@ -64,6 +64,7 @@ struct vdec_thread : ppu_thread
{
AVCodec* codec{};
AVCodecContext* ctx{};
SwsContext* sws{};
const s32 type;
const u32 profile;
@@ -147,6 +148,7 @@ struct vdec_thread : ppu_thread
{
avcodec_close(ctx);
avcodec_free_context(&ctx);
sws_freeContext(sws);
}
virtual std::string dump() const override
@@ -361,7 +363,7 @@ struct vdec_thread : ppu_thread
{
au_count--;
}
while (std::lock_guard<std::mutex>{mutex}, max_frames && out.size() > max_frames)
{
thread_ctrl::wait();
@@ -483,7 +485,7 @@ s32 cellVdecClose(ppu_thread& ppu, u32 handle)
vdec->cmd_push({vdec_cmd::close, 0});
vdec->max_frames = 0;
}
vdec->notify();
vdec->join();
idm::remove<ppu_thread>(handle);
@@ -586,7 +588,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
}
vdec->notify();
if (outBuff)
{
const int w = frame->width;
@@ -632,7 +634,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
}
}
std::unique_ptr<SwsContext, void(*)(SwsContext*)> sws(sws_getContext(w, h, in_f, w, h, out_f, SWS_POINT, NULL, NULL, NULL), sws_freeContext);
vdec->sws = sws_getCachedContext(vdec->sws, w, h, in_f, w, h, out_f, SWS_POINT, NULL, NULL, NULL);
u8* in_data[4] = { frame->data[0], frame->data[1], frame->data[2], alpha_plane.get() };
int in_line[4] = { frame->linesize[0], frame->linesize[1], frame->linesize[2], w * 1 };
@@ -648,7 +650,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
out_line[2] = w / 2;
}
sws_scale(sws.get(), in_data, in_line, 0, h, out_data, out_line);
sws_scale(vdec->sws, in_data, in_line, 0, h, out_data, out_line);
//const u32 buf_size = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128);
@@ -771,7 +773,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5;
avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important
avc->timing_info_present_flag = true;
switch (frc)
{
case CELL_VDEC_FRC_24000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; break;
@@ -838,7 +840,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
mp2->horizontal_size = frame->width;
mp2->vertical_size = frame->height;
mp2->aspect_ratio_information = CELL_VDEC_MPEG2_ARI_SAR_1_1; // ???
switch (frc)
{
case CELL_VDEC_FRC_24000DIV1001: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_24000DIV1001; break;
+3 -3
View File
@@ -55,7 +55,7 @@ s32 cellVpostClose(u32 handle)
return CELL_VPOST_ERROR_C_ARG_HDL_INVALID;
}
idm::remove<VpostInstance>(handle);
idm::remove<VpostInstance>(handle);
return CELL_OK;
}
@@ -120,7 +120,7 @@ s32 cellVpostExec(u32 handle, vm::cptr<u8> inPicBuff, vm::cptr<CellVpostCtrlPara
//u64 stamp1 = get_system_time();
std::unique_ptr<SwsContext, void(*)(SwsContext*)> sws(sws_getContext(w, h, AV_PIX_FMT_YUVA420P, ow, oh, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL), sws_freeContext);
vpost->sws = sws_getCachedContext(vpost->sws, w, h, AV_PIX_FMT_YUVA420P, ow, oh, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL);
//u64 stamp2 = get_system_time();
@@ -129,7 +129,7 @@ s32 cellVpostExec(u32 handle, vm::cptr<u8> inPicBuff, vm::cptr<CellVpostCtrlPara
u8* out_data[4] = { outPicBuff.get_ptr(), NULL, NULL, NULL };
int out_line[4] = { static_cast<int>(ow*4), 0, 0, 0 };
sws_scale(sws.get(), in_data, in_line, 0, h, out_data, out_line);
sws_scale(vpost->sws, in_data, in_line, 0, h, out_data, out_line);
//ConLog.Write("cellVpostExec() perf (access=%d, getContext=%d, scale=%d, finalize=%d)",
//stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);
+12
View File
@@ -1,5 +1,10 @@
#pragma once
extern "C"
{
#include "libswscale/swscale.h"
}
namespace vm { using namespace ps3; }
// Error Codes
@@ -327,8 +332,15 @@ public:
const bool to_rgba;
SwsContext* sws{};
VpostInstance(bool rgba)
: to_rgba(rgba)
{
}
~VpostInstance()
{
sws_freeContext(sws);
}
};
+2 -1
View File
@@ -147,7 +147,8 @@ s32 sceNpSnsFbCheckThrottle()
s32 sceNpSnsFbCheckConfig()
{
fmt::throw_exception("Unimplemented" HERE);
sceNpSns.todo("sceNpSnsFbCheckConfig()");
return CELL_OK;
}
s32 sceNpSnsFbLoadThrottle()
+40 -2
View File
@@ -16,6 +16,10 @@
logs::channel sceNpTrophy("sceNpTrophy");
TrophyNotificationBase::~TrophyNotificationBase()
{
}
struct trophy_context_t
{
static const u32 id_base = 1;
@@ -264,7 +268,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
const size_t kTargetBufferLength = 31;
char target[kTargetBufferLength + 1];
target[kTargetBufferLength] = 0;
strcpy_trunc(target, fmt::format("TROP_%02d.SFM", /*rpcs3::config.system.language.value()*/0));
strcpy_trunc(target, fmt::format("TROP_%02d.SFM", static_cast<s32>(g_cfg.sys.language)));
if (trp.ContainsEntry(target))
{
@@ -286,7 +290,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
for (s32 i = 0; i <= 18; i++)
{
strcpy_trunc(target, fmt::format("TROP_%02d.SFM", i));
if (i != /*rpcs3::config.system.language.value()*/0)
if (i != g_cfg.sys.language)
{
trp.RemoveEntry(target);
}
@@ -490,6 +494,40 @@ error_code sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::pt
*platinumId = SCE_NP_TROPHY_INVALID_TROPHY_ID; // TODO
}
if (g_cfg.misc.show_trophy_popups)
{
// Figure out how many zeros are needed for padding. (either 0, 1, or 2)
std::string padding = "";
if (trophyId < 10)
{
padding = "00";
}
else if (trophyId < 100)
{
padding = "0";
}
// Get icon for the notification.
std::string trophyIconPath = "/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROP" + padding + std::to_string(trophyId) + ".PNG";
fs::file trophyIconFile = fs::file(vfs::get(trophyIconPath));
u32 iconSize = trophyIconFile.size();
std::vector<uchar> trophyIconData;
trophyIconFile.read(trophyIconData, iconSize);
vm::ptr<SceNpTrophyDetails> details = vm::make_var(SceNpTrophyDetails());
vm::ptr<SceNpTrophyData> _ = vm::make_var(SceNpTrophyData());
s32 ret = sceNpTrophyGetTrophyInfo(context, handle, trophyId, details, _);
if (ret != CELL_OK)
{
sceNpTrophy.error("Failed to get info for trophy dialog. Error code %x", ret);
*details = SceNpTrophyDetails();
}
Emu.CallAfter([det = *details, trophyIconData]() {
Emu.GetCallbacks().get_trophy_notification_dialog()->ShowTrophyNotification(det, trophyIconData);
});
}
return CELL_OK;
}
+11
View File
@@ -137,3 +137,14 @@ enum
};
using SceNpTrophyStatusCallback = s32(u32 context, u32 status, s32 completed, s32 total, vm::ptr<void> arg);
// Forward declare this function since trophyunlock needs it
error_code sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr<SceNpTrophyDetails> details, vm::ptr<SceNpTrophyData> data);
class TrophyNotificationBase
{
public:
virtual ~TrophyNotificationBase();
virtual s32 ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophyIconBfr) = 0;
};
File diff suppressed because it is too large Load Diff
+736
View File
@@ -6,6 +6,7 @@
#include "Utilities/bit_set.h"
#include "Utilities/BEType.h"
#include "PPUOpcodes.h"
// PPU Function Attributes
enum class ppu_attr : u32
@@ -941,3 +942,738 @@ struct ppu_iname
return value;
}
};
// PPU Analyser Context
struct ppu_acontext
{
// General-purpose register range
struct spec_gpr
{
// Integral range: normalized undef = (0;UINT64_MAX), unnormalized undefs are possible (when max = min - 1)
// Bit range: constant 0 = (0;0), constant 1 = (1;1), normalized undef = (0;1), unnormalized undef = (1;0)
u64 imin = 0; // Integral range begin
u64 imax = -1; // Integral range end
u64 bmin = 0; // Bit range begin
u64 bmax = -1; // Bit range end
void set_undef()
{
imin = 0;
imax = -1;
bmin = 0;
bmax = -1;
}
// (Number of possible values - 1), 0 = const
u64 div() const
{
return imax - imin;
}
// Return zero bits for zeros, ones for ones or undefs
u64 mask() const
{
return bmin | bmax;
}
// Return one bits for ones, zeros for zeros or undefs
u64 ones() const
{
return bmin & bmax;
}
// Return one bits for undefs
u64 undefs() const
{
return bmin ^ bmax;
}
// Return number of trailing zero bits
u64 tz() const
{
return ::cnttz64(mask());
}
// Range NOT
spec_gpr operator ~() const
{
spec_gpr r;
r.imin = ~imax;
r.imax = ~imin;
r.bmin = ~bmax;
r.bmax = ~bmin;
return r;
}
// Range ADD
spec_gpr operator +(const spec_gpr& rhs) const
{
spec_gpr r{};
const u64 adiv = div();
const u64 bdiv = rhs.div();
// Check overflow, generate normalized range
if (adiv != -1 && bdiv != -1 && adiv <= adiv + bdiv)
{
r = range(imin + rhs.imin, imax + rhs.imax);
}
// Carry for bitrange computation
u64 cmin = 0;
u64 cmax = 0;
const u64 amask = mask();
const u64 bmask = rhs.mask();
const u64 aones = ones();
const u64 bones = rhs.ones();
for (u32 i = 0; i < 64; i++)
{
cmin += ((amask >> i) & 1) + ((bmask >> i) & 1);
cmax += ((aones >> i) & 1) + ((bones >> i) & 1);
// Discover some constant bits
if (cmin == cmax)
{
r.bmin |= (cmin & 1) << i;
r.bmax &= ~((~cmin & 1) << i);
}
cmin >>= 1;
cmax >>= 1;
}
return r;
}
// Range AND
spec_gpr operator &(const spec_gpr& rhs) const
{
// Ignore inverted ranges (TODO)
if (imin > imax || rhs.imin > rhs.imax)
{
return approx(ones() & rhs.ones(), mask() & rhs.mask());
}
// Const (TODO: remove when unnecessary)
if (imin == imax && rhs.imin == rhs.imax)
{
return fixed(imin & rhs.imin);
}
// Swap (TODO: remove when unnecessary)
if (imin == imax || rhs.undefs() > undefs())
{
return rhs & *this;
}
// Copy and attempt to partially preserve integral range
spec_gpr r = *this;
for (u32 i = 63; ~i; i--)
{
const u64 m = 1ull << i;
if (!(rhs.mask() & m))
{
if (r.undefs() & m)
{
// undef -> 0
r.imin &= ~(m - 1);
r.imax |= (m - 1);
r.imin &= ~m;
r.imax &= ~m;
}
else if (r.ones() & m)
{
// 1 -> 0
if ((r.imin ^ r.imax) > (m - 1))
{
r.imin &= ~(m - 1);
r.imax |= (m - 1);
}
r.imin &= ~m;
r.imax &= ~m;
}
}
else if (rhs.undefs() & m)
{
// -> undef
r.imin &= ~(m - 1);
r.imax |= (m - 1);
r.imin &= ~m;
r.imax |= m;
}
}
r.bmin = ones() & rhs.ones();
r.bmax = mask() & rhs.mask();
return r;
}
// Range OR
spec_gpr operator |(const spec_gpr& rhs) const
{
// Ignore inverted ranges (TODO)
if (imin > imax || rhs.imin > rhs.imax)
{
return approx(ones() | rhs.ones(), mask() | rhs.mask());
}
// Const (TODO: remove when unnecessary)
if (imin == imax && rhs.imin == rhs.imax)
{
return fixed(imin | rhs.imin);
}
// Swap (TODO: remove when unnecessary)
if (imin == imax || rhs.undefs() > undefs())
{
return rhs | *this;
}
// Copy and attempt to partially preserve integral range
spec_gpr r = *this;
for (u32 i = 63; ~i; i--)
{
const u64 m = 1ull << i;
if (rhs.ones() & m)
{
if (r.undefs() & m)
{
// undef -> 1
r.imin &= ~(m - 1);
r.imax |= (m - 1);
r.imin |= m;
r.imax |= m;
}
else if (!(r.mask() & m))
{
// 0 -> 1
if ((r.imin ^ r.imax) > (m - 1))
{
r.imin &= ~(m - 1);
r.imax |= (m - 1);
}
r.imin |= m;
r.imax |= m;
}
}
else if (rhs.undefs() & m)
{
// -> undef
r.imin &= ~(m - 1);
r.imax |= (m - 1);
r.imin &= ~m;
r.imax |= m;
}
}
r.bmin = ones() | rhs.ones();
r.bmax = mask() | rhs.mask();
return r;
}
// Range XOR
spec_gpr operator ^(const spec_gpr& rhs)
{
return (~*this & rhs) | (*this & ~rhs);
}
// Check whether the value is in range
bool test(u64 value) const
{
if (imin <= imax)
{
if (value < imin || value > imax)
{
return false;
}
}
else
{
if (value < imin && value > imax)
{
return false;
}
}
if ((value & mask()) != value)
{
return false;
}
if ((value | ones()) != value)
{
return false;
}
return true;
}
// Constant value
static spec_gpr fixed(u64 value)
{
spec_gpr r;
r.imin = value;
r.imax = value;
r.bmin = value;
r.bmax = value;
return r;
}
// Range (tz = number of constant trailing zeros)
static spec_gpr range(u64 min, u64 max, u64 tz = 0)
{
const u64 mask = tz < 64 ? ~0ull << tz : 0ull;
spec_gpr r;
r.bmin = 0;
r.bmax = mask;
// Normalize min/max for tz (TODO)
if (min < max)
{
// Inverted constant MSB mask
const u64 mix = ~0ull >> ::cntlz64(min ^ max, true);
r.bmin |= min & ~mix;
r.bmax &= max | mix;
r.imin = (min + ~mask) & mask;
r.imax = max & mask;
verify("Impossible range" HERE), r.imin <= r.imax;
}
else
{
r.imin = min & mask;
r.imax = (max + ~mask) & mask;
verify("Impossible range" HERE), r.imin >= r.imax;
}
// Fix const values
if (r.imin == r.imax)
{
r.bmin = r.imin;
r.bmax = r.imax;
}
return r;
}
// Make from bitrange (normalize, approximate range values)
static spec_gpr approx(u64 bmin, u64 bmax)
{
spec_gpr r;
r.imin = bmin & ~(bmin ^ bmax);
r.imax = bmax | (bmin ^ bmax);
r.bmin = bmin & ~(bmin ^ bmax);
r.bmax = bmax | (bmin ^ bmax);
return r;
}
} gpr[32]{};
// Vector registers (draft)
struct spec_vec
{
u8 imin8[16]{};
u8 imax8[16]{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
u16 imin16[8]{};
u16 imax16[8]{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
u32 imin32[4]{};
u32 imax32[4]{0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu};
u64 bmin64[2]{};
u64 bmax64[2]{0xffffffffffffffffull, 0xffffffffffffffffull};
};
// Info
u32 cia;
// Analyser step
void UNK(ppu_opcode_t);
void MFVSCR(ppu_opcode_t);
void MTVSCR(ppu_opcode_t);
void VADDCUW(ppu_opcode_t);
void VADDFP(ppu_opcode_t);
void VADDSBS(ppu_opcode_t);
void VADDSHS(ppu_opcode_t);
void VADDSWS(ppu_opcode_t);
void VADDUBM(ppu_opcode_t);
void VADDUBS(ppu_opcode_t);
void VADDUHM(ppu_opcode_t);
void VADDUHS(ppu_opcode_t);
void VADDUWM(ppu_opcode_t);
void VADDUWS(ppu_opcode_t);
void VAND(ppu_opcode_t);
void VANDC(ppu_opcode_t);
void VAVGSB(ppu_opcode_t);
void VAVGSH(ppu_opcode_t);
void VAVGSW(ppu_opcode_t);
void VAVGUB(ppu_opcode_t);
void VAVGUH(ppu_opcode_t);
void VAVGUW(ppu_opcode_t);
void VCFSX(ppu_opcode_t);
void VCFUX(ppu_opcode_t);
void VCMPBFP(ppu_opcode_t);
void VCMPEQFP(ppu_opcode_t);
void VCMPEQUB(ppu_opcode_t);
void VCMPEQUH(ppu_opcode_t);
void VCMPEQUW(ppu_opcode_t);
void VCMPGEFP(ppu_opcode_t);
void VCMPGTFP(ppu_opcode_t);
void VCMPGTSB(ppu_opcode_t);
void VCMPGTSH(ppu_opcode_t);
void VCMPGTSW(ppu_opcode_t);
void VCMPGTUB(ppu_opcode_t);
void VCMPGTUH(ppu_opcode_t);
void VCMPGTUW(ppu_opcode_t);
void VCTSXS(ppu_opcode_t);
void VCTUXS(ppu_opcode_t);
void VEXPTEFP(ppu_opcode_t);
void VLOGEFP(ppu_opcode_t);
void VMADDFP(ppu_opcode_t);
void VMAXFP(ppu_opcode_t);
void VMAXSB(ppu_opcode_t);
void VMAXSH(ppu_opcode_t);
void VMAXSW(ppu_opcode_t);
void VMAXUB(ppu_opcode_t);
void VMAXUH(ppu_opcode_t);
void VMAXUW(ppu_opcode_t);
void VMHADDSHS(ppu_opcode_t);
void VMHRADDSHS(ppu_opcode_t);
void VMINFP(ppu_opcode_t);
void VMINSB(ppu_opcode_t);
void VMINSH(ppu_opcode_t);
void VMINSW(ppu_opcode_t);
void VMINUB(ppu_opcode_t);
void VMINUH(ppu_opcode_t);
void VMINUW(ppu_opcode_t);
void VMLADDUHM(ppu_opcode_t);
void VMRGHB(ppu_opcode_t);
void VMRGHH(ppu_opcode_t);
void VMRGHW(ppu_opcode_t);
void VMRGLB(ppu_opcode_t);
void VMRGLH(ppu_opcode_t);
void VMRGLW(ppu_opcode_t);
void VMSUMMBM(ppu_opcode_t);
void VMSUMSHM(ppu_opcode_t);
void VMSUMSHS(ppu_opcode_t);
void VMSUMUBM(ppu_opcode_t);
void VMSUMUHM(ppu_opcode_t);
void VMSUMUHS(ppu_opcode_t);
void VMULESB(ppu_opcode_t);
void VMULESH(ppu_opcode_t);
void VMULEUB(ppu_opcode_t);
void VMULEUH(ppu_opcode_t);
void VMULOSB(ppu_opcode_t);
void VMULOSH(ppu_opcode_t);
void VMULOUB(ppu_opcode_t);
void VMULOUH(ppu_opcode_t);
void VNMSUBFP(ppu_opcode_t);
void VNOR(ppu_opcode_t);
void VOR(ppu_opcode_t);
void VPERM(ppu_opcode_t);
void VPKPX(ppu_opcode_t);
void VPKSHSS(ppu_opcode_t);
void VPKSHUS(ppu_opcode_t);
void VPKSWSS(ppu_opcode_t);
void VPKSWUS(ppu_opcode_t);
void VPKUHUM(ppu_opcode_t);
void VPKUHUS(ppu_opcode_t);
void VPKUWUM(ppu_opcode_t);
void VPKUWUS(ppu_opcode_t);
void VREFP(ppu_opcode_t);
void VRFIM(ppu_opcode_t);
void VRFIN(ppu_opcode_t);
void VRFIP(ppu_opcode_t);
void VRFIZ(ppu_opcode_t);
void VRLB(ppu_opcode_t);
void VRLH(ppu_opcode_t);
void VRLW(ppu_opcode_t);
void VRSQRTEFP(ppu_opcode_t);
void VSEL(ppu_opcode_t);
void VSL(ppu_opcode_t);
void VSLB(ppu_opcode_t);
void VSLDOI(ppu_opcode_t);
void VSLH(ppu_opcode_t);
void VSLO(ppu_opcode_t);
void VSLW(ppu_opcode_t);
void VSPLTB(ppu_opcode_t);
void VSPLTH(ppu_opcode_t);
void VSPLTISB(ppu_opcode_t);
void VSPLTISH(ppu_opcode_t);
void VSPLTISW(ppu_opcode_t);
void VSPLTW(ppu_opcode_t);
void VSR(ppu_opcode_t);
void VSRAB(ppu_opcode_t);
void VSRAH(ppu_opcode_t);
void VSRAW(ppu_opcode_t);
void VSRB(ppu_opcode_t);
void VSRH(ppu_opcode_t);
void VSRO(ppu_opcode_t);
void VSRW(ppu_opcode_t);
void VSUBCUW(ppu_opcode_t);
void VSUBFP(ppu_opcode_t);
void VSUBSBS(ppu_opcode_t);
void VSUBSHS(ppu_opcode_t);
void VSUBSWS(ppu_opcode_t);
void VSUBUBM(ppu_opcode_t);
void VSUBUBS(ppu_opcode_t);
void VSUBUHM(ppu_opcode_t);
void VSUBUHS(ppu_opcode_t);
void VSUBUWM(ppu_opcode_t);
void VSUBUWS(ppu_opcode_t);
void VSUMSWS(ppu_opcode_t);
void VSUM2SWS(ppu_opcode_t);
void VSUM4SBS(ppu_opcode_t);
void VSUM4SHS(ppu_opcode_t);
void VSUM4UBS(ppu_opcode_t);
void VUPKHPX(ppu_opcode_t);
void VUPKHSB(ppu_opcode_t);
void VUPKHSH(ppu_opcode_t);
void VUPKLPX(ppu_opcode_t);
void VUPKLSB(ppu_opcode_t);
void VUPKLSH(ppu_opcode_t);
void VXOR(ppu_opcode_t);
void TDI(ppu_opcode_t);
void TWI(ppu_opcode_t);
void MULLI(ppu_opcode_t);
void SUBFIC(ppu_opcode_t);
void CMPLI(ppu_opcode_t);
void CMPI(ppu_opcode_t);
void ADDIC(ppu_opcode_t);
void ADDI(ppu_opcode_t);
void ADDIS(ppu_opcode_t);
void BC(ppu_opcode_t);
void SC(ppu_opcode_t);
void B(ppu_opcode_t);
void MCRF(ppu_opcode_t);
void BCLR(ppu_opcode_t);
void CRNOR(ppu_opcode_t);
void CRANDC(ppu_opcode_t);
void ISYNC(ppu_opcode_t);
void CRXOR(ppu_opcode_t);
void CRNAND(ppu_opcode_t);
void CRAND(ppu_opcode_t);
void CREQV(ppu_opcode_t);
void CRORC(ppu_opcode_t);
void CROR(ppu_opcode_t);
void BCCTR(ppu_opcode_t);
void RLWIMI(ppu_opcode_t);
void RLWINM(ppu_opcode_t);
void RLWNM(ppu_opcode_t);
void ORI(ppu_opcode_t);
void ORIS(ppu_opcode_t);
void XORI(ppu_opcode_t);
void XORIS(ppu_opcode_t);
void ANDI(ppu_opcode_t);
void ANDIS(ppu_opcode_t);
void RLDICL(ppu_opcode_t);
void RLDICR(ppu_opcode_t);
void RLDIC(ppu_opcode_t);
void RLDIMI(ppu_opcode_t);
void RLDCL(ppu_opcode_t);
void RLDCR(ppu_opcode_t);
void CMP(ppu_opcode_t);
void TW(ppu_opcode_t);
void LVSL(ppu_opcode_t);
void LVEBX(ppu_opcode_t);
void SUBFC(ppu_opcode_t);
void ADDC(ppu_opcode_t);
void MULHDU(ppu_opcode_t);
void MULHWU(ppu_opcode_t);
void MFOCRF(ppu_opcode_t);
void LWARX(ppu_opcode_t);
void LDX(ppu_opcode_t);
void LWZX(ppu_opcode_t);
void SLW(ppu_opcode_t);
void CNTLZW(ppu_opcode_t);
void SLD(ppu_opcode_t);
void AND(ppu_opcode_t);
void CMPL(ppu_opcode_t);
void LVSR(ppu_opcode_t);
void LVEHX(ppu_opcode_t);
void SUBF(ppu_opcode_t);
void LDUX(ppu_opcode_t);
void DCBST(ppu_opcode_t);
void LWZUX(ppu_opcode_t);
void CNTLZD(ppu_opcode_t);
void ANDC(ppu_opcode_t);
void TD(ppu_opcode_t);
void LVEWX(ppu_opcode_t);
void MULHD(ppu_opcode_t);
void MULHW(ppu_opcode_t);
void LDARX(ppu_opcode_t);
void DCBF(ppu_opcode_t);
void LBZX(ppu_opcode_t);
void LVX(ppu_opcode_t);
void NEG(ppu_opcode_t);
void LBZUX(ppu_opcode_t);
void NOR(ppu_opcode_t);
void STVEBX(ppu_opcode_t);
void SUBFE(ppu_opcode_t);
void ADDE(ppu_opcode_t);
void MTOCRF(ppu_opcode_t);
void STDX(ppu_opcode_t);
void STWCX(ppu_opcode_t);
void STWX(ppu_opcode_t);
void STVEHX(ppu_opcode_t);
void STDUX(ppu_opcode_t);
void STWUX(ppu_opcode_t);
void STVEWX(ppu_opcode_t);
void SUBFZE(ppu_opcode_t);
void ADDZE(ppu_opcode_t);
void STDCX(ppu_opcode_t);
void STBX(ppu_opcode_t);
void STVX(ppu_opcode_t);
void SUBFME(ppu_opcode_t);
void MULLD(ppu_opcode_t);
void ADDME(ppu_opcode_t);
void MULLW(ppu_opcode_t);
void DCBTST(ppu_opcode_t);
void STBUX(ppu_opcode_t);
void ADD(ppu_opcode_t);
void DCBT(ppu_opcode_t);
void LHZX(ppu_opcode_t);
void EQV(ppu_opcode_t);
void ECIWX(ppu_opcode_t);
void LHZUX(ppu_opcode_t);
void XOR(ppu_opcode_t);
void MFSPR(ppu_opcode_t);
void LWAX(ppu_opcode_t);
void DST(ppu_opcode_t);
void LHAX(ppu_opcode_t);
void LVXL(ppu_opcode_t);
void MFTB(ppu_opcode_t);
void LWAUX(ppu_opcode_t);
void DSTST(ppu_opcode_t);
void LHAUX(ppu_opcode_t);
void STHX(ppu_opcode_t);
void ORC(ppu_opcode_t);
void ECOWX(ppu_opcode_t);
void STHUX(ppu_opcode_t);
void OR(ppu_opcode_t);
void DIVDU(ppu_opcode_t);
void DIVWU(ppu_opcode_t);
void MTSPR(ppu_opcode_t);
void DCBI(ppu_opcode_t);
void NAND(ppu_opcode_t);
void STVXL(ppu_opcode_t);
void DIVD(ppu_opcode_t);
void DIVW(ppu_opcode_t);
void LVLX(ppu_opcode_t);
void LDBRX(ppu_opcode_t);
void LSWX(ppu_opcode_t);
void LWBRX(ppu_opcode_t);
void LFSX(ppu_opcode_t);
void SRW(ppu_opcode_t);
void SRD(ppu_opcode_t);
void LVRX(ppu_opcode_t);
void LSWI(ppu_opcode_t);
void LFSUX(ppu_opcode_t);
void SYNC(ppu_opcode_t);
void LFDX(ppu_opcode_t);
void LFDUX(ppu_opcode_t);
void STVLX(ppu_opcode_t);
void STDBRX(ppu_opcode_t);
void STSWX(ppu_opcode_t);
void STWBRX(ppu_opcode_t);
void STFSX(ppu_opcode_t);
void STVRX(ppu_opcode_t);
void STFSUX(ppu_opcode_t);
void STSWI(ppu_opcode_t);
void STFDX(ppu_opcode_t);
void STFDUX(ppu_opcode_t);
void LVLXL(ppu_opcode_t);
void LHBRX(ppu_opcode_t);
void SRAW(ppu_opcode_t);
void SRAD(ppu_opcode_t);
void LVRXL(ppu_opcode_t);
void DSS(ppu_opcode_t);
void SRAWI(ppu_opcode_t);
void SRADI(ppu_opcode_t);
void EIEIO(ppu_opcode_t);
void STVLXL(ppu_opcode_t);
void STHBRX(ppu_opcode_t);
void EXTSH(ppu_opcode_t);
void STVRXL(ppu_opcode_t);
void EXTSB(ppu_opcode_t);
void STFIWX(ppu_opcode_t);
void EXTSW(ppu_opcode_t);
void ICBI(ppu_opcode_t);
void DCBZ(ppu_opcode_t);
void LWZ(ppu_opcode_t);
void LWZU(ppu_opcode_t);
void LBZ(ppu_opcode_t);
void LBZU(ppu_opcode_t);
void STW(ppu_opcode_t);
void STWU(ppu_opcode_t);
void STB(ppu_opcode_t);
void STBU(ppu_opcode_t);
void LHZ(ppu_opcode_t);
void LHZU(ppu_opcode_t);
void LHA(ppu_opcode_t);
void LHAU(ppu_opcode_t);
void STH(ppu_opcode_t);
void STHU(ppu_opcode_t);
void LMW(ppu_opcode_t);
void STMW(ppu_opcode_t);
void LFS(ppu_opcode_t);
void LFSU(ppu_opcode_t);
void LFD(ppu_opcode_t);
void LFDU(ppu_opcode_t);
void STFS(ppu_opcode_t);
void STFSU(ppu_opcode_t);
void STFD(ppu_opcode_t);
void STFDU(ppu_opcode_t);
void LD(ppu_opcode_t);
void LDU(ppu_opcode_t);
void LWA(ppu_opcode_t);
void STD(ppu_opcode_t);
void STDU(ppu_opcode_t);
void FDIVS(ppu_opcode_t);
void FSUBS(ppu_opcode_t);
void FADDS(ppu_opcode_t);
void FSQRTS(ppu_opcode_t);
void FRES(ppu_opcode_t);
void FMULS(ppu_opcode_t);
void FMADDS(ppu_opcode_t);
void FMSUBS(ppu_opcode_t);
void FNMSUBS(ppu_opcode_t);
void FNMADDS(ppu_opcode_t);
void MTFSB1(ppu_opcode_t);
void MCRFS(ppu_opcode_t);
void MTFSB0(ppu_opcode_t);
void MTFSFI(ppu_opcode_t);
void MFFS(ppu_opcode_t);
void MTFSF(ppu_opcode_t);
void FCMPU(ppu_opcode_t);
void FRSP(ppu_opcode_t);
void FCTIW(ppu_opcode_t);
void FCTIWZ(ppu_opcode_t);
void FDIV(ppu_opcode_t);
void FSUB(ppu_opcode_t);
void FADD(ppu_opcode_t);
void FSQRT(ppu_opcode_t);
void FSEL(ppu_opcode_t);
void FMUL(ppu_opcode_t);
void FRSQRTE(ppu_opcode_t);
void FMSUB(ppu_opcode_t);
void FMADD(ppu_opcode_t);
void FNMSUB(ppu_opcode_t);
void FNMADD(ppu_opcode_t);
void FCMPO(ppu_opcode_t);
void FNEG(ppu_opcode_t);
void FMR(ppu_opcode_t);
void FNABS(ppu_opcode_t);
void FABS(ppu_opcode_t);
void FCTID(ppu_opcode_t);
void FCTIDZ(ppu_opcode_t);
void FCFID(ppu_opcode_t);
};
+4 -4
View File
@@ -16,7 +16,7 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_mod
, m_module(module)
, m_is_be(false)
, m_info(info)
, m_pure_attr(AttributeSet::get(m_context, AttributeSet::FunctionIndex, {Attribute::NoUnwind, Attribute::ReadNone}))
, m_pure_attr(AttributeList::get(m_context,AttributeList::FunctionIndex, AttrBuilder().addAttribute(Attribute::NoUnwind).addAttribute(Attribute::ReadNone)))
{
// There is no weak linkage on JIT, so let's create variables with different names for each module part
const u32 gsuffix = m_info.name.empty() ? info.funcs[0].addr : info.funcs[0].addr - m_info.segs[0].addr;
@@ -133,7 +133,7 @@ Function* PPUTranslator::Translate(const ppu_function& info)
const u64 base = m_reloc ? m_reloc->addr : 0;
m_addr = info.addr - base;
m_thread = &*m_function->getArgumentList().begin();
m_thread = &*m_function->arg_begin();
m_base_loaded = m_ir->CreateLoad(m_base);
m_body = BasicBlock::Create(m_context, "__body", m_function);
@@ -290,7 +290,7 @@ Value* PPUTranslator::RegInit(Value*& local)
Value* PPUTranslator::RegLoad(Value*& local)
{
const uint index = ::narrow<uint>(&local - m_locals);
const auto index = ::narrow<uint>(&local - m_locals);
if (local)
{
@@ -315,7 +315,7 @@ void PPUTranslator::FlushRegisters()
for (auto& local : m_locals)
{
const uint index = static_cast<uint>(&local - m_locals);
const auto index = ::narrow<uint>(&local - m_locals);
// Store value if necessary
if (local && m_globals[index])
+3 -3
View File
@@ -120,7 +120,7 @@ class PPUTranslator final //: public CPUTranslator
std::map<u64, const ppu_reloc*> m_relocs;
// Attributes for function calls which are "pure" and may be optimized away if their results are unused
const llvm::AttributeSet m_pure_attr;
const llvm::AttributeList m_pure_attr;
// IR builder
llvm::IRBuilder<>* m_ir;
@@ -404,7 +404,7 @@ public:
// Call a function with attribute list
template<typename... Args>
llvm::CallInst* Call(llvm::Type* ret, llvm::AttributeSet attr, llvm::StringRef name, Args... args)
llvm::CallInst* Call(llvm::Type* ret, llvm::AttributeList attr, llvm::StringRef name, Args... args)
{
// Call the function
return m_ir->CreateCall(m_module->getOrInsertFunction(name, llvm::FunctionType::get(ret, {args->getType()...}, false), attr), {args...});
@@ -414,7 +414,7 @@ public:
template<typename... Args>
llvm::CallInst* Call(llvm::Type* ret, llvm::StringRef name, Args... args)
{
return Call(ret, llvm::AttributeSet{}, name, args...);
return Call(ret, llvm::AttributeList{}, name, args...);
}
// Handle compilation errors
+3 -1
View File
@@ -999,6 +999,7 @@ u32 SPUThread::get_ch_count(u32 ch)
case SPU_RdSigNotify2: return ch_snr2.get_count();
case MFC_RdAtomicStat: return ch_atomic_stat.get_count();
case SPU_RdEventStat: return get_events() != 0;
case MFC_Cmd: return std::max(16 - mfc_queue.size(), (u32)0);
}
fmt::throw_exception("Unknown/illegal channel (ch=%d [%s])" HERE, ch, ch < 128 ? spu_ch_name[ch] : "???");
@@ -1434,8 +1435,9 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
case MFC_Cmd:
{
ch_mfc_cmd.cmd = MFC(value & 0xff);
auto cmd = ch_mfc_cmd; // save and restore previous command arguments
process_mfc_cmd();
ch_mfc_cmd = {}; // clear non-persistent data
ch_mfc_cmd = cmd;
return true;
}
+1
View File
@@ -1326,6 +1326,7 @@ error_code sys_fs_disk_free(vm::ps3::cptr<char> path, vm::ptr<u64> total_free, v
error_code sys_fs_utime(vm::ps3::cptr<char> path, vm::ps3::cptr<CellFsUtimbuf> timep)
{
sys_fs.warning("sys_fs_utime(path=%s, timep=*0x%x)", path, timep);
sys_fs.warning("** actime=%u, modtime=%u", timep->actime, timep->modtime);
const std::string local_path = vfs::get(path.get_ptr());
+33 -7
View File
@@ -1237,6 +1237,18 @@ s32 sys_net_bnet_setsockopt(ppu_thread& ppu, s32 s, s32 level, s32 optname, vm::
native_linger.l_linger = ((const sys_net_linger*)optval.get_ptr())->l_linger;
break;
}
case SYS_NET_SO_USECRYPTO:
{
//TODO
sys_net.error("sys_net_bnet_setsockopt(s=%d, SOL_SOCKET): Stubbed option (0x%x) (SYS_NET_SO_USECRYPTO)", s, optname);
return 0;
}
case SYS_NET_SO_USESIGNATURE:
{
//TODO
sys_net.error("sys_net_bnet_setsockopt(s=%d, SOL_SOCKET): Stubbed option (0x%x) (SYS_NET_SO_USESIGNATURE)", s, optname);
return 0;
}
default:
{
sys_net.error("sys_net_bnet_setsockopt(s=%d, SOL_SOCKET): unknown option (0x%x)", s, optname);
@@ -1333,24 +1345,38 @@ s32 sys_net_bnet_socket(ppu_thread& ppu, s32 family, s32 type, s32 protocol)
{
sys_net.warning("sys_net_bnet_socket(family=%d, type=%d, protocol=%d)", family, type, protocol);
if (family != SYS_NET_AF_INET)
if (family != SYS_NET_AF_INET && family != SYS_NET_AF_UNSPEC)
{
sys_net.error("sys_net_bnet_socket(): unknown family (%d)", family);
}
if (type != SYS_NET_SOCK_STREAM && type != SYS_NET_SOCK_DGRAM)
if (type != SYS_NET_SOCK_STREAM && type != SYS_NET_SOCK_DGRAM && type != SYS_NET_SOCK_DGRAM_P2P)
{
sys_net.error("sys_net_bnet_socket(): unsupported type (%d)", type);
return -SYS_NET_EPROTONOSUPPORT;
}
const int native_domain = AF_INET;
const int native_domain = family == SYS_NET_AF_INET ? AF_INET :
family == SYS_NET_AF_UNSPEC ? AF_UNSPEC : AF_INET;
const int native_type =
type == SYS_NET_SOCK_STREAM ? SOCK_STREAM :
type == SYS_NET_SOCK_DGRAM ? SOCK_DGRAM : SOCK_RAW;
const int native_proto =
type == SYS_NET_SOCK_STREAM ? 0 :
type == SYS_NET_SOCK_DGRAM ? 0 : 0;
type == SYS_NET_SOCK_DGRAM ? SOCK_DGRAM :
type == SYS_NET_SOCK_DGRAM_P2P ? SOCK_DGRAM : SOCK_RAW;
int native_proto =
protocol == SYS_NET_IPPROTO_IP ? IPPROTO_IP :
protocol == SYS_NET_IPPROTO_ICMP ? IPPROTO_ICMP :
protocol == SYS_NET_IPPROTO_IGMP ? IPPROTO_IGMP :
protocol == SYS_NET_IPPROTO_TCP ? IPPROTO_TCP :
protocol == SYS_NET_IPPROTO_UDP ? IPPROTO_UDP :
protocol == SYS_NET_IPPROTO_ICMPV6 ? IPPROTO_ICMPV6 : 0;
if (native_domain == AF_UNSPEC && type == SYS_NET_SOCK_DGRAM)
{
//Windows gets all errory if you try a unspec socket with protocol 0
native_proto = IPPROTO_UDP;
}
const auto native_socket = ::socket(native_domain, native_type, native_proto);
+9 -4
View File
@@ -3,6 +3,7 @@
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Crypto/unedat.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h"
@@ -288,19 +289,23 @@ void _sys_process_exit2(ppu_thread& ppu, s32 status, vm::ptr<sys_exit2_param> ar
vm::temporary_unlock(ppu);
Emu.CallAfter([path = std::move(path), argv = std::move(argv), envp = std::move(envp), data = std::move(data)]()
Emu.CallAfter([path = std::move(path), argv = std::move(argv), envp = std::move(envp), data = std::move(data), disc = vfs::get("/dev_bdvd/"), klic = fxm::get_always<LoadedNpdrmKeys_t>()->devKlic]() mutable
{
sys_process.success("Process finished -> %s", argv[0]);
Emu.SetForceBoot(true);
Emu.Stop();
Emu.argv = std::move(argv);
Emu.envp = std::move(envp);
Emu.data = std::move(data);
Emu.BootGame(path, true);
Emu.disc = std::move(disc);
if (Emu.IsReady() && !g_cfg.misc.autostart)
if (klic != std::array<u8, 16>{})
{
Emu.Run();
Emu.klic.assign(klic.begin(), klic.end());
}
Emu.SetForceBoot(true);
Emu.BootGame(path, true);
});
thread_ctrl::eternalize();
+22 -9
View File
@@ -7,6 +7,7 @@
#include "Emu/Cell/ErrorCodes.h"
#include "Crypto/unedat.h"
#include "sys_fs.h"
#include "sys_prx.h"
namespace vm { using namespace ps3; }
@@ -76,13 +77,11 @@ static const std::unordered_map<std::string, int> s_prx_ignore
{ "/dev_flash/sys/external/libsysutil_video_export.sprx", 0 },
{ "/dev_flash/sys/external/libsysutil_video_player.sprx", 0 },
{ "/dev_flash/sys/external/libsysutil_video_upload.sprx", 0 },
{ "/dev_flash/sys/external/libusbd.sprx", 0 },
{ "/dev_flash/sys/external/libusbpspcm.sprx", 0 },
{ "/dev_flash/sys/external/libvdec.sprx", 0 },
{ "/dev_flash/sys/external/libvoice.sprx", 0 },
};
error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, fs::file src = {})
{
std::string name = vpath.substr(vpath.find_last_of('/') + 1);
std::string path = vfs::get(vpath);
@@ -125,7 +124,12 @@ error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<sys_prx_
return not_an_error(idm::last_id());
}
const ppu_prx_object obj = decrypt_self(fs::file(path), fxm::get_always<LoadedNpdrmKeys_t>()->devKlic.data());
if (!src)
{
src.open(path);
}
const ppu_prx_object obj = decrypt_self(std::move(src), fxm::get_always<LoadedNpdrmKeys_t>()->devKlic.data());
if (obj != elf_error::ok)
{
@@ -154,14 +158,23 @@ error_code sys_prx_get_ppu_guid()
error_code _sys_prx_load_module_by_fd(s32 fd, u64 offset, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
{
sys_prx.todo("_sys_prx_load_module_by_fd(fd=%d, offset=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, flags, pOpt);
return CELL_OK;
sys_prx.warning("_sys_prx_load_module_by_fd(fd=%d, offset=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, flags, pOpt);
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
if (!file)
{
return CELL_EBADF;
}
return prx_load_module(fmt::format("%s_x%x", file->name.data(), offset), flags, pOpt, lv2_file::make_view(file, offset));
}
error_code _sys_prx_load_module_on_memcontainer_by_fd(s32 fd, u64 offset, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
{
sys_prx.todo("_sys_prx_load_module_on_memcontainer_by_fd(fd=%d, offset=0x%x, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, mem_ct, flags, pOpt);
return CELL_OK;
sys_prx.warning("_sys_prx_load_module_on_memcontainer_by_fd(fd=%d, offset=0x%x, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, mem_ct, flags, pOpt);
return _sys_prx_load_module_by_fd(fd, offset, flags, pOpt);
}
error_code _sys_prx_load_module_list(s32 count, vm::cpptr<char, u32, u64> path_list, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list)
@@ -268,7 +281,7 @@ error_code _sys_prx_unload_module(u32 id, u64 flags, vm::ptr<sys_prx_unload_modu
ppu_unload_prx(*prx);
//s32 result = prx->exit ? prx->exit() : CELL_OK;
return CELL_OK;
}
+7
View File
@@ -242,6 +242,7 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6
case 0x001: // FIFO
render->ctrl->get = a3;
render->ctrl->put = a4;
render->internal_get = a3;
break;
case 0x100: // Display mode set
@@ -322,6 +323,12 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6
//a5 low bits = ret.format = base | ((base + ((size - 1) / 0x10000)) << 13) | (comp << 26) | (1 << 30);
auto& tile = render->tiles[a3];
// When tile is going to be unbinded, we can use it as a hint that the address will no longer be used as a surface and can be removed/invalidated
// Todo: There may be more checks such as format/size/width can could be done
if (tile.binded && a5 == 0)
render->notify_tile_unbound(a3);
tile.location = ((a4 >> 32) & 0xF) - 1;
tile.offset = ((((a4 >> 32) & 0xFFFFFFFF) >> 16) * 0x10000);
tile.size = ((((a4 & 0x7FFFFFFF) >> 16) + 1) * 0x10000) - tile.offset;
+2 -2
View File
@@ -296,7 +296,7 @@ error_code sys_spu_thread_group_create(vm::ptr<u32> id, u32 num, s32 prio, vm::p
// TODO: max num value should be affected by sys_spu_initialize() settings
if (!num || num > 6 || prio < 16 || prio > 255)
if (attr->nsize > 0x80 || !num || num > 6 || ((prio < 16 || prio > 255) && attr->type != SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT))
{
return CELL_EINVAL;
}
@@ -306,7 +306,7 @@ error_code sys_spu_thread_group_create(vm::ptr<u32> id, u32 num, s32 prio, vm::p
sys_spu.todo("Unsupported SPU Thread Group type (0x%x)", attr->type);
}
*id = idm::make<lv2_spu_group>(std::string(attr->name.get_ptr(), attr->nsize - 1), num, prio, attr->type, attr->ct);
*id = idm::make<lv2_spu_group>(std::string(attr->name.get_ptr(), std::max<u32>(attr->nsize, 1) - 1), num, prio, attr->type, attr->ct);
return CELL_OK;
}
+1 -1
View File
@@ -11,7 +11,7 @@ const HCRYPTPROV s_crypto_provider = []() -> HCRYPTPROV
{
HCRYPTPROV result;
if (!CryptAcquireContextW(&result, nullptr, nullptr, PROV_RSA_FULL, 0))
if (!CryptAcquireContextW(&result, nullptr, nullptr, PROV_RSA_FULL, 0) && !CryptAcquireContextW(&result, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
return 0;
}
+157 -21
View File
@@ -4,14 +4,37 @@
#include "Emu/Cell/ErrorCodes.h"
#include "sys_usbd.h"
#include "sys_ppu_thread.h"
namespace vm { using namespace ps3; }
logs::channel sys_usbd("sys_usbd");
s32 sys_usbd_initialize()
std::vector<usbDevice> devices = {
// System devices
usbDevice{ DeviceListUnknownDataType{0x1, 0x2, 0x2, 0x44}, 50, deviceDescriptor{0x12, 0x1, 0x0200, 0, 0, 0, 0x40, 0x054C, 0x0250, 0x0009, 3, 4, 5, 1}},
usbDevice{ DeviceListUnknownDataType{0x1, 0x3, 0x2, 0xAD}, 326, deviceDescriptor{0x12, 0x1, 0x0200, 0xE0, 0x1, 0x1, 0x40, 0x054C, 0x0267, 0x0001, 1, 2, 0, 1}},
// USB Drive
usbDevice{ DeviceListUnknownDataType{0x0, 0x4, 0x2, 0x0}, 50, deviceDescriptor{0x12, 0x1, 0x0200, 0, 0, 0, 0x40, 0x1516, 0x1226, 0x0100, 1, 2, 3, 1}},
// Skylanders Portal
usbDevice{ DeviceListUnknownDataType{0x0, 0x5, 0x2, 0xF8}, 59, deviceDescriptor{0x12, 0x1, 0x0200, 0, 0, 0, 0x20, 0x1430, 0x0150, 0x0100, 1, 2, 0, 1}},
};
bool has_register_extra_ldd;
int receive_event_called_count;
/*
* sys_usbd_initialize changes handle to a semi-unique identifier.
* identifier generation is speculated to be:
* f(n+1) = (f(n) + 2<<9) % 14847 + f_min (probably just f(0)-14847 but it could be different)
* Thanks to @flash-fire for thinking up the identifier generation code.
* TODO: try to get hardware to return not CELL_OK (perhaps set handle to NULL).
*/
s32 sys_usbd_initialize(vm::ptr<u32> handle)
{
sys_usbd.todo("sys_usbd_initialize()");
sys_usbd.warning("sys_usbd_initialize(0x%x)", handle.get_ptr());
*handle = 805322496;
has_register_extra_ldd = false;
receive_event_called_count = 0;
return CELL_OK;
}
@@ -21,21 +44,118 @@ s32 sys_usbd_finalize()
return CELL_OK;
}
s32 sys_usbd_get_device_list()
s32 sys_usbd_get_device_list(u32 handle, vm::ptr<DeviceListUnknownDataType> device_list, char unknown)
{
sys_usbd.todo("sys_usbd_get_device_list()");
return CELL_OK;
sys_usbd.warning("sys_usbd_get_device_list(handle=%d, device_list=0x%x, unknown=%c)", handle, device_list, unknown);
// Unknown is just 0x7F
for (int i = 0; i < devices.size(); i++)
{
device_list[i] = devices[i].basicDevice;
}
return devices.size();
}
s32 sys_usbd_get_descriptor_size()
s32 sys_usbd_register_extra_ldd(u32 handle, vm::ptr<void> lddOps, u16 strLen, u16 vendorID, u16 productID, u16 unk1)
{
sys_usbd.todo("sys_usbd_get_descriptor_size()");
return CELL_OK;
sys_usbd.warning("sys_usbd_register_extra_ldd(handle=%u, lddOps=0x%x, unk1=%u, vendorID=%u, productID=%u, unk2=%u)", handle, lddOps, strLen, vendorID, productID, unk1);
has_register_extra_ldd = true;
// No idea what 9 means.
return 9;
}
s32 sys_usbd_get_descriptor()
s32 sys_usbd_get_descriptor_size(u32 handle, u8 deviceNumber)
{
sys_usbd.todo("sys_usbd_get_descriptor()");
sys_usbd.warning("sys_usbd_get_descriptor_size(handle=%u, deviceNumber=%u)", handle, deviceNumber);
return devices[deviceNumber-2].descSize;
}
s32 sys_usbd_get_descriptor(u32 handle, u8 deviceNumber, vm::ptr<deviceDescriptor> descriptor, s64 descSize)
{
sys_usbd.warning("sys_usbd_get_descriptor(handle=%u, deviceNumber=%u, descriptor=0x%x, descSize=%u)", handle, deviceNumber, descriptor, descSize);
// Just gonna have to hack it for now
u8 device = deviceNumber-2;
unsigned char* desc = (unsigned char*)descriptor.get_ptr();
if (device == 0)
{
unsigned char bytes[] = {0x12, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x40, 0x4c, 0x5, 0x50, 0x2, 0x9, 0x0, 0x3, 0x4, 0x5, 0x1,
0x9, 0x2, 0x20, 0x0, 0x1, 0x1, 0x0, 0x80, 0xfa,
0x9, 0x4, 0x0, 0x0, 0x2, 0x8, 0x5, 0x50, 0x0,
0x7, 0x5, 0x81, 0x2, 0x0, 0x2, 0x0,
0x7, 0x5, 0x2, 0x2, 0x0, 0x2, 0x0};
memcpy(desc, bytes, descSize);
}
else if (device == 1)
{
unsigned char bytes[] = {0x12, 0x1, 0x0, 0x2, 0xe0, 0x1, 0x1, 0x40, 0x4c, 0x5, 0x67, 0x2, 0x0, 0x1, 0x1, 0x2, 0x0, 0x1,
0x9, 0x2, 0x34, 0x1, 0x4, 0x1, 0x0, 0xc0, 0x0,
0x9, 0x4, 0x0, 0x0, 0x3, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x81, 0x3, 0x40, 0x0, 0x1,
0x7, 0x5, 0x2, 0x2, 0x0, 0x2, 0x0,
0x7, 0x5, 0x82, 0x2, 0x0, 0x2, 0x0,
0x9, 0x4, 0x1, 0x0, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x3, 0x1, 0x0, 0x0, 0x4,
0x7, 0x5, 0x83, 0x1, 0x0, 0x0, 0x4,
0x9, 0x4, 0x1, 0x1, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x3, 0x1, 0xb, 0x0, 0x4,
0x7, 0x5, 0x83, 0x1, 0xb, 0x0, 0x4,
0x9, 0x4, 0x1, 0x2, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x3, 0x1, 0x13, 0x0, 0x4,
0x7, 0x5, 0x83, 0x1, 0x13, 0x0, 0x4,
0x9, 0x4, 0x1, 0x3, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x3, 0x1, 0x1b, 0x0, 0x4,
0x7, 0x5, 0x83, 0x1, 0x1b, 0x0, 0x4,
0x9, 0x4, 0x1, 0x4, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x3, 0x1, 0x23, 0x0, 0x4,
0x7, 0x5, 0x83, 0x1, 0x23, 0x0, 0x4,
0x9, 0x4, 0x1, 0x5, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x3, 0x1, 0x33, 0x0, 0x4,
0x7, 0x5, 0x83, 0x1, 0x33, 0x0, 0x4,
0x9, 0x4, 0x1, 0x6, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x3, 0x1, 0x40, 0x0, 0x4,
0x7, 0x5, 0x83, 0x1, 0x40, 0x0, 0x4,
0x9, 0x4, 0x2, 0x0, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x4, 0x3, 0x40, 0x0, 0x1,
0x7, 0x5, 0x85, 0x3, 0x40, 0x0, 0x1,
0x9, 0x4, 0x2, 0x1, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x4, 0x3, 0x80, 0x0, 0x1,
0x7, 0x5, 0x85, 0x3, 0x80, 0x0, 0x1,
0x9, 0x4, 0x2, 0x2, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x4, 0x3, 0x0, 0x1, 0x1,
0x7, 0x5, 0x85, 0x3, 0x0, 0x1, 0x1,
0x9, 0x4, 0x2, 0x3, 0x2, 0xe0, 0x1, 0x1, 0x0,
0x7, 0x5, 0x4, 0x3, 0x0, 0x4, 0x1,
0x7, 0x5, 0x85, 0x3, 0x0, 0x4, 0x1,
0x9, 0x4, 0x3, 0x0, 0x0, 0xfe, 0x1, 0x0, 0x0,
0x7, 0x21, 0x7, 0x88, 0x13, 0xff, 0x3};
memcpy(desc, bytes, descSize);
}
else if (device == 2)
{
// USB Drive
unsigned char bytes[] = {0x12, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x40, 0x16, 0x15, 0x26, 0x12, 0x0, 0x1, 0x1, 0x2, 0x3, 0x1,
0x9, 0x2, 0x20, 0x0, 0x1, 0x1, 0x0, 0x80, 0xfa,
0x9, 0x4, 0x0, 0x0, 0x2, 0x8, 0x6, 0x50, 0x0,
0x7, 0x5, 0x81, 0x2, 0x0, 0x2, 0x0,
0x7, 0x5, 0x2, 0x2, 0x0, 0x2, 0x0};
memcpy(desc, bytes, descSize);
}
else if (device == 3 || device == 4)
{
// Skylanders Portal
unsigned char bytes[] = {0x12, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x20, 0x30, 0x14, 0x50, 0x1, 0x0, 0x1, 0x1, 0x2, 0x0, 0x1,
0x9, 0x2, 0x29, 0x0, 0x1, 0x1, 0x0, 0x80, 0x96,
0x9, 0x4, 0x0, 0x0, 0x2, 0x3, 0x0, 0x0, 0x0,
0x9, 0x21, 0x11, 0x1, 0x0, 0x1, 0x22, 0x1d, 0x0,
0x7, 0x5, 0x81, 0x3, 0x20, 0x0, 0x1,
0x7, 0x5, 0x1, 0x3, 0x20, 0x0, 0x1};
memcpy(desc, bytes, descSize);
}
else
return -1;
return CELL_OK;
}
@@ -51,9 +171,9 @@ s32 sys_usbd_unregister_ldd()
return CELL_OK;
}
s32 sys_usbd_open_pipe()
s32 sys_usbd_open_pipe(u32 handle, vm::ptr<void> endDisc)
{
sys_usbd.todo("sys_usbd_open_pipe()");
sys_usbd.todo("sys_usbd_open_pipe(handle=%d, endDisc=0x%x)", handle, endDisc);
return CELL_OK;
}
@@ -69,9 +189,31 @@ s32 sys_usbd_close_pipe()
return CELL_OK;
}
s32 sys_usbd_receive_event()
s32 sys_usbd_receive_event(ppu_thread& ppu, u32 handle, vm::ptr<u64> arg1, vm::ptr<u64> arg2, vm::ptr<u64> arg3)
{
sys_usbd.todo("sys_usbd_receive_event()");
sys_usbd.todo("sys_usbd_receive_event(handle=%u, arg1=0x%x, arg2=0x%x, arg3=0x%x)", handle, arg1, arg2, arg3);
_sys_ppu_thread_exit(ppu, CELL_OK);
// TODO
/*if (receive_event_called_count == 0)
{
*arg1 = 2;
*arg2 = 5;
*arg3 = 0;
receive_event_called_count++;
}
else if (receive_event_called_count == 1)
{
*arg1 = 1;
*arg2 = 6;
*arg3 = 0;
receive_event_called_count++;
}
else
{
_sys_ppu_thread_exit(ppu, CELL_OK);
}*/
return CELL_OK;
}
@@ -140,9 +282,3 @@ s32 sys_usbd_get_device_speed()
sys_usbd.todo("sys_usbd_get_device_speed()");
return CELL_OK;
}
s32 sys_usbd_register_extra_ldd()
{
sys_usbd.todo("sys_usbd_register_extra_ldd()");
return CELL_OK;
}
+43 -7
View File
@@ -1,18 +1,54 @@
#pragma once
namespace vm { using namespace ps3; }
// SysCalls
s32 sys_usbd_initialize();
struct DeviceListUnknownDataType
{
u8 unk1;
u8 deviceID;
u8 unk3;
u8 unk4;
} ;
/* 0x01 device descriptor */
struct deviceDescriptor
{
u8 bLength; /* descriptor size in bytes */
u8 bDescriptorType; /* constant USB_DESCRIPTOR_TYPE_DEVICE */
u16 bcdUSB; /* USB spec release compliance number */
u8 bDeviceClass; /* class code */
u8 bDeviceSubClass; /* subclass code */
u8 bDeviceProtocol; /* protocol code */
u8 bMaxPacketSize0; /* max packet size for endpoint 0 */
u16 idVendor; /* USB-IF Vendor ID (VID) */
u16 idProduct; /* Product ID (PID) */
u16 bcdDevice; /* device release number */
u8 iManufacturer; /* manufacturer string descriptor index */
u8 iProduct; /* product string desccriptor index */
u8 iSerialNumber; /* serial number string descriptor index */
u8 bNumConfigurations; /* number of configurations */
};
struct usbDevice
{
DeviceListUnknownDataType basicDevice;
s32 descSize;
deviceDescriptor descriptor;
};
s32 sys_usbd_initialize(vm::ptr<u32> handle);
s32 sys_usbd_finalize();
s32 sys_usbd_get_device_list();
s32 sys_usbd_get_descriptor_size();
s32 sys_usbd_get_descriptor();
s32 sys_usbd_get_device_list(u32 handle, vm::ptr<DeviceListUnknownDataType> device_list, char unknown);
s32 sys_usbd_get_descriptor_size(u32 handle, u8 deviceNumber);
s32 sys_usbd_get_descriptor(u32 handle, u8 deviceNumber, vm::ptr<deviceDescriptor> descriptor, s64 descSize);
s32 sys_usbd_register_ldd();
s32 sys_usbd_unregister_ldd();
s32 sys_usbd_open_pipe();
s32 sys_usbd_open_pipe(u32 handle, vm::ptr<void> endDisc);
s32 sys_usbd_open_default_pipe();
s32 sys_usbd_close_pipe();
s32 sys_usbd_receive_event();
s32 sys_usbd_receive_event(ppu_thread& ppu, u32 handle, vm::ptr<u64> arg1, vm::ptr<u64> arg2, vm::ptr<u64> arg3);
s32 sys_usbd_detect_event();
s32 sys_usbd_attach();
s32 sys_usbd_transfer_data();
@@ -24,4 +60,4 @@ s32 sys_usbd_send_event();
s32 sys_usbd_allocate_memory();
s32 sys_usbd_free_memory();
s32 sys_usbd_get_device_speed();
s32 sys_usbd_register_extra_ldd();
s32 sys_usbd_register_extra_ldd(u32 handle, vm::ptr<void> lddOps, u16 strLen, u16 vendorID, u16 productID, u16 unk1);
+268 -1
View File
@@ -1,7 +1,10 @@
#pragma once
#include <cmath>
#include <vector>
#include <memory>
#include "stdafx.h"
#include "../../Utilities/Config.h"
#include "../../Utilities/types.h"
// TODO: HLE info (constants, structs, etc.) should not be available here
@@ -159,6 +162,13 @@ struct Pad
u32 m_device_capability;
u32 m_device_type;
// Cable State: 0 - 1 plugged in ?
u8 m_cable_state;
// DS4: 0 - 9 while unplugged, 0 - 10 while plugged in, 11 charge complete
// XInput: 0 = Empty, 1 = Low, 2 = Medium, 3 = Full
u8 m_battery_level;
std::vector<Button> m_buttons;
std::vector<AnalogStick> m_sticks;
std::vector<AnalogSensor> m_sensors;
@@ -238,23 +248,280 @@ struct Pad
}
};
struct pad_config : cfg::node
{
std::string cfg_type = "";
std::string cfg_name = "";
cfg::string ls_left { this, "Left Stick Left", "" };
cfg::string ls_down { this, "Left Stick Down", "" };
cfg::string ls_right{ this, "Left Stick Right", "" };
cfg::string ls_up { this, "Left Stick Up", "" };
cfg::string rs_left { this, "Right Stick Left", "" };
cfg::string rs_down { this, "Right Stick Down", "" };
cfg::string rs_right{ this, "Right Stick Right", "" };
cfg::string rs_up { this, "Right Stick Up", "" };
cfg::string start { this, "Start", "" };
cfg::string select { this, "Select", "" };
cfg::string ps { this, "PS Button", "" };
cfg::string square { this, "Square", "" };
cfg::string cross { this, "Cross", "" };
cfg::string circle { this, "Circle", "" };
cfg::string triangle{ this, "Triangle", "" };
cfg::string left { this, "Left", "" };
cfg::string down { this, "Down", "" };
cfg::string right { this, "Right", "" };
cfg::string up { this, "Up", "" };
cfg::string r1 { this, "R1", "" };
cfg::string r2 { this, "R2", "" };
cfg::string r3 { this, "R3", "" };
cfg::string l1 { this, "L1", "" };
cfg::string l2 { this, "L2", "" };
cfg::string l3 { this, "L3", "" };
cfg::_int<0, 1000000> lstickdeadzone{ this, "Left Stick Deadzone", 0 };
cfg::_int<0, 1000000> rstickdeadzone{ this, "Right Stick Deadzone", 0 };
cfg::_int<0, 1000000> ltriggerthreshold{ this, "Left Trigger Threshold", 0 };
cfg::_int<0, 1000000> rtriggerthreshold{ this, "Right Trigger Threshold", 0 };
cfg::_int<0, 1000000> padsquircling{ this, "Pad Squircling Factor", 0 };
cfg::_int<0, 255> colorR{ this, "Color Value R", 0 };
cfg::_int<0, 255> colorG{ this, "Color Value G", 0 };
cfg::_int<0, 255> colorB{ this, "Color Value B", 0 };
cfg::_bool enable_vibration_motor_large{ this, "Enable Large Vibration Motor", true };
cfg::_bool enable_vibration_motor_small{ this, "Enable Small Vibration Motor", true };
cfg::_bool switch_vibration_motors{ this, "Switch Vibration Motors", false };
bool load()
{
if (fs::file cfg_file{ cfg_name, fs::read })
{
return from_string(cfg_file.to_string());
}
return false;
}
void save()
{
fs::file(cfg_name, fs::rewrite).write(to_string());
}
bool exist()
{
return fs::is_file(cfg_name);
}
};
class PadHandlerBase
{
protected:
static const u32 MAX_GAMEPADS = 7;
int m_trigger_threshold = 0;
int m_thumb_threshold = 0;
bool b_has_deadzones = false;
bool b_has_rumble = false;
bool b_has_config = false;
pad_config m_pad_config;
template <typename T>
T lerp(T v0, T v1, T t) {
return std::fma(t, v1, std::fma(-t, v0, v0));
}
// Search an unordered map for a string value and return found keycode
int FindKeyCode(std::unordered_map<u32, std::string> map, const std::string& name)
{
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name) return it->first;
}
return -1;
};
long FindKeyCode(std::unordered_map<u64, std::string> map, const std::string& name)
{
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name) return it->first;
}
return -1;
};
// Get normalized trigger value based on the range defined by a threshold
u16 NormalizeTriggerInput(u16 value, int threshold)
{
if (value <= threshold || threshold >= trigger_max)
{
return static_cast<u16>(0);
}
else if (threshold <= trigger_min)
{
return value;
}
else
{
return (u16)(float(trigger_max) * float(value - threshold) / float(trigger_max - threshold));
}
};
// Get new scaled value between 0 and 255 based on its minimum and maximum
float ScaleStickInput(s32 raw_value, int minimum, int maximum)
{
// value based on max range converted to [0, 1]
float val = float(Clamp(raw_value, minimum, maximum) - minimum) / float(abs(maximum) + abs(minimum));
return 255.0f * val;
};
// normalizes a directed input, meaning it will correspond to a single "button" and not an axis with two directions
// the input values must lie in 0+
u16 NormalizeDirectedInput(u16 raw_value, float threshold, float maximum)
{
if (threshold >= maximum || maximum <= 0)
{
return static_cast<u16>(0);
}
float val = float(Clamp(raw_value, 0, maximum)) / maximum; // value based on max range converted to [0, 1]
if (threshold <= 0)
{
return static_cast<u16>(255.0f * val);
}
else
{
float thresh = threshold / maximum; // threshold converted to [0, 1]
return static_cast<u16>(255.0f * std::min(1.0f, (val - thresh) / (1.0f - thresh)));
}
};
u16 NormalizeStickInput(s32 raw_value, int threshold, bool ignore_threshold = false)
{
if (ignore_threshold)
{
return static_cast<u16>(ScaleStickInput(raw_value, 0, thumb_max));
}
else
{
return NormalizeDirectedInput(raw_value, threshold, thumb_max);
}
}
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13%
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
// return is new x and y values in 0-255 range
std::tuple<u16, u16> NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone)
{
const float dzRange = deadzone / float((std::abs(thumb_max) + std::abs(thumb_min)));
float X = inX / 255.0f;
float Y = inY / 255.0f;
if (dzRange > 0.f)
{
const float mag = std::min(sqrtf(X*X + Y*Y), 1.f);
if (mag <= 0)
{
return std::tuple<u16, u16>(ConvertAxis(X), ConvertAxis(Y));
}
if (mag > dzRange) {
float pos = lerp(0.13f, 1.f, (mag - dzRange) / (1 - dzRange));
float scale = pos / mag;
X = X * scale;
Y = Y * scale;
}
else {
float pos = lerp(0.f, 0.13f, mag / dzRange);
float scale = pos / mag;
X = X * scale;
Y = Y * scale;
}
}
return std::tuple<u16, u16>( ConvertAxis(X), ConvertAxis(Y) );
};
// get clamped value between min and max
s32 Clamp(f32 input, s32 min, s32 max)
{
if (input > max)
return max;
else if (input < min)
return min;
else return static_cast<s32>(input);
};
// get clamped value between 0 and 255
u16 Clamp0To255(f32 input)
{
return static_cast<u16>(Clamp(input, 0, 255));
};
// get clamped value between 0 and 1023
u16 Clamp0To1023(f32 input)
{
return static_cast<u16>(Clamp(input, 0, 1023));
}
// input has to be [-1,1]. result will be [0,255]
u16 ConvertAxis(float value)
{
return static_cast<u16>((value + 1.0)*(255.0 / 2.0));
};
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
// This function assumes inX and inY is already in 0-255
std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY, float squircle_factor)
{
// convert inX and Y to a (-1, 1) vector;
const f32 x = ((f32)inX - 127.5f) / 127.5f;
const f32 y = ((f32)inY - 127.5f) / 127.5f;
// compute angle and len of given point to be used for squircle radius
const f32 angle = std::atan2(y, x);
const f32 r = std::sqrt(std::pow(x, 2.f) + std::pow(y, 2.f));
// now find len/point on the given squircle from our current angle and radius in polar coords
// https://thatsmaths.com/2016/07/14/squircles/
const f32 newLen = (1 + std::pow(std::sin(2 * angle), 2.f) / (squircle_factor / 1000.f)) * r;
// we now have len and angle, convert to cartisian
const int newX = Clamp0To255(((newLen * std::cos(angle)) + 1) * 127.5f);
const int newY = Clamp0To255(((newLen * std::sin(angle)) + 1) * 127.5f);
return std::tuple<u16, u16>(newX, newY);
}
public:
s32 thumb_min = 0;
s32 thumb_max = 255;
s32 trigger_min = 0;
s32 trigger_max = 255;
s32 vibration_min = 0;
s32 vibration_max = 255;
virtual bool Init() { return true; };
virtual ~PadHandlerBase() = default;
//Does it have GUI Config?
bool has_config() { return b_has_config; };
bool has_rumble() { return b_has_rumble; };
bool has_deadzones() { return b_has_deadzones; };
pad_config* GetConfig() { return &m_pad_config; };
//Sets window to config the controller(optional)
virtual void ConfigController(std::string device) {};
virtual void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback) {};
virtual void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) {};
//Return list of devices for that handler
virtual std::vector<std::string> ListDevices() = 0;
//Callback called during pad_thread::ThreadFunc
virtual void ThreadProc() = 0;
//Binds a Pad to a device
virtual bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) = 0;
private:
virtual void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) {};
};
+84 -97
View File
@@ -456,18 +456,22 @@ void write_vertex_array_data_to_buffer(gsl::span<gsl::byte> raw_dst_span, gsl::s
namespace
{
template<typename T>
std::tuple<T, T> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
std::tuple<T, T, u32> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
{
T min_index = -1;
T max_index = 0;
verify(HERE), (dst.size_bytes() >= src.size_bytes());
size_t dst_idx = 0;
u32 dst_idx = 0;
for (T index : src)
{
if (is_primitive_restart_enabled && index == primitive_restart_index)
{
// List types do not need primitive restart. Just skip over this instead
if (rsx::method_registers.current_draw_clause.is_disjoint_primitive)
continue;
index = -1;
}
else
@@ -478,125 +482,108 @@ std::tuple<T, T> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T>
dst[dst_idx++] = index;
}
return std::make_tuple(min_index, max_index);
return std::make_tuple(min_index, max_index, dst_idx);
}
// FIXME: expanded primitive type may not support primitive restart correctly
template<typename T>
std::tuple<T, T> expand_indexed_triangle_fan(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
std::tuple<T, T, u32> expand_indexed_triangle_fan(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
{
T min_index = -1;
const T invalid_index = (T)-1;
T min_index = invalid_index;
T max_index = 0;
verify(HERE), (dst.size() >= 3 * (src.size() - 2));
const T index0 = src[0];
if (!is_primitive_restart_enabled || index0 != -1) // Cut
u32 dst_idx = 0;
u32 src_idx = 0;
bool needs_anchor = true;
T anchor = invalid_index;
T last_index = invalid_index;
for (size_t src_idx = 0; src_idx < src.size(); ++src_idx)
{
min_index = std::min(min_index, index0);
max_index = std::max(max_index, index0);
if (needs_anchor)
{
if (is_primitive_restart_enabled && src[src_idx] == primitive_restart_index)
continue;
anchor = src[src_idx];
needs_anchor = false;
continue;
}
if (is_primitive_restart_enabled && src[src_idx] == primitive_restart_index)
{
needs_anchor = true;
last_index = invalid_index;
continue;
}
T index = src[src_idx];
max_index = std::max(max_index, index);
min_index = std::min(min_index, index);
if (last_index == invalid_index)
{
//Need at least one anchor and one outer index to create a triange
last_index = index;
continue;
}
dst[dst_idx++] = anchor;
dst[dst_idx++] = last_index;
dst[dst_idx++] = index;
last_index = index;
}
size_t dst_idx = 0;
while (src.size() > 2)
{
gsl::span<to_be_t<const T>> tri_indexes = src.subspan(0, 2);
T index1 = tri_indexes[0];
if (is_primitive_restart_enabled && index1 == primitive_restart_index)
{
index1 = -1;
}
else
{
min_index = std::min(min_index, index1);
max_index = std::max(max_index, index1);
}
T index2 = tri_indexes[1];
if (is_primitive_restart_enabled && index2 == primitive_restart_index)
{
index2 = -1;
}
else
{
min_index = std::min(min_index, index2);
max_index = std::max(max_index, index2);
}
dst[dst_idx++] = index0;
dst[dst_idx++] = index1;
dst[dst_idx++] = index2;
src = src.subspan(2);
}
return std::make_tuple(min_index, max_index);
return std::make_tuple(min_index, max_index, dst_idx);
}
// FIXME: expanded primitive type may not support primitive restart correctly
template<typename T>
std::tuple<T, T> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
std::tuple<T, T, u32> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
{
T min_index = -1;
T max_index = 0;
verify(HERE), (4 * dst.size_bytes() >= 6 * src.size_bytes());
size_t dst_idx = 0;
while (!src.empty())
u32 dst_idx = 0;
u8 set_size = 0;
T tmp_indices[4];
for (int src_idx = 0; src_idx < src.size(); ++src_idx)
{
gsl::span<to_be_t<const T>> quad_indexes = src.subspan(0, 4);
T index0 = quad_indexes[0];
if (is_primitive_restart_enabled && index0 == primitive_restart_index)
T index = src[src_idx];
if (is_primitive_restart_enabled && index == primitive_restart_index)
{
index0 = -1;
}
else
{
min_index = std::min(min_index, index0);
max_index = std::max(max_index, index0);
}
T index1 = quad_indexes[1];
if (is_primitive_restart_enabled && index1 == primitive_restart_index)
{
index1 = -1;
}
else
{
min_index = std::min(min_index, index1);
max_index = std::max(max_index, index1);
}
T index2 = quad_indexes[2];
if (is_primitive_restart_enabled && index2 == primitive_restart_index)
{
index2 = -1;
}
else
{
min_index = std::min(min_index, index2);
max_index = std::max(max_index, index2);
}
T index3 = quad_indexes[3];
if (is_primitive_restart_enabled &&index3 == primitive_restart_index)
{
index3 = -1;
}
else
{
min_index = std::min(min_index, index3);
max_index = std::max(max_index, index3);
//empty temp buffer
set_size = 0;
continue;
}
// First triangle
dst[dst_idx++] = index0;
dst[dst_idx++] = index1;
dst[dst_idx++] = index2;
// Second triangle
dst[dst_idx++] = index2;
dst[dst_idx++] = index3;
dst[dst_idx++] = index0;
tmp_indices[set_size++] = index;
max_index = std::max(max_index, index);
min_index = std::min(min_index, index);
src = src.subspan(4);
if (set_size == 4)
{
// First triangle
dst[dst_idx++] = tmp_indices[0];
dst[dst_idx++] = tmp_indices[1];
dst[dst_idx++] = tmp_indices[2];
// Second triangle
dst[dst_idx++] = tmp_indices[2];
dst[dst_idx++] = tmp_indices[3];
dst[dst_idx++] = tmp_indices[0];
set_size = 0;
}
}
return std::make_tuple(min_index, max_index);
return std::make_tuple(min_index, max_index, dst_idx);
}
}
@@ -714,7 +701,7 @@ namespace
// TODO: Unify indexed and non indexed primitive expansion ?
template<typename T>
std::tuple<T, T> write_index_array_data_to_buffer_impl(gsl::span<T> dst,
std::tuple<T, T, u32> write_index_array_data_to_buffer_impl(gsl::span<T> dst,
gsl::span<const be_t<T>> src,
rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector<std::pair<u32, u32> > &first_count_arguments,
std::function<bool(rsx::primitive_type)> expands)
@@ -743,7 +730,7 @@ namespace
}
}
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<gsl::byte> dst,
std::tuple<u32, u32, u32> write_index_array_data_to_buffer(gsl::span<gsl::byte> dst,
gsl::span<const gsl::byte> src,
rsx::index_array_type type, rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector<std::pair<u32, u32> > &first_count_arguments,
std::function<bool(rsx::primitive_type)> expands)
+2 -2
View File
@@ -29,10 +29,10 @@ u32 get_index_type_size(rsx::index_array_type type);
/**
* Write count indexes using (first, first + count) ranges.
* Returns min/max index found during the process.
* Returns min/max index found during the process and the number of valid indices written to the buffer.
* The function expands index buffer for non native primitive type if expands(draw_mode) return true.
*/
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<gsl::byte> dst, gsl::span<const gsl::byte> src,
std::tuple<u32, u32, u32> write_index_array_data_to_buffer(gsl::span<gsl::byte> dst, gsl::span<const gsl::byte> src,
rsx::index_array_type, rsx::primitive_type draw_mode, bool restart_index_enabled, u32 restart_index, const std::vector<std::pair<u32, u32> > &first_count_arguments,
std::function<bool(rsx::primitive_type)> expands);
@@ -38,10 +38,17 @@ void FragmentProgramDecompiler::SetDst(std::string code, bool append_mask)
if (!dst.no_dest)
{
code = NoOverflow(code);
if (dst.exp_tex)
{
//If dst.exp_tex really is _bx2 postfix, we need to unpack dynamic range
AddCode("//exp tex flag is set");
code = "((" + code + "- 0.5) * 2.)";
}
if (dst.saturate)
code = saturate(code);
else
code = ClampValue(code, dst.prec);
}
code += (append_mask ? "$m" : "");
@@ -188,20 +195,13 @@ std::string FragmentProgramDecompiler::NotZeroPositive(const std::string& code)
return "max(abs(" + code + "), 1.E-10)";
}
std::string FragmentProgramDecompiler::NoOverflow(const std::string& code)
std::string FragmentProgramDecompiler::ClampValue(const std::string& code, u32 precision)
{
//FP16 is expected to overflow alot easier at 0+-65504
//FP32 can still work upto 0+-3.4E38
//See http://http.download.nvidia.com/developer/Papers/2005/FP_Specials/FP_Specials.pdf
if (dst.exp_tex)
{
//If dst.exp_tex really is _bx2 postfix, we need to unpack dynamic range
AddCode("//exp tex flag is set");
return "((" + code + "- 0.5) * 2.)";
}
switch (dst.prec)
switch (precision)
{
case 0:
break;
@@ -209,6 +209,10 @@ std::string FragmentProgramDecompiler::NoOverflow(const std::string& code)
return "clamp(" + code + ", -65504., 65504.)";
case 2:
return "clamp(" + code + ", -2., 2.)";
case 3:
return "clamp(" + code + ", -1., 1.)";
case 4:
return "clamp(" + code + ", 0., 1.)";
}
return code;
@@ -394,7 +398,9 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
if (strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle;
//Warning: Modifier order matters. e.g neg should be applied after precision clamping (tested with Naruto UNS)
if (src.abs) ret = "abs(" + ret + ")";
if (src1.input_prec_mod) ret = ClampValue(ret, src1.input_prec_mod);
if (src.neg) ret = "-" + ret;
return ret;
@@ -735,21 +741,12 @@ std::string FragmentProgramDecompiler::Decompile()
if (SIP()) break;
if (handle_tex_srb(opcode)) break;
if (forced_unit == FORCE_NONE)
{
if (handle_sct(opcode)) break;
if (handle_scb(opcode)) break;
}
else if (forced_unit == FORCE_SCT)
{
forced_unit = FORCE_NONE;
if (handle_sct(opcode)) break;
}
else if (forced_unit == FORCE_SCB)
{
forced_unit = FORCE_NONE;
if (handle_scb(opcode)) break;
}
//FENCT/FENCB do not actually reject instructions if they dont match the forced unit
//Tested with Dark Souls II where the repecting FENCX instruction will result in empty luminance averaging shaders
//TODO: More reasearch is needed to determine what real HW does
if (handle_sct(opcode)) break;
if (handle_scb(opcode)) break;
forced_unit = FORCE_NONE;
LOG_ERROR(RSX, "Unknown/illegal instruction: 0x%x (forced unit %d)", opcode, prev_force_unit);
break;
@@ -55,8 +55,8 @@ class FragmentProgramDecompiler
std::string NotZero(const std::string& code);
std::string NotZeroPositive(const std::string& code);
//Prevents operations from overflowing the max range (tested with fp_dynamic3 autotest sample)
std::string NoOverflow(const std::string& code);
//Prevents operations from overflowing the desired range (tested with fp_dynamic3 autotest sample, DS2 for src1.input_prec_mod)
std::string ClampValue(const std::string& code, u32 precision);
/**
* Returns true if the dst set is not a vector (i.e only a single component)
+73 -5
View File
@@ -278,6 +278,8 @@ namespace glsl
OS << "vec4 read_location(int location)\n";
OS << "{\n";
OS << " attribute_desc desc = fetch_desc(location);\n";
OS << " //if attribute is disabled return 1 (makes all operations with it nop except add/sub - TODO)\n";
OS << " if (desc.attribute_size == 0) return vec4(1.);\n";
OS << "\n";
OS << " int vertex_id = " << vertex_id_name << " - int(vertex_base_index);\n";
OS << " if (desc.frequency == 0)\n";
@@ -334,11 +336,6 @@ namespace glsl
OS << " return decodeLinearDepth(texture(tex, coord.xy).r);\n";
OS << "}\n\n";
OS << "vec4 texture2DReconstruct(sampler2DRect tex, vec2 coord)\n";
OS << "{\n";
OS << " return decodeLinearDepth(texture(tex, coord.xy).r);\n";
OS << "}\n\n";
OS << "vec4 get_wpos()\n";
OS << "{\n";
OS << " float abs_scale = abs(wpos_scale);\n";
@@ -350,4 +347,75 @@ namespace glsl
{
program_common::insert_fog_declaration(OS, "vec4", "fog_c");
}
static std::string getFunctionImpl(FUNCTION f)
{
switch (f)
{
default:
abort();
case FUNCTION::FUNCTION_DP2:
return "vec4(dot($0.xy, $1.xy))";
case FUNCTION::FUNCTION_DP2A:
return "vec4(dot($0.xy, $1.xy) + $2.x)";
case FUNCTION::FUNCTION_DP3:
return "vec4(dot($0.xyz, $1.xyz))";
case FUNCTION::FUNCTION_DP4:
return "vec4(dot($0, $1))";
case FUNCTION::FUNCTION_DPH:
return "vec4(dot(vec4($0.xyz, 1.0), $1))";
case FUNCTION::FUNCTION_SFL:
return "vec4(0., 0., 0., 0.)";
case FUNCTION::FUNCTION_STR:
return "vec4(1., 1., 1., 1.)";
case FUNCTION::FUNCTION_FRACT:
return "fract($0)";
case FUNCTION::FUNCTION_REFL:
return "vec4($0 - 2.0 * (dot($0, $1)) * $1)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D:
return "texture($t, $0.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ:
return "textureProj($t, $0.x, $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD:
return "textureLod($t, $0.x, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD:
return "textureGrad($t, $0.x, $1.x, $2.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D:
return "texture($t, $0.xy * texture_parameters[$_i].xy)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ:
return "textureProj($t, $0 , $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD:
return "textureLod($t, $0.xy * texture_parameters[$_i].xy, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD:
return "textureGrad($t, $0.xy * texture_parameters[$_i].xy , $1.xy, $2.xy)";
case FUNCTION::FUNCTION_TEXTURE_SHADOW2D:
return "texture($t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SHADOW2D_PROJ:
return "textureProj($t, $0, $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE:
return "texture($t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ:
return "texture($t, ($0.xyz / $0.w))";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD:
return "textureLod($t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_GRAD:
return "textureGrad($t, $0.xyz, $1.xyz, $2.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D:
return "texture($t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ:
return "textureProj($t, $0.xyzw, $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD:
return "textureLod($t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_GRAD:
return "textureGrad($t, $0.xyz, $1.xyz, $2.xyz)";
case FUNCTION::FUNCTION_DFDX:
return "dFdx($0)";
case FUNCTION::FUNCTION_DFDY:
return "dFdy($0)";
case FUNCTION::FUNCTION_VERTEX_TEXTURE_FETCH2D:
return "textureLod($t, $0.xy, 0)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA:
return "texture2DReconstruct($t, $0.xy * texture_parameters[$_i].xy)";
}
}
}
+7 -3
View File
@@ -46,6 +46,8 @@ struct data_heap
size_t m_min_guard_size; //If an allocation touches the guard region, reset the heap to avoid going over budget
size_t m_current_allocated_size;
size_t m_largest_allocated_pool;
char* m_name;
public:
data_heap() = default;
~data_heap() = default;
@@ -54,8 +56,10 @@ public:
size_t m_get_pos; // End of free space
void init(size_t heap_size, size_t min_guard_size=0x10000)
void init(size_t heap_size, const char* buffer_name = "unnamed", size_t min_guard_size=0x10000)
{
m_name = const_cast<char*>(buffer_name);
m_size = heap_size;
m_put_pos = 0;
m_get_pos = heap_size - 1;
@@ -71,8 +75,8 @@ public:
{
if (!can_alloc<Alignement>(size))
{
fmt::throw_exception("Working buffer not big enough, buffer_length=%d allocated=%d requested=%d guard=%d largest_pool=%d" HERE,
m_size, m_current_allocated_size, size, m_min_guard_size, m_largest_allocated_pool);
fmt::throw_exception("[%s] Working buffer not big enough, buffer_length=%d allocated=%d requested=%d guard=%d largest_pool=%d" HERE,
m_name, m_size, m_current_allocated_size, size, m_min_guard_size, m_largest_allocated_pool);
}
size_t alloc_size = align(size, Alignement);
+194 -67
View File
@@ -17,6 +17,7 @@ namespace rsx
struct surface_subresource_storage
{
surface_type surface = nullptr;
u32 base_address = 0;
u16 x = 0;
u16 y = 0;
@@ -29,8 +30,8 @@ namespace rsx
surface_subresource_storage() {}
surface_subresource_storage(surface_type src, u16 X, u16 Y, u16 W, u16 H, bool _Bound, bool _Depth, bool _Clipped = false)
: surface(src), x(X), y(Y), w(W), h(H), is_bound(_Bound), is_depth_surface(_Depth), is_clipped(_Clipped)
surface_subresource_storage(u32 addr, surface_type src, u16 X, u16 Y, u16 W, u16 H, bool _Bound, bool _Depth, bool _Clipped = false)
: base_address(addr), surface(src), x(X), y(Y), w(W), h(H), is_bound(_Bound), is_depth_surface(_Depth), is_clipped(_Clipped)
{}
};
@@ -46,11 +47,25 @@ namespace rsx
template <typename image_storage_type>
struct render_target_descriptor
{
GcmTileInfo *tile = nullptr;
rsx::surface_antialiasing aa_mode = rsx::surface_antialiasing::center_1_sample;
u16 raster_offset_x = 0;
u16 raster_offset_y = 0;
u32 raster_address_offset = 0;
virtual image_storage_type get_surface() const = 0;
virtual u16 get_surface_width() const = 0;
virtual u16 get_surface_height() const = 0;
virtual u16 get_rsx_pitch() const = 0;
virtual u16 get_native_pitch() const = 0;
void set_raster_offset(u16 x, u16 y, u8 bpp)
{
raster_offset_x = x;
raster_offset_y = y;
raster_address_offset = (y * get_rsx_pitch()) + (x * bpp);
}
};
/**
@@ -114,6 +129,7 @@ namespace rsx
std::tuple<u32, surface_type> m_bound_depth_stencil = {};
std::list<surface_storage_type> invalidated_resources;
u64 cache_tag = 0ull;
surface_store() = default;
~surface_store() = default;
@@ -163,8 +179,11 @@ namespace rsx
new_surface_storage = std::move(rtt);
if (old_surface)
{
//Exchange this surface with the invalidated one
Traits::notify_surface_invalidated(old_surface_storage);
rtt = std::move(old_surface_storage);
}
else
//rtt is now empty - erase it
invalidated_resources.erase(It);
@@ -177,8 +196,11 @@ namespace rsx
}
if (old_surface != nullptr && new_surface == nullptr)
{
//This was already determined to be invalid and is excluded from testing above
Traits::notify_surface_invalidated(old_surface_storage);
invalidated_resources.push_back(std::move(old_surface_storage));
}
if (new_surface != nullptr)
{
@@ -227,8 +249,11 @@ namespace rsx
new_surface_storage = std::move(ds);
if (old_surface)
{
//Exchange this surface with the invalidated one
Traits::notify_surface_invalidated(old_surface_storage);
ds = std::move(old_surface_storage);
}
else
invalidated_resources.erase(It);
@@ -240,8 +265,11 @@ namespace rsx
}
if (old_surface != nullptr && new_surface == nullptr)
{
//This was already determined to be invalid and is excluded from testing above
Traits::notify_surface_invalidated(old_surface_storage);
invalidated_resources.push_back(std::move(old_surface_storage));
}
if (new_surface != nullptr)
{
@@ -272,6 +300,8 @@ namespace rsx
// u32 clip_x = clip_horizontal_reg;
// u32 clip_y = clip_vertical_reg;
cache_tag++;
// Make previous RTTs sampleable
for (std::tuple<u32, surface_type> &rtt : m_bound_render_targets)
{
@@ -494,8 +524,11 @@ namespace rsx
if (surface == ref)
{
Traits::notify_surface_invalidated(It->second);
invalidated_resources.push_back(std::move(It->second));
m_render_targets_storage.erase(It);
cache_tag++;
return;
}
}
@@ -509,21 +542,63 @@ namespace rsx
if (surface == ref)
{
Traits::notify_surface_invalidated(It->second);
invalidated_resources.push_back(std::move(It->second));
m_depth_stencil_storage.erase(It);
cache_tag++;
return;
}
}
}
}
/**
* Invalidates surface that exists at an address
*/
void invalidate_surface_address(u32 addr, bool depth)
{
if (address_is_bound(addr, depth))
{
LOG_ERROR(RSX, "Cannot invalidate a currently bound render target!");
return;
}
if (!depth)
{
auto It = m_render_targets_storage.find(addr);
if (It != m_render_targets_storage.end())
{
Traits::notify_surface_invalidated(It->second);
invalidated_resources.push_back(std::move(It->second));
m_render_targets_storage.erase(It);
cache_tag++;
return;
}
}
else
{
auto It = m_depth_stencil_storage.find(addr);
if (It != m_depth_stencil_storage.end())
{
Traits::notify_surface_invalidated(It->second);
invalidated_resources.push_back(std::move(It->second));
m_depth_stencil_storage.erase(It);
cache_tag++;
return;
}
}
}
/**
* Clipping and fitting lookup funcrions
* surface_overlaps - returns true if surface overlaps a given surface address and returns the relative x and y position of the surface address within the surface
* address_is_bound - returns true if the surface at a given address is actively bound
* get_surface_subresource_if_available - returns a sectiion descriptor that allows to crop surfaces stored in memory
*/
bool surface_overlaps_address(surface_type surface, u32 surface_address, u32 texaddr, u16 *x, u16 *y, bool scale_to_fit, bool double_height)
bool surface_overlaps_address(surface_type surface, u32 surface_address, u32 texaddr, u16 *x, u16 *y)
{
bool is_subslice = false;
u16 x_offset = 0;
@@ -532,52 +607,70 @@ namespace rsx
if (surface_address > texaddr)
return false;
u32 offset = texaddr - surface_address;
if (texaddr >= surface_address)
const u32 offset = texaddr - surface_address;
if (offset == 0)
{
if (offset == 0)
*x = 0;
*y = 0;
return true;
}
else
{
surface_format_info info;
Traits::get_surface_info(surface, &info);
bool doubled_x = false;
bool doubled_y = false;
switch (surface->aa_mode)
{
case rsx::surface_antialiasing::square_rotated_4_samples:
case rsx::surface_antialiasing::square_centered_4_samples:
doubled_y = true;
//fall through
case rsx::surface_antialiasing::diagonal_centered_2_samples:
doubled_x = true;
break;
}
u32 range = info.rsx_pitch * info.surface_height;
if (doubled_y) range <<= 1;
if (offset < range)
{
y_offset = (offset / info.rsx_pitch);
x_offset = (offset % info.rsx_pitch) / info.bpp;
if (doubled_x) x_offset /= 2;
if (doubled_y) y_offset /= 2;
is_subslice = true;
}
else
{
surface_format_info info;
Traits::get_surface_info(surface, &info);
u32 range = info.rsx_pitch * info.surface_height;
if (double_height) range *= 2;
if (offset < range)
{
const u32 y = (offset / info.rsx_pitch);
u32 x = (offset % info.rsx_pitch) / info.bpp;
if (scale_to_fit)
{
const f32 x_scale = (f32)info.rsx_pitch / info.native_pitch;
x = (u32)((f32)x / x_scale);
}
x_offset = x;
y_offset = y;
if (double_height) y_offset /= 2;
is_subslice = true;
}
}
if (is_subslice)
{
*x = x_offset;
*y = y_offset;
return true;
}
}
if (is_subslice)
{
*x = x_offset;
*y = y_offset;
return true;
}
return false;
}
//Fast hit test
inline bool surface_overlaps_address_fast(surface_type surface, u32 surface_address, u32 texaddr)
{
if (surface_address > texaddr)
return false;
const u32 offset = texaddr - surface_address;
const u32 range = surface->get_rsx_pitch() * surface->get_surface_height();
return (offset < range);
}
bool address_is_bound(u32 address, bool is_depth) const
{
if (is_depth)
@@ -604,30 +697,35 @@ namespace rsx
return true;
}
surface_subresource get_surface_subresource_if_applicable(u32 texaddr, u16 requested_width, u16 requested_height, u16 requested_pitch, bool scale_to_fit = false, bool crop = false, bool ignore_depth_formats = false, bool double_height = false)
surface_subresource get_surface_subresource_if_applicable(u32 texaddr, u16 requested_width, u16 requested_height, u16 requested_pitch,
bool crop = false, bool ignore_depth_formats = false, bool ignore_color_formats = false)
{
auto test_surface = [&](surface_type surface, u32 this_address, u16 &x_offset, u16 &y_offset, u16 &w, u16 &h, bool &clipped)
{
if (surface_overlaps_address(surface, this_address, texaddr, &x_offset, &y_offset, scale_to_fit, double_height))
if (surface_overlaps_address(surface, this_address, texaddr, &x_offset, &y_offset))
{
surface_format_info info;
Traits::get_surface_info(surface, &info);
if (info.rsx_pitch != requested_pitch)
return false;
u16 real_width = requested_width;
u16 real_height = requested_height;
if (scale_to_fit)
switch (surface->aa_mode)
{
f32 pitch_scaling = (f32)requested_pitch / info.native_pitch;
real_width = (u16)((f32)requested_width / pitch_scaling);
case rsx::surface_antialiasing::diagonal_centered_2_samples:
real_width /= 2;
break;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
real_width /= 2;
real_height /= 2;
break;
}
if (region_fits(info.surface_width, info.surface_height, x_offset, y_offset, real_width, requested_height))
if (region_fits(info.surface_width, info.surface_height, x_offset, y_offset, real_width, real_height))
{
w = real_width;
h = requested_height;
h = real_height;
clipped = false;
return true;
@@ -640,17 +738,17 @@ namespace rsx
u16 remaining_height = info.surface_height - y_offset;
w = std::min(real_width, remaining_width);
h = std::min(requested_height, remaining_height);
h = std::min(real_height, remaining_height);
clipped = true;
return true;
}
if (info.surface_width >= requested_width && info.surface_height >= requested_height)
if (info.surface_width >= real_width && info.surface_height >= real_height)
{
LOG_WARNING(RSX, "Overlapping surface exceeds bounds; returning full surface region");
w = real_width;
h = requested_height;
h = real_height;
clipped = true;
return true;
@@ -668,26 +766,55 @@ namespace rsx
u16 w;
u16 h;
for (auto &tex_info : m_render_targets_storage)
if (!ignore_color_formats)
{
u32 this_address = std::get<0>(tex_info);
surface = std::get<1>(tex_info).get();
for (auto &tex_info : m_render_targets_storage)
{
const u32 this_address = std::get<0>(tex_info);
if (texaddr < this_address)
continue;
if (test_surface(surface, this_address, x_offset, y_offset, w, h, clipped))
return { surface, x_offset, y_offset, w, h, address_is_bound(this_address, false), false, clipped };
surface = std::get<1>(tex_info).get();
if (surface->get_rsx_pitch() != requested_pitch)
continue;
if (requested_width == 0 || requested_height == 0)
{
if (!surface_overlaps_address_fast(surface, this_address, texaddr))
continue;
else
return{ this_address, surface, 0, 0, 0, 0, false, false, false };
}
if (test_surface(surface, this_address, x_offset, y_offset, w, h, clipped))
return{ this_address, surface, x_offset, y_offset, w, h, address_is_bound(this_address, false), false, clipped };
}
}
if (ignore_depth_formats)
return{};
//Check depth surfaces for overlap
for (auto &tex_info : m_depth_stencil_storage)
if (!ignore_depth_formats)
{
u32 this_address = std::get<0>(tex_info);
surface = std::get<1>(tex_info).get();
//Check depth surfaces for overlap
for (auto &tex_info : m_depth_stencil_storage)
{
const u32 this_address = std::get<0>(tex_info);
if (texaddr < this_address)
continue;
if (test_surface(surface, this_address, x_offset, y_offset, w, h, clipped))
return { surface, x_offset, y_offset, w, h, address_is_bound(this_address, true), true, clipped };
surface = std::get<1>(tex_info).get();
if (surface->get_rsx_pitch() != requested_pitch)
continue;
if (requested_width == 0 || requested_height == 0)
{
if (!surface_overlaps_address_fast(surface, this_address, texaddr))
continue;
else
return{ this_address, surface, 0, 0, 0, 0, false, true, false };
}
if (test_surface(surface, this_address, x_offset, y_offset, w, h, clipped))
return{ this_address, surface, x_offset, y_offset, w, h, address_is_bound(this_address, true), true, clipped };
}
}
return{};
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -410,7 +410,7 @@ namespace
gsl::span<gsl::byte> dst{
reinterpret_cast<gsl::byte*>(mapped_buffer), ::narrow<u32>(buffer_size)};
std::tie(min_index, max_index) =
std::tie(min_index, max_index, index_count) =
write_index_array_data_to_buffer(dst, command.raw_index_buffer, indexed_type,
rsx::method_registers.current_draw_clause.primitive,
rsx::method_registers.restart_index_enabled(),
+1
View File
@@ -183,4 +183,5 @@ protected:
virtual std::array<std::vector<gsl::byte>, 4> copy_render_targets_to_memory() override;
virtual std::array<std::vector<gsl::byte>, 2> copy_depth_stencil_buffer_to_memory() override;
virtual std::pair<std::string, std::string> get_programs() const override;
virtual void notify_tile_unbound(u32 tile) override;
};
+7 -1
View File
@@ -54,7 +54,7 @@ void D3D12GSRender::load_program()
};
get_current_vertex_program();
get_current_fragment_program(rtt_lookup_func);
get_current_fragment_program_legacy(rtt_lookup_func);
if (!current_fragment_program.valid)
return;
@@ -316,4 +316,10 @@ std::pair<std::string, std::string> D3D12GSRender::get_programs() const
{
return std::make_pair(m_pso_cache.get_transform_program(current_vertex_program).content, m_pso_cache.get_shader_program(current_fragment_program).content);
}
void D3D12GSRender::notify_tile_unbound(u32 tile)
{
u32 addr = rsx::get_address(tiles[tile].offset, tiles[tile].location);
m_rtts.invalidate_surface_address(addr, false);
}
#endif
@@ -103,9 +103,6 @@ namespace
void D3D12GSRender::clear_surface(u32 arg)
{
// Ignore clear if surface target is set to CELL_GCM_SURFACE_TARGET_NONE
if (rsx::method_registers.surface_color_target() == rsx::surface_target::none) return;
std::chrono::time_point<steady_clock> start_duration = steady_clock::now();
std::chrono::time_point<steady_clock> rtt_duration_start = steady_clock::now();
@@ -142,6 +142,9 @@ struct render_target_traits
//TODO
}
static
void notify_surface_invalidated(const ComPtr<ID3D12Resource>&)
{}
static
bool rtt_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_color_format surface_color_format, size_t width, size_t height, bool=false)
-71
View File
@@ -4,77 +4,6 @@
namespace gl
{
std::string getFunctionImpl(FUNCTION f)
{
switch (f)
{
default:
abort();
case FUNCTION::FUNCTION_DP2:
return "vec4(dot($0.xy, $1.xy))";
case FUNCTION::FUNCTION_DP2A:
return "vec4(dot($0.xy, $1.xy) + $2.x)";
case FUNCTION::FUNCTION_DP3:
return "vec4(dot($0.xyz, $1.xyz))";
case FUNCTION::FUNCTION_DP4:
return "vec4(dot($0, $1))";
case FUNCTION::FUNCTION_DPH:
return "vec4(dot(vec4($0.xyz, 1.0), $1))";
case FUNCTION::FUNCTION_SFL:
return "vec4(0., 0., 0., 0.)";
case FUNCTION::FUNCTION_STR:
return "vec4(1., 1., 1., 1.)";
case FUNCTION::FUNCTION_FRACT:
return "fract($0)";
case FUNCTION::FUNCTION_REFL:
return "vec4($0 - 2.0 * (dot($0, $1)) * $1)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D:
return "texture($t, $0.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ:
return "textureProj($t, $0.x, $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD:
return "textureLod($t, $0.x, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD:
return "textureGrad($t, $0.x, $1.x, $2.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D:
return "texture($t, $0.xy * $t_coord_scale)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ:
return "textureProj($t, $0 , $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD:
return "textureLod($t, $0.xy * $t_coord_scale, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD:
return "textureGrad($t, $0.xy * $t_coord_scale , $1.xy, $2.xy)";
case FUNCTION::FUNCTION_TEXTURE_SHADOW2D:
return "texture($t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SHADOW2D_PROJ:
return "textureProj($t, $0, $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE:
return "texture($t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ:
return "texture($t, ($0.xyz / $0.w))";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD:
return "textureLod($t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_GRAD:
return "textureGrad($t, $0.xyz, $1.xyz, $2.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D:
return "texture($t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ:
return "textureProj($t, $0.xyzw, $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD:
return "textureLod($t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_GRAD:
return "textureGrad($t, $0.xyz, $1.xyz, $2.xyz)";
case FUNCTION::FUNCTION_DFDX:
return "dFdx($0)";
case FUNCTION::FUNCTION_DFDY:
return "dFdy($0)";
case FUNCTION::FUNCTION_VERTEX_TEXTURE_FETCH2D:
return "textureLod($t, $0.xy, 0)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA:
return "texture2DReconstruct($t, $0.xy * $t_coord_scale)";
}
}
int get_varying_register_location(const std::string &var_name)
{
static const std::pair<std::string, int> reg_table[] =
-1
View File
@@ -6,6 +6,5 @@
namespace gl
{
std::string getFunctionImpl(FUNCTION f);
int get_varying_register_location(const std::string &var_name);
}
+1 -6
View File
@@ -15,7 +15,7 @@ std::string GLFragmentDecompilerThread::getFloatTypeName(size_t elementCount)
std::string GLFragmentDecompilerThread::getFunction(FUNCTION f)
{
return gl::getFunctionImpl(f);
return glsl::getFunctionImpl(f);
}
std::string GLFragmentDecompilerThread::saturate(const std::string & code)
@@ -173,11 +173,6 @@ namespace
case rsx::texture_dimension_extended::texture_dimension_3d:
case rsx::texture_dimension_extended::texture_dimension_cubemap: vec_type = "vec3";
}
if (prog.unnormalized_coords & (1 << index))
OS << "\t" << vec_type << " tex" << index << "_coord_scale = texture_parameters[" << index << "].xy / textureSize(tex" << index << ", 0);\n";
else
OS << "\t" << vec_type << " tex" << index << "_coord_scale = " << vec_type << "(1.);\n";
}
std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index)
+386 -284
View File
@@ -24,14 +24,14 @@ namespace
GLGSRender::GLGSRender() : GSRender()
{
m_shaders_cache.reset(new gl::shader_cache(m_prog_buffer, "opengl", "v1"));
m_shaders_cache.reset(new gl::shader_cache(m_prog_buffer, "opengl", "v1.1"));
if (g_cfg.video.disable_vertex_cache)
m_vertex_cache.reset(new gl::null_vertex_cache());
else
m_vertex_cache.reset(new gl::weak_vertex_cache());
supports_multidraw = true;
supports_multidraw = !g_cfg.video.strict_rendering_mode;
}
extern CellGcmContextData current_context;
@@ -51,7 +51,7 @@ namespace
case rsx::comparison_function::greater_or_equal: return GL_GEQUAL;
case rsx::comparison_function::always: return GL_ALWAYS;
}
throw;
fmt::throw_exception("Unsupported comparison op 0x%X" HERE, (u32)op);;
}
GLenum stencil_op(rsx::stencil_op op)
@@ -67,7 +67,7 @@ namespace
case rsx::stencil_op::incr_wrap: return GL_INCR_WRAP;
case rsx::stencil_op::decr_wrap: return GL_DECR_WRAP;
}
throw;
fmt::throw_exception("Unsupported stencil op 0x%X" HERE, (u32)op);
}
GLenum blend_equation(rsx::blend_equation op)
@@ -75,16 +75,20 @@ namespace
switch (op)
{
// Note : maybe add is signed on gl
case rsx::blend_equation::add_signed:
LOG_TRACE(RSX, "blend equation add_signed used. Emulating using FUNC_ADD");
case rsx::blend_equation::add: return GL_FUNC_ADD;
case rsx::blend_equation::min: return GL_MIN;
case rsx::blend_equation::max: return GL_MAX;
case rsx::blend_equation::substract: return GL_FUNC_SUBTRACT;
case rsx::blend_equation::reverse_substract_signed:
LOG_TRACE(RSX, "blend equation reverse_subtract_signed used. Emulating using FUNC_REVERSE_SUBTRACT");
case rsx::blend_equation::reverse_substract: return GL_FUNC_REVERSE_SUBTRACT;
case rsx::blend_equation::reverse_substract_signed: throw "unsupported";
case rsx::blend_equation::add_signed: throw "unsupported";
case rsx::blend_equation::reverse_add_signed: throw "unsupported";
case rsx::blend_equation::reverse_add_signed:
default:
LOG_ERROR(RSX, "Blend equation 0x%X is unimplemented!", (u32)op);
return GL_FUNC_ADD;
}
throw;
}
GLenum blend_factor(rsx::blend_factor op)
@@ -107,7 +111,7 @@ namespace
case rsx::blend_factor::constant_alpha: return GL_CONSTANT_ALPHA;
case rsx::blend_factor::one_minus_constant_alpha: return GL_ONE_MINUS_CONSTANT_ALPHA;
}
throw;
fmt::throw_exception("Unsupported blend factor 0x%X" HERE, (u32)op);
}
GLenum logic_op(rsx::logic_op op)
@@ -131,7 +135,7 @@ namespace
case rsx::logic_op::logic_nand: return GL_NAND;
case rsx::logic_op::logic_set: return GL_SET;
}
throw;
fmt::throw_exception("Unsupported logic op 0x%X" HERE, (u32)op);
}
GLenum front_face(rsx::front_face op)
@@ -143,7 +147,7 @@ namespace
case rsx::front_face::cw: return (invert ? GL_CCW : GL_CW);
case rsx::front_face::ccw: return (invert ? GL_CW : GL_CCW);
}
throw;
fmt::throw_exception("Unsupported front face 0x%X" HERE, (u32)op);
}
GLenum cull_face(rsx::cull_face op)
@@ -156,7 +160,7 @@ namespace
case rsx::cull_face::back: return (invert ? GL_FRONT : GL_BACK);
case rsx::cull_face::front_and_back: return GL_FRONT_AND_BACK;
}
throw;
fmt::throw_exception("Unsupported cull face 0x%X" HERE, (u32)op);
}
}
@@ -171,141 +175,13 @@ void GLGSRender::begin()
return;
init_buffers();
if (!framebuffer_status_valid)
return;
std::chrono::time_point<steady_clock> then = steady_clock::now();
bool color_mask_b = rsx::method_registers.color_mask_b();
bool color_mask_g = rsx::method_registers.color_mask_g();
bool color_mask_r = rsx::method_registers.color_mask_r();
bool color_mask_a = rsx::method_registers.color_mask_a();
gl_state.color_mask(color_mask_r, color_mask_g, color_mask_b, color_mask_a);
gl_state.depth_mask(rsx::method_registers.depth_write_enabled());
gl_state.stencil_mask(rsx::method_registers.stencil_mask());
if (gl_state.enable(rsx::method_registers.depth_test_enabled(), GL_DEPTH_TEST))
{
gl_state.depth_func(comparison_op(rsx::method_registers.depth_func()));
float range_near = rsx::method_registers.clip_min();
float range_far = rsx::method_registers.clip_max();
//Workaround to preserve depth precision but respect z direction
//Ni no Kuni sets a very restricted z range (0.9x - 1.) and depth reads / tests are broken
if (range_near <= range_far)
gl_state.depth_range(0.f, 1.f);
else
gl_state.depth_range(1.f, 0.f);
}
if (glDepthBoundsEXT && (gl_state.enable(rsx::method_registers.depth_bounds_test_enabled(), GL_DEPTH_BOUNDS_TEST_EXT)))
{
gl_state.depth_bounds(rsx::method_registers.depth_bounds_min(), rsx::method_registers.depth_bounds_max());
}
gl_state.enable(rsx::method_registers.dither_enabled(), GL_DITHER);
if (gl_state.enable(rsx::method_registers.blend_enabled(), GL_BLEND))
{
glBlendFuncSeparate(blend_factor(rsx::method_registers.blend_func_sfactor_rgb()),
blend_factor(rsx::method_registers.blend_func_dfactor_rgb()),
blend_factor(rsx::method_registers.blend_func_sfactor_a()),
blend_factor(rsx::method_registers.blend_func_dfactor_a()));
auto blend_colors = rsx::get_constant_blend_colors();
glBlendColor(blend_colors[0], blend_colors[1], blend_colors[2], blend_colors[3]);
glBlendEquationSeparate(blend_equation(rsx::method_registers.blend_equation_rgb()),
blend_equation(rsx::method_registers.blend_equation_a()));
}
if (gl_state.enable(rsx::method_registers.stencil_test_enabled(), GL_STENCIL_TEST))
{
glStencilFunc(comparison_op(rsx::method_registers.stencil_func()),
rsx::method_registers.stencil_func_ref(),
rsx::method_registers.stencil_func_mask());
glStencilOp(stencil_op(rsx::method_registers.stencil_op_fail()), stencil_op(rsx::method_registers.stencil_op_zfail()),
stencil_op(rsx::method_registers.stencil_op_zpass()));
if (rsx::method_registers.two_sided_stencil_test_enabled())
{
glStencilMaskSeparate(GL_BACK, rsx::method_registers.back_stencil_mask());
glStencilFuncSeparate(GL_BACK, comparison_op(rsx::method_registers.back_stencil_func()),
rsx::method_registers.back_stencil_func_ref(), rsx::method_registers.back_stencil_func_mask());
glStencilOpSeparate(GL_BACK, stencil_op(rsx::method_registers.back_stencil_op_fail()),
stencil_op(rsx::method_registers.back_stencil_op_zfail()), stencil_op(rsx::method_registers.back_stencil_op_zpass()));
}
}
gl_state.enablei(rsx::method_registers.blend_enabled_surface_1(), GL_BLEND, 1);
gl_state.enablei(rsx::method_registers.blend_enabled_surface_2(), GL_BLEND, 2);
gl_state.enablei(rsx::method_registers.blend_enabled_surface_3(), GL_BLEND, 3);
if (gl_state.enable(rsx::method_registers.logic_op_enabled(), GL_COLOR_LOGIC_OP))
{
gl_state.logic_op(logic_op(rsx::method_registers.logic_operation()));
}
gl_state.line_width(rsx::method_registers.line_width());
gl_state.enable(rsx::method_registers.line_smooth_enabled(), GL_LINE_SMOOTH);
gl_state.enable(rsx::method_registers.poly_offset_point_enabled(), GL_POLYGON_OFFSET_POINT);
gl_state.enable(rsx::method_registers.poly_offset_line_enabled(), GL_POLYGON_OFFSET_LINE);
gl_state.enable(rsx::method_registers.poly_offset_fill_enabled(), GL_POLYGON_OFFSET_FILL);
//offset_bias is the constant factor, multiplied by the implementation factor R
//offst_scale is the slope factor, multiplied by the triangle slope factor M
gl_state.polygon_offset(rsx::method_registers.poly_offset_scale(), rsx::method_registers.poly_offset_bias());
if (gl_state.enable(rsx::method_registers.cull_face_enabled(), GL_CULL_FACE))
{
gl_state.cull_face(cull_face(rsx::method_registers.cull_face_mode()));
}
gl_state.front_face(front_face(rsx::method_registers.front_face_mode()));
//TODO
//NV4097_SET_ANISO_SPREAD
//NV4097_SET_SPECULAR_ENABLE
//NV4097_SET_TWO_SIDE_LIGHT_EN
//NV4097_SET_FLAT_SHADE_OP
//NV4097_SET_EDGE_FLAG
//NV4097_SET_COLOR_KEY_COLOR
//NV4097_SET_SHADER_CONTROL
//NV4097_SET_ZMIN_MAX_CONTROL
//NV4097_SET_ANTI_ALIASING_CONTROL
//NV4097_SET_CLIP_ID_TEST_ENABLE
std::chrono::time_point<steady_clock> now = steady_clock::now();
m_begin_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(now - then).count();
}
namespace
{
GLenum get_gl_target_for_texture(const rsx::fragment_texture& tex)
GLenum get_gl_target_for_texture(const rsx::texture_dimension_extended type)
{
switch (tex.get_extended_texture_dimension())
{
case rsx::texture_dimension_extended::texture_dimension_1d: return GL_TEXTURE_1D;
case rsx::texture_dimension_extended::texture_dimension_2d: return GL_TEXTURE_2D;
case rsx::texture_dimension_extended::texture_dimension_cubemap: return GL_TEXTURE_CUBE_MAP;
case rsx::texture_dimension_extended::texture_dimension_3d: return GL_TEXTURE_3D;
}
fmt::throw_exception("Unknown texture target" HERE);
}
GLenum get_gl_target_for_texture(const rsx::vertex_texture& tex)
{
switch (tex.get_extended_texture_dimension())
switch (type)
{
case rsx::texture_dimension_extended::texture_dimension_1d: return GL_TEXTURE_1D;
case rsx::texture_dimension_extended::texture_dimension_2d: return GL_TEXTURE_2D;
@@ -318,12 +194,17 @@ namespace
void GLGSRender::end()
{
std::chrono::time_point<steady_clock> state_check_start = steady_clock::now();
if (skip_frame || !framebuffer_status_valid || (conditional_render_enabled && conditional_render_test_failed) || !check_program_state())
{
rsx::thread::end();
return;
}
std::chrono::time_point<steady_clock> state_check_end = steady_clock::now();
m_begin_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(state_check_end - state_check_start).count();
if (manually_flush_ring_buffers)
{
//Use approximations to reseve space. This path is mostly for debug purposes anyway
@@ -342,6 +223,73 @@ void GLGSRender::end()
std::optional<std::tuple<GLenum, u32> > indexed_draw_info;
std::tie(vertex_draw_count, actual_vertex_count, vertex_base, indexed_draw_info) = set_vertex_buffer();
//Load textures
{
std::chrono::time_point<steady_clock> textures_start = steady_clock::now();
std::lock_guard<std::mutex> lock(m_sampler_mutex);
void* unused = nullptr;
bool update_framebuffer_sourced = false;
if (surface_store_tag != m_rtts.cache_tag)
{
update_framebuffer_sourced = true;
surface_store_tag = m_rtts.cache_tag;
}
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
{
if (!fs_sampler_state[i])
fs_sampler_state[i] = std::make_unique<gl::texture_cache::sampled_image_descriptor>();
if (m_samplers_dirty || m_textures_dirty[i] ||
(update_framebuffer_sourced && fs_sampler_state[i]->upload_context == rsx::texture_upload_context::framebuffer_storage))
{
auto sampler_state = static_cast<gl::texture_cache::sampled_image_descriptor*>(fs_sampler_state[i].get());
if (rsx::method_registers.fragment_textures[i].enabled())
{
*sampler_state = m_gl_texture_cache.upload_texture(unused, rsx::method_registers.fragment_textures[i], m_rtts);
if (m_textures_dirty[i])
m_gl_sampler_states[i].apply(rsx::method_registers.fragment_textures[i]);
}
else
{
*sampler_state = {};
}
m_textures_dirty[i] = false;
}
}
for (int i = 0; i < rsx::limits::vertex_textures_count; ++i)
{
if (!vs_sampler_state[i])
vs_sampler_state[i] = std::make_unique<gl::texture_cache::sampled_image_descriptor>();
if (m_samplers_dirty || m_vertex_textures_dirty[i] ||
(update_framebuffer_sourced && vs_sampler_state[i]->upload_context == rsx::texture_upload_context::framebuffer_storage))
{
auto sampler_state = static_cast<gl::texture_cache::sampled_image_descriptor*>(vs_sampler_state[i].get());
if (rsx::method_registers.vertex_textures[i].enabled())
{
*sampler_state = m_gl_texture_cache.upload_texture(unused, rsx::method_registers.vertex_textures[i], m_rtts);
}
else
*sampler_state = {};
m_vertex_textures_dirty[i] = false;
}
}
m_samplers_dirty.store(false);
std::chrono::time_point<steady_clock> textures_end = steady_clock::now();
m_textures_upload_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(textures_end - textures_start).count();
}
std::chrono::time_point<steady_clock> program_start = steady_clock::now();
//Load program here since it is dependent on vertex state
@@ -361,20 +309,102 @@ void GLGSRender::end()
//glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
}
//Bind textures and resolve external copy operations
std::chrono::time_point<steady_clock> textures_start = steady_clock::now();
int unused_location;
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
{
if (m_program->uniforms.has_location("tex" + std::to_string(i), &unused_location))
{
auto sampler_state = static_cast<gl::texture_cache::sampled_image_descriptor*>(fs_sampler_state[i].get());
if (sampler_state->flag)
continue;
sampler_state->flag = true;
auto &tex = rsx::method_registers.fragment_textures[i];
glActiveTexture(GL_TEXTURE0 + i);
if (tex.enabled())
{
GLenum target = get_gl_target_for_texture(sampler_state->image_type);
if (sampler_state->image_handle)
{
glBindTexture(target, sampler_state->image_handle);
}
else if (sampler_state->external_subresource_desc.external_handle)
{
void *unused = nullptr;
glBindTexture(target, m_gl_texture_cache.create_temporary_subresource(unused, sampler_state->external_subresource_desc));
sampler_state->flag = false;
}
else
{
glBindTexture(target, GL_NONE);
}
}
else
{
glBindTexture(GL_TEXTURE_2D, GL_NONE);
}
}
}
for (int i = 0; i < rsx::limits::vertex_textures_count; ++i)
{
if (m_program->uniforms.has_location("vtex" + std::to_string(i), &unused_location))
{
auto sampler_state = static_cast<gl::texture_cache::sampled_image_descriptor*>(vs_sampler_state[i].get());
if (sampler_state->flag)
continue;
sampler_state->flag = true;
glActiveTexture(GL_TEXTURE0 + rsx::limits::fragment_textures_count + i);
if (sampler_state->image_handle)
{
glBindTexture(GL_TEXTURE_2D, sampler_state->image_handle);
}
else if (sampler_state->external_subresource_desc.external_handle)
{
void *unused = nullptr;
glBindTexture(GL_TEXTURE_2D, m_gl_texture_cache.create_temporary_subresource(unused, sampler_state->external_subresource_desc));
sampler_state->flag = false;
}
else
{
glBindTexture(GL_TEXTURE_2D, GL_NONE);
}
}
}
std::chrono::time_point<steady_clock> textures_end = steady_clock::now();
m_textures_upload_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(textures_end - textures_start).count();
update_draw_state();
//Check if depth buffer is bound and valid
//If ds is not initialized clear it; it seems new depth textures should have depth cleared
auto copy_rtt_contents = [](gl::render_target *surface)
{
//Copy data from old contents onto this one
//1. Clip a rectangular region defning the data
//2. Perform a GPU blit
u16 parent_w = surface->old_contents->width();
u16 parent_h = surface->old_contents->height();
u16 copy_w, copy_h;
if (surface->get_compatible_internal_format() == surface->old_contents->get_compatible_internal_format())
{
//Copy data from old contents onto this one
//1. Clip a rectangular region defning the data
//2. Perform a GPU blit
u16 parent_w = surface->old_contents->width();
u16 parent_h = surface->old_contents->height();
u16 copy_w, copy_h;
std::tie(std::ignore, std::ignore, copy_w, copy_h) = rsx::clip_region<u16>(parent_w, parent_h, 0, 0, surface->width(), surface->height(), true);
glCopyImageSubData(surface->old_contents->id(), GL_TEXTURE_2D, 0, 0, 0, 0, surface->id(), GL_TEXTURE_2D, 0, 0, 0, 0, copy_w, copy_h, 1);
surface->set_cleared();
}
//TODO: download image contents and reupload them or do a memory cast to copy memory contents if not compatible
std::tie(std::ignore, std::ignore, copy_w, copy_h) = rsx::clip_region<u16>(parent_w, parent_h, 0, 0, surface->width(), surface->height(), true);
glCopyImageSubData(surface->old_contents->id(), GL_TEXTURE_2D, 0, 0, 0, 0, surface->id(), GL_TEXTURE_2D, 0, 0, 0, 0, copy_w, copy_h, 1);
surface->set_cleared();
surface->old_contents = nullptr;
};
@@ -452,43 +482,6 @@ void GLGSRender::end()
glEnable(GL_SCISSOR_TEST);
std::chrono::time_point<steady_clock> textures_start = steady_clock::now();
//Setup textures
//Setting unused texture to 0 is not needed, but makes program validation happy if we choose to enforce it
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
{
int location;
if (rsx::method_registers.fragment_textures[i].enabled() && m_program->uniforms.has_location("tex" + std::to_string(i), &location))
{
m_gl_texture_cache.upload_and_bind_texture(i, get_gl_target_for_texture(rsx::method_registers.fragment_textures[i]), rsx::method_registers.fragment_textures[i], m_rtts);
if (m_textures_dirty[i])
{
m_gl_sampler_states[i].apply(rsx::method_registers.fragment_textures[i]);
m_textures_dirty[i] = false;
}
}
}
//Vertex textures
for (int i = 0; i < rsx::limits::vertex_textures_count; ++i)
{
int texture_index = i + rsx::limits::fragment_textures_count;
int location;
if (!rsx::method_registers.vertex_textures[i].enabled())
continue;
if (m_program->uniforms.has_location("vtex" + std::to_string(i), &location))
{
m_gl_texture_cache.upload_and_bind_texture(texture_index, GL_TEXTURE_2D, rsx::method_registers.vertex_textures[i], m_rtts);
}
}
std::chrono::time_point<steady_clock> textures_end = steady_clock::now();
m_textures_upload_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(textures_end - textures_start).count();
std::chrono::time_point<steady_clock> draw_start = steady_clock::now();
if (g_cfg.video.debug_output)
@@ -497,14 +490,15 @@ void GLGSRender::end()
}
const GLenum draw_mode = gl::draw_mode(rsx::method_registers.current_draw_clause.primitive);
bool single_draw = rsx::method_registers.current_draw_clause.first_count_commands.size() <= 1 || rsx::method_registers.current_draw_clause.is_disjoint_primitive;
bool single_draw = !supports_multidraw || (rsx::method_registers.current_draw_clause.first_count_commands.size() <= 1 || rsx::method_registers.current_draw_clause.is_disjoint_primitive);
if (indexed_draw_info)
{
const GLenum index_type = std::get<0>(indexed_draw_info.value());
const u32 index_offset = std::get<1>(indexed_draw_info.value());
const bool restarts_valid = gl::is_primitive_native(rsx::method_registers.current_draw_clause.primitive) && !rsx::method_registers.current_draw_clause.is_disjoint_primitive;
if (gl_state.enable(rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART))
if (gl_state.enable(restarts_valid && rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART))
{
glPrimitiveRestartIndex((index_type == GL_UNSIGNED_SHORT)? 0xffff: 0xffffffff);
}
@@ -545,21 +539,32 @@ void GLGSRender::end()
}
else
{
std::vector<GLint> firsts;
std::vector<GLsizei> counts;
const auto draw_count = rsx::method_registers.current_draw_clause.first_count_commands.size();
firsts.reserve(draw_count);
counts.reserve(draw_count);
u32 base_index = rsx::method_registers.current_draw_clause.first_count_commands.front().first;
for (const auto &range : rsx::method_registers.current_draw_clause.first_count_commands)
if (gl::get_driver_caps().vendor_AMD == false)
{
firsts.push_back(range.first - base_index);
counts.push_back(range.second);
}
std::vector<GLint> firsts;
std::vector<GLsizei> counts;
const auto draw_count = rsx::method_registers.current_draw_clause.first_count_commands.size();
glMultiDrawArrays(draw_mode, firsts.data(), counts.data(), (GLsizei)draw_count);
firsts.reserve(draw_count);
counts.reserve(draw_count);
for (const auto &range : rsx::method_registers.current_draw_clause.first_count_commands)
{
firsts.push_back(range.first - base_index);
counts.push_back(range.second);
}
glMultiDrawArrays(draw_mode, firsts.data(), counts.data(), (GLsizei)draw_count);
}
else
{
//MultiDrawArrays is broken on some primitive types using AMD. One known type is GL_TRIANGLE_STRIP but there could be more
for (const auto &range : rsx::method_registers.current_draw_clause.first_count_commands)
{
glDrawArrays(draw_mode, range.first - base_index, range.second);
}
}
}
}
@@ -614,6 +619,9 @@ void GLGSRender::on_init_thread()
{
GSRender::on_init_thread();
m_frame->disable_wm_event_queue();
m_frame->hide();
gl::init();
//Enable adaptive vsync if vsync is requested
@@ -754,12 +762,13 @@ void GLGSRender::on_init_thread()
m_thread_id = std::this_thread::get_id();
m_shaders_cache->load();
m_frame->enable_wm_event_queue();
m_frame->show();
}
void GLGSRender::on_exit()
{
glFinish();
m_prog_buffer.clear();
if (draw_fbo)
@@ -827,13 +836,15 @@ void GLGSRender::on_exit()
glDeleteQueries(1, &query.handle);
}
return GSRender::on_exit();
glFlush();
glFinish();
GSRender::on_exit();
}
void GLGSRender::clear_surface(u32 arg)
{
if (skip_frame || !framebuffer_status_valid) return;
if (rsx::method_registers.surface_color_target() == rsx::surface_target::none) return;
if ((arg & 0xf3) == 0) return;
GLbitfield mask = 0;
@@ -925,49 +936,23 @@ bool GLGSRender::do_method(u32 cmd, u32 arg)
bool GLGSRender::check_program_state()
{
auto rtt_lookup_func = [this](u32 texaddr, rsx::fragment_texture &tex, bool is_depth) -> std::tuple<bool, u16>
{
gl::render_target *surface = nullptr;
if (!is_depth)
surface = m_rtts.get_texture_from_render_target_if_applicable(texaddr);
else
{
surface = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr);
if (!surface && m_gl_texture_cache.is_depth_texture(texaddr, (u32)get_texture_size(tex)))
return std::make_tuple(true, 0);
}
if (!surface)
{
auto rsc = m_rtts.get_surface_subresource_if_applicable(texaddr, 0, 0, tex.pitch());
if (!rsc.surface || rsc.is_depth_surface != is_depth)
return std::make_tuple(false, 0);
surface = rsc.surface;
}
return std::make_tuple(true, surface->get_native_pitch());
};
get_current_fragment_program(rtt_lookup_func);
if (current_fragment_program.valid == false)
return false;
get_current_vertex_program();
return true;
return (rsx::method_registers.shader_program_address() != 0);
}
void GLGSRender::load_program(u32 vertex_base, u32 vertex_count)
{
get_current_fragment_program(fs_sampler_state);
verify(HERE), current_fragment_program.valid;
get_current_vertex_program();
auto &fragment_program = current_fragment_program;
auto &vertex_program = current_vertex_program;
vertex_program.skip_vertex_input_check = true; //not needed for us since decoding is done server side
fragment_program.unnormalized_coords = 0; //unused
void* pipeline_properties = nullptr;
auto old_program = m_program;
m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, pipeline_properties);
m_program->use();
@@ -1034,6 +1019,122 @@ void GLGSRender::load_program(u32 vertex_base, u32 vertex_count)
m_transform_constants_dirty = false;
}
void GLGSRender::update_draw_state()
{
std::chrono::time_point<steady_clock> then = steady_clock::now();
bool color_mask_b = rsx::method_registers.color_mask_b();
bool color_mask_g = rsx::method_registers.color_mask_g();
bool color_mask_r = rsx::method_registers.color_mask_r();
bool color_mask_a = rsx::method_registers.color_mask_a();
gl_state.color_mask(color_mask_r, color_mask_g, color_mask_b, color_mask_a);
gl_state.depth_mask(rsx::method_registers.depth_write_enabled());
gl_state.stencil_mask(rsx::method_registers.stencil_mask());
if (gl_state.enable(rsx::method_registers.depth_test_enabled(), GL_DEPTH_TEST))
{
gl_state.depth_func(comparison_op(rsx::method_registers.depth_func()));
float range_near = rsx::method_registers.clip_min();
float range_far = rsx::method_registers.clip_max();
//Workaround to preserve depth precision but respect z direction
//Ni no Kuni sets a very restricted z range (0.9x - 1.) and depth reads / tests are broken
if (range_near <= range_far)
gl_state.depth_range(0.f, 1.f);
else
gl_state.depth_range(1.f, 0.f);
}
if (glDepthBoundsEXT && (gl_state.enable(rsx::method_registers.depth_bounds_test_enabled(), GL_DEPTH_BOUNDS_TEST_EXT)))
{
gl_state.depth_bounds(rsx::method_registers.depth_bounds_min(), rsx::method_registers.depth_bounds_max());
}
gl_state.enable(rsx::method_registers.dither_enabled(), GL_DITHER);
if (gl_state.enable(rsx::method_registers.blend_enabled(), GL_BLEND))
{
glBlendFuncSeparate(blend_factor(rsx::method_registers.blend_func_sfactor_rgb()),
blend_factor(rsx::method_registers.blend_func_dfactor_rgb()),
blend_factor(rsx::method_registers.blend_func_sfactor_a()),
blend_factor(rsx::method_registers.blend_func_dfactor_a()));
auto blend_colors = rsx::get_constant_blend_colors();
glBlendColor(blend_colors[0], blend_colors[1], blend_colors[2], blend_colors[3]);
glBlendEquationSeparate(blend_equation(rsx::method_registers.blend_equation_rgb()),
blend_equation(rsx::method_registers.blend_equation_a()));
}
if (gl_state.enable(rsx::method_registers.stencil_test_enabled(), GL_STENCIL_TEST))
{
glStencilFunc(comparison_op(rsx::method_registers.stencil_func()),
rsx::method_registers.stencil_func_ref(),
rsx::method_registers.stencil_func_mask());
glStencilOp(stencil_op(rsx::method_registers.stencil_op_fail()), stencil_op(rsx::method_registers.stencil_op_zfail()),
stencil_op(rsx::method_registers.stencil_op_zpass()));
if (rsx::method_registers.two_sided_stencil_test_enabled())
{
glStencilMaskSeparate(GL_BACK, rsx::method_registers.back_stencil_mask());
glStencilFuncSeparate(GL_BACK, comparison_op(rsx::method_registers.back_stencil_func()),
rsx::method_registers.back_stencil_func_ref(), rsx::method_registers.back_stencil_func_mask());
glStencilOpSeparate(GL_BACK, stencil_op(rsx::method_registers.back_stencil_op_fail()),
stencil_op(rsx::method_registers.back_stencil_op_zfail()), stencil_op(rsx::method_registers.back_stencil_op_zpass()));
}
}
gl_state.enablei(rsx::method_registers.blend_enabled_surface_1(), GL_BLEND, 1);
gl_state.enablei(rsx::method_registers.blend_enabled_surface_2(), GL_BLEND, 2);
gl_state.enablei(rsx::method_registers.blend_enabled_surface_3(), GL_BLEND, 3);
if (gl_state.enable(rsx::method_registers.logic_op_enabled(), GL_COLOR_LOGIC_OP))
{
gl_state.logic_op(logic_op(rsx::method_registers.logic_operation()));
}
gl_state.line_width(rsx::method_registers.line_width());
gl_state.enable(rsx::method_registers.line_smooth_enabled(), GL_LINE_SMOOTH);
gl_state.enable(rsx::method_registers.poly_offset_point_enabled(), GL_POLYGON_OFFSET_POINT);
gl_state.enable(rsx::method_registers.poly_offset_line_enabled(), GL_POLYGON_OFFSET_LINE);
gl_state.enable(rsx::method_registers.poly_offset_fill_enabled(), GL_POLYGON_OFFSET_FILL);
//offset_bias is the constant factor, multiplied by the implementation factor R
//offst_scale is the slope factor, multiplied by the triangle slope factor M
gl_state.polygon_offset(rsx::method_registers.poly_offset_scale(), rsx::method_registers.poly_offset_bias());
if (gl_state.enable(rsx::method_registers.cull_face_enabled(), GL_CULL_FACE))
{
gl_state.cull_face(cull_face(rsx::method_registers.cull_face_mode()));
}
gl_state.front_face(front_face(rsx::method_registers.front_face_mode()));
//TODO
//NV4097_SET_ANISO_SPREAD
//NV4097_SET_SPECULAR_ENABLE
//NV4097_SET_TWO_SIDE_LIGHT_EN
//NV4097_SET_FLAT_SHADE_OP
//NV4097_SET_EDGE_FLAG
//NV4097_SET_COLOR_KEY_COLOR
//NV4097_SET_SHADER_CONTROL
//NV4097_SET_ZMIN_MAX_CONTROL
//NV4097_SET_ANTI_ALIASING_CONTROL
//NV4097_SET_CLIP_ID_TEST_ENABLE
std::chrono::time_point<steady_clock> now = steady_clock::now();
m_begin_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(now - then).count();
}
void GLGSRender::flip(int buffer)
{
if (skip_frame)
@@ -1156,7 +1257,9 @@ void GLGSRender::flip(int buffer)
m_text_printer.print_text(0, 72, m_frame->client_width(), m_frame->client_height(), "draw call execution: " + std::to_string(m_draw_time) + "us");
auto num_dirty_textures = m_gl_texture_cache.get_unreleased_textures_count();
auto texture_memory_size = m_gl_texture_cache.get_texture_memory_in_use() / (1024 * 1024);
m_text_printer.print_text(0, 108, m_frame->client_width(), m_frame->client_height(), "Unreleased textures: " + std::to_string(num_dirty_textures));
m_text_printer.print_text(0, 126, m_frame->client_width(), m_frame->client_height(), "Texture memory: " + std::to_string(texture_memory_size) + "M");
}
m_frame->flip(m_context);
@@ -1169,10 +1272,6 @@ void GLGSRender::flip(int buffer)
tex->remove();
m_rtts.invalidated_resources.clear();
if (g_cfg.video.invalidate_surface_cache_every_frame)
m_rtts.invalidate_surface_cache_data(nullptr);
m_vertex_cache->purge();
//If we are skipping the next frame, do not reset perf counters
@@ -1195,38 +1294,45 @@ u64 GLGSRender::timestamp() const
bool GLGSRender::on_access_violation(u32 address, bool is_writing)
{
if (is_writing)
return m_gl_texture_cache.invalidate_address(address);
else
bool can_flush = (std::this_thread::get_id() == m_thread_id);
auto result = m_gl_texture_cache.invalidate_address(address, is_writing, can_flush);
if (!result.violation_handled)
return false;
{
if (std::this_thread::get_id() != m_thread_id)
{
bool flushable;
gl::cached_texture_section* section_to_post;
std::tie(flushable, section_to_post) = m_gl_texture_cache.address_is_flushable(address);
if (!flushable) return false;
work_item &task = post_flush_request(address, section_to_post);
vm::temporary_unlock();
{
std::unique_lock<std::mutex> lock(task.guard_mutex);
task.cv.wait(lock, [&task] { return task.processed; });
}
task.received = true;
return task.result;
}
return m_gl_texture_cache.flush_address(address);
std::lock_guard<std::mutex> lock(m_sampler_mutex);
m_samplers_dirty.store(true);
}
if (result.num_flushable > 0)
{
work_item &task = post_flush_request(address, result);
vm::temporary_unlock();
{
std::unique_lock<std::mutex> lock(task.guard_mutex);
task.cv.wait(lock, [&task] { return task.processed; });
}
task.received = true;
return true;
}
return true;
}
void GLGSRender::on_notify_memory_unmapped(u32 address_base, u32 size)
{
if (m_gl_texture_cache.invalidate_range(address_base, size, false))
//Discard all memory in that range without bothering with writeback (Force it for strict?)
if (m_gl_texture_cache.invalidate_range(address_base, size, true, true, false).violation_handled)
{
m_gl_texture_cache.purge_dirty();
{
std::lock_guard<std::mutex> lock(m_sampler_mutex);
m_samplers_dirty.store(true);
}
}
}
void GLGSRender::do_local_task()
@@ -1242,20 +1348,7 @@ void GLGSRender::do_local_task()
if (q.processed) continue;
std::unique_lock<std::mutex> lock(q.guard_mutex);
//Check if the suggested section is valid
if (!q.section_to_flush->is_flushed())
{
m_gl_texture_cache.flush_address(q.address_to_flush);
q.result = true;
}
else
{
//Another thread has unlocked this memory region already
//Return success
q.result = true;
}
q.result = m_gl_texture_cache.flush_all(q.section_data);
q.processed = true;
//Notify thread waiting on this
@@ -1264,14 +1357,14 @@ void GLGSRender::do_local_task()
}
}
work_item& GLGSRender::post_flush_request(u32 address, gl::cached_texture_section *section)
work_item& GLGSRender::post_flush_request(u32 address, gl::texture_cache::thrashed_set& flush_data)
{
std::lock_guard<std::mutex> lock(queue_guard);
work_queue.emplace_back();
work_item &result = work_queue.back();
result.address_to_flush = address;
result.section_to_flush = section;
result.section_data = std::move(flush_data);
return result;
}
@@ -1286,9 +1379,18 @@ void GLGSRender::synchronize_buffers()
bool GLGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst_info& dst, bool interpolate)
{
m_samplers_dirty.store(true);
return m_gl_texture_cache.blit(src, dst, interpolate, m_rtts);
}
void GLGSRender::notify_tile_unbound(u32 tile)
{
//TODO: Handle texture writeback
//u32 addr = rsx::get_address(tiles[tile].offset, tiles[tile].location);
//on_notify_memory_unmapped(addr, tiles[tile].size);
//m_rtts.invalidate_surface_address(addr, false);
}
void GLGSRender::check_zcull_status(bool framebuffer_swap, bool force_read)
{
if (g_cfg.video.disable_zcull_queries)
+11 -29
View File
@@ -28,7 +28,7 @@ struct work_item
std::mutex guard_mutex;
u32 address_to_flush = 0;
gl::cached_texture_section *section_to_flush = nullptr;
gl::texture_cache::thrashed_set section_data;
volatile bool processed = false;
volatile bool result = false;
@@ -310,33 +310,6 @@ struct driver_state
}
};
struct sw_ring_buffer
{
std::vector<u8> data;
u32 ring_pos = 0;
u32 ring_length = 0;
sw_ring_buffer(u32 size)
{
data.resize(size);
ring_length = size;
}
void* get(u32 dwords)
{
const u32 required = (dwords << 2);
if ((ring_pos + required) > ring_length)
{
ring_pos = 0;
return data.data();
}
void *result = data.data() + ring_pos;
ring_pos += required;
return result;
}
};
class GLGSRender : public GSRender
{
private:
@@ -405,6 +378,12 @@ private:
const u32 occlusion_query_count = 128;
std::array<occlusion_query_info, 128> occlusion_query_data = {};
std::mutex m_sampler_mutex;
u64 surface_store_tag = 0;
std::atomic_bool m_samplers_dirty = {true};
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::fragment_textures_count> fs_sampler_state = {};
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::vertex_textures_count> vs_sampler_state = {};
public:
GLGSRender();
@@ -422,13 +401,15 @@ private:
bool check_program_state();
void load_program(u32 vertex_base, u32 vertex_count);
void update_draw_state();
public:
void read_buffers();
void write_buffers();
void set_viewport();
void synchronize_buffers();
work_item& post_flush_request(u32 address, gl::cached_texture_section *section);
work_item& post_flush_request(u32 address, gl::texture_cache::thrashed_set& flush_data);
bool scaled_image_from_memory(rsx::blit_src_info& src_info, rsx::blit_dst_info& dst_info, bool interpolate) override;
@@ -453,6 +434,7 @@ protected:
bool on_access_violation(u32 address, bool is_writing) override;
void on_notify_memory_unmapped(u32 address_base, u32 size) override;
void notify_tile_unbound(u32 tile) override;
virtual std::array<std::vector<gsl::byte>, 4> copy_render_targets_to_memory() override;
virtual std::array<std::vector<gsl::byte>, 2> copy_depth_stencil_buffer_to_memory() override;
+7
View File
@@ -84,6 +84,7 @@ namespace gl
bool NV_texture_barrier_supported = false;
bool initialized = false;
bool vendor_INTEL = false;
bool vendor_AMD = false;
void initialize()
{
@@ -192,6 +193,12 @@ namespace gl
if (!EXT_dsa_supported && glGetTextureImageEXT && glTextureBufferRangeEXT)
EXT_dsa_supported = true;
}
#ifdef _WIN32
else if (vendor_string.find("amd") != std::string::npos || vendor_string.find("ati") != std::string::npos)
{
vendor_AMD = true;
}
#endif
initialized = true;
}
+52 -10
View File
@@ -165,21 +165,36 @@ void GLGSRender::init_buffers(bool skip_reading)
const u16 clip_horizontal = rsx::method_registers.surface_clip_width();
const u16 clip_vertical = rsx::method_registers.surface_clip_height();
const u16 clip_x = rsx::method_registers.surface_clip_origin_x();
const u16 clip_y = rsx::method_registers.surface_clip_origin_y();
framebuffer_status_valid = false;
if (clip_horizontal == 0 || clip_vertical == 0)
{
LOG_ERROR(RSX, "Invalid framebuffer setup, w=%d, h=%d", clip_horizontal, clip_vertical);
framebuffer_status_valid = false;
return;
}
const auto surface_addresses = get_color_surface_addresses();
const auto depth_address = get_zeta_surface_address();
for (const auto &addr: surface_addresses)
{
if (addr)
{
framebuffer_status_valid = true;
break;
}
}
if (!framebuffer_status_valid && !depth_address)
return;
const auto pitchs = get_pitchs();
const auto surface_format = rsx::method_registers.surface_color();
const auto depth_format = rsx::method_registers.surface_depth_fmt();
const auto surface_addresses = get_color_surface_addresses();
const auto depth_address = get_zeta_surface_address();
m_rtts.prepare_render_target(nullptr, surface_format, depth_format, clip_horizontal, clip_vertical,
rsx::method_registers.surface_color_target(),
surface_addresses, depth_address);
@@ -189,6 +204,11 @@ void GLGSRender::init_buffers(bool skip_reading)
bool old_format_found = false;
gl::texture::format old_format;
const auto color_offsets = get_offsets();
const auto color_locations = get_locations();
const auto aa_mode = rsx::method_registers.surface_antialias();
const auto bpp = get_format_block_size_in_bytes(surface_format);
for (int i = 0; i < rsx::limits::color_buffers_count; ++i)
{
if (surface_info[i].pitch && g_cfg.video.write_color_buffers)
@@ -204,14 +224,15 @@ void GLGSRender::init_buffers(bool skip_reading)
if (std::get<0>(m_rtts.m_bound_render_targets[i]))
{
__glcheck draw_fbo.color[i] = *std::get<1>(m_rtts.m_bound_render_targets[i]);
auto rtt = std::get<1>(m_rtts.m_bound_render_targets[i]);
draw_fbo.color[i] = *rtt;
std::get<1>(m_rtts.m_bound_render_targets[i])->set_rsx_pitch(pitchs[i]);
rtt->set_rsx_pitch(pitchs[i]);
surface_info[i] = { surface_addresses[i], pitchs[i], false, surface_format, depth_format, clip_horizontal, clip_vertical };
//Verify pitch given is correct if pitch <= 64 (especially 64)
if (pitchs[i] <= 64)
{
{
const u16 native_pitch = std::get<1>(m_rtts.m_bound_render_targets[i])->get_native_pitch();
if (native_pitch > pitchs[i])
{
@@ -223,6 +244,14 @@ void GLGSRender::init_buffers(bool skip_reading)
surface_info[i].pitch = 0;
}
}
rtt->tile = find_tile(color_offsets[i], color_locations[i]);
rtt->aa_mode = aa_mode;
rtt->set_raster_offset(clip_x, clip_y, bpp);
m_gl_texture_cache.notify_surface_changed(surface_addresses[i]);
if (surface_info[i].pitch)
m_gl_texture_cache.tag_framebuffer(surface_addresses[i] + rtt->raster_address_offset);
}
else
surface_info[i] = {};
@@ -230,10 +259,16 @@ void GLGSRender::init_buffers(bool skip_reading)
if (std::get<0>(m_rtts.m_bound_depth_stencil))
{
auto ds = std::get<1>(m_rtts.m_bound_depth_stencil);
u8 texel_size = 2;
if (depth_format == rsx::surface_depth_format::z24s8)
__glcheck draw_fbo.depth_stencil = *std::get<1>(m_rtts.m_bound_depth_stencil);
{
draw_fbo.depth_stencil = *ds;
texel_size = 4;
}
else
__glcheck draw_fbo.depth = *std::get<1>(m_rtts.m_bound_depth_stencil);
draw_fbo.depth = *ds;
const u32 depth_surface_pitch = rsx::method_registers.surface_z_pitch();
std::get<1>(m_rtts.m_bound_depth_stencil)->set_rsx_pitch(rsx::method_registers.surface_z_pitch());
@@ -253,6 +288,13 @@ void GLGSRender::init_buffers(bool skip_reading)
depth_surface_info.pitch = 0;
}
}
ds->aa_mode = aa_mode;
ds->set_raster_offset(clip_x, clip_y, texel_size);
m_gl_texture_cache.notify_surface_changed(depth_address);
if (depth_surface_info.pitch)
m_gl_texture_cache.tag_framebuffer(depth_address + ds->raster_address_offset);
}
else
depth_surface_info = {};
@@ -390,7 +432,7 @@ void GLGSRender::read_buffers()
}
else
{
m_gl_texture_cache.invalidate_range(texaddr, range);
m_gl_texture_cache.invalidate_range(texaddr, range, false, false, true);
std::unique_ptr<u8[]> buffer(new u8[pitch * height]);
color_buffer.read(buffer.get(), width, height, pitch);
+4
View File
@@ -253,6 +253,10 @@ struct gl_render_target_traits
static void invalidate_rtt_surface_contents(void *, gl::render_target *rtt, gl::render_target* /*old*/, bool forced) { if (forced) rtt->set_cleared(false); }
static void invalidate_depth_surface_contents(void *, gl::render_target *ds, gl::render_target* /*old*/, bool) { ds->set_cleared(false); }
static
void notify_surface_invalidated(const std::unique_ptr<gl::render_target>&)
{}
static
bool rtt_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_color_format format, size_t width, size_t height, bool check_refs=false)
{
+1
View File
@@ -473,6 +473,7 @@ namespace gl
glBindTexture(target, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
+74 -28
View File
@@ -386,6 +386,8 @@ namespace gl
bool flush()
{
if (flushed) return true; //Already written, ignore
if (!copied)
{
LOG_WARNING(RSX, "Cache miss at address 0x%X. This is gonna hurt...", cpu_address_base);
@@ -399,7 +401,6 @@ namespace gl
}
}
protect(utils::protection::rw);
m_fence.wait_for_signal();
flushed = true;
@@ -424,6 +425,16 @@ namespace gl
rsx::scale_image_nearest(dst, const_cast<const void*>(data), width, height, rsx_pitch, real_pitch, pixel_size, samples);
}
/* switch (gcm_format)
{
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
rsx::shuffle_texel_data_wzyx<u16>(dst, rsx_pitch, width, height);
break;
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT:
rsx::shuffle_texel_data_wzyx<u32>(dst, rsx_pitch, width, height);
break;
}*/
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
@@ -443,22 +454,21 @@ namespace gl
{
//Read-only texture, destroy texture memory
glDeleteTextures(1, &vram_texture);
vram_texture = 0;
}
else
{
//Destroy pbo cache since vram texture is managed elsewhere
glDeleteBuffers(1, &pbo_id);
pbo_id = 0;
pbo_size = 0;
if (scaled_texture)
{
glDeleteTextures(1, &scaled_texture);
scaled_texture = 0;
}
}
vram_texture = 0;
scaled_texture = 0;
pbo_id = 0;
pbo_size = 0;
if (!m_fence.is_empty())
m_fence.destroy();
}
@@ -571,7 +581,7 @@ namespace gl
m_temporary_surfaces.resize(0);
}
u32 create_temporary_subresource(u32 src_id, GLenum sized_internal_fmt, u16 x, u16 y, u16 width, u16 height)
u32 create_temporary_subresource_impl(u32 src_id, GLenum sized_internal_fmt, const GLenum dst_type, u16 x, u16 y, u16 width, u16 height)
{
u32 dst_id = 0;
@@ -589,19 +599,23 @@ namespace gl
}
glGenTextures(1, &dst_id);
glBindTexture(GL_TEXTURE_2D, dst_id);
glBindTexture(dst_type, dst_id);
glTexStorage2D(GL_TEXTURE_2D, 1, sized_internal_fmt, width, height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
if (dst_type == GL_TEXTURE_2D)
glTexStorage2D(GL_TEXTURE_2D, 1, sized_internal_fmt, width, height);
else if (dst_type == GL_TEXTURE_1D)
glTexStorage1D(GL_TEXTURE_1D, 1, sized_internal_fmt, width);
glTexParameteri(dst_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(dst_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(dst_type, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(dst_type, GL_TEXTURE_MAX_LEVEL, 0);
//Empty GL_ERROR
glGetError();
glCopyImageSubData(src_id, GL_TEXTURE_2D, 0, x, y, 0,
dst_id, GL_TEXTURE_2D, 0, 0, 0, 0, width, height, 1);
dst_id, dst_type, 0, 0, 0, 0, width, height, 1);
m_temporary_surfaces.push_back(dst_id);
@@ -625,22 +639,59 @@ namespace gl
u32 create_temporary_subresource_view(void*&, u32* src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h) override
{
const GLenum ifmt = gl::get_sized_internal_format(gcm_format);
return create_temporary_subresource(*src, ifmt, x, y, w, h);
return create_temporary_subresource_impl(*src, ifmt, GL_TEXTURE_2D, x, y, w, h);
}
u32 create_temporary_subresource_view(void*&, gl::texture* src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h) override
{
if (auto as_rtt = dynamic_cast<gl::render_target*>(src))
{
return create_temporary_subresource(src->id(), (GLenum)as_rtt->get_compatible_internal_format(), x, y, w, h);
return create_temporary_subresource_impl(src->id(), (GLenum)as_rtt->get_compatible_internal_format(), GL_TEXTURE_2D, x, y, w, h);
}
else
{
const GLenum ifmt = gl::get_sized_internal_format(gcm_format);
return create_temporary_subresource(src->id(), ifmt, x, y, w, h);
return create_temporary_subresource_impl(src->id(), ifmt, GL_TEXTURE_2D, x, y, w, h);
}
}
u32 generate_cubemap_from_images(void*&, const u32 gcm_format, u16 size, std::array<u32, 6>& sources) override
{
const GLenum ifmt = gl::get_sized_internal_format(gcm_format);
GLuint dst_id = 0;
glGenTextures(1, &dst_id);
glBindTexture(GL_TEXTURE_CUBE_MAP, dst_id);
glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, ifmt, size, size);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
//Empty GL_ERROR
glGetError();
for (int i = 0; i < 6; ++i)
{
if (sources[i] != 0)
{
glCopyImageSubData(sources[i], GL_TEXTURE_2D, 0, 0, 0, 0,
dst_id, GL_TEXTURE_CUBE_MAP, 0, 0, 0, i, size, size, 1);
}
}
m_temporary_surfaces.push_back(dst_id);
if (GLenum err = glGetError())
{
LOG_WARNING(RSX, "Failed to copy image subresource with GL error 0x%X", err);
return 0;
}
return dst_id;
}
cached_texture_section* create_new_texture(void*&, u32 rsx_address, u32 rsx_size, u16 width, u16 height, u16 depth, u16 mipmaps, const u32 gcm_format,
const rsx::texture_upload_context context, const rsx::texture_dimension_extended type, const rsx::texture_create_flags flags,
std::pair<std::array<u8, 4>, std::array<u8, 4>>& /*remap_vector*/) override
@@ -670,10 +721,14 @@ namespace gl
cached.set_depth_flag(depth_flag);
cached.set_view_flags(flags);
cached.set_context(context);
cached.set_image_type(type);
//Its not necessary to lock blit dst textures as they are just reused as necessary
if (context != rsx::texture_upload_context::blit_engine_dst || g_cfg.video.strict_rendering_mode)
{
cached.protect(utils::protection::ro);
update_cache_tag();
}
return &cached;
}
@@ -773,6 +828,7 @@ namespace gl
}
clear_temporary_subresources();
m_temporary_subresource_cache.clear();
}
bool blit(rsx::blit_src_info& src, rsx::blit_dst_info& dst, bool linear_interpolate, gl_render_targets& m_rtts)
@@ -780,15 +836,5 @@ namespace gl
void* unused = nullptr;
return upload_scaled_image(src, dst, linear_interpolate, unused, m_rtts, m_hw_blitter);
}
template<typename RsxTextureType>
void upload_and_bind_texture(int index, GLenum target, RsxTextureType &tex, gl_render_targets &m_rtts)
{
glActiveTexture(GL_TEXTURE0 + index);
void* unused = nullptr;
auto id = upload_texture(unused, tex, m_rtts);
glBindTexture(target, id);
}
};
}
+1 -1
View File
@@ -51,7 +51,7 @@ namespace
u32 block_sz = vertex_draw_count * type_size;
gsl::span<gsl::byte> dst{ reinterpret_cast<gsl::byte*>(ptr), ::narrow<u32>(block_sz) };
std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, raw_index_buffer,
std::tie(min_index, max_index, vertex_draw_count) = write_index_array_data_to_buffer(dst, raw_index_buffer,
type, draw_mode, rsx::method_registers.restart_index_enabled(), rsx::method_registers.restart_index(), first_count_commands,
[](auto prim) { return !gl::is_primitive_native(prim); });
+1 -2
View File
@@ -18,10 +18,9 @@ std::string GLVertexDecompilerThread::getIntTypeName(size_t elementCount)
return "ivec4";
}
std::string GLVertexDecompilerThread::getFunction(FUNCTION f)
{
return gl::getFunctionImpl(f);
return glsl::getFunctionImpl(f);
}
std::string GLVertexDecompilerThread::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1)
+12 -11
View File
@@ -4,16 +4,6 @@
#include "GSRender.h"
draw_context_t GSFrameBase::new_context()
{
if (void* context = make_context())
{
return std::shared_ptr<void>(context, [this](void* ctxt) { delete_context(ctxt); });
}
return nullptr;
}
GSRender::GSRender()
{
m_frame = Emu.GetCallbacks().get_gs_frame().release();
@@ -42,11 +32,22 @@ void GSRender::on_init_thread()
{
if (m_frame)
{
m_context = m_frame->new_context();
m_context = m_frame->make_context();
m_frame->set_current(m_context);
}
}
void GSRender::on_exit()
{
if (m_frame)
{
m_frame->delete_context(m_context);
m_context = nullptr;
}
rsx::thread::on_exit();
}
void GSRender::flip(int buffer)
{
if (m_frame)
+19 -6
View File
@@ -24,12 +24,15 @@ enum wm_event
geometry_change_notice, //about to start resizing and/or moving the window
geometry_change_in_progress, //window being resized and/or moved
window_resized, //window was resized
window_moved //window moved without resize
window_minimized, //window was minimized
window_restored, //window was restored from a minimized state
window_moved, //window moved without resize
window_visibility_changed
};
using RSXDebuggerPrograms = std::vector<RSXDebuggerProgram>;
using draw_context_t = std::shared_ptr<void>;
using draw_context_t = void*;
class GSFrameBase
{
@@ -42,8 +45,8 @@ public:
virtual void hide() = 0;
virtual void show() = 0;
draw_context_t new_context();
virtual void delete_context(draw_context_t ctx) = 0;
virtual draw_context_t make_context() = 0;
virtual void set_current(draw_context_t ctx) = 0;
virtual void flip(draw_context_t ctx, bool skip_frame=false) = 0;
virtual int client_width() = 0;
@@ -52,12 +55,11 @@ public:
virtual void* handle() const = 0;
protected:
virtual void delete_context(void* ctx) = 0;
virtual void* make_context() = 0;
//window manager event management
wm_event m_raised_event;
std::atomic_bool wm_event_raised = {};
std::atomic_bool wm_event_queue_enabled = {};
public:
//synchronize native window access
@@ -83,6 +85,16 @@ public:
return get_default_wm_event();
}
void disable_wm_event_queue()
{
wm_event_queue_enabled.store(false);
}
void enable_wm_event_queue()
{
wm_event_queue_enabled.store(true);
}
};
class GSRender : public rsx::thread
@@ -97,6 +109,7 @@ public:
void on_init_rsx() override;
void on_init_thread() override;
void on_exit() override;
void flip(int buffer) override;
};
+4 -7
View File
@@ -147,7 +147,7 @@ union SRC1
u32 swizzle_w : 2;
u32 neg : 1;
u32 abs : 1;
u32 input_mod_src0 : 3;
u32 input_prec_mod : 3; // Looks to be a precision clamping modifier affecting all inputs (tested with Dark Souls II)
u32 : 6;
u32 scale : 3;
u32 opcode_is_branch : 1;
@@ -243,13 +243,10 @@ struct RSXFragmentProgram
void set_texture_dimension(const std::array<rsx::texture_dimension_extended, 16> &dimensions)
{
size_t id = 0;
for (const rsx::texture_dimension_extended &dim : dimensions)
texture_dimensions = 0;
for (u32 i = 0, offset = 0; i < 16; ++i, offset += 2)
{
texture_dimensions &= ~(0x3 << (id * 2));
u8 d = (u8)dim;
texture_dimensions |= ((d & 0x3) << (id * 2));
id++;
texture_dimensions |= (u32)dimensions[i] << offset;
}
}
+126 -28
View File
@@ -7,6 +7,7 @@
#include "Emu/Cell/PPUCallback.h"
#include "Common/BufferUtils.h"
#include "Common/texture_cache.h"
#include "rsx_methods.h"
#include "rsx_utils.h"
@@ -243,6 +244,7 @@ namespace rsx
};
m_rtts_dirty = true;
memset(m_textures_dirty, -1, sizeof(m_textures_dirty));
memset(m_vertex_textures_dirty, -1, sizeof(m_vertex_textures_dirty));
m_transform_constants_dirty = true;
}
@@ -392,6 +394,7 @@ namespace rsx
// Raise priority above other threads
thread_ctrl::set_native_priority(1);
thread_ctrl::set_ideal_processor_core(0);
// Round to nearest to deal with forward/reverse scaling
fesetround(FE_TONEAREST);
@@ -477,10 +480,10 @@ namespace rsx
//Execute backend-local tasks first
do_local_task();
const u32 get = ctrl->get;
ctrl->get.store(internal_get.load());
const u32 put = ctrl->put;
if (put == get || !Emu.IsRunning())
if (put == internal_get || !Emu.IsRunning())
{
if (has_deferred_call)
flush_command_queue();
@@ -491,16 +494,16 @@ namespace rsx
//Validate put and get registers
//TODO: Who should handle graphics exceptions??
const u32 get_address = RSXIOMem.RealAddr(get);
const u32 get_address = RSXIOMem.RealAddr(internal_get);
if (!get_address)
{
LOG_ERROR(RSX, "Invalid FIFO queue get/put registers found, get=0x%X, put=0x%X", get, put);
LOG_ERROR(RSX, "Invalid FIFO queue get/put registers found, get=0x%X, put=0x%X", internal_get.load(), put);
if (mem_faults_count >= 3)
{
LOG_ERROR(RSX, "Application has failed to recover, discarding FIFO queue");
ctrl->get = put;
internal_get = put;
}
else
{
@@ -512,29 +515,29 @@ namespace rsx
continue;
}
const u32 cmd = ReadIO32(get);
const u32 cmd = ReadIO32(internal_get);
const u32 count = (cmd >> 18) & 0x7ff;
if ((cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD)
{
u32 offs = cmd & 0x1ffffffc;
//LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put);
ctrl->get = offs;
internal_get = offs;
continue;
}
if ((cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD)
{
u32 offs = cmd & 0xfffffffc;
//LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put);
ctrl->get = offs;
internal_get = offs;
continue;
}
if ((cmd & RSX_METHOD_CALL_CMD_MASK) == RSX_METHOD_CALL_CMD)
{
m_call_stack.push(get + 4);
m_call_stack.push(internal_get + 4);
u32 offs = cmd & ~3;
//LOG_WARNING(RSX, "rsx call(0x%x) #0x%x - 0x%x", offs, cmd, get);
ctrl->get = offs;
internal_get = offs;
continue;
}
if (cmd == RSX_METHOD_RETURN_CMD)
@@ -542,26 +545,26 @@ namespace rsx
u32 get = m_call_stack.top();
m_call_stack.pop();
//LOG_WARNING(RSX, "rsx return(0x%x)", get);
ctrl->get = get;
internal_get = get;
continue;
}
if (cmd == 0) //nop
{
ctrl->get = get + 4;
internal_get += 4;
continue;
}
//Validate the args ptr if the command attempts to read from it
const u32 args_address = RSXIOMem.RealAddr(get + 4);
const u32 args_address = RSXIOMem.RealAddr(internal_get + 4);
if (!args_address && count)
{
LOG_ERROR(RSX, "Invalid FIFO queue args ptr found, get=0x%X, cmd=0x%X, count=%d", get, cmd, count);
LOG_ERROR(RSX, "Invalid FIFO queue args ptr found, get=0x%X, cmd=0x%X, count=%d", internal_get.load(), cmd, count);
if (mem_faults_count >= 3)
{
LOG_ERROR(RSX, "Application has failed to recover, discarding FIFO queue");
ctrl->get = put;
internal_get = put;
}
else
{
@@ -595,6 +598,7 @@ namespace rsx
bool execute_method_call = true;
//TODO: Flatten draw calls when multidraw is not supported to simplify checking in the end() methods
if (supports_multidraw)
{
//TODO: Make this cleaner
@@ -713,11 +717,11 @@ namespace rsx
{
//This is almost guaranteed to be heap corruption at this point
//Ignore the rest of the chain
ctrl->get = put;
internal_get = put;
continue;
}
ctrl->get = get + (count + 1) * 4;
internal_get += (count + 1) * 4;
}
}
@@ -1320,7 +1324,99 @@ namespace rsx
return result;
}
void thread::get_current_fragment_program(std::function<std::tuple<bool, u16>(u32, fragment_texture&, bool)> get_surface_info)
void thread::get_current_fragment_program(const std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::fragment_textures_count>& sampler_descriptors)
{
auto &result = current_fragment_program = {};
const u32 shader_program = rsx::method_registers.shader_program_address();
if (shader_program == 0)
return;
const u32 program_location = (shader_program & 0x3) - 1;
const u32 program_offset = (shader_program & ~0x3);
result.offset = program_offset;
result.addr = vm::base(rsx::get_address(program_offset, program_location));
result.valid = true;
result.ctrl = rsx::method_registers.shader_control();
result.unnormalized_coords = 0;
result.front_back_color_enabled = !rsx::method_registers.two_side_light_en();
result.back_color_diffuse_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE);
result.back_color_specular_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR);
result.front_color_diffuse_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE);
result.front_color_specular_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR);
result.redirected_textures = 0;
result.shadow_textures = 0;
std::array<texture_dimension_extended, 16> texture_dimensions;
const auto resolution_scale = rsx::get_resolution_scale();
for (u32 i = 0; i < rsx::limits::fragment_textures_count; ++i)
{
auto &tex = rsx::method_registers.fragment_textures[i];
result.texture_scale[i][0] = sampler_descriptors[i]->scale_x;
result.texture_scale[i][1] = sampler_descriptors[i]->scale_y;
result.textures_alpha_kill[i] = 0;
result.textures_zfunc[i] = 0;
if (!tex.enabled())
{
texture_dimensions[i] = texture_dimension_extended::texture_dimension_2d;
}
else
{
texture_dimensions[i] = sampler_descriptors[i]->image_type;
if (tex.alpha_kill_enabled())
{
//alphakill can be ignored unless a valid comparison function is set
const rsx::comparison_function func = (rsx::comparison_function)tex.zfunc();
if (func < rsx::comparison_function::always && func > rsx::comparison_function::never)
{
result.textures_alpha_kill[i] = 1;
result.textures_zfunc[i] = (u8)func;
}
}
const u32 texaddr = rsx::get_address(tex.offset(), tex.location());
const u32 raw_format = tex.format();
if (raw_format & CELL_GCM_TEXTURE_UN)
result.unnormalized_coords |= (1 << i);
if (sampler_descriptors[i]->is_depth_texture)
{
const u32 format = raw_format & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
switch (format)
{
case CELL_GCM_TEXTURE_A8R8G8B8:
case CELL_GCM_TEXTURE_D8R8G8B8:
case CELL_GCM_TEXTURE_A4R4G4B4:
case CELL_GCM_TEXTURE_R5G6B5:
result.redirected_textures |= (1 << i);
break;
case CELL_GCM_TEXTURE_DEPTH16:
case CELL_GCM_TEXTURE_DEPTH24_D8:
case CELL_GCM_TEXTURE_DEPTH16_FLOAT:
{
const auto compare_mode = (rsx::comparison_function)tex.zfunc();
if (result.textures_alpha_kill[i] == 0 &&
compare_mode < rsx::comparison_function::always &&
compare_mode > rsx::comparison_function::never)
result.shadow_textures |= (1 << i);
break;
}
default:
LOG_ERROR(RSX, "Depth texture bound to pipeline with unexpected format 0x%X", format);
}
}
}
}
result.set_texture_dimension(texture_dimensions);
}
void thread::get_current_fragment_program_legacy(std::function<std::tuple<bool, u16>(u32, fragment_texture&, bool)> get_surface_info)
{
auto &result = current_fragment_program = {};
@@ -1411,8 +1507,8 @@ namespace rsx
case CELL_GCM_TEXTURE_D8R8G8B8:
case CELL_GCM_TEXTURE_A4R4G4B4:
case CELL_GCM_TEXTURE_R5G6B5:
result.redirected_textures |= (1 << i);
break;
result.redirected_textures |= (1 << i);
break;
case CELL_GCM_TEXTURE_DEPTH16:
case CELL_GCM_TEXTURE_DEPTH24_D8:
case CELL_GCM_TEXTURE_DEPTH16_FLOAT:
@@ -1425,7 +1521,7 @@ namespace rsx
break;
}
default:
LOG_ERROR(RSX, "Depth texture bound to pipeline with unexpected format 0x%X", format);
LOG_ERROR(RSX, "Depth texture bound to pipeline with unexpected format 0x%X", format);
}
}
}
@@ -1458,7 +1554,7 @@ namespace rsx
{
for (GcmTileInfo &tile : tiles)
{
if (!tile.binded || tile.location != location)
if (!tile.binded || (tile.location & 1) != (location & 1))
{
continue;
}
@@ -1570,6 +1666,7 @@ namespace rsx
u32 volatile_offset = 0;
u32 persistent_offset = 0;
//NOTE: Order is important! Transient ayout is always push_buffers followed by register data
if (rsx::method_registers.current_draw_clause.is_immediate_draw)
{
for (const auto &info : layout.volatile_blocks)
@@ -1764,12 +1861,7 @@ namespace rsx
return;
}
for (const u8 index : layout.referenced_registers)
{
memcpy(transient, rsx::method_registers.register_vertex_info[index].data.data(), 16);
transient += 16;
}
//NOTE: Order is important! Transient ayout is always push_buffers followed by register data
if (draw_call.is_immediate_draw)
{
//NOTE: It is possible for immediate draw to only contain index data, so vertex data can be in persistent memory
@@ -1779,6 +1871,12 @@ namespace rsx
transient += info.second;
}
}
for (const u8 index : layout.referenced_registers)
{
memcpy(transient, rsx::method_registers.register_vertex_info[index].data.data(), 16);
transient += 16;
}
}
if (persistent != nullptr)

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