Compare commits

..

185 Commits

Author SHA1 Message Date
Zangetsu38 b4f96ed45e Fix 2017-09-01 23:33:33 +02:00
Zangetsu38 1a3f9f72cf Update LLVM 5.0 2017-09-01 23:33:32 +02:00
Zion Nimchuk bc46f7c0c3 Initial LLVM 5 port 2017-09-01 23:33:32 +02:00
Zangetsu38 bec46a9ba2 Update Project to Visual Studio 2017. 2017-09-01 22:12:07 +02:00
Ani e57caefd09 libad: Enable LLE load
Removes libad from ignore list.

It will only affect games that call for it, making them progress further with the Recompiler instead of dying in Unregistered Function, as there's no HLE implementation of libad.

Tested with Guitar Hero 5 [BLES00576]
2017-09-01 21:10:50 +01:00
Nekotekina 7e99f6bc5f Add supporters 2017-09-01 21:39:32 +03:00
Nekotekina a85caaee1d Set PPU stack bounds 2017-09-01 21:24:43 +03:00
Nekotekina 5b00aaf561 Fix decrypt_self usage 2017-09-01 02:10:57 +03:00
Nekotekina 174f11bdbd Fix access violation handler 2017-09-01 01:22:48 +03:00
Nekotekina 05442bdb11 Protect SPU segments 2017-09-01 00:59:25 +03:00
Nekotekina 9ba3cea2b1 RawSPU: implemented read SPU_RunCntl_offs 2017-08-31 23:22:52 +03:00
Nekotekina 20d48289b8 RawSPU: implement read SPU_NPC_offs 2017-08-31 22:55:39 +03:00
Nekotekina 8f9410ceff Implemented syscall sys_event_port_connect_ipc 2017-08-31 22:10:22 +03:00
Nekotekina 3a08dd7dde RawSPU: implement Prxy_TagStatus_offs
Rollback to immediate MFC transfers
2017-08-31 22:03:47 +03:00
Nekotekina cfb858a51c Load liblv2.sprx by default 2017-08-31 21:46:58 +03:00
Nekotekina 37d7fdbcae Fix sys_raw_spu_image_load 2017-08-31 21:44:42 +03:00
Nekotekina 62c14e9437 Fix sys_raw_spu_load 2017-08-31 21:44:26 +03:00
Nekotekina 90b8346312 Implemented syscall _sys_spu_image_get_segments 2017-08-31 21:39:12 +03:00
Nekotekina 167d6a08f8 Implemented syscall _sys_spu_image_get_information 2017-08-31 21:30:13 +03:00
Nekotekina 649d68a00f +sys_spu_elf_get_segments 2017-08-31 20:38:17 +03:00
Nekotekina 8807cd06b7 +sys_spu_elf_get_information 2017-08-31 20:37:54 +03:00
Nekotekina b533d57717 sys_spu_image: minor update
Cleanup
Templates extended
2017-08-31 20:36:51 +03:00
Nekotekina 14a6269243 Fix fatal error dialog 2017-08-31 05:21:26 +03:00
Nekotekina 7b96190e6c Log backup rotation (incomplete) 2017-08-30 17:15:35 +03:00
Nekotekina 010b75251f fs::rename fixed
Added overwriting policy
sys_fs_rename improved
2017-08-30 17:14:30 +03:00
Nekotekina da3f3fd1fb Fix ipc_manager::add
Thanks to @Farseer2 for debugging
2017-08-29 21:26:31 +03:00
Nekotekina 26e13b4f5f Compress log to RPCS3.log.gz 2017-08-29 17:12:13 +03:00
Nekotekina a771fcb397 Fill log with \n 2017-08-29 17:12:13 +03:00
JayC-03 64a6fbe39f Add missing game categories
Used by some media apps, 
YouTube boots now.
2017-08-29 03:19:35 +03:00
Zion Nimchuk 43b860d267 Make travis CI build with PulseAudio backend. 2017-08-29 01:36:59 +03:00
Zion 818df50bb5 Spelling correction 2017-08-28 18:43:47 +03:00
Nekotekina 2570911283 Register Win32 error 32 2017-08-27 16:09:34 +03:00
Nekotekina f59a448f3f Copy sys_spu_segment info in SPU TG
No idea whether it fixes something or not
2017-08-27 03:00:10 +03:00
Nekotekina 834712bb58 Reserve log space for higher severity levels 2017-08-27 03:00:10 +03:00
Nekotekina d98f739043 Make impossible to disable fatal errors 2017-08-27 03:00:10 +03:00
Nekotekina aa5dc5455e _sys_spu_image_import implemented
vm:var<T[]> improved (begin/end)
sys_spu_image_import rewritten
2017-08-27 03:00:10 +03:00
Ani dfc970c926 Point forums URLs to the new one
Updates forums URLs to our new forums
2017-08-27 01:27:38 +03:00
Ani 68ecf340c5 Update Contributing Guidelines
Updates contributing guidelines to use Game Compatibility wiki page and new forums hyperlinks
2017-08-27 01:27:38 +03:00
Ani 3d626e84ef GUI: Add Kuroi (Dark) Theme
New and first theme for RPCS3.
It's based on a dark color scheme.
2017-08-27 01:27:38 +03:00
Ani 95abf768a7 Fix GitIgnore 2017-08-27 01:27:38 +03:00
scribam cb00190c3e [Qt] Replace deprecated qSort function by std::sort 2017-08-26 22:32:40 +01:00
scribam 8fdf1b23a3 Update cell_FreeType2.cpp 2017-08-26 22:03:15 +01:00
kd-11 2e9405db4c rsx: Remove index expansion for quad strips 2017-08-26 21:53:54 +03:00
kd-11 fe5828cb47 rsx: Implement QUAD_STRIP
- QUAD_STRIP evaluates to TRIANGLE_STRIP in memory. The memory layout is identical.
- The only difference between the two modes would be the primitive_ID but that doesnt matter on RSX
- Its worth noting that results will be different between the two modes if input vertices are non-coplanar for every set of N verts
2017-08-26 21:53:54 +03:00
kd-11 e56d8db6a3 gl: Do not modify bound depth/stencil buffers bound to zcull memory
- Fixes some rare cases where zcull always fails
2017-08-26 21:53:54 +03:00
kd-11 e76b6e3f27 gl: Workaround for restrictive z range 2017-08-26 21:53:54 +03:00
kd-11 9a7ce2fd29 rsx/vp: ARL fix 2017-08-26 21:53:54 +03:00
kd-11 462b93f62c vulkan: Gracefully handle back-to-back flip request spam 2017-08-26 21:53:54 +03:00
kd-11 f71f67c4ff rsx: Make fragment state dynamic to reduce shader permutations 2017-08-26 21:53:54 +03:00
kd-11 8358bda133 gl/rsx: Fixes to zcull pixel counting 2017-08-26 21:53:54 +03:00
scribam 85199e200b [Qt] Simplify firmware libraries searching 2017-08-25 22:20:57 +03:00
RipleyTom 5681801b85 cellOskDialogLoadAsync fix
Takes into account text limit and initial text
2017-08-25 21:31:27 +03:00
Talkashie 86ef07b166 Correct typo 2017-08-25 18:42:41 +01:00
Nekotekina 00339cb99b Fix log mapping (Linux) 2017-08-24 21:20:18 +03:00
Andrew O'Neil daf3760cd4 Add PulseAudio audio backend 2017-08-24 17:43:34 +03:00
Nekotekina c1450ad616 Reenable thread_local for all platforms 2017-08-24 16:27:07 +03:00
Nekotekina 025a09ed87 Optimize RPCS3.log and limit it to 64 MiB
Use memory-mapped file for writing
2017-08-23 23:11:18 +03:00
Nekotekina 1716db14ed Fix moving disc games with arbitrary dir name 2017-08-23 21:26:18 +03:00
Nekotekina d0e171784c Implemented fs::file::get_handle 2017-08-22 21:18:26 +03:00
Nekotekina a68983b551 Ensure all log messages are displayed 2017-08-22 21:06:37 +03:00
Megamouse c7c0139788 stylesheets: add custom color to gamepad 2017-08-22 15:28:22 +03:00
Zangetsu38 37bc2b3bb9 rsx: implement pixel size 16. 2017-08-21 17:32:21 +03:00
Megamouse c85806c422 GUI: improve reset to deafult button 2017-08-21 01:05:57 +03:00
Megamouse ee98683538 stylesheets: UI Colors fixes 2017-08-21 01:05:57 +03:00
Megamouse a822d990d2 stylesheets: UI_Colors hotfix 2017-08-20 17:56:52 +03:00
Megamouse 33d3303bdf GUI: hide utilities by default 2017-08-20 17:32:30 +03:00
Megamouse 8b35df8327 misc: add build warning to log 2017-08-20 17:32:30 +03:00
Megamouse 0854ed2b51 misc: get rid of some compiler warnings 2017-08-20 17:32:30 +03:00
Megamouse 713c1a7a86 cg_disasm: fix frame by removing parent 2017-08-20 17:32:30 +03:00
Megamouse fb816a0eb9 osk: fix backspace 2017-08-20 17:32:30 +03:00
Megamouse fff62df6a2 stylesheets: make UI Colors optional 2017-08-20 16:14:32 +03:00
Zion Nimchuk e6a07e80d7 Fix evdev joystick detection 2017-08-19 20:05:33 +03:00
Zion Nimchuk 514a98321d Use newer binutils version to link against newer ffmpeg libraries 2017-08-19 20:05:33 +03:00
Zion Nimchuk 36ac35361f Update ffmpeg submodule with updated libs and headers for linux 2017-08-19 20:05:33 +03:00
Zion Nimchuk bc7d728eb3 Fix linux builds giving experimental build even if not on experimental build. 2017-08-19 20:05:33 +03:00
Zion Nimchuk 66a43c35db Fix evdev controller detection, add joystick squircling 2017-08-19 20:05:33 +03:00
Robbie e9f057c91b Make removing a save fast 2017-08-19 18:17:46 +03:00
Robbie 196cdfafa6 Implement a proper save manager. 2017-08-19 18:17:46 +03:00
Nekotekina 590ca7115f Rewrite cellVideoOutConfigure 2017-08-19 17:35:04 +03:00
Jake 650db9c962 cellPad: remove unneeded & 2017-08-19 12:27:53 +03:00
Jake 5d7c454e52 rsx: Vertex Decompiler, fix sca register assignment 2017-08-19 12:27:53 +03:00
Jake 4d5f98017f d3d12: ignore 0 sized rt dma copy 2017-08-19 12:27:53 +03:00
Jake 7ecf6cb014 rsx: Ignore sending system reserved semaphores to renderer 2017-08-19 12:27:53 +03:00
Danila Malyutin 9d1aebce74 Silence some obvious warnings
Makes travis logs a bit cleaner
2017-08-18 23:09:52 +03:00
scribam dc9671c639 Add cellAtracGetSamplingRate and cellAtracMultiGetSamplingRate functions 2017-08-18 22:42:38 +03:00
scribam 93bfe8164c Move sys_gamepad files to the correct directory 2017-08-18 21:59:25 +03:00
probonopd d6329eaa1a Make it pass desktop-file-validate in Ubuntu 14.04 2017-08-18 20:57:21 +03:00
kd-11 f21a3069a5 vulkan: Don't keep invalidated objects around too long
Games like Tales of Vesperia seem to be using a random memory allocator with very low collision chance.
This means objects are very unlikely to be reused in such games leading to pile-up
2017-08-18 16:51:38 +03:00
kd-11 a8b989b51d vk: Improve window resize handling
- Be careful not to request images not available
- Request a triple buffer at all times if available to keep acquisition from locking up
2017-08-18 16:51:38 +03:00
kd-11 142bfb5250 rsx: Fix immediate indexed drawing 2017-08-18 16:51:38 +03:00
kd-11 334327df67 rsx: Add a success message on program compile completion
- Should help users wondering if rpcs3 'froze' during shader compile
2017-08-16 23:58:30 +03:00
kd-11 2400210144 vk: Reimplement access violation sync handling 2017-08-16 23:58:30 +03:00
kd-11 1b1c300aad vulkan: Restructure frame queues 2017-08-16 23:58:30 +03:00
kd-11 531b03e7af vk: Catch leaking imageview refs on resize 2017-08-16 23:58:30 +03:00
kd-11 650c1c64f1 gl: Workarounds for intel GPUs which dont seem to be truly GL4 compliant 2017-08-16 23:58:30 +03:00
kd-11 2fd4726919 rsx: Fix single vertex array input declarations 2017-08-16 23:58:30 +03:00
kd-11 b86745ee4e gl: Fix vsync; always use adaptive vsync instead of double-buffered 2017-08-16 23:58:30 +03:00
kd-11 c04aa05398 rsx: Shader pipeline fixes and improvements
- Do not set zfunc if alphakill is not enabled. This is because at the moment alphakill requires a different shader to be built

- use glsl loop-unroll friendly comparison; skip vertex input compare if either key requests it

- Minor tweaks to fp key generation
2017-08-16 23:58:30 +03:00
kd-11 3c9bab8563 ui: Move disable vertex cache to debug. Also add an option to disable zcull emulation in the debugger 2017-08-16 23:58:30 +03:00
kd-11 0dc24799f1 gui: Add delete shader cache option in the context menu 2017-08-16 23:58:30 +03:00
kd-11 6eb1786635 rsx: Clamp depth range to [0,1]
- Fixes remaining issues with Ni no Kuni
2017-08-16 23:58:30 +03:00
kd-11 bbf2a97d2e rsx: Zero-initialize the vertex register block
- Some games reference constant regs that they never initialize
2017-08-16 23:58:30 +03:00
kd-11 00c6a589a5 rsx/util: Add simple consistent hash function
rsx/vk/shaders_cache: Move vp control mask to dynamic state

rsx/vk/gl: adds a shader cache for GL. Also Separates pipeline storage for each backend

rsx: Add more texture state variables to the cache
2017-08-16 23:58:30 +03:00
kd-11 c7dca1dbef rsx/vk: Implement shaders cache and fix broken pipeline_storage comparison and hash
- Fix pipeline state storage to uniquely store each pipeline variant
- Adds a progress bar to indicate loading is taking place
2017-08-16 23:58:30 +03:00
kd-11 1da732bbf5 rsx/gl/vk: Invalidate texture regions when memory is unmapped
- Free GPU resources immediately if mappings change to avoid leaking VRAM
2017-08-16 23:58:30 +03:00
kd-11 00b0311c86 rsx/gl/vulkan: Refactoring and partial vulkan rewrite
- Updates vulkan to use GPU vertex processing
- Rewrites vulkan to buffer entire frames and present when first available to avoid stalls
- Move more state into dynamic descriptors to reduce progam cache misses; Fix render pass conflicts before texture access
- Discards incomplete cb at destruction to avoid refs to destroyed objects
- Move set_viewport to the uninterruptible block before drawing in case cb is switched before we're ready
- Manage frame contexts separately for easier async frame management
- Avoid wasteful create-destroy cycles when sampling rtts
2017-08-16 23:58:30 +03:00
kd-11 6a707f515e vk/gl: Factorize shared GLSL code
- prep vulkan for shared glsl backend
2017-08-16 23:58:30 +03:00
kd-11 c0409a819e gl: Workaround for depth/color format mismatch when using hardware blit 2017-08-16 23:58:30 +03:00
kd-11 b2b5f564a1 rsx: Add a few more depth format types to known behaviour paths 2017-08-16 23:58:30 +03:00
kd-11 d54c2dd39a gl: Move vertex processing to the GPU
- Significant gains from greatly reduced CPU work
- Also reorders command submission in end() to improve throughput

- Refactors most of the vertex buffer handling
- All vertex processing is moved GPU side
2017-08-16 23:58:30 +03:00
Megamouse e668ecd453 stylesheets: fix gamegrid font 2017-08-16 16:11:11 +01:00
Megamouse 0020359b8f stylesheets: fix color settings 2017-08-16 16:11:11 +01:00
Megamouse a0176775ff stylesheets: make toolbar styles more accessible 2017-08-16 16:11:11 +01:00
Megamouse a18fddb831 stylesheets: move white header section to default stylesheet 2017-08-16 16:11:11 +01:00
Megamouse ea462ae7d7 stylesheets: fix default not working 2017-08-16 16:11:11 +01:00
Ryan Gonzalez 6d14583f28 Better evdev joystick axis scaling (#3202)
Fix evdev scaling when the minimum value is <0
Declare a trigger as pressed as long as any value >0 is given
2017-08-15 22:14:13 +03:00
scribam 956117a74f Fix the window title when the option "show_fps_in_title" is not checked 2017-08-15 21:34:16 +03:00
scribam 0c1d4e43e4 Simplify m_show_fps assignation 2017-08-15 21:34:16 +03:00
scribam ae156801df Simplify qstr function 2017-08-15 21:34:16 +03:00
RipleyTom 844e09c40e Fix search edit context menu weird color 2017-08-15 21:14:09 +03:00
RipleyTom 81da93a302 Fix rare occurence where there is a /PS3_GAME+something directory which leads to weird behavior 2017-08-15 21:14:09 +03:00
RipleyTom e0508c6c64 unpkg fix 2017-08-15 15:58:16 +03:00
RipleyTom db9618ac2f Resets sleep timer on button press
Adds windows sleep timer reset on ds4 button input

Refactoring

Shorter version
2017-08-15 15:28:53 +03:00
RipleyTom a38182b967 Adds check for pkg signature in QT part 2017-08-15 14:30:32 +03:00
RipleyTom 474bd7beaf Adds support for multi-files pkg. 2017-08-15 14:30:32 +03:00
Talkashie d8c449aadf Update cellNetCtl.cpp 2017-08-14 18:17:46 +03:00
Talkashie 2c611ec0ba Update cellHttp.cpp 2017-08-14 18:17:46 +03:00
Nekotekina b44f5e59ac Fix appveyor.yml 2017-08-14 02:48:52 +03:00
Nekotekina 0ad0510624 Fix appveyor.yml 2017-08-14 02:34:00 +03:00
Nekotekina d2fb69cda3 Add build warning 2017-08-13 23:26:32 +03:00
Nekotekina 2047cb8d1d CFG: print errors for enums 2017-08-13 21:39:08 +03:00
Nekotekina 24f9f06279 Check FNID duplication 2017-08-13 21:39:08 +03:00
Nekotekina b671bb72dc Rewrite Drag&Drop classification 2017-08-13 21:39:08 +03:00
Nekotekina af11ad6253 Fix deadlock in vm::unmap 2017-08-13 21:39:08 +03:00
Nekotekina 0d9b89fb34 Update supporters 2017-08-13 21:39:08 +03:00
RipleyTom 80fee5ac1e (#3214)
Adds cpu to log.
Adds [DO NOT USE] to D3D12 selection.
2017-08-13 18:32:48 +03:00
Talkashie a909bd6edd Register missing functions in cellSysutil (#3206) 2017-08-13 00:32:00 +03:00
Megamouse eeb4d4d4de emu_settings: fix faulty custom config file creation 2017-08-12 12:53:51 +03:00
Megamouse 4c42043940 game_list_frame: add scrollAfter option to Refresh for Talkashie 2017-08-12 12:53:51 +03:00
praydog 6136abd0f8 Minor DS4 Bluetooth fix (#3140)
* Fix DS4 input not working after controller restart (bluetooth)

* Fix bad hid_free_enumeration logic

* Tabbing

* Proper way of telling DS4 to send 0x11 reports

* Dead code removal
2017-08-11 00:41:13 +03:00
Zion Nimchuk 69a5f3d58b Update ffmpeg 2017-08-10 15:34:55 +03:00
scribam 98ef419abd Add sceNpTssGetDataNoLimit and sceNpTssGetDataNoLimitAsync functions 2017-08-10 15:03:54 +03:00
scribam 77354f0f90 Add _sce_net_add_name_server function 2017-08-10 15:03:54 +03:00
scribam 108f87c08f Add cellUsbdRegisterCompositeLdd, cellUsbdUnregisterCompositeLdd and cellUsbdResetDevice functions 2017-08-10 15:03:54 +03:00
scribam 08e2698b9c Add cellSearchGetContentInfoSharable function 2017-08-10 15:03:54 +03:00
scribam 6e81db7b43 Add cellVideoOutSetCopyControl function 2017-08-10 15:03:54 +03:00
scribam e9f12ae30a Stub cellAvconfExt functions 2017-08-10 15:03:54 +03:00
scribam 2f977aae18 Stub cellSysutilAvc2 functions 2017-08-10 15:03:54 +03:00
Megamouse 0e5a862d8a fix resize on boot 2017-08-10 02:53:40 +03:00
kd-11 1e46cd255b gl: Fix inconsistent state tracking 2017-08-10 00:16:20 +03:00
kd-11 e5e6af41a6 gl: Fix occlusion statistics clearing 2017-08-10 00:16:20 +03:00
kd-11 ce437eb8d2 gl: Properly initialize pipeline properties 2017-08-10 00:16:20 +03:00
kd-11 4c019c55d2 rsx/gl: Fix zcull queries and log conditional render modes
- Fixes a situation where a query readback is requested while zcull render is still active
2017-08-10 00:16:20 +03:00
Megamouse ae440a92ac use new range for combobox, remove obsolete code 2017-08-09 23:44:29 +03:00
Robbie 54d2e8bfdd Remove some warnings from Linux and fixed something from code review. 2017-08-09 22:11:28 +03:00
Robbie 3f206981d9 Finesse size of goto address. Downgrade image loading failed to warning. 2017-08-09 22:11:28 +03:00
Robbie fa7407cd42 Remove about 100 warnings from rpcs3qt code. 2017-08-09 22:11:28 +03:00
Robbie 866b9524b3 Add rpcs3 icon to save dialogs. 2017-08-09 22:11:28 +03:00
Robbie d1cde4d0a7 Perform refactoring of pads to remove the ugly pad initialization. 2017-08-09 22:11:28 +03:00
Zion b01e7e3362 Fix Fedora glew install instructions, Fixes #3182 2017-08-09 14:19:25 +03:00
Aurora e9b020beaa Update build instructions for macOS 2017-08-08 23:20:07 +03:00
Aurora 2fcd38c2bc Reduce the zero-page size on macOS, so that PPUThread works 2017-08-08 23:20:07 +03:00
Aurora 300b34e268 Disable PIE on macOS too 2017-08-08 23:20:07 +03:00
Aurora ce0e87373d Update hidapi 2017-08-08 23:20:07 +03:00
Aurora 7e1c6a5819 Make it build on macOS with Clang 2017-08-08 23:20:07 +03:00
Nekotekina 613214cdca Improve error formatting 2017-08-08 22:17:51 +03:00
Malcolm Jestadt 009f53a267 fix segfault in boot recent list 2017-08-08 02:34:24 +03:00
Megamouse f3ad922a8f drag and dropperinno (#3037) 2017-08-06 22:29:28 +03:00
Nekotekina 7b27a8e993 Fix idm::init, fxm::init 2017-08-06 16:13:11 +03:00
kd-11 fcb7072fee Implement hardware zcull emulation
rsx/gl: Support s1 immediate values; ogl minor refactoring
2017-08-06 14:29:42 +03:00
kd-11 7ab1792ef7 rsx: Implement conditional locks 2017-08-06 14:29:42 +03:00
Jan Beich 40d305b35d Make ALSA optional 2017-08-06 02:02:57 +01:00
RipleyTom 2d7e91ba8a Yield instead of sleeping rsx thread. (#3158)
Another Yield
2017-08-06 01:46:01 +01:00
Nekotekina b05434bc6f Fix Firmware message 2017-08-05 17:07:30 +03:00
Nekotekina 7b4c044480 Relax allocations in ppu_load_exec 2017-08-04 14:33:53 +03:00
Nekotekina c14eb4e54a Implement error report stacking 2017-08-04 14:33:53 +03:00
Nekotekina f6c8f46462 CFG: catch exceptions 2017-08-04 14:33:53 +03:00
Nekotekina faf9ed9fec CFG: provide _int range in to_list() 2017-08-04 14:33:53 +03:00
Megamouse 930ce4af60 log_frame: fix random stack 2017-08-03 23:06:54 +03:00
Megamouse d51a986dd4 GUI: fix icon sizes and exterminate gamelist bug
recreate old icon size values
2017-08-03 23:06:54 +03:00
Jake 02845f546e Add gcm to auto lle / liblv2 2017-08-02 01:33:12 +03:00
Jake fff34a7f0f d3d12: Fix 0 sized framebuffer crashes 2017-08-02 01:33:12 +03:00
Jake 21dd715b42 sys_rsx: implement support for lle-gcm 2017-08-02 01:33:12 +03:00
Jake d9a693019b rsx/gcm: Implement rsx dma. Refactor gcm/rsx to not be as codependent 2017-08-02 01:33:12 +03:00
mp-t 607d2486ea Code review (#3114)
* Fix always-true conditions in sceNp module

* gl_render_targets: useless check on unsigned variable, possible bug

* fixed UB in crypto utility functions

* copy-paste error in vk::init_default_resources

* pass strings by const ref

* Dont copy vectors. Make sure copies are not needed because functions are used in a multi-threaded context.
2017-08-01 20:22:33 +03:00
197 changed files with 8034 additions and 3754 deletions
+5
View File
@@ -41,6 +41,10 @@
/Vulkan/Vulkan-build
/Vulkan/glslang-build
# Themes
!/bin/GuiConfigs/
/bin/GuiConfigs/*.ini
/bin/rpcs3.ini
/bin/rpcs3.ipdb
/bin/rpcs3.iobj
@@ -71,6 +75,7 @@ rpcs3/git-version.h
!/bin/dev_hdd0/game/
/bin/dev_hdd0/game/*
!/bin/dev_hdd0/game/TEST12345/
/bin/dev_hdd0/disc/*
# Ignore other system generated files
bin/dev_hdd0/*.txt
+13
View File
@@ -62,12 +62,24 @@ before_install:
brew update; brew update;
brew install ccache glew llvm40;
fi;
# We need to update binutils to a newer version to link against the ffmpeg libs on.
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
sudo add-apt-repository ppa:jonathonf/binutils -y ;
sudo apt-get update ;
sudo apt-get install binutils -y;
ld --version ;
fi;
before_script:
- git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Utilities/yaml-cpp 3rdparty/cereal 3rdparty/hidapi Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers
- mkdir build
- cd build
- export CMAKE_PREFIX_PATH=~/Qt/5.9.1/gcc_64/lib/cmake
- if [ "$TRAVIS_PULL_REQUEST" = false ]; then
export CXXFLAGS="$CXXFLAGS -DBRANCH=$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH";
else
export CXXFLAGS="$CXXFLAGS -DBRANCH=$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH/#$TRAVIS_PULL_REQUEST";
fi;
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr;
- make -j 3
- # AppImage generation
@@ -126,6 +138,7 @@ addons:
#- qtbase5-dev
- libudev-dev
- libevdev-dev
- libpulse-dev
coverity_scan:
project:
name: $TRAVIS_REPO_SLUG
+2 -2
View File
@@ -1,6 +1,6 @@
# Getting Started
Before getting started using the emulator, read the [Quickstart Guide](https://rpcs3.net/quickstart) and the [FAQ](https://rpcs3.net/faq). After reading those, if you need support, visit our [Forums](http://www.emunewz.net/forum/forumdisplay.php?fid=172).
Before getting started using the emulator, read the [Quickstart Guide](https://rpcs3.net/quickstart) and the [FAQ](https://rpcs3.net/faq). After reading those, if you need support, visit our [Forums](https://forums.rpcs3.net).
# Issue Reporting
@@ -13,7 +13,7 @@ Before getting started using the emulator, read the [Quickstart Guide](https://r
- Use understandable English. It doesn't need to be perfect, but clear enough to understand your message.
- While reporting issues, don't forget to include details about your system (OS, CPU, GPU, etc.), as well as the RPCS3.log file.
Submitting your test results for Commercial Games must be done on our forums' [Commercial Games](http://www.emunewz.net/forum/forumdisplay.php?fid=193) section. If there's already a thread for the game you want to report post in it, otherwise please make a new thread following the [Guidelines for submitting new games](http://www.emunewz.net/forum/showthread.php?tid=174376).
Submitting your test results for Commercial Games must be done on our forums. Please read the [Game Compatibility](https://github.com/RPCS3/rpcs3/wiki/Game-Compatibility) wiki page before doing so.
# Contributing
+8 -5
View File
@@ -8,9 +8,9 @@ RPCS3
The world's first open-source PlayStation 3 emulator/debugger written in C++ for Windows and Linux.
You can find some basic information in our [**website**](https://rpcs3.net/).
For discussion about this emulator and PS3 emulation please visit our [**forums**](http://www.emunewz.net/forum/forumdisplay.php?fid=172) and our [**Discord server**](https://discord.me/RPCS3).
For discussion about this emulator and PS3 emulation please visit our [**forums**](https://forums.rpcs3.net) and our [**Discord server**](https://discord.me/RPCS3).
[**Support Lead Developer Nekotekina on Patreon**](https://www.patreon.com/Nekotekina)
[**Support Lead Developers Nekotekina and kd-11 on Patreon**](https://www.patreon.com/Nekotekina)
## Development
@@ -33,12 +33,12 @@ If you want to contribute please take a look at the [Coding Style](https://githu
* 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`
* Arch: `sudo pacman -S glew openal cmake llvm qt5-base`
* Fedora: `sudo dnf install cmake qt5-devel vulkan-devel libGLEW`
* Fedora: `sudo dnf install cmake qt5-devel vulkan-devel glew glew-devel`
### Mac OSX
Mac OSX is not supported at this moment because it doesn't meet system requirements (OpenGL 4.3)
* Xcode 6+ (tested with Xcode 6.4)
* Install with Homebrew: `brew install glew`
* Install with Homebrew: `brew install glew llvm qt cmake`
## Building on Windows:
@@ -66,7 +66,10 @@ To initialize the repository don't forget to execute `git submodule update --ini
4) `cmake CMakeLists.txt && make GitVersion && make` </br>
5) Run RPCS3 with `./bin/rpcs3` </br>
If you are on OSX and want to build with llvm don't forget to add `-DLLVM_DIR=...` (or wherever llvm brew was installed) to cmake invocation.
If you are on OSX and want to build with brew llvm and qt don't forget to add the following environment variables
* `LLVM_DIR=/usr/local/opt/llvm/` (or wherever llvm was installed).
* `Qt5_DIR=/usr/local/opt/qt/lib/cmake/Qt5` (or wherever qt was installed).
When using GDB, configure it to ignore SIGSEGV signal (`handle SIGSEGV nostop noprint`).
+25 -3
View File
@@ -48,6 +48,11 @@ namespace cfg
static void decode(const YAML::Node& data, class _base& rhs);
}
std::vector<std::string> cfg::make_int_range(s64 min, s64 max)
{
return {std::to_string(min), std::to_string(max)};
}
bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
{
// TODO: this could be rewritten without exceptions (but it should be as safe as possible and provide logs)
@@ -82,6 +87,8 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, const std::string& value)
{
u64 max = -1;
for (u64 i = 0;; i++)
{
std::string var;
@@ -99,6 +106,8 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) f
{
break;
}
max = i;
}
try
@@ -108,14 +117,22 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) f
if (pos != value.size())
{
if (out) cfg.error("cfg::try_to_enum_value('%s'): unexpected characters (pos=%zu)", value, pos);
return false;
}
if (val > max)
{
if (out) cfg.error("cfg::try_to_enum_value('%s'): out of bounds(0..%u)", value, max);
return false;
}
if (out) *out = val;
return true;
}
catch (...)
catch (const std::exception& e)
{
if (out) cfg.error("cfg::try_to_enum_value('%s'): invalid enum value: %s", value, e.what());
return false;
}
}
@@ -268,14 +285,19 @@ std::string cfg::node::to_string() const
YAML::Emitter out;
cfg::encode(out, *this);
return{ out.c_str(), out.size() };
return {out.c_str(), out.size()};
}
bool cfg::node::from_string(const std::string& value)
bool cfg::node::from_string(const std::string& value) try
{
cfg::decode(YAML::Load(value), *this);
return true;
}
catch (const std::exception& e)
{
cfg.fatal("%s thrown: %s", typeid(e).name(), e.what());
return false;
}
void cfg::node::from_default()
{
+8
View File
@@ -12,6 +12,9 @@
namespace cfg
{
// Format min and max values
std::vector<std::string> make_int_range(s64 min, s64 max);
// Convert string to signed integer
bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max);
@@ -249,6 +252,11 @@ namespace cfg
return false;
}
std::vector<std::string> to_list() const override
{
return make_int_range(Min, Max);
}
};
// Alias for 32 bit int
+66 -6
View File
@@ -93,6 +93,7 @@ static fs::error to_error(DWORD e)
case ERROR_NEGATIVE_SEEK: return fs::error::inval;
case ERROR_DIRECTORY: return fs::error::inval;
case ERROR_INVALID_NAME: return fs::error::inval;
case ERROR_SHARING_VIOLATION: return fs::error::acces;
default: fmt::throw_exception("Unknown Win32 error: %u.", e);
}
}
@@ -509,7 +510,7 @@ bool fs::remove_dir(const std::string& path)
#endif
}
bool fs::rename(const std::string& from, const std::string& to)
bool fs::rename(const std::string& from, const std::string& to, bool overwrite)
{
const auto device = get_virtual_device(from);
@@ -524,14 +525,43 @@ bool fs::rename(const std::string& from, const std::string& to)
}
#ifdef _WIN32
if (!MoveFileW(to_wchar(from).get(), to_wchar(to).get()))
const auto ws1 = to_wchar(from);
const auto ws2 = to_wchar(to);
if (!MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING : 0))
{
g_tls_error = to_error(GetLastError());
DWORD error1 = GetLastError();
if (overwrite && error1 == ERROR_ACCESS_DENIED && is_dir(from) && is_dir(to))
{
if (RemoveDirectoryW(ws2.get()))
{
if (MoveFileW(ws1.get(), ws2.get()))
{
return true;
}
error1 = GetLastError();
CreateDirectoryW(ws2.get(), NULL); // TODO
}
else
{
error1 = GetLastError();
}
}
g_tls_error = to_error(error1);
return false;
}
return true;
#else
if (!overwrite && exists(to))
{
g_tls_error = fs::error::exist;
return false;
}
if (::rename(from.c_str(), to.c_str()) != 0)
{
g_tls_error = to_error(errno);
@@ -764,7 +794,13 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
disp = test(mode & fs::trunc) ? TRUNCATE_EXISTING : OPEN_EXISTING;
}
const HANDLE handle = CreateFileW(to_wchar(path).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD share = FILE_SHARE_READ;
if (!test(mode & fs::unshare))
{
share |= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
}
const HANDLE handle = CreateFileW(to_wchar(path).get(), access, share, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE)
{
@@ -772,7 +808,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return;
}
class windows_file final : public file_base
class windows_file final : public file_base, public get_native_handle
{
const HANDLE m_handle;
@@ -879,6 +915,11 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return size.QuadPart;
}
native_handle get() override
{
return m_handle;
}
};
m_file = std::make_unique<windows_file>(handle);
@@ -902,7 +943,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return;
}
class unix_file final : public file_base
class unix_file final : public file_base, public get_native_handle
{
const int m_fd;
@@ -991,6 +1032,11 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return file_info.st_size;
}
native_handle get() override
{
return m_fd;
}
};
m_file = std::make_unique<unix_file>(fd);
@@ -1066,6 +1112,20 @@ fs::file::file(const void* ptr, std::size_t size)
m_file = std::make_unique<memory_stream>(ptr, size);
}
fs::native_handle fs::file::get_handle() const
{
if (auto getter = dynamic_cast<get_native_handle*>(m_file.get()))
{
return getter->get();
}
#ifdef _WIN32
return INVALID_HANDLE_VALUE;
#else
return -1;
#endif
}
void fs::dir::xnull() const
{
fmt::throw_exception<std::logic_error>("fs::dir is null");
+18 -1
View File
@@ -10,6 +10,12 @@
namespace fs
{
#ifdef _WIN32
using native_handle = void*;
#else
using native_handle = int;
#endif
// File open mode flags
enum class open_mode : u32
{
@@ -19,6 +25,7 @@ namespace fs
create,
trunc,
excl,
unshare,
__bitset_enum_max
};
@@ -29,6 +36,7 @@ namespace fs
constexpr auto create = +open_mode::create; // Create file if it doesn't exist
constexpr auto trunc = +open_mode::trunc; // Clear opened file if it's not empty
constexpr auto excl = +open_mode::excl; // Failure if the file already exists (used with `create`)
constexpr auto unshare = +open_mode::unshare; // Prevent opening the file twice
constexpr auto rewrite = open_mode::write + open_mode::create + open_mode::trunc;
@@ -55,6 +63,12 @@ namespace fs
s64 ctime;
};
// Native handle getter
struct get_native_handle
{
virtual native_handle get() = 0;
};
// File handle base
struct file_base
{
@@ -145,7 +159,7 @@ namespace fs
bool create_path(const std::string& path);
// Rename (move) file or directory
bool rename(const std::string& from, const std::string& to);
bool rename(const std::string& from, const std::string& to, bool overwrite);
// Copy file contents
bool copy_file(const std::string& from, const std::string& to, bool overwrite);
@@ -347,6 +361,9 @@ namespace fs
if (seek(0), !read(result)) xfail();
return result;
}
// Get native handle if available
native_handle get_handle() const;
};
class dir final
+3 -3
View File
@@ -90,13 +90,13 @@ extern void jit_finalize()
// Helper class
struct MemoryManager : llvm::RTDyldMemoryManager
{
std::unordered_map<std::string, std::uintptr_t>& m_link;
std::unordered_map<std::string, u64>& m_link;
std::array<u8, 16>* m_tramps{};
u8* m_code_addr{}; // TODO
MemoryManager(std::unordered_map<std::string, std::uintptr_t>& table)
MemoryManager(std::unordered_map<std::string, u64>& table)
: m_link(table)
{
}
@@ -371,7 +371,7 @@ public:
}
};
jit_compiler::jit_compiler(const std::unordered_map<std::string, std::uintptr_t>& _link, std::string _cpu)
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, std::string _cpu)
: m_link(std::move(_link))
, m_cpu(std::move(_cpu))
{
+175 -18
View File
@@ -3,16 +3,21 @@
#include "StrFmt.h"
#include "sema.h"
#include "Utilities/sysinfo.h"
#include "rpcs3_version.h"
#include <string>
#include <unordered_map>
#ifdef _WIN32
#define NOMINMAX
#include <Windows.h>
#else
#include <chrono>
#include <sys/mman.h>
#endif
#include <zlib.h>
static std::string empty_string()
{
return {};
@@ -44,29 +49,38 @@ 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;
class file_writer
{
// Could be memory-mapped file
fs::file m_file;
std::string m_name;
#ifdef _WIN32
::HANDLE m_fmap;
#endif
atomic_t<std::size_t> m_pos{0};
std::size_t m_size{0};
uchar* m_fptr{};
public:
file_writer(const std::string& name);
virtual ~file_writer() = default;
virtual ~file_writer();
// Append raw data
void log(const char* text, std::size_t size);
void log(logs::level sev, const char* text, std::size_t size);
};
struct file_listener : public file_writer, public listener
{
file_listener(const std::string& name)
: file_writer(name)
, listener()
{
const std::string& start = fmt::format("\xEF\xBB\xBF" "RPCS3 v%s\n", rpcs3::version.to_string());
file_writer::log(start.data(), start.size());
}
file_listener(const std::string& name);
virtual ~file_listener() = default;
// Encode level, current thread name, channel name and write log message
virtual void log(u64 stamp, const message& msg, const std::string& prefix, const std::string& text) override;
@@ -137,12 +151,26 @@ namespace logs
}
};
struct stored_message
{
message m;
u64 stamp;
std::string prefix;
std::string text;
};
// Channel registry mutex
semaphore<> g_mutex;
// Channel registry
std::unordered_map<std::string, channel_info> g_channels;
// Messages for delayed listener initialization
std::vector<stored_message> g_messages;
// Must be set to true in main()
atomic_t<bool> g_init{false};
void reset()
{
semaphore_lock lock(g_mutex);
@@ -159,6 +187,17 @@ namespace logs
g_channels[ch_name].set_level(value);
}
// Must be called in main() to stop accumulating messages in g_messages
void set_init()
{
if (!g_init)
{
semaphore_lock lock(g_mutex);
g_messages.clear();
g_init = true;
}
}
}
logs::listener::~listener()
@@ -170,11 +209,19 @@ void logs::listener::add(logs::listener* _new)
// Get first (main) listener
listener* lis = get_logger();
semaphore_lock lock(g_mutex);
// Install new listener at the end of linked list
while (lis->m_next || !lis->m_next.compare_and_swap_test(nullptr, _new))
{
lis = lis->m_next;
}
// Send initial messages
for (const auto& msg : g_messages)
{
_new->log(msg.stamp, msg.m, msg.prefix, msg.text);
}
}
void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, const u64* args)
@@ -207,12 +254,29 @@ void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, const u
}
// Get text
std::string text;
thread_local std::string text; text.clear();
fmt::raw_append(text, fmt, sup, args);
std::string prefix = g_tls_log_prefix();
// Get first (main) listener
listener* lis = get_logger();
if (!g_init)
{
semaphore_lock lock(g_mutex);
if (!g_init)
{
while (lis)
{
lis->log(stamp, *this, prefix, text);
lis = lis->m_next;
}
// Store message additionally
g_messages.emplace_back(stored_message{*this, stamp, std::move(prefix), text});
}
}
// Send message to all listeners
while (lis)
@@ -225,13 +289,28 @@ void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, const u
[[noreturn]] extern void catch_all_exceptions();
logs::file_writer::file_writer(const std::string& name)
: m_name(fs::get_config_dir() + name)
{
try
{
if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append))
if (!m_file.open(m_name, fs::read + fs::write + fs::create + fs::trunc + fs::unshare))
{
fmt::throw_exception("Can't create log file %s (error %s)", name, fs::g_tls_error);
fmt::throw_exception("Can't create file %s (error %s)", name, fs::g_tls_error);
}
#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;
#else
m_file.trunc(s_log_size);
m_fptr = (uchar*)::mmap(0, s_log_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_file.get_handle(), 0);
#endif
verify(m_name.c_str()), m_fptr;
std::memset(m_fptr, '\n', s_log_size);
// Rotate backups (TODO)
fs::rename(m_name + ".gz", m_name + "1.gz", true);
}
catch (...)
{
@@ -239,14 +318,92 @@ logs::file_writer::file_writer(const std::string& name)
}
}
void logs::file_writer::log(const char* text, std::size_t size)
logs::file_writer::~file_writer()
{
m_file.write(text, size);
if (m_size == 0)
{
m_size = std::min<std::size_t>(+m_pos, s_log_size);
}
// Compress
z_stream zs{};
if (deflateInit2(&zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) == Z_OK)
{
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();
if (deflate(&zs, Z_FINISH) != Z_STREAM_ERROR)
{
fs::file(m_name + ".gz", fs::rewrite).write(buf.get(), zs.total_out);
}
if (deflateEnd(&zs) != Z_OK)
{
}
}
#ifdef _WIN32
UnmapViewOfFile(m_fptr);
CloseHandle(m_fmap);
m_file.seek(m_size);
SetEndOfFile(m_file.get_handle());
#else
::munmap(m_fptr, s_log_size);
m_file.trunc(m_size);
#endif
}
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)
{
return;
}
// Acquire memory
const auto pos = m_pos.fetch_add(size);
// 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;
}
}
logs::file_listener::file_listener(const std::string& name)
: file_writer(name)
, listener()
{
// Write UTF-8 BOM
file_writer::log(logs::level::always, "\xEF\xBB\xBF", 3);
// Write initial message
stored_message ver;
ver.m.ch = nullptr;
ver.m.sev = level::always;
ver.stamp = 0;
ver.text = fmt::format("RPCS3 v%s\n%s", rpcs3::version.to_string(), utils::get_system_info());
file_writer::log(logs::level::always, ver.text.data(), ver.text.size());
file_writer::log(logs::level::always, "\n", 1);
g_messages.emplace_back(std::move(ver));
}
void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::string& prefix, const std::string& _text)
{
std::string text; text.reserve(prefix.size() + _text.size() + 200);
thread_local std::string text;
// Used character: U+00B7 (Middle Dot)
switch (msg.sev)
@@ -275,7 +432,7 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st
text += "} ";
}
if ('\0' != *msg.ch->name)
if (msg.ch && '\0' != *msg.ch->name)
{
text += msg.ch->name;
text += msg.sev == level::todo ? " TODO: " : ": ";
@@ -288,5 +445,5 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st
text += _text;
text += '\n';
file_writer::log(text.data(), text.size());
file_writer::log(msg.sev, text.data(), text.size());
}
+2 -2
View File
@@ -257,8 +257,8 @@ struct fmt::cfmt_src
void skip(std::size_t extra)
{
++sup += extra;
++args += extra;
sup += extra + 1;
args += extra + 1;
}
std::size_t fmt_string(std::string& out, std::size_t extra) const
+16 -4
View File
@@ -30,13 +30,25 @@ 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: Check the FAQ, README, other sources.\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 += "Press (Ctrl+C) to copy this message.";
MessageBoxA(0, _msg.c_str(), "Fatal error", MB_ICONERROR); // TODO: unicode message
_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
@@ -1236,7 +1248,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
return true;
}
if (vm::check_addr(addr, std::max<std::size_t>(1, d_size)))
if (vm::check_addr(addr, std::max<std::size_t>(1, d_size), vm::page_allocated | (is_writing ? vm::page_writable : vm::page_readable)))
{
if (cpu)
{
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
namespace rpcs3
{
template<typename T>
static size_t hash_base(T value)
{
return static_cast<size_t>(value);
}
template<typename T>
static size_t hash_struct(const T& value)
{
// FNV 64-bit
size_t result = 14695981039346656037ull;
const unsigned char *bytes = reinterpret_cast<const unsigned char*>(&value);
for (size_t n = 0; n < sizeof(T); ++n)
{
result ^= bytes[n];
result *= 1099511628211ull;
}
return result;
}
}
+10 -4
View File
@@ -32,7 +32,6 @@
#define SAFE_BUFFERS
#define NEVER_INLINE __attribute__((noinline))
#define FORCE_INLINE __attribute__((always_inline)) inline
#define thread_local __thread
#endif
#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size")
@@ -919,7 +918,7 @@ struct error_code
error_code() = default;
// Implementation must be provided specially
static s32 error_report(const fmt_type_info* sup, u64 arg);
static s32 error_report(const fmt_type_info* sup, u64 arg, const fmt_type_info* sup2, u64 arg2);
// Helper type
enum class not_an_error : s32
@@ -940,7 +939,7 @@ struct error_code
// Not an error constructor
template<typename ET, typename = decltype(ET::__not_an_error)>
error_code(const ET& value, int = 0)
error_code(const ET& value, std::nullptr_t = nullptr)
: value(static_cast<s32>(value))
{
}
@@ -948,7 +947,14 @@ struct error_code
// Error constructor
template<typename ET, typename = std::enable_if_t<is_error<ET>::value>>
error_code(const ET& value)
: value(error_report(fmt::get_type_info<fmt_unveil_t<ET>>(), fmt_unveil<ET>::get(value)))
: value(error_report(fmt::get_type_info<fmt_unveil_t<ET>>(), fmt_unveil<ET>::get(value), nullptr, 0))
{
}
// Error constructor (2 args)
template<typename ET, typename T2, typename = std::enable_if_t<is_error<ET>::value>>
error_code(const ET& value, const T2& value2)
: value(error_report(fmt::get_type_info<fmt_unveil_t<ET>>(), fmt_unveil<ET>::get(value), fmt::get_type_info<fmt_unveil_t<T2>>(), fmt_unveil<T2>::get(value2)))
{
}
+4 -1
View File
@@ -15,6 +15,9 @@ before_build:
- 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
- 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 15 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 15 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/lib/cmake/llvm -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
@@ -25,7 +28,7 @@ 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.9\msvc2017_64
- set QTDIR=C:\Qt\5.9.1\msvc2017_64
- set OPENALDIR=C:\rpcs3\3rdparty\OpenAL
- set PATH=C:\Program Files (x86)\MSBuild\15.0\Bin;%QTDIR%;%PATH%
- set COMMIT_SHA=%APPVEYOR_REPO_COMMIT:~0,8%
+248
View File
@@ -0,0 +1,248 @@
/*
Kuroi (Dark) Theme for RPCS3
by Ani @ https://github.com/AniLeo
r1 (2017.08.15)
*/
/*
Color Scheme
(Darker to Lighter)
Black
> 292929
> 323232
> 333333
> 3d3d3d
> 404040
> 444444
Light Grey
> 828790
> bdc3c7
> ecf0f1
> b1b1b1
> 7f8c8d
Green
> 2ecc71
Red
> e74c3c
*/
/* Every widget */
QWidget {
background-color: #323232;
color: #bdc3c7;
alternate-background-color: #3d3d3d;
}
/* Mouse tooltips */
QToolTip {
border: 1px solid #323232;
background-color: #323232;
color: #ecf0f1;
}
/* Table headers */
QHeaderView::section {
background-color: #323232;
color: #ecf0f1;
padding-left: 4px;
border: 1px solid #323232;
}
/* Settings Dialog: Tabs */
QTabBar::tab {
color: #ecf0f1;
border: 1px solid #444;
border-bottom-style: none;
background-color: #333333;
padding-left: 16px;
padding-right: 16px;
padding-top: 4px;
padding-bottom: 4px;
margin-right: -2px;
}
QTabBar::tab:last {
margin-right: 0px;
}
QTabBar::tab:!selected {
color: #b1b1b1;
border-bottom-style: solid;
margin-top: 3px;
background-color: #292929;
}
QTabBar::tab:hover {
background-color: #333333;
color: #ecf0f1;
}
/* Checkboxes */
QCheckBox::indicator {
border-radius: 2px;
border: 1px solid #ecf0f1;
width: 10px;
height: 10px;
margin-top: 1px;
}
QCheckBox::indicator:checked {
background-color: #2ecc71; /* Green */
}
QCheckBox::indicator:unchecked {
background-color: #e74c3c; /* Red */
}
QCheckBox::indicator::disabled {
background-color: #7f8c8d; /* Gray */
}
/* Radio Buttons */
QRadioButton::indicator {
border-radius: 6px;
border: 1px solid #ecf0f1;
width: 10px;
height: 10px;
margin-top: 1px;
}
QRadioButton::indicator:checked {
background-color: #2ecc71; /* Green */
}
QRadioButton::indicator:unchecked {
background-color: #e74c3c; /* Red */
}
QRadioButton::indicator::disabled {
background-color: #7f8c8d; /* Gray */
}
/* Combo Boxes */
QComboBox {
background-color: #404040;
color: #fff;
border: 1px solid #1e1e1e;
border-radius: 3px;
padding-bottom: 2px;
padding-left: 4px;
}
QComboBox::disabled {
background-color: #828790;
color: #fff;
}
/* Group Boxes (Settings Dialog) */
QGroupBox {
margin-top: 17px;
font-size: 13px;
border: 1px solid #bdc3c7;
border-radius: 4px;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center;
padding: 5px 10px 5px 10px;
color: #fff;
}
/* Buttons */
QPushButton {
background-color: #404040;
}
QPushButton::disabled {
background-color: #444444;
color: #828790;
}
/* Log and Debugger borders */
QTextEdit {
border: 1px solid #828790;
}
/* For dock buttons to be visible */
QDockWidget::close-button, QDockWidget::float-button {
background-color: #bdc3c7;
border: 1px solid #000;
border-radius: 4px;
}
/* Disable ugly borders */
QTabWidget::pane {
border: 0px solid #828790;
}
/* Top menu bar */
QMenuBar::item:selected {
background: #444444;
}
QMenu::item {
padding-left: 20px;
padding-right: 15px;
padding-top: 4px;
padding-bottom: 4px;
}
QMenu::item:selected {
background: #444444;
border: 1px solid #bdc3c7;
}
QMenu::item:disabled {
background-color: #444444;
color: #828790;
}
/* Libraries list */
QListWidget::item:selected {
background-color: #3d3d3d;
color: #ecf0f1;
}
QListWidget::item:hover {
background-color: #4c4b4b;
color: #ecf0f1;
}
/* Pad Settings: Controller Image */
QLabel#l_controller {
color: #bdc3c7;
}
/* Game Grid Font */
QLabel#gamegrid_font {
font-weight: 600;
font-size: 8pt;
font-family: Lucida Grande;
color: #ecf0f1;
}
/* Slider on toolbar */
QWidget#sizeSliderContainer {
background: transparent;
}
/* Debug UI Settings buttons */
QLabel#color_button {
background: transparent;
}
/* Seachbar on main toolbar */
QLineEdit#mw_searchbar {
margin-left:14px;
color: #ecf0f1;
}
/* Uniform colors in Toolbar */
QToolButton {
background: transparent;
color: transparent;
}
QToolButton::disabled {
background-color: #828790;
}
QToolButton::hover {
background-color: #444444;
}
/* Set Theme UI colors */
QLabel#gamelist_icon_background_color {
background-color: #323232;
}
QLabel#gamelist_toolbar_icon_color {
background-color: #e3e3e3;
}
+1 -1
Submodule llvm updated: 079c1f30fc...a3b2103ffc
+42 -11
View File
@@ -87,7 +87,10 @@ endif()
if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
# This hides our LLVM from mesa's LLVM, otherwise we get some unresolvable conflicts.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--exclude-libs,ALL")
if(NOT APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--exclude-libs,ALL")
endif()
if(WIN32)
set(CMAKE_RC_COMPILER_INIT windres)
enable_language(RC)
@@ -101,17 +104,23 @@ if(NOT MSVC)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# This fixes 'some' of the st11range issues. See issue #2516
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -image-base=0x10000")
if(APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -image-base=0x10000")
endif()
endif()
# Some distros have the compilers set to use PIE by default, but RPCS3 doesn't work with PIE, so we need to disable it.
CHECK_C_COMPILER_FLAG("-no-pie" HAS_NO_PIE)
if(HAS_NO_PIE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
endif()
CHECK_C_COMPILER_FLAG("-nopie" HAS_NOPIE)
if(HAS_NOPIE)
if (NOT HAS_NO_PIE)
if(APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-no_pie")
else()
CHECK_C_COMPILER_FLAG("-no-pie" HAS_NO_PIE)
CHECK_C_COMPILER_FLAG("-nopie" HAS_NOPIE)
if(HAS_NO_PIE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
elseif(HAS_NOPIE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nopie")
endif()
endif()
@@ -127,7 +136,7 @@ endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
#on some Linux distros shm_unlink and similar functions are in librt only
set(ADDITIONAL_LIBS "rt" "X11" "asound")
set(ADDITIONAL_LIBS "rt" "X11")
elseif(NOT MSVC AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
#it seems like glibc includes the iconv functions we use but other libc
#implementations like the one on OSX don't seem implement them
@@ -158,9 +167,29 @@ elseif(WIN32)
set(PLATFORM_ARCH "Windows/x86_64")
else()
set(PLATFORM_ARCH "linux/x86_64")
option(USE_ALSA "ALSA audio backend" ON)
option(USE_PULSE "PulseAudio audio backend" ON)
option(USE_LIBEVDEV "libevdev-based joystick support" ON)
endif()
if(USE_ALSA)
find_package(PkgConfig)
pkg_check_modules(ALSA alsa)
if(ALSA_FOUND)
add_definitions(-DHAVE_ALSA)
include_directories(SYSTEM ${ALSA_INCLUDE_DIRS})
list(APPEND ADDITIONAL_LIBS ${ALSA_LDFLAGS})
endif()
endif()
if(USE_PULSE)
find_package(PkgConfig)
pkg_check_modules(PULSE libpulse-simple)
if(PULSE_FOUND)
add_definitions(-DHAVE_PULSE)
include_directories(SYSTEM ${PULSE_INCLUDE_DIRS})
list(APPEND ADDITIONAL_LIBS ${PULSE_LDFLAGS})
endif()
endif()
if(USE_LIBEVDEV)
find_package(PkgConfig)
pkg_check_modules(LIBEVDEV libevdev)
@@ -321,7 +350,9 @@ if(WIN32)
target_link_libraries(rpcs3 avformat.lib avcodec.lib avutil.lib swresample.lib swscale.lib png16_static ${OPENAL_LIBRARY} ${ADDITIONAL_LIBS})
else()
target_link_libraries(rpcs3 ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
if(APPLE)
target_link_libraries(rpcs3 hidapi-mac "-framework CoreFoundation" "-framework IOKit")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(rpcs3 hidapi-hidraw udev vulkan)
else()
target_link_libraries(rpcs3 hidapi-libusb usb)
+8 -8
View File
@@ -150,8 +150,8 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
const int metadata_section_size = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0 || (edat->flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
const int metadata_offset = 0x100;
std::unique_ptr<u8> enc_data;
std::unique_ptr<u8> dec_data;
std::unique_ptr<u8[]> enc_data;
std::unique_ptr<u8[]> dec_data;
u8 hash[0x10] = { 0 };
u8 key_result[0x10] = { 0 };
u8 hash_result[0x14] = { 0 };
@@ -315,7 +315,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD
{
const int total_blocks = (int)((edat->file_size + edat->block_size - 1) / edat->block_size);
u64 size_left = (int)edat->file_size;
std::unique_ptr<u8> data(new u8[edat->block_size]);
std::unique_ptr<u8[]> data(new u8[edat->block_size]);
for (int i = 0; i < total_blocks; i++)
{
@@ -427,8 +427,8 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
long bytes_read = 0;
long bytes_to_read = metadata_size;
std::unique_ptr<u8> metadata(new u8[metadata_size]);
std::unique_ptr<u8> empty_metadata(new u8[metadata_size]);
std::unique_ptr<u8[]> metadata(new u8[metadata_size]);
std::unique_ptr<u8[]> empty_metadata(new u8[metadata_size]);
while (bytes_to_read > 0)
{
@@ -487,7 +487,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
if ((edat->flags & EDAT_FLAG_0x20) != 0) //Sony failed again, they used buffer from 0x100 with half size of real metadata.
{
int metadata_buf_size = block_num * 0x10;
std::unique_ptr<u8> metadata_buf(new u8[metadata_buf_size]);
std::unique_ptr<u8[]> metadata_buf(new u8[metadata_buf_size]);
f->seek(file_offset + metadata_offset);
f->read(metadata_buf.get(), metadata_buf_size);
sha1(metadata_buf.get(), metadata_buf_size, signature_hash);
@@ -516,7 +516,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
{
// Setup header signature hash.
memset(signature_hash, 0, 20);
std::unique_ptr<u8> header_buf(new u8[0xD8]);
std::unique_ptr<u8[]> header_buf(new u8[0xD8]);
f->seek(file_offset);
f->read(header_buf.get(), 0xD8);
sha1(header_buf.get(), 0xD8, signature_hash );
@@ -577,7 +577,7 @@ int validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *
int dev_hash_result = 0;
const int file_name_length = (int) strlen(file_name);
std::unique_ptr<u8> buf(new u8[0x30 + file_name_length]);
std::unique_ptr<u8[]> buf(new u8[0x30 + file_name_length]);
// Build the title buffer (content_id + file_name).
memcpy(buf.get(), npd->content_id, 0x30);
+90 -11
View File
@@ -3,19 +3,77 @@
#include "aes.h"
#include "sha1.h"
#include "key_vault.h"
#include "Utilities/StrFmt.h"
#include "unpkg.h"
bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>& sync)
bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>& sync, const std::string& pkg_filepath)
{
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;
if (!pkg_f.read(header))
auto archive_seek = [&](const s64 new_offset, const fs::seek_mode damode = fs::seek_set)
{
if(damode == fs::seek_set) cur_offset = new_offset;
else if (damode == fs::seek_cur) cur_offset += new_offset;
u64 _offset = 0;
for (u32 i = 0; i < filelist.size(); i++)
{
if (cur_offset < (_offset + filelist[i].size()))
{
cur_file = i;
cur_file_offset = cur_offset - _offset;
filelist[i].seek(cur_file_offset);
break;
}
_offset += filelist[i].size();
}
};
auto archive_read = [&](const void *data_ptr, const u64 num_bytes)
{
u64 num_bytes_left = filelist[cur_file].size() - cur_file_offset;
//check if it continues in another file
if (num_bytes > num_bytes_left)
{
filelist[cur_file].read((u8 *)data_ptr, num_bytes_left);
if ((cur_file + 1) < filelist.size()) cur_file++;
else
{
cur_offset += num_bytes_left;
cur_file_offset = filelist[cur_file].size();
return num_bytes_left;
}
u64 num_read = filelist[cur_file].read((u8 *)data_ptr + num_bytes_left, num_bytes - num_bytes_left);
cur_offset += (num_read + num_bytes_left);
cur_file_offset = num_read;
return (num_read+num_bytes_left);
}
u64 num_read = filelist[cur_file].read((u8 *)data_ptr, num_bytes);
cur_offset += num_read;
cur_file_offset += num_read;
return num_read;
};
if (archive_read(&header, sizeof(header)) != sizeof(header))
{
LOG_ERROR(LOADER, "PKG file is too short!");
return false;
@@ -51,8 +109,29 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
if (header.pkg_size > pkg_f.size())
{
LOG_ERROR(LOADER, "PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size);
return false;
//Check if multi-files pkg
if (pkg_filepath.length() < 7 || pkg_filepath.substr(pkg_filepath.length() - 7).compare("_00.pkg") != 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 archive_filename = fmt::format("%s_%2d.pkg", name_wo_number, filelist.size());
fs::file archive_file(archive_filename);
if (!archive_file)
{
LOG_ERROR(LOADER, "Missing part of the multi-files pkg: %s", archive_filename);
return false;
}
cursize += archive_file.size();
filelist.push_back(std::move(archive_file));
}
}
if (header.data_size + header.data_offset > header.pkg_size)
@@ -64,7 +143,7 @@ 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};
pkg_f.seek(header.pkg_info_off);
archive_seek(header.pkg_info_off);
for (u32 i = 0; i < header.pkg_info_num; i++)
{
@@ -74,7 +153,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
be_t<u32> size;
} packet;
pkg_f.read(packet);
archive_read(&packet, sizeof(packet));
// TODO
switch (+packet.id)
@@ -83,7 +162,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
{
if (packet.size == sizeof(drm_type))
{
pkg_f.read(drm_type);
archive_read(&drm_type, sizeof(drm_type));
continue;
}
@@ -93,7 +172,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
{
if (packet.size == sizeof(content_type))
{
pkg_f.read(content_type);
archive_read(&content_type, sizeof(content_type));
continue;
}
@@ -101,7 +180,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
}
}
pkg_f.seek(packet.size, fs::seek_cur);
archive_seek(packet.size, fs::seek_cur);
}
// Allocate buffer with BUF_SIZE size or more if required
@@ -110,10 +189,10 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
// Define decryption subfunction (`psp` arg selects the key for specific block)
auto decrypt = [&](u64 offset, u64 size, const uchar* key) -> u64
{
pkg_f.seek(start_offset + header.data_offset + offset);
archive_seek(start_offset + header.data_offset + offset);
// Read the data and set available size
const u64 read = pkg_f.read(buf.get(), size);
const u64 read = archive_read(buf.get(), size);
// Get block count
const u64 blocks = (read + 15) / 16;
+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>&);
bool pkg_install(const class fs::file& pkg_f, const std::string& dir, atomic_t<double>&, const std::string& pkg_filepath);
+2 -2
View File
@@ -118,7 +118,7 @@ void aesecb128_encrypt(unsigned char *key, unsigned char *in, unsigned char *out
bool hmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len)
{
std::unique_ptr<u8> out(new u8[key_len]);
std::unique_ptr<u8[]> out(new u8[key_len]);
sha1_hmac(key, key_len, in, in_len, out.get());
@@ -132,7 +132,7 @@ void hmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_
bool cmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len)
{
std::unique_ptr<u8> out(new u8[key_len]);
std::unique_ptr<u8[]> out(new u8[key_len]);
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
+1 -1
View File
@@ -4,7 +4,7 @@
#include "ALSAThread.h"
#ifdef __linux__
#ifdef HAVE_ALSA
#include <alsa/asoundlib.h>
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#ifdef __linux__
#ifdef HAVE_ALSA
#include "Emu/Audio/AudioThread.h"
+60
View File
@@ -0,0 +1,60 @@
#include "Emu/System.h"
#include "PulseThread.h"
#ifdef HAVE_PULSE
#include <pulse/simple.h>
#include <pulse/error.h>
PulseThread::PulseThread()
{
}
PulseThread::~PulseThread()
{
this->Close();
}
void PulseThread::Play()
{
}
void PulseThread::Close()
{
if(this->connection) {
pa_simple_free(this->connection);
this->connection = nullptr;
}
}
void PulseThread::Stop()
{
}
void PulseThread::Open(const void* src, int size)
{
pa_sample_spec ss;
ss.format = g_cfg.audio.convert_to_u16 ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
ss.channels = g_cfg.audio.downmix_to_2ch ? 2 : 8;
ss.rate = 48000;
int err;
this->connection = pa_simple_new(NULL, "RPCS3", PA_STREAM_PLAYBACK, NULL, "Game", &ss, NULL, NULL, &err);
if(!this->connection) {
fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err));
}
this->AddData(src, size);
}
void PulseThread::AddData(const void* src, int size)
{
if(this->connection) {
int err;
if(pa_simple_write(this->connection, src, size, &err) < 0) {
fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err));
}
}
}
#endif
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#ifdef HAVE_PULSE
#include <pulse/simple.h>
#include "Emu/Audio/AudioThread.h"
class PulseThread : public AudioThread
{
public:
PulseThread();
virtual ~PulseThread() override;
virtual void Play() override;
virtual void Open(const void* src, int size) override;
virtual void Close() override;
virtual void Stop() override;
virtual void AddData(const void* src, int size) override;
private:
pa_simple *connection = nullptr;
};
#endif
+8
View File
@@ -195,6 +195,12 @@ s32 cellAtracGetInternalErrorInfo(vm::ptr<CellAtracHandle> pHandle, vm::ptr<s32>
return CELL_OK;
}
s32 cellAtracGetSamplingRate()
{
UNIMPLEMENTED_FUNC(cellAtrac);
return CELL_OK;
}
DECLARE(ppu_module_manager::cellAtrac)("cellAtrac", []()
{
REG_FUNC(cellAtrac, cellAtracSetDataAndGetMemSize);
@@ -227,4 +233,6 @@ DECLARE(ppu_module_manager::cellAtrac)("cellAtrac", []()
REG_FUNC(cellAtrac, cellAtracResetPlayPosition);
REG_FUNC(cellAtrac, cellAtracGetInternalErrorInfo);
REG_FUNC(cellAtrac, cellAtracGetSamplingRate);
});
@@ -203,6 +203,12 @@ s32 cellAtracMultiGetInternalErrorInfo(vm::ptr<CellAtracMultiHandle> pHandle, vm
return CELL_OK;
}
s32 cellAtracMultiGetSamplingRate()
{
UNIMPLEMENTED_FUNC(cellAtracMulti);
return CELL_OK;
}
DECLARE(ppu_module_manager::cellAtracMulti)("cellAtracMulti", []()
{
REG_FUNC(cellAtracMulti, cellAtracMultiSetDataAndGetMemSize);
@@ -236,4 +242,6 @@ DECLARE(ppu_module_manager::cellAtracMulti)("cellAtracMulti", []()
REG_FUNC(cellAtracMulti, cellAtracMultiResetPlayPosition);
REG_FUNC(cellAtracMulti, cellAtracMultiGetInternalErrorInfo);
REG_FUNC(cellAtracMulti, cellAtracMultiGetSamplingRate);
});
+42 -35
View File
@@ -11,39 +11,39 @@ logs::channel cellAvconfExt("cellAvconfExt");
vm::gvar<f32> g_gamma; // TODO
s32 cellAudioOutUnregisterDevice()
s32 cellAudioOutUnregisterDevice(u32 deviceNumber)
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
cellAvconfExt.todo("cellAudioOutUnregisterDevice(deviceNumber=0x%x)", deviceNumber);
return CELL_OK;
}
s32 cellAudioOutGetDeviceInfo2()
s32 cellAudioOutGetDeviceInfo2(u32 deviceNumber, u32 deviceIndex, vm::ptr<CellAudioOutDeviceInfo2> info)
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
cellAvconfExt.todo("cellAudioOutGetDeviceInfo2(deviceNumber=0x%x, deviceIndex=0x%x, info=*0x%x)", deviceNumber, deviceIndex, info);
return CELL_OK;
}
s32 cellVideoOutSetXVColor()
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
UNIMPLEMENTED_FUNC(cellAvconfExt);
return CELL_OK;
}
s32 cellVideoOutSetupDisplay()
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
UNIMPLEMENTED_FUNC(cellAvconfExt);
return CELL_OK;
}
s32 cellAudioInGetDeviceInfo()
s32 cellAudioInGetDeviceInfo(u32 deviceNumber, u32 deviceIndex, vm::ptr<CellAudioInDeviceInfo> info)
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
cellAvconfExt.todo("cellAudioInGetDeviceInfo(deviceNumber=0x%x, deviceIndex=0x%x, info=*0x%x)", deviceNumber, deviceIndex, info);
return CELL_OK;
}
s32 cellVideoOutConvertCursorColor()
s32 cellVideoOutConvertCursorColor(u32 videoOut, s32 displaybuffer_format, f32 gamma, s32 source_buffer_format, vm::ptr<void> src_addr, vm::ptr<u32> dest_addr, s32 num)
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
cellAvconfExt.todo("cellVideoOutConvertCursorColor(videoOut=%d, displaybuffer_format=0x%x, gamma=0x%x, source_buffer_format=0x%x, src_addr=*0x%x, dest_addr=*0x%x, num=0x%x)", videoOut, displaybuffer_format, gamma, source_buffer_format, src_addr, dest_addr, num);
return CELL_OK;
}
@@ -61,16 +61,16 @@ s32 cellVideoOutGetGamma(u32 videoOut, vm::ptr<f32> gamma)
return CELL_OK;
}
s32 cellAudioInGetAvailableDeviceInfo()
s32 cellAudioInGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioInDeviceInfo> info)
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
return CELL_OK;
cellAvconfExt.todo("cellAudioInGetAvailableDeviceInfo(count=0x%x, info=*0x%x)", count, info);
return 0; // number of available devices
}
s32 cellAudioOutGetAvailableDeviceInfo()
s32 cellAudioOutGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioOutDeviceInfo2> info)
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
return CELL_OK;
cellAvconfExt.todo("cellAudioOutGetAvailableDeviceInfo(count=0x%x, info=*0x%x)", count, info);
return 0; // number of available devices
}
s32 cellVideoOutSetGamma(u32 videoOut, f32 gamma)
@@ -92,37 +92,37 @@ s32 cellVideoOutSetGamma(u32 videoOut, f32 gamma)
return CELL_OK;
}
s32 cellAudioOutRegisterDevice()
s32 cellAudioOutRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::ptr<CellAudioOutRegistrationOption> option, vm::ptr<CellAudioOutDeviceConfiguration> config)
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
cellAvconfExt.todo("cellAudioOutRegisterDevice(deviceType=0x%llx, name=%s, option=*0x%x, config=*0x%x)", deviceType, name, option, config);
return 0; // device number
}
s32 cellAudioOutSetDeviceMode(u32 deviceMode)
{
cellAvconfExt.todo("cellAudioOutSetDeviceMode(deviceMode=0x%x)", deviceMode);
return CELL_OK;
}
s32 cellAudioOutSetDeviceMode()
s32 cellAudioInSetDeviceMode(u32 deviceMode)
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
cellAvconfExt.todo("cellAudioInSetDeviceMode(deviceMode=0x%x)", deviceMode);
return CELL_OK;
}
s32 cellAudioInSetDeviceMode()
s32 cellAudioInRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::ptr<CellAudioInRegistrationOption> option, vm::ptr<CellAudioInDeviceConfiguration> config)
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
cellAvconfExt.todo("cellAudioInRegisterDevice(deviceType=0x%llx, name=%s, option=*0x%x, config=*0x%x)", deviceType, name, option, config);
return 0; // device number
}
s32 cellAudioInUnregisterDevice(u32 deviceNumber)
{
cellAvconfExt.todo("cellAudioInUnregisterDevice(deviceNumber=0x%x)", deviceNumber);
return CELL_OK;
}
s32 cellAudioInRegisterDevice()
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
return CELL_OK;
}
s32 cellAudioInUnregisterDevice()
{
UNIMPLEMENTED_FUNC(cellAvconfExt);
return CELL_OK;
}
s32 cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<float> screenSize)
s32 cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<f32> screenSize)
{
cellAvconfExt.warning("cellVideoOutGetScreenSize(videoOut=%d, screenSize=*0x%x)", videoOut, screenSize);
@@ -143,6 +143,12 @@ s32 cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<float> screenSize)
return CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET;
}
s32 cellVideoOutSetCopyControl(u32 videoOut, u32 control)
{
cellAvconfExt.todo("cellVideoOutSetCopyControl(videoOut=%d, control=0x%x)", videoOut, control);
return CELL_OK;
}
DECLARE(ppu_module_manager::cellAvconfExt)("cellSysutilAvconfExt", []()
{
@@ -168,4 +174,5 @@ DECLARE(ppu_module_manager::cellAvconfExt)("cellSysutilAvconfExt", []()
REG_FUNC(cellSysutilAvconfExt, cellAudioInRegisterDevice);
REG_FUNC(cellSysutilAvconfExt, cellAudioInUnregisterDevice);
REG_FUNC(cellSysutilAvconfExt, cellVideoOutGetScreenSize);
REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetCopyControl);
});
+2 -2
View File
@@ -262,7 +262,7 @@ error_code cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr
return CELL_GAME_ERROR_BUSY;
}
}
else if (category == "AP" || category == "AV" || category == "HG")
else if (category == "AP" || category == "AV" || category == "HG" || category == "AT" || category == "AM" || category == "SF")
{
*type = CELL_GAME_GAMETYPE_HDD;
*attributes = 0; // TODO
@@ -393,7 +393,7 @@ error_code cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentInfoPa
fmt::throw_exception("cellGameContentPermit(): epic fail: directory '%s' already exists", dir);
}
if (fs::rename(prm->temp, vdir))
if (fs::rename(prm->temp, vdir, false))
{
cellGame.success("cellGameContentPermit(): directory '%s' has been created", dir);
}
+1 -1
View File
@@ -484,7 +484,7 @@ s32 cellGcmSetDisplayBuffer(u8 id, u32 offset, u32 pitch, u32 width, u32 height)
m_config->gcm_buffers[id].width = width;
m_config->gcm_buffers[id].height = height;
if (id + 1 > render->display_buffers_count)
if (id + 1u > render->display_buffers_count)
{
render->display_buffers_count = id + 1;
}
+7
View File
@@ -65,6 +65,12 @@ s32 cellHttpSetProxy()
return CELL_OK;
}
s32 cellHttpGetCookie()
{
UNIMPLEMENTED_FUNC(cellHttp);
return CELL_OK;
}
s32 cellHttpGetProxy()
{
UNIMPLEMENTED_FUNC(cellHttp);
@@ -701,6 +707,7 @@ DECLARE(ppu_module_manager::cellHttp)("cellHttp", []()
REG_FUNC(cellHttp, cellHttpsInit);
REG_FUNC(cellHttp, cellHttpsEnd);
REG_FUNC(cellHttp, cellHttpSetProxy);
REG_FUNC(cellHttp, cellHttpGetCookie);
REG_FUNC(cellHttp, cellHttpGetProxy);
REG_FUNC(cellHttp, cellHttpInitCookie);
+3 -3
View File
@@ -161,7 +161,7 @@ bool _L10nCodeParse(s32 code, HostCode& retCode)
#ifdef _MSC_VER
// Use code page to transform std::string to std::wstring.
s32 _OEM2Wide(HostCode oem_code, const std::string src, std::wstring& dst)
s32 _OEM2Wide(HostCode oem_code, const std::string& src, std::wstring& dst)
{
//Such length returned should include the '\0' character.
s32 length = MultiByteToWideChar(oem_code, 0, src.c_str(), -1, NULL, 0);
@@ -178,7 +178,7 @@ s32 _OEM2Wide(HostCode oem_code, const std::string src, std::wstring& dst)
}
// Use Code page to transform std::wstring to std::string.
s32 _Wide2OEM(HostCode oem_code, const std::wstring src, std::string& dst)
s32 _Wide2OEM(HostCode oem_code, const std::wstring& src, std::string& dst)
{
//Such length returned should include the '\0' character.
s32 length = WideCharToMultiByte(oem_code, 0, src.c_str(), -1, NULL, 0, NULL, NULL);
@@ -195,7 +195,7 @@ s32 _Wide2OEM(HostCode oem_code, const std::wstring src, std::string& dst)
}
// Convert Codepage to Codepage (all char*)
std::string _OemToOem(HostCode src_code, HostCode dst_code, const std::string str)
std::string _OemToOem(HostCode src_code, HostCode dst_code, const std::string& str)
{
std::wstring wide; std::string result;
_OEM2Wide(src_code, str, wide);
+1 -1
View File
@@ -83,7 +83,7 @@ public:
virtual ~MsgDialogBase();
virtual void Create(const std::string& msg) = 0;
virtual void CreateOsk(const std::string& msg, char16_t* osk_text) = 0;
virtual void CreateOsk(const std::string& msg, char16_t* osk_text, u32 charlimit) = 0;
virtual void ProgressBarSetMsg(u32 progressBarIndex, const std::string& msg) = 0;
virtual void ProgressBarReset(u32 progressBarIndex) = 0;
virtual void ProgressBarInc(u32 progressBarIndex, u32 delta) = 0;
+57
View File
@@ -202,6 +202,54 @@ error_code cellNetCtlGetNatInfo(vm::ptr<CellNetCtlNatInfo> natInfo)
return CELL_OK;
}
error_code cellNetCtlAddHandlerGameInt()
{
cellNetCtl.todo("cellNetCtlAddHandlerGameInt()");
return CELL_OK;
}
error_code cellNetCtlConnectGameInt()
{
cellNetCtl.todo("cellNetCtlConnectGameInt()");
return CELL_OK;
}
error_code cellNetCtlDelHandlerGameInt()
{
cellNetCtl.todo("cellNetCtlDelHandlerGameInt()");
return CELL_OK;
}
error_code cellNetCtlDisconnectGameInt()
{
cellNetCtl.todo("cellNetCtlDisconnectGameInt()");
return CELL_OK;
}
error_code cellNetCtlGetInfoGameInt()
{
cellNetCtl.todo("cellNetCtlGetInfoGameInt()");
return CELL_OK;
}
error_code cellNetCtlGetScanInfoGameInt()
{
cellNetCtl.todo("cellNetCtlGetScanInfoGameInt()");
return CELL_OK;
}
error_code cellNetCtlGetStateGameInt()
{
cellNetCtl.todo("cellNetCtlGetStateGameInt()");
return CELL_OK;
}
error_code cellNetCtlScanGameInt()
{
cellNetCtl.todo("cellNetCtlScanGameInt()");
return CELL_OK;
}
error_code cellGameUpdateInit()
{
cellNetCtl.todo("cellGameUpdateInit()");
@@ -274,6 +322,15 @@ DECLARE(ppu_module_manager::cellNetCtl)("cellNetCtl", []()
REG_FUNC(cellNetCtl, cellNetCtlGetNatInfo);
REG_FUNC(cellNetCtl, cellNetCtlAddHandlerGameInt);
REG_FUNC(cellNetCtl, cellNetCtlConnectGameInt);
REG_FUNC(cellNetCtl, cellNetCtlDelHandlerGameInt);
REG_FUNC(cellNetCtl, cellNetCtlDisconnectGameInt);
REG_FUNC(cellNetCtl, cellNetCtlGetInfoGameInt);
REG_FUNC(cellNetCtl, cellNetCtlGetScanInfoGameInt);
REG_FUNC(cellNetCtl, cellNetCtlGetStateGameInt);
REG_FUNC(cellNetCtl, cellNetCtlScanGameInt);
REG_FUNC(cellNetCtl, cellGameUpdateInit);
REG_FUNC(cellNetCtl, cellGameUpdateTerm);
+9 -2
View File
@@ -14,14 +14,21 @@ s32 cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dialogPara
{
cellOskDialog.warning("cellOskDialogLoadAsync(container=0x%x, dialogParam=*0x%x, inputFieldInfo=*0x%x)", container, dialogParam, inputFieldInfo);
u32 maxLength = (inputFieldInfo->limit_length >= 512) ? 511 : (u32)inputFieldInfo->limit_length;
std::memset(s_osk_text, 0, sizeof(s_osk_text));
if (inputFieldInfo->init_text.addr() != 0)
for (u32 i = 0; (i < maxLength) && (inputFieldInfo->init_text[i] != 0); i++)
s_osk_text[i] = inputFieldInfo->init_text[i];
const auto osk = Emu.GetCallbacks().get_msg_dialog();
bool result = false;
osk->on_close = [&](s32 status)
{
sysutil_send_system_cmd(status == CELL_MSGDIALOG_BUTTON_OK ? CELL_SYSUTIL_OSKDIALOG_FINISHED : CELL_SYSUTIL_OSKDIALOG_INPUT_CANCELED, 0);
if (status != CELL_MSGDIALOG_BUTTON_OK) sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_INPUT_CANCELED, 0);
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0);
result = true;
};
@@ -32,7 +39,7 @@ s32 cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dialogPara
Emu.CallAfter([&]()
{
osk->CreateOsk("On Screen Keyboard", s_osk_text);
osk->CreateOsk("On Screen Keyboard", s_osk_text, maxLength);
});
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_LOADED, 0);
+1 -1
View File
@@ -248,7 +248,7 @@ s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
}
data->button[0] = 0x0; // always 0
// bits 15-8 reserved, 7-4 = 0x7, 3-0: data->len/2;
data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15) & 0xF;
data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15);
//lets still send new data anyway, not sure whats expected still
data->button[CELL_PAD_BTN_OFFSET_DIGITAL1] = pad.m_digital_1;
data->button[CELL_PAD_BTN_OFFSET_DIGITAL2] = pad.m_digital_2;
+7
View File
@@ -118,6 +118,12 @@ s32 cellSearchGetContentInfoDeveloperData()
return CELL_OK;
}
s32 cellSearchGetContentInfoSharable()
{
UNIMPLEMENTED_FUNC(cellSearch);
return CELL_OK;
}
s32 cellSearchCancel()
{
UNIMPLEMENTED_FUNC(cellSearch);
@@ -150,6 +156,7 @@ DECLARE(ppu_module_manager::cellSearch)("cellSearchUtility", []()
REG_FUNC(cellSearchUtility, cellSearchGetContentInfoPathMovieThumb);
REG_FUNC(cellSearchUtility, cellSearchPrepareFile);
REG_FUNC(cellSearchUtility, cellSearchGetContentInfoDeveloperData);
REG_FUNC(cellSearchUtility, cellSearchGetContentInfoSharable);
REG_FUNC(cellSearchUtility, cellSearchCancel);
REG_FUNC(cellSearchUtility, cellSearchEnd);
});
+1 -1
View File
@@ -17,7 +17,7 @@
logs::channel cellSpurs("cellSpurs");
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img);
error_code sys_spu_image_close(vm::ptr<sys_spu_image> img);
// TODO
struct cell_error_t
+37 -1
View File
@@ -585,6 +585,36 @@ s32 _ZN8cxmlutil7GetFileERKN4cxml7ElementEPKcPNS0_4FileE()
return CELL_OK;
}
s32 _ZN16sysutil_cxmlutil11FixedMemory3EndEi()
{
UNIMPLEMENTED_FUNC(cellSysutil);
return CELL_OK;
}
s32 _ZN16sysutil_cxmlutil11FixedMemory5BeginEi()
{
UNIMPLEMENTED_FUNC(cellSysutil);
return CELL_OK;
}
s32 _ZN16sysutil_cxmlutil11FixedMemory8AllocateEN4cxml14AllocationTypeEPvS3_jPS3_Pj()
{
UNIMPLEMENTED_FUNC(cellSysutil);
return CELL_OK;
}
s32 _ZN16sysutil_cxmlutil12PacketWriter5WriteEPKvjPv()
{
UNIMPLEMENTED_FUNC(cellSysutil);
return CELL_OK;
}
s32 _ZN16sysutil_cxmlutil12PacketWriterC1EiiRN4cxml8DocumentE()
{
UNIMPLEMENTED_FUNC(cellSysutil);
return CELL_OK;
}
s32 cellSysutil_E1EC7B6A(vm::ptr<u32> unk)
{
cellSysutil.todo("cellSysutil_E1EC7B6A(unk=*0x%x)", unk);
@@ -675,6 +705,12 @@ DECLARE(ppu_module_manager::cellSysutil)("cellSysutil", []()
REG_FUNC(cellSysutil, _ZN8cxmlutil16CheckElementNameERKN4cxml7ElementEPKc);
REG_FUNC(cellSysutil, _ZN8cxmlutil16FindChildElementERKN4cxml7ElementEPKcS5_S5_);
REG_FUNC(cellSysutil, _ZN8cxmlutil7GetFileERKN4cxml7ElementEPKcPNS0_4FileE);
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil11FixedMemory3EndEi);
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil11FixedMemory5BeginEi);
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil11FixedMemory8AllocateEN4cxml14AllocationTypeEPvS3_jPS3_Pj);
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil12PacketWriter5WriteEPKvjPv);
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil12PacketWriterC1EiiRN4cxml8DocumentE);
REG_FNID(cellSysutil, 0xE1EC7B6A, cellSysutil_E1EC7B6A);
});
+181 -101
View File
@@ -7,129 +7,181 @@
logs::channel cellSysutilAvc2("cellSysutilAvc2");
s32 cellSysutilAvc2GetPlayerInfo()
template<>
void fmt_class_string<CellSysutilAvc2Error>::format(std::string& out, u64 arg)
{
fmt::throw_exception("Unimplemented" HERE);
format_enum(out, arg, [](auto error)
{
switch (error)
{
STR_CASE(CELL_AVC2_ERROR_UNKNOWN);
STR_CASE(CELL_AVC2_ERROR_NOT_SUPPORTED);
STR_CASE(CELL_AVC2_ERROR_NOT_INITIALIZED);
STR_CASE(CELL_AVC2_ERROR_ALREADY_INITIALIZED);
STR_CASE(CELL_AVC2_ERROR_INVALID_ARGUMENT);
STR_CASE(CELL_AVC2_ERROR_OUT_OF_MEMORY);
STR_CASE(CELL_AVC2_ERROR_ERROR_BAD_ID);
STR_CASE(CELL_AVC2_ERROR_INVALID_STATUS);
STR_CASE(CELL_AVC2_ERROR_TIMEOUT);
STR_CASE(CELL_AVC2_ERROR_NO_SESSION);
STR_CASE(CELL_AVC2_ERROR_WINDOW_ALREADY_EXISTS);
STR_CASE(CELL_AVC2_ERROR_TOO_MANY_WINDOWS);
STR_CASE(CELL_AVC2_ERROR_TOO_MANY_PEER_WINDOWS);
STR_CASE(CELL_AVC2_ERROR_WINDOW_NOT_FOUND);
}
return unknown;
});
}
s32 cellSysutilAvc2JoinChat()
error_code cellSysutilAvc2GetPlayerInfo(vm::cptr<SceNpMatching2RoomMemberId> player_id, vm::ptr<CellSysutilAvc2PlayerInfo> player_info)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetPlayerInfo(player_id=*0x%x, player_info=*0x%x)", player_id, player_info);
return CELL_OK;
}
s32 cellSysutilAvc2StopStreaming()
error_code cellSysutilAvc2JoinChat(vm::cptr<SceNpMatching2RoomId> room_id)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2JoinChat(room_id=*0x%x)", room_id);
return CELL_OK;
}
s32 cellSysutilAvc2ChangeVideoResolution()
error_code cellSysutilAvc2StopStreaming()
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2StopStreaming()");
return CELL_OK;
}
s32 cellSysutilAvc2ShowScreen()
error_code cellSysutilAvc2ChangeVideoResolution(CellSysutilAvc2VideoResolution resolution)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2ChangeVideoResolution(resolution=0x%x)", resolution);
return CELL_OK;
}
s32 cellSysutilAvc2GetVideoMuting()
error_code cellSysutilAvc2ShowScreen()
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2ShowScreen()");
return CELL_OK;
}
s32 cellSysutilAvc2GetWindowAttribute()
error_code cellSysutilAvc2GetVideoMuting(vm::ptr<u8> muting)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetVideoMuting(muting=*0x%x)", muting);
*muting = 1;
return CELL_OK;
}
s32 cellSysutilAvc2StopStreaming2()
error_code cellSysutilAvc2GetWindowAttribute(SceNpMatching2RoomMemberId member_id, vm::ptr<CellSysutilAvc2WindowAttribute> attr)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowAttribute(member_id=0x%x, attr=*0x%x)", member_id, attr);
return CELL_OK;
}
s32 cellSysutilAvc2SetVoiceMuting()
error_code cellSysutilAvc2StopStreaming2(CellSysutilAvc2MediaType mediaType)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2StopStreaming2(mediaType=0x%x)", mediaType);
return CELL_OK;
}
s32 cellSysutilAvc2StartVoiceDetection()
error_code cellSysutilAvc2SetVoiceMuting(u8 muting)
{
cellSysutilAvc2.todo("cellSysutilAvc2SetVoiceMuting(muting=0x%x)", muting);
return CELL_OK;
}
error_code cellSysutilAvc2StartVoiceDetection()
{
cellSysutilAvc2.todo("cellSysutilAvc2StartVoiceDetection()");
return CELL_OK;
}
s32 cellSysutilAvc2UnloadAsync()
error_code cellSysutilAvc2UnloadAsync()
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2UnloadAsync()");
return CELL_OK;
}
s32 cellSysutilAvc2StopVoiceDetection()
error_code cellSysutilAvc2StopVoiceDetection()
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2StopVoiceDetection()");
return CELL_OK;
}
s32 cellSysutilAvc2GetAttribute()
error_code cellSysutilAvc2GetAttribute(vm::ptr<CellSysutilAvc2Attribute> attr)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetAttribute(attr=*0x%x)", attr);
return CELL_OK;
}
s32 cellSysutilAvc2LoadAsync()
error_code cellSysutilAvc2LoadAsync(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2LoadAsync(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param);
return CELL_OK;
}
s32 cellSysutilAvc2SetSpeakerVolumeLevel()
error_code cellSysutilAvc2SetSpeakerVolumeLevel(f32 level)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2SetSpeakerVolumeLevel(level=0x%x)", level);
return CELL_OK;
}
s32 cellSysutilAvc2SetWindowString()
error_code cellSysutilAvc2SetWindowString(SceNpMatching2RoomMemberId member_id, vm::cptr<char> string)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2SetWindowString(member_id=0x%x, string=%s)", member_id, string);
return CELL_OK;
}
s32 cellSysutilAvc2EstimateMemoryContainerSize(vm::cptr<CellSysutilAvc2InitParam> initparam, vm::ptr<u32> size)
error_code cellSysutilAvc2EstimateMemoryContainerSize(vm::cptr<CellSysutilAvc2InitParam> initparam, vm::ptr<u32> size)
{
cellSysutilAvc2.todo("cellSysutilAvc2EstimateMemoryContainerSize(initparam=*0x%x, size=*0x%x)", initparam, size);
return CELL_OK;
}
s32 cellSysutilAvc2SetVideoMuting()
error_code cellSysutilAvc2SetVideoMuting(u8 muting)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2SetVideoMuting(muting=0x%x)", muting);
return CELL_OK;
}
s32 cellSysutilAvc2SetPlayerVoiceMuting()
error_code cellSysutilAvc2SetPlayerVoiceMuting(SceNpMatching2RoomMemberId member_id, u8 muting)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2SetPlayerVoiceMuting(member_id=0x%x, muting=0x%x)", member_id, muting);
return CELL_OK;
}
s32 cellSysutilAvc2SetStreamingTarget()
error_code cellSysutilAvc2SetStreamingTarget()
{
fmt::throw_exception("Unimplemented" HERE);
UNIMPLEMENTED_FUNC(cellSysutilAvc2);
return CELL_OK;
}
s32 cellSysutilAvc2Unload()
error_code cellSysutilAvc2Unload()
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2Unload()");
return CELL_OK;
}
s32 cellSysutilAvc2DestroyWindow()
error_code cellSysutilAvc2DestroyWindow(SceNpMatching2RoomMemberId member_id)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2DestroyWindow(member_id=0x%x)", member_id);
return CELL_OK;
}
s32 cellSysutilAvc2SetWindowPosition()
error_code cellSysutilAvc2SetWindowPosition(SceNpMatching2RoomMemberId member_id, f32 x, f32 y, f32 z)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2SetWindowPosition(member_id=0x%x, x=0x%x, y=0x%x, z=0x%x)", member_id, x, y, z);
return CELL_OK;
}
s32 cellSysutilAvc2GetSpeakerVolumeLevel()
error_code cellSysutilAvc2GetSpeakerVolumeLevel(vm::ptr<f32> level)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetSpeakerVolumeLevel(level=*0x%x)", level);
return CELL_OK;
}
s32 cellSysutilAvc2IsCameraAttached(vm::ptr<u8> status)
error_code cellSysutilAvc2IsCameraAttached(vm::ptr<u8> status)
{
cellSysutilAvc2.todo("cellSysutilAvc2IsCameraAttached(status=*0x%x)", status);
@@ -138,37 +190,43 @@ s32 cellSysutilAvc2IsCameraAttached(vm::ptr<u8> status)
return CELL_OK;
}
s32 cellSysutilAvc2MicRead()
error_code cellSysutilAvc2MicRead(vm::ptr<void> ptr, vm::ptr<u32> pSize)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2MicRead(ptr=*0x%x, pSize=*0x%x)", ptr, pSize);
return CELL_OK;
}
s32 cellSysutilAvc2GetPlayerVoiceMuting()
error_code cellSysutilAvc2GetPlayerVoiceMuting(SceNpMatching2RoomMemberId member_id, vm::ptr<u8> muting)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetPlayerVoiceMuting(member_id=0x%x, muting=*0x%x)", member_id, muting);
return CELL_OK;
}
s32 cellSysutilAvc2JoinChatRequest()
error_code cellSysutilAvc2JoinChatRequest(vm::cptr<SceNpMatching2RoomId> room_id)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2JoinChatRequest(room_id=*0x%x)", room_id);
return CELL_OK;
}
s32 cellSysutilAvc2StartStreaming()
error_code cellSysutilAvc2StartStreaming()
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2StartStreaming()");
return CELL_OK;
}
s32 cellSysutilAvc2SetWindowAttribute()
error_code cellSysutilAvc2SetWindowAttribute(SceNpMatching2RoomMemberId member_id, vm::cptr<CellSysutilAvc2WindowAttribute> attr)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2SetWindowAttribute(member_id=0x%x, attr=*0x%x)", member_id, attr);
return CELL_OK;
}
s32 cellSysutilAvc2GetWindowShowStatus()
error_code cellSysutilAvc2GetWindowShowStatus(SceNpMatching2RoomMemberId member_id, vm::ptr<u8> visible)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowShowStatus(member_id=0x%x, visible=*0x%x)", member_id, visible);
return CELL_OK;
}
s32 cellSysutilAvc2InitParam(u16 version, vm::ptr<CellSysutilAvc2InitParam> option)
error_code cellSysutilAvc2InitParam(u16 version, vm::ptr<CellSysutilAvc2InitParam> option)
{
cellSysutilAvc2.warning("cellSysutilAvc2InitParam(version=%d, option=*0x%x)", version, option);
@@ -215,99 +273,118 @@ s32 cellSysutilAvc2InitParam(u16 version, vm::ptr<CellSysutilAvc2InitParam> opti
return CELL_OK;
}
s32 cellSysutilAvc2GetWindowSize()
error_code cellSysutilAvc2GetWindowSize(SceNpMatching2RoomMemberId member_id, vm::ptr<f32> width, vm::ptr<f32> height)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowSize(member_id=0x%x, width=*0x%x, height=*0x%x)", member_id, width, height);
return CELL_OK;
}
s32 cellSysutilAvc2SetStreamPriority()
error_code cellSysutilAvc2SetStreamPriority(u8 priority)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2SetStreamPriority(priority=0x%x)", priority);
return CELL_OK;
}
s32 cellSysutilAvc2LeaveChatRequest()
error_code cellSysutilAvc2LeaveChatRequest()
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2LeaveChatRequest()");
return CELL_OK;
}
s32 cellSysutilAvc2IsMicAttached()
error_code cellSysutilAvc2IsMicAttached(vm::ptr<u8> status)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2IsMicAttached(status=*0x%x)", status);
*status = CELL_AVC2_MIC_STATUS_DETACHED;
return CELL_OK;
}
s32 cellSysutilAvc2CreateWindow()
error_code cellSysutilAvc2CreateWindow(SceNpMatching2RoomMemberId member_id)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2CreateWindow(member_id=0x%x)", member_id);
return CELL_OK;
}
s32 cellSysutilAvc2GetSpeakerMuting()
error_code cellSysutilAvc2GetSpeakerMuting(vm::ptr<u8> muting)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetSpeakerMuting(muting=*0x%x)", muting);
return CELL_OK;
}
s32 cellSysutilAvc2ShowWindow()
error_code cellSysutilAvc2ShowWindow(SceNpMatching2RoomMemberId member_id)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2ShowWindow(member_id=0x%x)", member_id);
return CELL_OK;
}
s32 cellSysutilAvc2SetWindowSize()
error_code cellSysutilAvc2SetWindowSize(SceNpMatching2RoomMemberId member_id, f32 width, f32 height)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2SetWindowSize(member_id=0x%x, width=0x%x, height=0x%x)", member_id, width, height);
return CELL_OK;
}
s32 cellSysutilAvc2EnumPlayers()
error_code cellSysutilAvc2EnumPlayers(vm::ptr<s32> players_num, vm::ptr<SceNpMatching2RoomMemberId> players_id)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2EnumPlayers(players_num=*0x%x, players_id=*0x%x)", players_num, players_id);
return CELL_OK;
}
s32 cellSysutilAvc2GetWindowString()
error_code cellSysutilAvc2GetWindowString(SceNpMatching2RoomMemberId member_id, vm::ptr<char> string, vm::ptr<u8> len)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowString(member_id=0x%x, string=*0x%x, len=*0x%x)", member_id, string, len);
return CELL_OK;
}
s32 cellSysutilAvc2LeaveChat()
error_code cellSysutilAvc2LeaveChat()
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2LeaveChat()");
return CELL_OK;
}
s32 cellSysutilAvc2SetSpeakerMuting()
error_code cellSysutilAvc2SetSpeakerMuting(u8 muting)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2SetSpeakerMuting(muting=0x%x)", muting);
return CELL_OK;
}
s32 cellSysutilAvc2Load(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
error_code cellSysutilAvc2Load(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
{
cellSysutilAvc2.todo("cellSysutilAvc2Load(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param);
return CELL_OK;
}
s32 cellSysutilAvc2SetAttribute(vm::cptr<CellSysutilAvc2Attribute> attr)
error_code cellSysutilAvc2SetAttribute(vm::cptr<CellSysutilAvc2Attribute> attr)
{
cellSysutilAvc2.todo("cellSysutilAvc2SetAttribute(attr=*0x%x)", attr);
return CELL_OK;
}
s32 cellSysutilAvc2UnloadAsync2()
error_code cellSysutilAvc2UnloadAsync2(CellSysutilAvc2MediaType mediaType)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2UnloadAsync2(mediaType=0x%x)", mediaType);
return CELL_OK;
}
s32 cellSysutilAvc2StartStreaming2()
error_code cellSysutilAvc2StartStreaming2(CellSysutilAvc2MediaType mediaType)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2StartStreaming2(mediaType=0x%x)", mediaType);
return CELL_OK;
}
s32 cellSysutilAvc2HideScreen()
error_code cellSysutilAvc2HideScreen()
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2HideScreen()");
return CELL_OK;
}
s32 cellSysutilAvc2HideWindow()
error_code cellSysutilAvc2HideWindow(SceNpMatching2RoomMemberId member_id)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2HideWindow(member_id=0x%x)", member_id);
return CELL_OK;
}
s32 cellSysutilAvc2GetVoiceMuting(vm::ptr<u8> muting)
error_code cellSysutilAvc2GetVoiceMuting(vm::ptr<u8> muting)
{
cellSysutilAvc2.todo("cellSysutilAvc2GetVoiceMuting(muting=*0x%x)", muting);
@@ -316,19 +393,22 @@ s32 cellSysutilAvc2GetVoiceMuting(vm::ptr<u8> muting)
return CELL_OK;
}
s32 cellSysutilAvc2GetScreenShowStatus()
error_code cellSysutilAvc2GetScreenShowStatus(vm::ptr<u8> visible)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetScreenShowStatus(visible=*0x%x)", visible);
return CELL_OK;
}
s32 cellSysutilAvc2Unload2()
error_code cellSysutilAvc2Unload2(CellSysutilAvc2MediaType mediaType)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2Unload2(mediaType=0x%x)", mediaType);
return CELL_OK;
}
s32 cellSysutilAvc2GetWindowPosition()
error_code cellSysutilAvc2GetWindowPosition(SceNpMatching2RoomMemberId member_id, vm::ptr<f32> x, vm::ptr<f32> y, vm::ptr<f32> z)
{
fmt::throw_exception("Unimplemented" HERE);
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowPosition(member_id=0x%x, x=*0x%x, y=*0x%x, z=*0x%x)", member_id, x, y, z);
return CELL_OK;
}
+25 -8
View File
@@ -3,7 +3,7 @@
namespace vm { using namespace ps3; }
// Error codes
enum
enum CellSysutilAvc2Error : u32
{
CELL_AVC2_ERROR_UNKNOWN = 0x8002b701,
CELL_AVC2_ERROR_NOT_SUPPORTED = 0x8002b702,
@@ -113,6 +113,14 @@ enum
CELL_AVC2_CAMERA_STATUS_UNKNOWN = 3,
};
enum
{
CELL_AVC2_MIC_STATUS_DETACHED = 0,
CELL_AVC2_MIC_STATUS_ATTACHED_OFF = 1,
CELL_AVC2_MIC_STATUS_ATTACHED_ON = 2,
CELL_AVC2_MIC_STATUS_UNKNOWN = 3,
};
typedef u32 CellSysutilAvc2AttributeId;
typedef u32 CellSysutilAvc2WindowAttributeId;
@@ -143,7 +151,7 @@ struct CellSysutilAvc2VideoInitParam
be_t<u16> max_video_windows;
be_t<u16> max_video_framerate;
be_t<u32> max_video_bitrate;
CellSysutilAvc2CoordinatesForm coordinates_form;
be_t<CellSysutilAvc2CoordinatesForm> coordinates_form;
u8 video_stream_sharing;
};
@@ -166,15 +174,15 @@ struct CellSysutilAvc2InitParam
struct CellSysutilAvc2RoomMemberList
{
vm::ptr<SceNpMatching2RoomMemberId> member_id;
vm::bptr<SceNpMatching2RoomMemberId> member_id;
u8 member_num;
};
struct CellSysutilAvc2MemberIpAndPortList
{
vm::ptr<SceNpMatching2RoomMemberId> member_id;
vm::ptr<u32> dst_addr; // in_addr
vm::ptr<u16> dst_port;
vm::bptr<SceNpMatching2RoomMemberId> member_id;
vm::bptr<u32> dst_addr; // in_addr
vm::bptr<u16> dst_port; // in_port_t
be_t<SceNpMatching2RoomMemberId> my_member_id;
u8 member_num;
};
@@ -183,7 +191,7 @@ union CellSysutilAvc2AttributeParam
{
be_t<u64> int_param;
be_t<f32> float_param;
vm::ptr<void> ptr_param;
vm::bptr<void> ptr_param;
};
struct CellSysutilAvc2Attribute
@@ -196,7 +204,7 @@ union CellSysutilAvc2WindowAttributeParam
{
be_t<s32> int_vector[4];
be_t<f32> float_vector[4];
vm::ptr<void> ptr_vector[4];
vm::bptr<void> ptr_vector[4];
};
struct CellSysutilAvc2WindowAttribute
@@ -204,3 +212,12 @@ struct CellSysutilAvc2WindowAttribute
be_t<CellSysutilAvc2WindowAttributeId> attr_id;
CellSysutilAvc2WindowAttributeParam attr_param;
};
struct CellSysutilAvc2PlayerInfo
{
be_t<SceNpMatching2RoomMemberId> member_id;
u8 joined;
u8 connected;
u8 mic_attached;
u8 reserved[11];
};
+23
View File
@@ -43,6 +43,12 @@ s32 cellUsbdRegisterLdd()
return CELL_OK;
}
s32 cellUsbdRegisterCompositeLdd()
{
UNIMPLEMENTED_FUNC(cellUsbd);
return CELL_OK;
}
s32 cellUsbdRegisterExtraLdd()
{
UNIMPLEMENTED_FUNC(cellUsbd);
@@ -61,6 +67,12 @@ s32 cellUsbdUnregisterLdd()
return CELL_OK;
}
s32 cellUsbdUnregisterCompositeLdd()
{
UNIMPLEMENTED_FUNC(cellUsbd);
return CELL_OK;
}
s32 cellUsbdUnregisterExtraLdd()
{
UNIMPLEMENTED_FUNC(cellUsbd);
@@ -151,6 +163,13 @@ s32 cellUsbdFreeMemory()
return CELL_OK;
}
s32 cellUsbdResetDevice()
{
UNIMPLEMENTED_FUNC(cellUsbd);
return CELL_OK;
}
DECLARE(ppu_module_manager::cellUsbd)("cellUsbd", []()
{
REG_FUNC(cellUsbd, cellUsbdInit);
@@ -161,9 +180,11 @@ DECLARE(ppu_module_manager::cellUsbd)("cellUsbd", []()
REG_FUNC(cellUsbd, cellUsbdGetThreadPriority);
REG_FUNC(cellUsbd, cellUsbdRegisterLdd);
REG_FUNC(cellUsbd, cellUsbdRegisterCompositeLdd);
REG_FUNC(cellUsbd, cellUsbdRegisterExtraLdd);
REG_FUNC(cellUsbd, cellUsbdRegisterExtraLdd2);
REG_FUNC(cellUsbd, cellUsbdUnregisterLdd);
REG_FUNC(cellUsbd, cellUsbdUnregisterCompositeLdd);
REG_FUNC(cellUsbd, cellUsbdUnregisterExtraLdd);
REG_FUNC(cellUsbd, cellUsbdOpenPipe);
@@ -184,4 +205,6 @@ DECLARE(ppu_module_manager::cellUsbd)("cellUsbd", []()
REG_FUNC(cellUsbd, cellUsbdAllocateMemory);
REG_FUNC(cellUsbd, cellUsbdFreeMemory);
REG_FUNC(cellUsbd, cellUsbdResetDevice);
});
+14 -16
View File
@@ -128,26 +128,24 @@ error_code cellVideoOutGetResolution(u32 resolutionId, vm::ptr<CellVideoOutResol
error_code cellVideoOutConfigure(u32 videoOut, vm::ptr<CellVideoOutConfiguration> config, vm::ptr<CellVideoOutOption> option, u32 waitForEvent)
{
cellSysutil.warning("cellVideoOutConfigure(videoOut=%d, config=*0x%x, option=*0x%x, waitForEvent=%d)", videoOut, config, option, waitForEvent);
cellSysutil.todo("cellVideoOutConfigure(videoOut=%d, config=*0x%x, option=*0x%x, waitForEvent=%d)", videoOut, config, option, waitForEvent);
switch (videoOut)
if (!config)
{
case CELL_VIDEO_OUT_PRIMARY:
if (config->resolutionId != g_video_out_resolution_id.at(g_cfg.video.resolution)
|| (config->format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8 &&
config->format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8 &&
config->format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT)
|| (config->aspect != CELL_VIDEO_OUT_ASPECT_AUTO && config->aspect != g_video_out_aspect_id.at(g_cfg.video.aspect_ratio)))
{
return CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION;
}
return CELL_OK;
case CELL_VIDEO_OUT_SECONDARY:
return CELL_OK;
return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER;
}
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
if (!config->pitch)
{
return CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE;
}
if (config->resolutionId == 0x92 || config->resolutionId == 0xa1)
{
return CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION;
}
return CELL_OK;
}
error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutConfiguration> config, vm::ptr<CellVideoOutOption> option)
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -976,7 +976,7 @@ s32 sceNpManagerGetOnlineId(vm::ptr<SceNpOnlineId> onlineId)
return SCE_NP_ERROR_OFFLINE;
}
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
{
return SCE_NP_ERROR_INVALID_STATE;
}
@@ -998,7 +998,7 @@ s32 sceNpManagerGetNpId(ppu_thread& ppu, vm::ptr<SceNpId> npId)
return SCE_NP_ERROR_OFFLINE;
}
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
{
return SCE_NP_ERROR_INVALID_STATE;
}
@@ -1086,7 +1086,7 @@ s32 sceNpManagerGetAccountRegion(vm::ptr<SceNpCountryCode> countryCode, vm::ptr<
return SCE_NP_ERROR_OFFLINE;
}
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
{
return SCE_NP_ERROR_INVALID_STATE;
}
@@ -1108,7 +1108,7 @@ s32 sceNpManagerGetAccountAge(vm::ptr<s32> age)
return SCE_NP_ERROR_OFFLINE;
}
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
{
return SCE_NP_ERROR_INVALID_STATE;
}
@@ -1130,7 +1130,7 @@ s32 sceNpManagerGetContentRatingFlag(vm::ptr<s32> isRestricted, vm::ptr<s32> age
return SCE_NP_ERROR_OFFLINE;
}
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
{
return SCE_NP_ERROR_INVALID_STATE;
}
@@ -1156,7 +1156,7 @@ s32 sceNpManagerGetChatRestrictionFlag(vm::ptr<s32> isRestricted)
return SCE_NP_ERROR_OFFLINE;
}
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
{
return SCE_NP_ERROR_INVALID_STATE;
}
+15
View File
@@ -368,6 +368,19 @@ s32 sceNpTssGetDataAsync()
return CELL_OK;
}
s32 sceNpTssGetDataNoLimit()
{
UNIMPLEMENTED_FUNC(sceNpTus);
return CELL_OK;
}
s32 sceNpTssGetDataNoLimitAsync()
{
UNIMPLEMENTED_FUNC(sceNpTus);
return CELL_OK;
}
DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []()
{
REG_FUNC(sceNpTus, sceNpTusInit);
@@ -430,4 +443,6 @@ DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []()
REG_FUNC(sceNpTus, sceNpTusDeleteMultiSlotDataVUserAsync);
REG_FUNC(sceNpTus, sceNpTssGetData);
REG_FUNC(sceNpTus, sceNpTssGetDataAsync);
REG_FUNC(sceNpTus, sceNpTssGetDataNoLimit);
REG_FUNC(sceNpTus, sceNpTssGetDataNoLimitAsync);
});
+1 -1
View File
@@ -31,7 +31,7 @@ struct ps3_fmt_src
void skip(std::size_t extra)
{
++g_count += (u32)extra;
g_count += (u32)extra + 1;
}
std::size_t fmt_string(std::string& out, std::size_t extra) const
+7
View File
@@ -1211,6 +1211,12 @@ namespace sys_net
return CELL_OK;
}
s32 _sce_net_add_name_server()
{
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}
s32 _sce_net_add_name_server_with_char()
{
UNIMPLEMENTED_FUNC(libnet);
@@ -1342,6 +1348,7 @@ DECLARE(ppu_module_manager::libnet)("sys_net", []()
REG_FUNC_(sys_netset_if_up);
REG_FUNC_(sys_netset_open);
REG_FUNC_(_sce_net_add_name_server);
REG_FUNC_(_sce_net_add_name_server_with_char);
REG_FUNC_(_sce_net_flush_route);
+342 -22
View File
@@ -5,6 +5,7 @@
#include "Emu/Cell/RawSPUThread.h"
#include "Emu/Cell/lv2/sys_spu.h"
#include "Crypto/unself.h"
#include "Loader/ELF.h"
#include "sysPrxForUser.h"
extern logs::channel sysPrxForUser;
@@ -16,46 +17,365 @@ spu_printf_cb_t g_spu_printf_dgcb;
spu_printf_cb_t g_spu_printf_atcb;
spu_printf_cb_t g_spu_printf_dtcb;
s32 sys_spu_elf_get_information(u32 elf_img, vm::ptr<u32> entry, vm::ptr<s32> nseg)
struct spu_elf_ldr
{
sysPrxForUser.todo("sys_spu_elf_get_information(elf_img=0x%x, entry=*0x%x, nseg=*0x%x)", elf_img, entry, nseg);
be_t<u32> _vtable;
vm::bptr<void> src;
be_t<u32> x8;
be_t<u64> ehdr_off;
be_t<u64> phdr_off;
s32 get_ehdr(vm::ptr<elf_ehdr<elf_be, u64>> out)
{
if (!src)
{
return -1;
}
if (_vtable == vm::cast(u32{1}))
{
vm::ptr<elf_ehdr<elf_be, u32>> ehdr = vm::cast(src.addr() + ehdr_off);
std::memcpy(out.get_ptr(), ehdr.get_ptr(), 0x10); // Not needed?
out->e_type = ehdr->e_type;
out->e_machine = ehdr->e_machine;
out->e_version = ehdr->e_version;
out->e_entry = ehdr->e_entry;
out->e_phoff = ehdr->e_phoff;
out->e_shoff = ehdr->e_shoff;
out->e_flags = ehdr->e_flags;
out->e_ehsize = ehdr->e_ehsize;
out->e_phentsize = ehdr->e_phentsize;
out->e_phnum = ehdr->e_phnum;
out->e_shentsize = ehdr->e_shentsize;
out->e_shnum = ehdr->e_shnum;
out->e_shstrndx = ehdr->e_shstrndx;
}
else
{
vm::ptr<elf_ehdr<elf_be, u64>> ehdr = vm::cast(src.addr() + ehdr_off);
*out = *ehdr;
}
return 0;
}
s32 get_phdr(vm::ptr<elf_phdr<elf_be, u64>> out, u32 count)
{
if (!src)
{
return -1;
}
if (_vtable == vm::cast(u32{1}))
{
vm::ptr<elf_ehdr<elf_be, u32>> ehdr = vm::cast(src.addr() + ehdr_off);
vm::ptr<elf_phdr<elf_be, u32>> phdr = vm::cast(src.addr() + (phdr_off ? +phdr_off : +ehdr->e_phoff));
for (; count; count--, phdr++, out++)
{
out->p_type = phdr->p_type;
out->p_flags = phdr->p_flags;
out->p_offset = phdr->p_offset;
out->p_vaddr = phdr->p_vaddr;
out->p_paddr = phdr->p_paddr;
out->p_filesz = phdr->p_filesz;
out->p_memsz = phdr->p_memsz;
out->p_align = phdr->p_align;
}
}
else
{
vm::ptr<elf_ehdr<elf_be, u64>> ehdr = vm::cast(src.addr() + ehdr_off);
vm::ptr<elf_phdr<elf_be, u64>> phdr = vm::cast(src.addr() + (phdr_off ? +phdr_off : +ehdr->e_phoff));
std::memcpy(out.get_ptr(), phdr.get_ptr(), sizeof(*out) * count);
}
return 0;
}
};
struct spu_elf_info
{
u8 e_class;
vm::bptr<spu_elf_ldr> ldr;
struct sce_hdr
{
be_t<u32> se_magic;
be_t<u32> se_hver;
be_t<u16> se_flags;
be_t<u16> se_type;
be_t<u32> se_meta;
be_t<u64> se_hsize;
be_t<u64> se_esize;
} sce0;
struct self_hdr
{
be_t<u64> se_htype;
be_t<u64> se_appinfooff;
be_t<u64> se_elfoff;
be_t<u64> se_phdroff;
be_t<u64> se_shdroff;
be_t<u64> se_secinfoff;
be_t<u64> se_sceveroff;
be_t<u64> se_controloff;
be_t<u64> se_controlsize;
be_t<u64> pad;
} self;
// Doesn't exist there
spu_elf_ldr _overlay;
error_code init(vm::ptr<void> src, s32 arg2 = 0)
{
if (!src)
{
return CELL_EINVAL;
}
u32 ehdr_off = 0;
u32 phdr_off = 0;
// Check SCE header if found
std::memcpy(&sce0, src.get_ptr(), sizeof(sce0));
if (sce0.se_magic == 0x53434500 /* SCE\0 */)
{
if (sce0.se_hver != 2 || sce0.se_type != 1 || sce0.se_meta == 0)
{
return CELL_ENOEXEC;
}
std::memcpy(&self, src.get_ptr(), sizeof(self));
ehdr_off = static_cast<u32>(+self.se_elfoff);
phdr_off = static_cast<u32>(+self.se_phdroff);
if (self.se_htype != 3 || !ehdr_off || !phdr_off)
{
return CELL_ENOEXEC;
}
}
// Check ELF header
vm::ptr<elf_ehdr<elf_be, u32>> ehdr = vm::cast(src.addr() + ehdr_off);
if (ehdr->e_magic != "\177ELF"_u32 || ehdr->e_data != 2 /* BE */)
{
return CELL_ENOEXEC;
}
if (ehdr->e_class != 1 && ehdr->e_class != 2)
{
return CELL_ENOEXEC;
}
e_class = ehdr->e_class;
ldr = vm::get_addr(&_overlay);
ldr->_vtable = vm::cast(u32{e_class}); // TODO
ldr->src = vm::static_ptr_cast<u8>(src);
ldr->x8 = arg2;
ldr->ehdr_off = ehdr_off;
ldr->phdr_off = phdr_off;
return CELL_OK;
}
};
error_code sys_spu_elf_get_information(u32 elf_img, vm::ptr<u32> entry, vm::ptr<s32> nseg)
{
sysPrxForUser.warning("sys_spu_elf_get_information(elf_img=0x%x, entry=*0x%x, nseg=*0x%x)", elf_img, entry, nseg);
// Initialize ELF loader
vm::var<spu_elf_info> info(spu_elf_info{});
if (auto res = info->init(vm::cast(elf_img)))
{
return res;
}
// Reject SCE header
if (info->sce0.se_magic == 0x53434500)
{
return CELL_ENOEXEC;
}
// Load ELF header
vm::var<elf_ehdr<elf_be, u64>> ehdr(elf_ehdr<elf_be, u64>{});
if (info->ldr->get_ehdr(ehdr) || ehdr->e_machine != elf_machine::spu || !ehdr->e_phnum)
{
return CELL_ENOEXEC;
}
// Load program headers
vm::var<elf_phdr<elf_be, u64>[]> phdr(ehdr->e_phnum);
if (info->ldr->get_phdr(phdr, ehdr->e_phnum))
{
return CELL_ENOEXEC;
}
const s32 num_segs = sys_spu_image::get_nsegs<false>(phdr);
if (num_segs < 0)
{
return CELL_ENOEXEC;
}
*entry = static_cast<u32>(ehdr->e_entry);
*nseg = num_segs;
return CELL_OK;
}
s32 sys_spu_elf_get_segments(u32 elf_img, vm::ptr<sys_spu_segment> segments, s32 nseg)
error_code sys_spu_elf_get_segments(u32 elf_img, vm::ptr<sys_spu_segment> segments, s32 nseg)
{
sysPrxForUser.todo("sys_spu_elf_get_segments(elf_img=0x%x, segments=*0x%x, nseg=0x%x)", elf_img, segments, nseg);
sysPrxForUser.warning("sys_spu_elf_get_segments(elf_img=0x%x, segments=*0x%x, nseg=0x%x)", elf_img, segments, nseg);
// Initialize ELF loader
vm::var<spu_elf_info> info(spu_elf_info{});
if (auto res = info->init(vm::cast(elf_img)))
{
return res;
}
// Load ELF header
vm::var<elf_ehdr<elf_be, u64>> ehdr(elf_ehdr<elf_be, u64>{});
if (info->ldr->get_ehdr(ehdr) || ehdr->e_machine != elf_machine::spu || !ehdr->e_phnum)
{
return CELL_ENOEXEC;
}
// Load program headers
vm::var<elf_phdr<elf_be, u64>[]> phdr(ehdr->e_phnum);
if (info->ldr->get_phdr(phdr, ehdr->e_phnum))
{
return CELL_ENOEXEC;
}
const s32 num_segs = sys_spu_image::fill<false>(segments, nseg, phdr, elf_img);
if (num_segs == -2)
{
return CELL_ENOMEM;
}
else if (num_segs < 0)
{
return CELL_ENOEXEC;
}
return CELL_OK;
}
s32 sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 type)
error_code sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 type)
{
sysPrxForUser.warning("sys_spu_image_import(img=*0x%x, src=0x%x, type=%d)", img, src, type);
// Load from memory (TODO)
img->load(fs::file{vm::base(src), 0 - src});
if (type != SYS_SPU_IMAGE_PROTECT && type != SYS_SPU_IMAGE_DIRECT)
{
return CELL_EINVAL;
}
return CELL_OK;
// Initialize ELF loader
vm::var<spu_elf_info> info(spu_elf_info{});
if (auto res = info->init(vm::cast(src)))
{
return res;
}
// Reject SCE header
if (info->sce0.se_magic == 0x53434500)
{
return CELL_ENOEXEC;
}
// Load ELF header
vm::var<elf_ehdr<elf_be, u64>> ehdr(elf_ehdr<elf_be, u64>{});
if (info->ldr->get_ehdr(ehdr) || ehdr->e_machine != elf_machine::spu || !ehdr->e_phnum)
{
return CELL_ENOEXEC;
}
// Load program headers
vm::var<elf_phdr<elf_be, u64>[]> phdr(ehdr->e_phnum);
if (info->ldr->get_phdr(phdr, ehdr->e_phnum))
{
return CELL_ENOEXEC;
}
if (type == SYS_SPU_IMAGE_PROTECT)
{
u32 img_size = 0;
for (const auto& p : phdr)
{
if (p.p_type != 1 && p.p_type != 4)
{
return CELL_ENOEXEC;
}
img_size = std::max<u32>(img_size, static_cast<u32>(p.p_offset + p.p_filesz));
}
return _sys_spu_image_import(img, src, img_size, 0);
}
else
{
s32 num_segs = sys_spu_image::get_nsegs(phdr);
if (num_segs < 0)
{
return CELL_ENOEXEC;
}
img->nsegs = num_segs;
img->entry_point = static_cast<u32>(ehdr->e_entry);
vm::ptr<sys_spu_segment> segs = vm::cast(vm::alloc(num_segs * sizeof(sys_spu_segment), vm::main));
if (!segs)
{
return CELL_ENOMEM;
}
if (sys_spu_image::fill(segs, num_segs, phdr, src) != num_segs)
{
vm::dealloc(segs.addr());
return CELL_ENOEXEC;
}
img->type = SYS_SPU_IMAGE_TYPE_USER;
img->segs = segs;
return CELL_OK;
}
}
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img)
error_code sys_spu_image_close(vm::ptr<sys_spu_image> img)
{
sysPrxForUser.warning("sys_spu_image_close(img=*0x%x)", img);
if (img->type == SYS_SPU_IMAGE_TYPE_USER)
{
//_sys_free(img->segs.addr());
vm::dealloc_verbose_nothrow(img->segs.addr(), vm::main);
}
else if (img->type == SYS_SPU_IMAGE_TYPE_KERNEL)
{
//return syscall_158(img);
// Call the syscall
return _sys_spu_image_close(img);
}
else
{
return CELL_EINVAL;
}
img->free();
return CELL_OK;
}
@@ -63,7 +383,7 @@ s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry)
{
sysPrxForUser.warning("sys_raw_spu_load(id=%d, path=%s, entry=*0x%x)", id, path, entry);
const fs::file elf_file = decrypt_self(fs::file(vfs::get(path.get_ptr())));
const fs::file elf_file = fs::file(vfs::get(path.get_ptr()));
if (!elf_file)
{
@@ -73,10 +393,10 @@ s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry)
sys_spu_image img;
img.load(elf_file);
img.deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
img.deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id, img.segs.get_ptr(), img.nsegs);
img.free();
*entry = img.entry_point | 1;
*entry = img.entry_point;
return CELL_OK;
}
@@ -86,15 +406,15 @@ s32 sys_raw_spu_image_load(ppu_thread& ppu, s32 id, vm::ptr<sys_spu_image> img)
sysPrxForUser.warning("sys_raw_spu_image_load(id=%d, img=*0x%x)", id, img);
// Load SPU segments
img->deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
img->deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id, img->segs.get_ptr(), img->nsegs);
// Use MMIO
vm::write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs, img->entry_point | 1);
vm::write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs, img->entry_point);
return CELL_OK;
}
s32 _sys_spu_printf_initialize(spu_printf_cb_t agcb, spu_printf_cb_t dgcb, spu_printf_cb_t atcb, spu_printf_cb_t dtcb)
error_code _sys_spu_printf_initialize(spu_printf_cb_t agcb, spu_printf_cb_t dgcb, spu_printf_cb_t atcb, spu_printf_cb_t dtcb)
{
sysPrxForUser.warning("_sys_spu_printf_initialize(agcb=*0x%x, dgcb=*0x%x, atcb=*0x%x, dtcb=*0x%x)", agcb, dgcb, atcb, dtcb);
@@ -107,7 +427,7 @@ s32 _sys_spu_printf_initialize(spu_printf_cb_t agcb, spu_printf_cb_t dgcb, spu_p
return CELL_OK;
}
s32 _sys_spu_printf_finalize()
error_code _sys_spu_printf_finalize()
{
sysPrxForUser.warning("_sys_spu_printf_finalize()");
@@ -119,7 +439,7 @@ s32 _sys_spu_printf_finalize()
return CELL_OK;
}
s32 _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
error_code _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
{
sysPrxForUser.warning("_sys_spu_printf_attach_group(group=0x%x)", group);
@@ -131,7 +451,7 @@ s32 _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
return g_spu_printf_agcb(ppu, group);
}
s32 _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
error_code _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
{
sysPrxForUser.warning("_sys_spu_printf_detach_group(group=0x%x)", group);
@@ -143,7 +463,7 @@ s32 _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
return g_spu_printf_dgcb(ppu, group);
}
s32 _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
error_code _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
{
sysPrxForUser.warning("_sys_spu_printf_attach_thread(thread=0x%x)", thread);
@@ -155,7 +475,7 @@ s32 _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
return g_spu_printf_atcb(ppu, thread);
}
s32 _sys_spu_printf_detach_thread(ppu_thread& ppu, u32 thread)
error_code _sys_spu_printf_detach_thread(ppu_thread& ppu, u32 thread)
{
sysPrxForUser.warning("_sys_spu_printf_detach_thread(thread=0x%x)", thread);
+1 -1
View File
@@ -11,7 +11,7 @@ public:
}
private:
u32 DisAsmBranchTarget(const s32 imm)
u32 DisAsmBranchTarget(const s32 imm) override
{
return dump_pc + (imm & ~3);
}
+1 -1
View File
@@ -133,7 +133,7 @@ extern std::string ppu_get_syscall_name(u64 code)
case 156: return "sys_spu_image_open";
case 157: return "_sys_spu_image_import";
case 158: return "_sys_spu_image_close";
case 159: return "_sys_raw_spu_image_load";
case 159: return "_sys_spu_image_get_segments";
case 160: return "sys_raw_spu_create";
case 161: return "sys_raw_spu_destroy";
case 163: return "sys_raw_spu_read_puint_mb";
+19 -5
View File
@@ -88,12 +88,26 @@ void ppu_module_manager::register_module(ppu_static_module* module)
ppu_static_function& ppu_module_manager::access_static_function(const char* module, u32 fnid)
{
return access().at(module)->functions[fnid];
auto& res = access().at(module)->functions[fnid];
if (res.name)
{
fmt::throw_exception("PPU FNID duplication in module %s (%s, 0x%x)", module, res.name, fnid);
}
return res;
}
ppu_static_variable& ppu_module_manager::access_static_variable(const char* module, u32 vnid)
{
return access().at(module)->variables[vnid];
auto& res = access().at(module)->variables[vnid];
if (res.name)
{
fmt::throw_exception("PPU VNID duplication in module %s (%s, 0x%x)", module, res.name, vnid);
}
return res;
}
const ppu_static_module* ppu_module_manager::get_module(const std::string& name)
@@ -975,7 +989,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
fmt::throw_exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
if (!vm::falloc(addr, size, vm::main))
if (!vm::falloc(addr, size))
fmt::throw_exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
// Copy segment data, hash it
@@ -1291,9 +1305,9 @@ void ppu_load_exec(const ppu_exec_object& elf)
{
const std::string lle_dir = vfs::get("/dev_flash/sys/external/");
if (!fs::is_dir(lle_dir))
if (!fs::is_dir(lle_dir) || !fs::is_file(lle_dir + "libsysmodule.sprx"))
{
LOG_ERROR(GENERAL, "/dev_flash/sys/external/ directory does not exist!"
LOG_ERROR(GENERAL, "PS3 firmware is not installed or the installed firmware is invalid."
"\nYou should install the PS3 Firmware (Menu: File -> Install Firmware)."
"\nVisit https://rpcs3.net/ for Quickstart Guide and more information.");
}
+1 -1
View File
@@ -578,7 +578,7 @@ ppu_thread::~ppu_thread()
ppu_thread::ppu_thread(const std::string& name, u32 prio, u32 stack)
: cpu_thread(idm::last_id())
, prio(prio)
, stack_size(std::max<u32>(stack, 0x4000))
, stack_size(stack ? ::align(std::min<u32>(stack, 0x100000), 0x1000) : 0x4000)
, stack_addr(0)
, start_time(get_system_time())
, m_name(name)
+1 -1
View File
@@ -41,7 +41,7 @@ struct TypeGen<T, std::enable_if_t<std::is_void<T>::value>>
};
template<typename T>
struct TypeGen<T, std::enable_if_t<std::is_same<T, s64>::value || std::is_same<T, u64>::value>>
struct TypeGen<T, std::enable_if_t<std::is_same<T, s64>::value || std::is_same<T, u64>::value || std::is_same<T, uptr>::value>>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getInt64Ty(context); }
};
+26 -14
View File
@@ -77,6 +77,25 @@ bool RawSPUThread::read_reg(const u32 addr, u32& value)
value = status;
return true;
}
case Prxy_TagStatus_offs:
{
value = mfc_proxy.size() ? 0 : +mfc_prxy_mask;
return true;
}
case SPU_NPC_offs:
{
//npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0);
value = npc;
return true;
}
case SPU_RunCntl_offs:
{
value = run_ctrl;
return true;
}
}
LOG_ERROR(SPU, "RawSPUThread[%d]: Read32(0x%x): unknown/illegal offset (0x%x)", index, addr, offset);
@@ -130,23 +149,15 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
case MFC_Class_CMD_offs:
{
g_tls_mfc[index].cmd = MFC(value & 0xff);
if (mfc_proxy.try_push(g_tls_mfc[index]))
{
auto mfc = fxm::check_unlocked<mfc_thread>();
do_dma_transfer(g_tls_mfc[index]);
g_tls_mfc[index] = {};
g_tls_mfc[index].cmd = MFC(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
if (test(mfc->state, cpu_flag::stop) && mfc->state.test_and_reset(cpu_flag::stop))
{
mfc->notify();
}
g_tls_mfc[index] = {};
g_tls_mfc[index].cmd = MFC(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
}
else
if (value & MFC_START_MASK)
{
g_tls_mfc[index] = {};
g_tls_mfc[index].cmd = MFC(MFC_PPU_DMA_QUEUE_FULL);
try_start();
}
return true;
}
@@ -172,6 +183,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
case Prxy_QueryMask_offs:
{
mfc_prxy_mask = value;
return true;
}
+1 -1
View File
@@ -166,7 +166,7 @@ void spu_recompiler::compile(spu_function_t& f)
dis_asm.dump_pc = m_pos;
dis_asm.disasm(m_pos);
compiler.comment(dis_asm.last_opcode.c_str());
log += dis_asm.last_opcode.c_str();
log += dis_asm.last_opcode;
log += '\n';
}
+1
View File
@@ -274,6 +274,7 @@ void SPUThread::cpu_init()
srr0 = 0;
ch_tag_upd = 0;
ch_tag_mask = 0;
mfc_prxy_mask = 0;
ch_tag_stat.data.store({});
ch_stall_mask = 0;
ch_stall_stat.data.store({});
+2
View File
@@ -550,6 +550,8 @@ public:
spu_channel_4_t ch_in_mbox;
atomic_t<u32> mfc_prxy_mask;
spu_channel_t ch_out_mbox;
spu_channel_t ch_out_intr_mbox;
+2 -2
View File
@@ -187,7 +187,7 @@ const std::array<ppu_function_t, 1024> s_ppu_syscall_table
BIND_FUNC(sys_event_port_disconnect), //137 (0x089)
BIND_FUNC(sys_event_port_send), //138 (0x08A)
BIND_FUNC(sys_event_flag_get), //139 (0x08B)
null_func,//BIND_FUNC(sys_event_port_connect_ipc) //140 (0x08C)
BIND_FUNC(sys_event_port_connect_ipc), //140 (0x08C)
BIND_FUNC(sys_timer_usleep), //141 (0x08D)
BIND_FUNC(sys_timer_sleep), //142 (0x08E)
null_func,//BIND_FUNC(sys_time_set_timezone) //143 (0x08F) ROOT
@@ -206,7 +206,7 @@ const std::array<ppu_function_t, 1024> s_ppu_syscall_table
BIND_FUNC(sys_spu_image_open), //156 (0x09C)
BIND_FUNC(_sys_spu_image_import), //157 (0x09D)
BIND_FUNC(_sys_spu_image_close), //158 (0x09E)
BIND_FUNC(_sys_raw_spu_image_load), //159 (0x09F)
BIND_FUNC(_sys_spu_image_get_segments), //159 (0x09F)
BIND_FUNC(sys_raw_spu_create), //160 (0x0A0)
BIND_FUNC(sys_raw_spu_destroy), //161 (0x0A1)
null_func, //162 (0x0A2) UNS
+31 -1
View File
@@ -323,7 +323,7 @@ error_code sys_event_port_create(vm::ptr<u32> eport_id, s32 port_type, u64 name)
{
sys_event.warning("sys_event_port_create(eport_id=*0x%x, port_type=%d, name=0x%llx)", eport_id, port_type, name);
if (port_type != SYS_EVENT_PORT_LOCAL)
if (port_type != SYS_EVENT_PORT_LOCAL && port_type != 3)
{
sys_event.error("sys_event_port_create(): unknown port type (%d)", port_type);
return CELL_EINVAL;
@@ -393,6 +393,36 @@ error_code sys_event_port_connect_local(u32 eport_id, u32 equeue_id)
return CELL_OK;
}
error_code sys_event_port_connect_ipc(u32 eport_id, u64 ipc_key)
{
sys_event.warning("sys_event_port_connect_ipc(eport_id=0x%x, ipc_key=0x%x)", eport_id, ipc_key);
auto queue = lv2_event_queue::find(ipc_key);
writer_lock lock(id_manager::g_mutex);
const auto port = idm::check_unlocked<lv2_obj, lv2_event_port>(eport_id);
if (!port || !queue)
{
return CELL_ESRCH;
}
if (port->type != 3)
{
return CELL_EINVAL;
}
if (!port->queue.expired())
{
return CELL_EISCONN;
}
port->queue = std::move(queue);
return CELL_ESRCH;
}
error_code sys_event_port_disconnect(u32 eport_id)
{
sys_event.warning("sys_event_port_disconnect(eport_id=0x%x)", eport_id);
+1
View File
@@ -136,5 +136,6 @@ error_code sys_event_queue_drain(u32 event_queue_id);
error_code sys_event_port_create(vm::ps3::ptr<u32> eport_id, s32 port_type, u64 name);
error_code sys_event_port_destroy(u32 eport_id);
error_code sys_event_port_connect_local(u32 event_port_id, u32 event_queue_id);
error_code sys_event_port_connect_ipc(u32 eport_id, u64 ipc_key);
error_code sys_event_port_disconnect(u32 eport_id);
error_code sys_event_port_send(u32 event_port_id, u64 data1, u64 data2, u64 data3);
+40 -42
View File
@@ -192,7 +192,6 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
if (!path[0])
{
sys_fs.error("sys_fs_open(%s) failed: path is invalid", path);
return CELL_EINVAL;
}
@@ -200,16 +199,14 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
if (local_path.empty())
{
sys_fs.error("sys_fs_open(%s) failed: device not mounted", path);
return CELL_ENOTMOUNTED;
return {CELL_ENOTMOUNTED, path};
}
// TODO: other checks for path
if (fs::is_dir(local_path))
{
sys_fs.error("sys_fs_open(%s) failed: path is a directory", path);
return CELL_EISDIR;
return {CELL_EISDIR, path};
}
bs_t<fs::open_mode> open_mode{};
@@ -277,20 +274,21 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
if (!file)
{
sys_fs.error("sys_fs_open(%s): failed to open file (flags=%#o, mode=%#o)", path, flags, mode);
if (test(open_mode & fs::excl))
{
return CELL_EEXIST; // approximation
return not_an_error(CELL_EEXIST); // approximation
}
return CELL_ENOENT;
return {CELL_ENOENT, path};
}
if ((flags & CELL_FS_O_MSELF) && (!verify_mself(*fd, file)))
return CELL_ENOTMSELF;
{
return {CELL_ENOTMSELF, path};
}
const auto casted_arg = vm::static_ptr_cast<const u64>(arg);
const auto casted_arg = vm::static_ptr_cast<const u64>(arg);//static_cast<const be_t<u32> *>(arg.get_ptr());
if (size == 8)
{
// check for sdata
@@ -305,8 +303,7 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
auto sdata_file = std::make_unique<EDATADecrypter>(std::move(file));
if (!sdata_file->ReadHeader())
{
sys_fs.error("sys_fs_open(%s): Error reading sdata header!", path);
return CELL_EFSSPECIFIC;
return {CELL_EFSSPECIFIC, path};
}
file.reset(std::move(sdata_file));
@@ -325,14 +322,14 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
auto sdata_file = std::make_unique<EDATADecrypter>(std::move(file), edatkeys->devKlic, edatkeys->rifKey);
if (!sdata_file->ReadHeader())
{
sys_fs.error("sys_fs_open(%s): Error reading edata header!", path);
return CELL_EFSSPECIFIC;
return {CELL_EFSSPECIFIC, path};
}
file.reset(std::move(sdata_file));
}
}
}
if (const u32 id = idm::make<lv2_fs_object, lv2_file>(path.get_ptr(), std::move(file), mode, flags))
{
*fd = id;
@@ -340,7 +337,7 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
}
// Out of file descriptors
return CELL_EMFILE;
return {CELL_EMFILE, path};
}
error_code sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
@@ -424,24 +421,21 @@ error_code sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
if (local_path.empty())
{
sys_fs.error("sys_fs_opendir(%s) failed: device not mounted", path);
return CELL_ENOTMOUNTED;
return {CELL_ENOTMOUNTED, path};
}
// TODO: other checks for path
if (fs::is_file(local_path))
{
sys_fs.error("sys_fs_opendir(%s) failed: path is a file", path);
return CELL_ENOTDIR;
return {CELL_ENOTDIR, path};
}
fs::dir dir(local_path);
if (!dir)
{
sys_fs.error("sys_fs_opendir(%s): failed to open directory", path);
return CELL_ENOENT;
return {CELL_ENOENT, path};
}
if (const u32 id = idm::make<lv2_fs_object, lv2_dir>(path.get_ptr(), std::move(dir)))
@@ -506,16 +500,14 @@ error_code sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
if (local_path.empty())
{
sys_fs.warning("sys_fs_stat(%s) failed: not mounted", path);
return CELL_ENOTMOUNTED;
return {CELL_ENOTMOUNTED, path};
}
fs::stat_t info;
if (!fs::stat(local_path, info))
{
sys_fs.error("sys_fs_stat(%s) failed: not found", path);
return CELL_ENOENT;
return {CELL_ENOENT, path};
}
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
@@ -572,12 +564,12 @@ error_code sys_fs_mkdir(vm::cptr<char> path, s32 mode)
if (fs::is_dir(local_path))
{
return CELL_EEXIST;
return {CELL_EEXIST, path};
}
if (!fs::create_path(local_path))
{
return CELL_EIO; // ???
return {CELL_EIO, path}; // ???
}
sys_fs.notice("sys_fs_mkdir(): directory %s created", path);
@@ -588,9 +580,16 @@ error_code sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
{
sys_fs.warning("sys_fs_rename(from=%s, to=%s)", from, to);
if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr())))
if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr()), false))
{
return CELL_ENOENT; // ???
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return {CELL_ENOENT, from};
case fs::error::exist: return {CELL_EEXIST, to};
default: sys_fs.error("sys_fs_rename(): unknown error %s", error);
}
return {CELL_EIO, from}; // ???
}
sys_fs.notice("sys_fs_rename(): %s renamed to %s", from, to);
@@ -605,11 +604,11 @@ error_code sys_fs_rmdir(vm::cptr<char> path)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return CELL_ENOENT;
case fs::error::noent: return {CELL_ENOENT, path};
default: sys_fs.error("sys_fs_rmdir(): unknown error %s", error);
}
return CELL_EIO; // ???
return {CELL_EIO, path}; // ???
}
sys_fs.notice("sys_fs_rmdir(): directory %s removed", path);
@@ -624,11 +623,11 @@ error_code sys_fs_unlink(vm::cptr<char> path)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return CELL_ENOENT;
case fs::error::noent: return {CELL_ENOENT, path};
default: sys_fs.error("sys_fs_unlink(): unknown error %s", error);
}
return CELL_EIO; // ???
return {CELL_EIO, path}; // ???
}
sys_fs.notice("sys_fs_unlink(): file %s deleted", path);
@@ -1006,8 +1005,7 @@ error_code sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
if (whence >= 3)
{
sys_fs.error("sys_fs_lseek(): invalid seek whence (%d)", whence);
return CELL_EINVAL;
return {CELL_EINVAL, whence};
}
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
@@ -1108,11 +1106,11 @@ error_code sys_fs_truncate(vm::cptr<char> path, u64 size)
{
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return CELL_ENOENT;
case fs::error::noent: return {CELL_ENOENT, path};
default: sys_fs.error("sys_fs_truncate(): unknown error %s", error);
}
return CELL_EIO; // ???
return {CELL_EIO, path}; // ???
}
return CELL_OK;
@@ -1175,11 +1173,11 @@ error_code sys_fs_disk_free(vm::ps3::cptr<char> path, vm::ptr<u64> total_free, v
{
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return CELL_ENOENT;
case fs::error::noent: return {CELL_ENOENT, path};
default: sys_fs.error("sys_fs_disk_free(): unknown error %s", error);
}
return CELL_EIO; // ???
return {CELL_EIO, path}; // ???
}
*total_free = info.total_free;
@@ -1196,11 +1194,11 @@ error_code sys_fs_utime(vm::ps3::cptr<char> path, vm::ps3::cptr<CellFsUtimbuf> t
{
switch (auto error = fs::g_tls_error)
{
case fs::error::noent: return CELL_ENOENT;
case fs::error::noent: return {CELL_ENOENT, path};
default: sys_fs.error("sys_fs_utime(): unknown error %s", error);
}
return CELL_EIO; // ???
return {CELL_EIO, path}; // ???
}
return CELL_OK;
+1 -3
View File
@@ -116,9 +116,7 @@ error_code prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_mod
return not_an_error(idm::last_id());
}
const auto loadedkeys = fxm::get_always<LoadedNpdrmKeys_t>();
const ppu_prx_object obj = decrypt_self(fs::file(vfs::get(path)), loadedkeys->devKlic.data());
const ppu_prx_object obj = decrypt_self(fs::file(vfs::get(path)), fxm::get_always<LoadedNpdrmKeys_t>()->devKlic.data());
if (obj != elf_error::ok)
{
+24 -1
View File
@@ -328,7 +328,30 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6
break;
case 0x301: // Depth-buffer (Z-cull)
break;
{
//a4 high = region = (1 << 0) | (zFormat << 4) | (aaFormat << 8);
//a4 low = size = ((width >> 6) << 22) | ((height >> 6) << 6);
//a5 high = start = cullStart&(~0xFFF);
//a5 low = offset = offset;
//a6 high = status0 = (zcullDir << 1) | (zcullFormat << 2) | ((sFunc & 0xF) << 12) | (sRef << 16) | (sMask << 24);
//a6 low = status1 = (0x2000 << 0) | (0x20 << 16);
auto &zcull = render->zculls[a3];
zcull.zFormat = ((a4 >> 32) >> 4) & 0xF;
zcull.aaFormat = ((a4 >> 32) >> 8) & 0xF;
zcull.width = ((a4 & 0xFFFFFFFF) >> 22) << 6;
zcull.height = (((a4 & 0xFFFFFFFF) >> 6) & 0xFF) << 6;
zcull.cullStart = (a5 >> 32);
zcull.offset = (a5 & 0xFFFFFFFF);
zcull.zcullDir = ((a6 >> 32) >> 1) & 0x1;
zcull.zcullFormat = ((a6 >> 32) >> 2) & 0x3FF;
zcull.sFunc = ((a6 >> 32) >> 12) & 0xF;
zcull.sRef = ((a6 >> 32) >> 16) & 0xFF;
zcull.sMask = ((a6 >> 32) >> 24) & 0xFF;
zcull.binded = (a6 & 0xFFFFFFFF) != 0;
}
break;
case 0x302: // something with zcull
break;
case 0x600: // Framebuffer setup
+55 -55
View File
@@ -3,6 +3,7 @@
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Crypto/unself.h"
#include "Crypto/unedat.h"
#include "Crypto/sha1.h"
#include "Loader/ELF.h"
#include "Utilities/bin_patch.h"
@@ -20,20 +21,13 @@ logs::channel sys_spu("sys_spu");
void sys_spu_image::load(const fs::file& stream)
{
const spu_exec_object obj{stream};
const spu_exec_object obj{stream, 0, elf_opt::no_sections + elf_opt::no_data};
if (obj != elf_error::ok)
{
fmt::throw_exception("Failed to load SPU image: %s" HERE, obj.get_error());
}
this->type = SYS_SPU_IMAGE_TYPE_KERNEL;
this->entry_point = obj.header.e_entry;
this->segs.set(vm::alloc(65 * 4096, vm::main));
this->nsegs = 0;
const u32 addr = this->segs.addr() + 4096;
for (const auto& shdr : obj.shdrs)
{
LOG_NOTICE(SPU, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", shdr.sh_type, shdr.sh_addr, shdr.sh_size, shdr.sh_flags);
@@ -43,37 +37,30 @@ void sys_spu_image::load(const fs::file& stream)
{
LOG_NOTICE(SPU, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
if (prog.p_type == SYS_SPU_SEGMENT_TYPE_COPY)
{
auto& seg = segs[nsegs++];
seg.type = prog.p_type;
seg.ls = prog.p_vaddr;
seg.addr = addr + prog.p_vaddr;
seg.size = std::min(prog.p_filesz, prog.p_memsz);
std::memcpy(vm::base(seg.addr), prog.bin.data(), seg.size);
if (prog.p_memsz > prog.p_filesz)
{
auto& zero = segs[nsegs++];
zero.type = SYS_SPU_SEGMENT_TYPE_FILL;
zero.ls = prog.p_vaddr + prog.p_filesz;
zero.addr = 0;
zero.size = prog.p_memsz - seg.size;
}
}
else if (prog.p_type == SYS_SPU_SEGMENT_TYPE_INFO)
{
auto& seg = segs[nsegs++];
seg.type = SYS_SPU_SEGMENT_TYPE_INFO;
seg.ls = prog.p_vaddr;
seg.addr = 0;
seg.size = prog.p_filesz;
}
else
if (prog.p_type != SYS_SPU_SEGMENT_TYPE_COPY && prog.p_type != SYS_SPU_SEGMENT_TYPE_INFO)
{
LOG_ERROR(SPU, "Unknown program type (0x%x)", prog.p_type);
}
}
const u32 mem_size = nsegs * sizeof(sys_spu_segment) + ::size32(stream);
type = SYS_SPU_IMAGE_TYPE_KERNEL;
entry_point = obj.header.e_entry;
nsegs = sys_spu_image::get_nsegs(obj.progs);
segs = vm::cast(vm::alloc(mem_size, vm::main));
const u32 src = segs.addr() + nsegs * sizeof(sys_spu_segment);
stream.seek(0);
stream.read(vm::base(src), stream.size());
if (nsegs < 0 || sys_spu_image::fill(segs, nsegs, obj.progs, src) != nsegs)
{
fmt::throw_exception("Failed to load SPU segments (%d)" HERE, nsegs);
}
vm::page_protect(segs.addr(), ::align(mem_size, 4096), 0, 0, vm::page_writable);
}
void sys_spu_image::free()
@@ -84,7 +71,7 @@ void sys_spu_image::free()
}
}
void sys_spu_image::deploy(u32 loc)
void sys_spu_image::deploy(u32 loc, sys_spu_segment* segs, u32 nsegs)
{
// Segment info dump
std::string dump;
@@ -94,19 +81,19 @@ void sys_spu_image::deploy(u32 loc)
sha1_starts(&sha);
u8 sha1_hash[20];
for (int i = 0; i < nsegs; i++)
for (u32 i = 0; i < nsegs; i++)
{
auto& seg = segs[i];
fmt::append(dump, "\n\t[%d] t=0x%x, ls=0x%x, size=0x%x, addr=0x%x", i, seg.type, seg.ls, seg.size, seg.addr);
// Hash big-endian values
sha1_update(&sha, (uchar*)&seg.type, sizeof(seg.type));
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
// Hash big-endian values
if (seg.type == SYS_SPU_SEGMENT_TYPE_COPY)
{
std::memcpy(vm::base(loc + seg.ls), vm::base(seg.addr), seg.size);
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
sha1_update(&sha, vm::g_base_addr + seg.addr, seg.size);
}
@@ -118,9 +105,15 @@ void sys_spu_image::deploy(u32 loc)
}
std::fill_n(vm::_ptr<u32>(loc + seg.ls), seg.size / 4, seg.addr);
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
sha1_update(&sha, (uchar*)&seg.addr, sizeof(seg.addr));
}
else if (seg.type == SYS_SPU_SEGMENT_TYPE_INFO)
{
const be_t<u32> size = seg.size + 0x14; // Workaround
sha1_update(&sha, (uchar*)&size, sizeof(size));
}
}
sha1_finish(&sha, sha1_hash);
@@ -158,22 +151,24 @@ error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
return CELL_OK;
}
error_code _sys_spu_image_get_information(vm::ptr<sys_spu_image> img, u32 ptr1, u32 ptr2)
error_code _sys_spu_image_get_information(vm::ptr<sys_spu_image> img, vm::ptr<u32> entry_point, vm::ptr<s32> nsegs)
{
sys_spu.todo("_sys_spu_image_get_information(img=*0x%x, 1=*0x%x, 2=*0x%x)", img, ptr1, ptr2);
sys_spu.warning("_sys_spu_image_get_information(img=*0x%x, entry_point=*0x%x, nsegs=*0x%x)", img, entry_point, nsegs);
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_get_information");
*entry_point = img->entry_point;
*nsegs = img->nsegs;
return CELL_OK;
}
error_code sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path)
{
sys_spu.warning("sys_spu_image_open(img=*0x%x, path=%s)", img, path);
const fs::file elf_file = decrypt_self(fs::file(vfs::get(path.get_ptr())));
const fs::file elf_file = decrypt_self(fs::file(vfs::get(path.get_ptr())), fxm::get_always<LoadedNpdrmKeys_t>()->devKlic.data());
if (!elf_file)
{
sys_spu.error("sys_spu_image_open() error: %s not found!", path);
sys_spu.error("sys_spu_image_open() error: failed to open %s!", path);
return CELL_ENOENT;
}
@@ -182,25 +177,29 @@ error_code sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path)
return CELL_OK;
}
error_code _sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 arg3, u32 arg4)
error_code _sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 size, u32 arg4)
{
sys_spu.todo("_sys_spu_image_import(img=*0x%x, src=*0x%x, arg3=0x%x, arg4=0x%x)", img, src, arg3, arg4);
sys_spu.warning("_sys_spu_image_import(img=*0x%x, src=*0x%x, size=0x%x, arg4=0x%x)", img, src, size, arg4);
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_import");
img->load(fs::file{vm::base(src), size});
return CELL_OK;
}
error_code _sys_spu_image_close(vm::ptr<sys_spu_image> img)
{
sys_spu.todo("_sys_spu_image_close(img=*0x%x)", img);
sys_spu.warning("_sys_spu_image_close(img=*0x%x)", img);
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_close");
vm::dealloc(img->segs.addr(), vm::main);
return CELL_OK;
}
error_code _sys_raw_spu_image_load(vm::ptr<sys_spu_image> img, u32 ptr, u32 arg3)
error_code _sys_spu_image_get_segments(vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_segment> segments, s32 nseg)
{
sys_spu.todo("_sys_raw_spu_image_load(img=*0x%x, ptr=*0x%x, arg3=0x%x)", img, ptr, arg3);
sys_spu.error("_sys_spu_image_get_segments(img=*0x%x, segments=*0x%x, nseg=%d)", img, segments, nseg);
fmt::throw_exception("Unimlemented syscall: _sys_raw_spu_image_load");
// TODO: apply SPU patches
std::memcpy(segments.get_ptr(), img->segs.get_ptr(), sizeof(sys_spu_segment) * nseg);
return CELL_OK;
}
error_code sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_num, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg)
@@ -242,7 +241,8 @@ error_code sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_
group->threads[spu_num] = std::move(spu);
group->args[spu_num] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
group->imgs[spu_num] = *img;
group->imgs[spu_num] = std::make_pair(*img, std::vector<sys_spu_segment>());
group->imgs[spu_num].second.assign(img->segs.get_ptr(), img->segs.get_ptr() + img->nsegs);
if (++group->init == group->num)
{
@@ -384,9 +384,9 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
auto& args = group->args[thread->index];
auto& img = group->imgs[thread->index];
img.deploy(thread->offset);
sys_spu_image::deploy(thread->offset, img.second.data(), img.first.nsegs);
thread->pc = img.entry_point;
thread->pc = img.first.entry_point;
thread->cpu_init();
thread->gpr[3] = v128::from64(0, args[0]);
thread->gpr[4] = v128::from64(0, args[1]);
+89 -6
View File
@@ -112,9 +112,92 @@ struct sys_spu_image
vm::ps3::bptr<sys_spu_segment> segs;
be_t<s32> nsegs;
template <bool CountInfo = true, typename Phdrs>
static s32 get_nsegs(const Phdrs& phdrs)
{
s32 num_segs = 0;
for (const auto& phdr : phdrs)
{
if (phdr.p_type != 1 && phdr.p_type != 4)
{
return -1;
}
if (phdr.p_type == 1 && phdr.p_filesz != phdr.p_memsz && phdr.p_filesz)
{
num_segs += 2;
}
else if (phdr.p_type == 1 || CountInfo)
{
num_segs += 1;
}
}
return num_segs;
}
template <bool WriteInfo = true, typename Phdrs>
static s32 fill(vm::ps3::ptr<sys_spu_segment> segs, s32 nsegs, const Phdrs& phdrs, u32 src)
{
s32 num_segs = 0;
for (const auto& phdr : phdrs)
{
if (phdr.p_type == 1)
{
if (phdr.p_filesz)
{
if (num_segs >= nsegs)
{
return -2;
}
auto* seg = &segs[num_segs++];
seg->type = SYS_SPU_SEGMENT_TYPE_COPY;
seg->ls = static_cast<u32>(phdr.p_vaddr);
seg->size = static_cast<u32>(phdr.p_filesz);
seg->addr = static_cast<u32>(phdr.p_offset + src);
}
if (phdr.p_memsz > phdr.p_filesz)
{
if (num_segs >= nsegs)
{
return -2;
}
auto* seg = &segs[num_segs++];
seg->type = SYS_SPU_SEGMENT_TYPE_FILL;
seg->ls = static_cast<u32>(phdr.p_vaddr + phdr.p_filesz);
seg->size = static_cast<u32>(phdr.p_memsz - phdr.p_filesz);
seg->addr = 0;
}
}
else if (WriteInfo && phdr.p_type == 4)
{
if (num_segs >= nsegs)
{
return -2;
}
auto* seg = &segs[num_segs++];
seg->type = SYS_SPU_SEGMENT_TYPE_INFO;
seg->size = 0x20;
seg->addr = static_cast<u32>(phdr.p_offset + 0x14 + src);
}
else if (phdr.p_type != 4)
{
return -1;
}
}
return num_segs;
}
void load(const fs::file& stream);
void free();
void deploy(u32 loc);
static void deploy(u32 loc, sys_spu_segment* segs, u32 nsegs);
};
enum : u32
@@ -153,7 +236,7 @@ struct lv2_spu_group
cond_variable cv; // used to signal waiting PPU thread
std::array<std::shared_ptr<SPUThread>, 256> threads; // SPU Threads
std::array<sys_spu_image, 256> imgs; // SPU Images
std::array<std::pair<sys_spu_image, std::vector<sys_spu_segment>>, 256> imgs; // SPU Images
std::array<std::array<u64, 4>, 256> args; // SPU Thread Arguments
std::weak_ptr<lv2_event_queue> ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events
@@ -203,11 +286,11 @@ class ppu_thread;
// Syscalls
error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu);
error_code _sys_spu_image_get_information(vm::ps3::ptr<sys_spu_image> img, u32 ptr1, u32 ptr2);
error_code _sys_spu_image_get_information(vm::ps3::ptr<sys_spu_image> img, vm::ps3::ptr<u32> entry_point, vm::ps3::ptr<s32> nsegs);
error_code sys_spu_image_open(vm::ps3::ptr<sys_spu_image> img, vm::ps3::cptr<char> path);
error_code _sys_spu_image_import(vm::ps3::ptr<sys_spu_image> img, u32 src, u32 arg3, u32 arg4);
error_code _sys_spu_image_import(vm::ps3::ptr<sys_spu_image> img, u32 src, u32 size, u32 arg4);
error_code _sys_spu_image_close(vm::ps3::ptr<sys_spu_image> img);
error_code _sys_raw_spu_image_load(vm::ps3::ptr<sys_spu_image> img, u32 ptr, u32 arg3);
error_code _sys_spu_image_get_segments(vm::ps3::ptr<sys_spu_image> img, vm::ps3::ptr<sys_spu_segment> segments, s32 nseg);
error_code sys_spu_thread_initialize(vm::ps3::ptr<u32> thread, u32 group, u32 spu_num, vm::ps3::ptr<sys_spu_image>, vm::ps3::ptr<sys_spu_thread_attribute>, vm::ps3::ptr<sys_spu_thread_argument>);
error_code sys_spu_thread_set_argument(u32 id, vm::ps3::ptr<sys_spu_thread_argument> arg);
error_code sys_spu_thread_group_create(vm::ps3::ptr<u32> id, u32 num, s32 prio, vm::ps3::ptr<sys_spu_thread_group_attribute> attr);
@@ -215,7 +298,7 @@ error_code sys_spu_thread_group_destroy(u32 id);
error_code sys_spu_thread_group_start(ppu_thread&, u32 id);
error_code sys_spu_thread_group_suspend(u32 id);
error_code sys_spu_thread_group_resume(u32 id);
error_code sys_spu_thread_group_yield(u32 id);
error_code sys_spu_thread_group_yield(u32 id);
error_code sys_spu_thread_group_terminate(u32 id, s32 value);
error_code sys_spu_thread_group_join(ppu_thread&, u32 id, vm::ps3::ptr<u32> cause, vm::ps3::ptr<u32> status);
error_code sys_spu_thread_group_set_priority(u32 id, s32 priority);
+8 -1
View File
@@ -26,7 +26,9 @@ public:
// Get object location
std::weak_ptr<T>& wptr = g_ipc.m_map[ipc_key];
if ((out && !(*out = wptr.lock())) || wptr.expired())
std::shared_ptr<T> old;
if ((out && !(old = wptr.lock())) || wptr.expired())
{
// Call a function which must return the object
if (out)
@@ -42,6 +44,11 @@ public:
return true;
}
if (out)
{
*out = std::move(old);
}
return false;
}
+2
View File
@@ -50,6 +50,7 @@ void idm::init()
{
// Allocate
g_map.resize(id_manager::typeinfo::get_count());
idm::clear();
}
void idm::clear()
@@ -75,6 +76,7 @@ void fxm::init()
{
// Allocate
g_vec.resize(id_manager::typeinfo::get_count());
fxm::clear();
}
void fxm::clear()
+15 -4
View File
@@ -6,6 +6,7 @@
#include "Utilities/VirtualMemory.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/lv2/sys_memory.h"
#include "Emu/RSX/GSRender.h"
#ifdef _WIN32
#include <Windows.h>
@@ -656,6 +657,7 @@ namespace vm
if (found != m_map.end())
{
const u32 size = found->second;
const auto rsxthr = fxm::get<GSRender>();
// Remove entry
m_map.erase(found);
@@ -663,6 +665,9 @@ namespace vm
// Unmap "real" memory pages
_page_unmap(addr, size);
// Notify rsx to invalidate range
if (rsxthr != nullptr) rsxthr->on_notify_memory_unmapped(addr, size);
// Write supplementary info if necessary
if (sup_out) *sup_out = m_sup[addr];
@@ -675,10 +680,8 @@ namespace vm
return 0;
}
u32 block_t::used()
u32 block_t::imp_used(const vm::writer_lock&)
{
reader_lock lock;
u32 result = 0;
for (auto& entry : m_map)
@@ -689,6 +692,13 @@ namespace vm
return result;
}
u32 block_t::used()
{
writer_lock lock(0);
return imp_used(lock);
}
std::shared_ptr<block_t> map(u32 addr, u32 size, u64 flags)
{
writer_lock lock(0);
@@ -734,7 +744,7 @@ namespace vm
{
if (*it && (*it)->addr == addr)
{
if (must_be_empty && (!it->unique() || (*it)->used()))
if (must_be_empty && (!it->unique() || (*it)->imp_used(lock)))
{
return *it;
}
@@ -787,6 +797,7 @@ namespace vm
std::make_shared<block_t>(0xD0000000, 0x10000000), // stack
std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU reserved
std::make_shared<block_t>(0x40000000, 0x10000000), // rsx contexts
std::make_shared<block_t>(0x30000000, 0x10000000), // main extend
};
}
}
+3
View File
@@ -156,6 +156,9 @@ namespace vm
// Unmap memory at specified location previously returned by alloc(), return size
u32 dealloc(u32 addr, u32* sup_out = nullptr);
// Internal
u32 imp_used(const vm::writer_lock&);
// Get allocated memory count
u32 used();
};
+10
View File
@@ -96,6 +96,16 @@ namespace vm
{
return m_size / SIZE_32(T);
}
auto begin() const
{
return *this + 0;
}
auto end() const
{
return *this + get_count();
}
};
// LE variable
+5 -4
View File
@@ -51,21 +51,22 @@ std::string CgBinaryDisasm::GetScaMaskDisasm()
std::string CgBinaryDisasm::GetDSTDisasm(bool isSca)
{
std::string ret;
std::string mask = GetMaskDisasm(isSca);
switch (isSca ? 0x1f : d3.dst)
switch ((isSca && d3.sca_dst_tmp != 0x3f) ? 0x1f : d3.dst)
{
case 0x1f:
ret += isSca ? fmt::format("R%d", d3.sca_dst_tmp) + GetScaMaskDisasm() : fmt::format("R%d", d0.dst_tmp) + GetVecMaskDisasm();
ret += (isSca ? fmt::format("R%d", d3.sca_dst_tmp) : fmt::format("R%d", d0.dst_tmp)) + mask;
break;
default:
if (d3.dst > 15)
LOG_ERROR(RSX, "dst index out of range: %u", d3.dst);
ret += fmt::format("o[%d]", d3.dst) + GetVecMaskDisasm();
ret += fmt::format("o[%d]", d3.dst) + mask;
// Vertex Program supports double destinations, notably in MOV
if (d0.dst_tmp != 0x3f)
ret += fmt::format(" R%d", d0.dst_tmp) + GetVecMaskDisasm();
ret += fmt::format(" R%d", d0.dst_tmp) + mask;
break;
}
+1 -15
View File
@@ -610,12 +610,12 @@ bool is_primitive_native(rsx::primitive_type draw_mode)
case rsx::primitive_type::line_strip:
case rsx::primitive_type::triangles:
case rsx::primitive_type::triangle_strip:
case rsx::primitive_type::quad_strip:
return true;
case rsx::primitive_type::line_loop:
case rsx::primitive_type::polygon:
case rsx::primitive_type::triangle_fan:
case rsx::primitive_type::quads:
case rsx::primitive_type::quad_strip:
return false;
}
fmt::throw_exception("Wrong primitive type" HERE);
@@ -641,8 +641,6 @@ u32 get_index_count(rsx::primitive_type draw_mode, u32 initial_index_count)
return (initial_index_count - 2) * 3;
case rsx::primitive_type::quads:
return (6 * initial_index_count) / 4;
case rsx::primitive_type::quad_strip:
return (6 * (initial_index_count - 2)) / 2;
default:
return 0;
}
@@ -691,18 +689,6 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst,
}
return;
case rsx::primitive_type::quad_strip:
for (unsigned i = 0; i < (count - 2) / 2; i++)
{
// First triangle
typedDst[6 * i] = 2 * i;
typedDst[6 * i + 1] = 2 * i + 1;
typedDst[6 * i + 2] = 2 * i + 2;
// Second triangle
typedDst[6 * i + 3] = 2 * i + 2;
typedDst[6 * i + 4] = 2 * i + 1;
typedDst[6 * i + 5] = 2 * i + 3;
}
return;
case rsx::primitive_type::points:
case rsx::primitive_type::lines:
case rsx::primitive_type::line_strip:
+347
View File
@@ -0,0 +1,347 @@
#pragma once
#include <sstream>
#include "ShaderParam.h"
namespace program_common
{
static void insert_compare_op(std::ostream& OS)
{
OS << "bool comparison_passes(float a, float b, uint func)\n";
OS << "{\n";
OS << " switch (func)\n";
OS << " {\n";
OS << " default:\n";
OS << " case 0: return false; //never\n";
OS << " case 1: return (a < b); //less\n";
OS << " case 2: return (a == b); //equal\n";
OS << " case 3: return (a <= b); //lequal\n";
OS << " case 4: return (a > b); //greater\n";
OS << " case 5: return (a != b); //nequal\n";
OS << " case 6: return (a >= b); //gequal\n";
OS << " case 7: return true; //always\n";
OS << " }\n";
OS << "}\n\n";
}
static void insert_fog_declaration(std::ostream& OS, const std::string wide_vector_type, const std::string input_coord, bool declare = false)
{
std::string template_body;
if (!declare)
template_body += "$T fetch_fog_value(uint mode)\n";
else
template_body += "$T fetch_fog_value(uint mode, $T $I)\n";
template_body += "{\n";
template_body += " $T result = $T(0., 0., 0., 0.);\n";
template_body += " switch(mode)\n";
template_body += " {\n";
template_body += " default:\n";
template_body += " return result;\n";
template_body += " case 0:\n";
template_body += " //linear\n";
template_body += " result = $T(fog_param1 * $I.x + (fog_param0 - 1.), fog_param1 * $I.x + (fog_param0 - 1.), 0., 0.);\n";
template_body += " break;\n";
template_body += " case 1:\n";
template_body += " //exponential\n";
template_body += " result = $T(11.084 * (fog_param1 * $I.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * $I.x + fog_param0 - 1.5)), 0., 0.);\n";
template_body += " break;\n";
template_body += " case 2:\n";
template_body += " //exponential2\n";
template_body += " result = $T(4.709 * (fog_param1 * $I.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * $I.x + fog_param0 - 1.5), 2.)), 0., 0.);\n";
template_body += " break;\n";
template_body += " case 3:\n";
template_body += " //exponential_abs\n";
template_body += " result = $T(11.084 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs($I.x) + fog_param0 - 1.5)), 0., 0.);\n";
template_body += " break;\n";
template_body += " case 4:\n";
template_body += " //exponential2_abs\n";
template_body += " result = $T(4.709 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), 2.)), 0., 0.);\n";
template_body += " break;\n";
template_body += " case 5:\n";
template_body += " //linear_abs\n";
template_body += " result = $T(fog_param1 * abs($I.x) + (fog_param0 - 1.), fog_param1 * abs($I.x) + (fog_param0 - 1.), 0., 0.);\n";
template_body += " break;\n";
template_body += " }\n";
template_body += "\n";
template_body += " result.y = clamp(result.y, 0., 1.);\n";
template_body += " return result;\n";
template_body += "}\n\n";
std::pair<std::string, std::string> replacements[] =
{std::make_pair("$T", wide_vector_type),
std::make_pair("$I", input_coord)};
OS << fmt::replace_all(template_body, replacements);
}
}
namespace glsl
{
enum program_domain
{
glsl_vertex_program = 0,
glsl_fragment_program = 1
};
enum glsl_rules
{
glsl_rules_opengl4,
glsl_rules_rpirv
};
static std::string getFloatTypeNameImpl(size_t elementCount)
{
switch (elementCount)
{
default:
abort();
case 1:
return "float";
case 2:
return "vec2";
case 3:
return "vec3";
case 4:
return "vec4";
}
}
static std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::string &Op1)
{
switch (f)
{
case COMPARE::FUNCTION_SEQ:
return "equal(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SGE:
return "greaterThanEqual(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SGT:
return "greaterThan(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SLE:
return "lessThanEqual(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SLT:
return "lessThan(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SNE:
return "notEqual(" + Op0 + ", " + Op1 + ")";
}
fmt::throw_exception("Unknown compare function" HERE);
}
static void insert_vertex_input_fetch(std::stringstream& OS, glsl_rules rules, bool glsl4_compliant=true)
{
std::string vertex_id_name = (rules == glsl_rules_opengl4) ? "gl_VertexID" : "gl_VertexIndex";
//Actually decode a vertex attribute from a raw byte stream
OS << "struct attribute_desc\n";
OS << "{\n";
OS << " int type;\n";
OS << " int attribute_size;\n";
OS << " int starting_offset;\n";
OS << " int stride;\n";
OS << " int swap_bytes;\n";
OS << " int is_volatile;\n";
OS << " int frequency;\n";
OS << " int divisor;\n";
OS << " int modulo;\n";
OS << "};\n\n";
OS << "uint get_bits(uvec4 v, int swap)\n";
OS << "{\n";
OS << " if (swap != 0) return (v.w | v.z << 8 | v.y << 16 | v.x << 24);\n";
OS << " return (v.x | v.y << 8 | v.z << 16 | v.w << 24);\n";
OS << "}\n\n";
OS << "uint get_bits(uvec2 v, int swap)\n";
OS << "{\n";
OS << " if (swap != 0) return (v.y | v.x << 8);\n";
OS << " return (v.x | v.y << 8);\n";
OS << "}\n\n";
OS << "int preserve_sign_s16(uint bits)\n";
OS << "{\n";
OS << " //convert raw 16 bit value into signed 32-bit integer counterpart\n";
OS << " uint sign = bits & 0x8000;\n";
OS << " if (sign != 0) return int(bits | 0xFFFF0000);\n";
OS << " return int(bits);\n";
OS << "}\n\n";
//For intel GPUs which cannot access vectors in indexed mode (driver bug? or glsl version too low?)
if (!glsl4_compliant)
{
OS << "void mov(inout vec4 vector, in int index, in float scalar)\n";
OS << "{\n";
OS << " switch(index)\n";
OS << " {\n";
OS << " case 0: vector.x = scalar; return;\n";
OS << " case 1: vector.y = scalar; return;\n";
OS << " case 2: vector.z = scalar; return;\n";
OS << " case 3: vector.w = scalar; return;\n";
OS << " }\n";
OS << "}\n";
}
else
{
OS << "#define mov(v, i, s) v[i] = s\n";
}
OS << "#define get_s16(v, s) preserve_sign_s16(get_bits(v, s))\n\n";
OS << "vec4 fetch_attribute(attribute_desc desc, int vertex_id, usamplerBuffer input_stream)\n";
OS << "{\n";
OS << " vec4 result = vec4(0., 0., 0., 1.);\n";
OS << " vec4 scale = vec4(1.);\n";
OS << " uvec4 tmp;\n";
OS << " uint bits;\n";
OS << " bool reverse_order = false;\n";
OS << "\n";
OS << " int first_byte = (vertex_id * desc.stride) + desc.starting_offset;\n";
OS << " for (int n = 0; n < 4; n++)\n";
OS << " {\n";
OS << " if (n == desc.attribute_size) break;\n";
OS << "\n";
OS << " switch (desc.type)\n";
OS << " {\n";
OS << " case 0:\n";
OS << " //signed normalized 16-bit\n";
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
OS << " mov(result, n, get_s16(tmp.xy, desc.swap_bytes));\n";
OS << " mov(scale, n, 32767.);\n";
OS << " break;\n";
OS << " case 1:\n";
OS << " //float\n";
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
OS << " tmp.z = texelFetch(input_stream, first_byte++).x;\n";
OS << " tmp.w = texelFetch(input_stream, first_byte++).x;\n";
OS << " mov(result, n, uintBitsToFloat(get_bits(tmp, desc.swap_bytes)));\n";
OS << " break;\n";
OS << " case 2:\n";
OS << " //half\n";
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
OS << " mov(result, n, unpackHalf2x16(uint(get_bits(tmp.xy, desc.swap_bytes))).x);\n";
OS << " break;\n";
OS << " case 3:\n";
OS << " //unsigned byte\n";
OS << " mov(result, n, texelFetch(input_stream, first_byte++).x);\n";
OS << " mov(scale, n, 255.);\n";
OS << " reverse_order = (desc.swap_bytes != 0);\n";
OS << " break;\n";
OS << " case 4:\n";
OS << " //signed word\n";
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
OS << " mov(result, n, get_s16(tmp.xy, desc.swap_bytes));\n";
OS << " break;\n";
OS << " case 5:\n";
OS << " //cmp\n";
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
OS << " tmp.z = texelFetch(input_stream, first_byte++).x;\n";
OS << " tmp.w = texelFetch(input_stream, first_byte++).x;\n";
OS << " bits = get_bits(tmp, desc.swap_bytes);\n";
OS << " result.x = preserve_sign_s16((bits & 0x7FF) << 5);\n";
OS << " result.y = preserve_sign_s16(((bits >> 11) & 0x7FF) << 5);\n";
OS << " result.z = preserve_sign_s16(((bits >> 22) & 0x3FF) << 6);\n";
OS << " result.w = 1.;\n";
OS << " scale = vec4(32767., 32767., 32767., 1.);\n";
OS << " break;\n";
OS << " case 6:\n";
OS << " //ub256\n";
OS << " mov(result, n, float(texelFetch(input_stream, first_byte++).x));\n";
OS << " reverse_order = (desc.swap_bytes != 0);\n";
OS << " break;\n";
OS << " }\n";
OS << " }\n\n";
OS << " result /= scale;\n";
OS << " return (reverse_order)? result.wzyx: result;\n";
OS << "}\n\n";
OS << "attribute_desc fetch_desc(int location)\n";
OS << "{\n";
OS << " attribute_desc result;\n";
OS << " int attribute_flags = input_attributes[location].w;\n";
OS << " result.type = input_attributes[location].x;\n";
OS << " result.attribute_size = input_attributes[location].y;\n";
OS << " result.starting_offset = input_attributes[location].z;\n";
OS << " result.stride = attribute_flags & 0xFF;\n";
OS << " result.swap_bytes = (attribute_flags >> 8) & 0x1;\n";
OS << " result.is_volatile = (attribute_flags >> 9) & 0x1;\n";
OS << " result.frequency = (attribute_flags >> 10) & 0x3;\n";
OS << " result.modulo = (attribute_flags >> 12) & 0x1;\n";
OS << " result.divisor = (attribute_flags >> 13) & 0xFFFF;\n";
OS << " return result;\n";
OS << "}\n\n";
OS << "vec4 read_location(int location)\n";
OS << "{\n";
OS << " attribute_desc desc = fetch_desc(location);\n";
OS << "\n";
OS << " int vertex_id = " << vertex_id_name << " - int(vertex_base_index);\n";
OS << " if (desc.frequency == 0)\n";
OS << " vertex_id = 0;\n";
OS << " else if (desc.frequency > 1)\n";
OS << " {\n";
OS << " //if a vertex modifier is active; vertex_base must be 0 and is ignored\n";
OS << " if (desc.modulo != 0)\n";
OS << " vertex_id = " << vertex_id_name << " % desc.divisor;\n";
OS << " else\n";
OS << " vertex_id = " << vertex_id_name << " / desc.divisor;\n";
OS << " }\n";
OS << "\n";
OS << " if (desc.is_volatile != 0)\n";
OS << " return fetch_attribute(desc, vertex_id, volatile_input_stream);\n";
OS << " else\n";
OS << " return fetch_attribute(desc, vertex_id, persistent_input_stream);\n";
OS << "}\n\n";
}
static void insert_glsl_legacy_function(std::ostream& OS, glsl::program_domain domain)
{
OS << "vec4 lit_legacy(vec4 val)";
OS << "{\n";
OS << " vec4 clamped_val = val;\n";
OS << " clamped_val.x = max(val.x, 0.);\n";
OS << " clamped_val.y = max(val.y, 0.);\n";
OS << " vec4 result;\n";
OS << " result.x = 1.;\n";
OS << " result.w = 1.;\n";
OS << " result.y = clamped_val.x;\n";
OS << " result.z = clamped_val.x > 0. ? exp(clamped_val.w * log(max(clamped_val.y, 1.E-10))) : 0.;\n";
OS << " return result;\n";
OS << "}\n\n";
if (domain == glsl::program_domain::glsl_vertex_program)
return;
program_common::insert_compare_op(OS);
//NOTE: After testing with GOW, the w component is either the original depth or wraps around to the x component
//Since component.r == depth_value with some precision loss, just use the precise depth value for now (further testing needed)
OS << "vec4 decodeLinearDepth(float depth_value)\n";
OS << "{\n";
OS << " uint value = uint(depth_value * 16777215);\n";
OS << " uint b = (value & 0xff);\n";
OS << " uint g = (value >> 8) & 0xff;\n";
OS << " uint r = (value >> 16) & 0xff;\n";
OS << " return vec4(float(r)/255., float(g)/255., float(b)/255., depth_value);\n";
OS << "}\n\n";
OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord)\n";
OS << "{\n";
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";
}
static void insert_fog_declaration(std::ostream& OS)
{
program_common::insert_fog_declaration(OS, "vec4", "fog_c");
}
}
+11 -3
View File
@@ -28,7 +28,7 @@ bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const R
return false;
if (binary1.data.size() != binary2.data.size())
return false;
if (binary1.rsx_vertex_inputs != binary2.rsx_vertex_inputs)
if (!binary1.skip_vertex_input_check && !binary2.skip_vertex_input_check && binary1.rsx_vertex_inputs != binary2.rsx_vertex_inputs)
return false;
const qword *instBuffer1 = (const qword*)binary1.data.data();
@@ -107,12 +107,20 @@ size_t fragment_program_hash::operator()(const RSXFragmentProgram& program) cons
bool fragment_program_compare::operator()(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2) const
{
if (binary1.texture_dimensions != binary2.texture_dimensions || binary1.unnormalized_coords != binary2.unnormalized_coords ||
binary1.height != binary2.height || binary1.origin_mode != binary2.origin_mode || binary1.pixel_center_mode != binary2.pixel_center_mode ||
binary1.back_color_diffuse_output != binary2.back_color_diffuse_output || binary1.back_color_specular_output != binary2.back_color_specular_output ||
binary1.front_back_color_enabled != binary2.front_back_color_enabled || binary1.alpha_func != binary2.alpha_func ||
binary1.front_back_color_enabled != binary2.front_back_color_enabled ||
binary1.shadow_textures != binary2.shadow_textures || binary1.redirected_textures != binary2.redirected_textures)
return false;
for (u8 index = 0; index < 16; ++index)
{
if (binary1.textures_alpha_kill[index] != binary2.textures_alpha_kill[index])
return false;
if (binary1.textures_zfunc[index] != binary2.textures_zfunc[index])
return false;
}
const qword *instBuffer1 = (const qword*)binary1.addr;
const qword *instBuffer2 = (const qword*)binary2.addr;
size_t instIndex = 0;
+11 -3
View File
@@ -5,6 +5,7 @@
#include "Emu/Memory/vm.h"
#include "Utilities/GSL.h"
#include "Utilities/hash.h"
enum class SHADER_TYPE
{
@@ -93,9 +94,9 @@ class program_state_cache
size_t operator()(const pipeline_key &key) const
{
size_t hashValue = 0;
hashValue ^= std::hash<unsigned>()(key.vertex_program_id);
hashValue ^= std::hash<unsigned>()(key.fragment_program_id);
hashValue ^= std::hash<pipeline_properties>()(key.properties);
hashValue ^= rpcs3::hash_base<unsigned>(key.vertex_program_id);
hashValue ^= rpcs3::hash_base<unsigned>(key.fragment_program_id);
hashValue ^= rpcs3::hash_struct<pipeline_properties>(key.properties);
return hashValue;
}
};
@@ -110,6 +111,7 @@ class program_state_cache
protected:
size_t m_next_id = 0;
bool m_cache_miss_flag;
binary_to_vertex_program m_vertex_shader_cache;
binary_to_fragment_program m_fragment_shader_cache;
std::unordered_map <pipeline_key, pipeline_storage_type, pipeline_key_hash, pipeline_key_compare> m_storage;
@@ -197,7 +199,10 @@ public:
{
const auto I = m_storage.find(key);
if (I != m_storage.end())
{
m_cache_miss_flag = false;
return I->second;
}
}
LOG_NOTICE(RSX, "Add program :");
@@ -205,6 +210,9 @@ public:
LOG_NOTICE(RSX, "*** fp id = %d", fragment_program.id);
m_storage[key] = backend_traits::build_pipeline(vertex_program, fragment_program, pipelineProperties, std::forward<Args>(args)...);
m_cache_miss_flag = true;
LOG_SUCCESS(RSX, "New program compiled successfully");
return m_storage[key];
}
@@ -43,7 +43,7 @@ std::string VertexProgramDecompiler::GetDST(bool isSca)
std::string mask = GetMask(isSca);
switch (isSca ? 0x1f : d3.dst)
switch ((isSca && d3.sca_dst_tmp != 0x3f) ? 0x1f : d3.dst)
{
case 0x1f:
ret += m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp)) + mask;
@@ -209,6 +209,7 @@ std::string VertexProgramDecompiler::Format(const std::string& code)
{ "$awm", std::bind(std::mem_fn(&VertexProgramDecompiler::AddAddrRegWithoutMask), this) },
{ "$am", std::bind(std::mem_fn(&VertexProgramDecompiler::AddAddrMask), this) },
{ "$a", std::bind(std::mem_fn(&VertexProgramDecompiler::AddAddrReg), this) },
{ "$vm", std::bind(std::mem_fn(&VertexProgramDecompiler::GetVecMask), this) },
{ "$t", std::bind(std::mem_fn(&VertexProgramDecompiler::GetTex), this) },
@@ -373,7 +374,7 @@ void VertexProgramDecompiler::SetDSTSca(const std::string& code)
SetDST(true, code);
}
std::string VertexProgramDecompiler::NotZeroPositive(const std::string code)
std::string VertexProgramDecompiler::NotZeroPositive(const std::string& code)
{
return "max(" + code + ", 1.E-10)";
}
@@ -606,8 +607,9 @@ std::string VertexProgramDecompiler::Decompile()
case RSX_VEC_OPCODE_MAX: SetDSTVec("max($0, $1)"); break;
case RSX_VEC_OPCODE_SLT: SetDSTVec(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SLT, "$0", "$1") + ")"); break;
case RSX_VEC_OPCODE_SGE: SetDSTVec(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SGE, "$0", "$1") + ")"); break;
// Note: It looks like ARL opcode ignore input/output swizzle mask (SH3)
case RSX_VEC_OPCODE_ARL: AddCode("$ifcond $awm = " + getIntTypeName(4) + "($0);"); break;
// Note: ARL uses the vec mask to determine channels and ignores the src input mask
// Tested with SH3, BLES00574 (G-Force) and NPUB90415 (Dead Space 2 Demo)
case RSX_VEC_OPCODE_ARL: AddCode("$ifcond $awm$vm = " + getIntTypeName(4) + "($0)$vm;"); break;
case RSX_VEC_OPCODE_FRC: SetDSTVec(getFunction(FUNCTION::FUNCTION_FRACT)); break;
case RSX_VEC_OPCODE_FLR: SetDSTVec("floor($0)"); break;
case RSX_VEC_OPCODE_SEQ: SetDSTVec(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")"); break;
@@ -61,7 +61,7 @@ struct VertexProgramDecompiler
const std::vector<u32>& m_data;
ParamArray m_parr;
std::string NotZeroPositive(const std::string code);
std::string NotZeroPositive(const std::string& code);
std::string GetMask(bool is_sca);
std::string GetVecMask();
std::string GetScaMask();
+4 -4
View File
@@ -42,7 +42,7 @@ namespace
fmt::throw_exception("Wrong vector size %d" HERE, size);
}
u32 get_vertex_count(const std::vector<std::pair<u32, u32> > first_count_commands)
u32 get_vertex_count(const std::vector<std::pair<u32, u32> >& first_count_commands)
{
u32 vertex_count = 0;
for (const auto &pair : first_count_commands)
@@ -89,7 +89,7 @@ void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex)
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + 512));
fill_scale_offset_data(mapped_buffer, true);
fill_user_clip_data((char*)mapped_buffer + 64);
fill_fragment_state_buffer((char *)mapped_buffer + 128, m_fragment_program);
fill_fragment_state_buffer((char *)mapped_buffer + 128, current_fragment_program);
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + 512));
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = {
@@ -124,7 +124,7 @@ void D3D12GSRender::upload_and_bind_vertex_shader_constants(size_t descriptor_in
D3D12_CONSTANT_BUFFER_VIEW_DESC D3D12GSRender::upload_fragment_shader_constants()
{
// Get constant from fragment program
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(m_fragment_program);
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(current_fragment_program);
// Multiple of 256 never 0
buffer_size = (buffer_size + 255) & ~255;
@@ -132,7 +132,7 @@ D3D12_CONSTANT_BUFFER_VIEW_DESC D3D12GSRender::upload_fragment_shader_constants(
size_t offset = 0;
float *mapped_buffer = m_buffer_data.map<float>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
m_pso_cache.fill_fragment_constants_buffer({ mapped_buffer, ::narrow<int>(buffer_size) }, m_fragment_program);
m_pso_cache.fill_fragment_constants_buffer({ mapped_buffer, ::narrow<int>(buffer_size) }, current_fragment_program);
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
return {
@@ -124,6 +124,8 @@ void insert_d3d12_legacy_function(std::ostream& OS, bool is_fragment_program)
if (!is_fragment_program)
return;
program_common::insert_compare_op(OS);
OS << "uint packSnorm2x16(float2 val)";
OS << "{\n";
OS << " uint high_bits = round(clamp(val.x, -1., 1.) * 32767.);\n";
@@ -1,6 +1,7 @@
#pragma once
#include "../Common/ShaderParam.h"
#include "../Common/GLSLCommon.h"
std::string getFloatTypeNameImp(size_t elementCount);
std::string getFunctionImp(FUNCTION f);
+1 -1
View File
@@ -304,7 +304,7 @@ D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(rsx::primitive_type draw_mode)
case rsx::primitive_type::triangle_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
case rsx::primitive_type::triangle_fan: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
case rsx::primitive_type::quads: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
case rsx::primitive_type::quad_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
case rsx::primitive_type::quad_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
case rsx::primitive_type::polygon: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
}
fmt::throw_exception("Invalid draw mode (0x%x)" HERE, (u32)draw_mode);
@@ -42,8 +42,12 @@ void D3D12FragmentDecompiler::insertHeader(std::stringstream & OS)
OS << " float4 userClipFactor[2];\n";
OS << " float fog_param0;\n";
OS << " float fog_param1;\n";
OS << " int isAlphaTested;\n";
OS << " float alphaRef;\n";
OS << " uint alpha_test;\n";
OS << " float alpha_ref;\n";
OS << " uint alpha_func;\n";
OS << " uint fog_mode;\n";
OS << " uint window_origin;\n";
OS << " uint window_height;\n";
OS << " float4 texture_parameters[16];\n";
OS << "};\n";
}
@@ -151,38 +155,6 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS)
namespace
{
// Note: It's not clear whether fog is computed per pixel or per vertex.
// But it makes more sense to compute exp of interpoled value than to interpolate exp values.
void insert_fog_declaration(std::stringstream & OS, rsx::fog_mode mode)
{
switch (mode)
{
case rsx::fog_mode::linear:
OS << " float4 fogc = float4(fog_param1 * In.fogc.x + (fog_param0 - 1.), fog_param1 * In.fogc.x + (fog_param0 - 1.), 0., 0.);\n";
break;
case rsx::fog_mode::exponential:
OS << " float4 fogc = float4(11.084 * (fog_param1 * In.fogc.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * In.fogc.x + fog_param0 - 1.5)), 0., 0.);\n";
break;
case rsx::fog_mode::exponential2:
OS << " float4 fogc = float4(4.709 * (fog_param1 * In.fogc.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * In.fogc.x + fog_param0 - 1.5), 2.)), 0., 0.);\n";
break;
case rsx::fog_mode::linear_abs:
OS << " float4 fogc = float4(fog_param1 * abs(In.fogc.x) + (fog_param0 - 1.), fog_param1 * abs(In.fogc.x) + (fog_param0 - 1.), 0., 0.);\n";
break;
case rsx::fog_mode::exponential_abs:
OS << " float4 fogc = float4(11.084 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5)), 0., 0.);\n";
break;
case rsx::fog_mode::exponential2_abs:
OS << " float4 fogc = float4(4.709 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5), 2.)), 0., 0.);\n";
break;
default:
OS << " float4 fogc = float4(0., 0., 0., 0.);\n";
return;
}
OS << " fogc.y = saturate(fogc.y);\n";
}
std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index)
{
std::string tex_name = "tex" + std::to_string(index) + ".Sample";
@@ -205,6 +177,18 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS)
{
insert_d3d12_legacy_function(OS, true);
for (const ParamType &PT : m_parr.params[PF_PARAM_IN])
{
for (const ParamItem &PI : PT.items)
{
if (PI.name == "fogc")
{
program_common::insert_fog_declaration(OS, "float4", "fogc", true);
break;
}
}
}
const std::set<std::string> output_value =
{
"r0", "r1", "r2", "r3", "r4",
@@ -231,7 +215,7 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS)
}
if (PI.name == "fogc")
{
insert_fog_declaration(OS, m_prog.fog_equation);
OS << " float4 fogc = fetch_fog_value(fog_mode, In.fogc);\n";
continue;
}
if (PI.name == "ssa")
@@ -239,10 +223,9 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS)
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";\n";
}
}
// A bit unclean, but works.
OS << " " << "float4 wpos = In.Position;\n";
if (m_prog.origin_mode == rsx::window_origin::bottom)
OS << " wpos.y = (" << std::to_string(m_prog.height) << " - wpos.y);\n";
OS << " float4 wpos = In.Position;\n";
OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n";
OS << " float4 ssa = is_front_face ? float4(1., 1., 1., 1.) : float4(-1., -1., -1., -1.);\n";
// Declare output
@@ -363,7 +346,7 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
}
}
OS << make_comparison_test(m_prog.alpha_func, "isAlphaTested && ", "Out." + first_output_name + ".a", "alphaRef");
OS << " if (alpha_test != 0 && !comparison_passes(Out." << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n";
}
OS << " return Out;\n";
+1 -1
View File
@@ -329,7 +329,7 @@ void D3D12GSRender::end()
std::chrono::time_point<steady_clock> program_load_end = steady_clock::now();
m_timers.program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
if (!m_fragment_program.valid)
if (!current_fragment_program.valid)
{
rsx::thread::end();
return;
-2
View File
@@ -61,8 +61,6 @@ private:
data_cache m_texture_cache;
bool invalidate_address(u32 addr);
RSXVertexProgram m_vertex_program;
RSXFragmentProgram m_fragment_program;
PipelineStateObjectCache m_pso_cache;
std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t> m_current_pso;
+5 -5
View File
@@ -53,10 +53,10 @@ void D3D12GSRender::load_program()
return std::make_tuple(true, native_pitch);
};
m_vertex_program = get_current_vertex_program();
m_fragment_program = get_current_fragment_program(rtt_lookup_func);
get_current_vertex_program();
get_current_fragment_program(rtt_lookup_func);
if (!m_fragment_program.valid)
if (!current_fragment_program.valid)
return;
D3D12PipelineProperties prop = {};
@@ -308,12 +308,12 @@ void D3D12GSRender::load_program()
}
}
m_current_pso = m_pso_cache.getGraphicPipelineState(m_vertex_program, m_fragment_program, prop, m_device.Get(), m_shared_root_signature.Get());
m_current_pso = m_pso_cache.getGraphicPipelineState(current_vertex_program, current_fragment_program, prop, m_device.Get(), m_shared_root_signature.Get());
return;
}
std::pair<std::string, std::string> D3D12GSRender::get_programs() const
{
return std::make_pair(m_pso_cache.get_transform_program(m_vertex_program).content, m_pso_cache.get_shader_program(m_fragment_program).content);
return std::make_pair(m_pso_cache.get_transform_program(current_vertex_program).content, m_pso_cache.get_shader_program(current_fragment_program).content);
}
#endif
@@ -298,6 +298,9 @@ void D3D12GSRender::copy_render_target_to_dma_location()
int clip_w = rsx::method_registers.surface_clip_width();
int clip_h = rsx::method_registers.surface_clip_height();
if (clip_w == 0 || clip_h == 0)
return;
size_t depth_row_pitch = align(clip_w * 4, 256);
size_t depth_buffer_offset_in_heap = 0;
-68
View File
@@ -1,22 +1,6 @@
#include "stdafx.h"
#include "GLCommonDecompiler.h"
std::string getFloatTypeNameImpl(size_t elementCount)
{
switch (elementCount)
{
default:
abort();
case 1:
return "float";
case 2:
return "vec2";
case 3:
return "vec3";
case 4:
return "vec4";
}
}
std::string getFunctionImpl(FUNCTION f)
{
@@ -84,55 +68,3 @@ std::string getFunctionImpl(FUNCTION f)
return "texture2DReconstruct($t, $0.xy * $t_coord_scale)";
}
}
std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::string &Op1)
{
switch (f)
{
case COMPARE::FUNCTION_SEQ:
return "equal(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SGE:
return "greaterThanEqual(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SGT:
return "greaterThan(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SLE:
return "lessThanEqual(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SLT:
return "lessThan(" + Op0 + ", " + Op1 + ")";
case COMPARE::FUNCTION_SNE:
return "notEqual(" + Op0 + ", " + Op1 + ")";
}
fmt::throw_exception("Unknown compare function" HERE);
}
void insert_glsl_legacy_function(std::ostream& OS, gl::glsl::program_domain domain)
{
OS << "vec4 lit_legacy(vec4 val)";
OS << "{\n";
OS << " vec4 clamped_val = val;\n";
OS << " clamped_val.x = max(val.x, 0);\n";
OS << " clamped_val.y = max(val.y, 0);\n";
OS << " vec4 result;\n";
OS << " result.x = 1.0;\n";
OS << " result.w = 1.;\n";
OS << " result.y = clamped_val.x;\n";
OS << " result.z = clamped_val.x > 0.0 ? exp(clamped_val.w * log(max(clamped_val.y, 1.E-10))) : 0.0;\n";
OS << " return result;\n";
OS << "}\n\n";
if (domain != gl::glsl::program_domain::glsl_fragment_program)
return;
//NOTE: We lose precision if we just store depth value into 8-bit textures i.e (depth, 0, 0)
//NOTE2: After testing with GOW, the w component is either the original depth or wraps around to the x component
//Since component.r == depth_value with some precision loss, just use the precise depth value for now (further testing needed)
OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord)\n";
OS << "{\n";
OS << " float depth_value = texture(tex, coord.xy).r;\n";
OS << " uint value = uint(depth_value * 16777215);\n";
OS << " uint b = (value & 0xff);\n";
OS << " uint g = (value >> 8) & 0xff;\n";
OS << " uint r = (value >> 16) & 0xff;\n";
OS << " return vec4(float(r)/255., float(g)/255., float(b)/255., depth_value);\n";
OS << "}\n\n";
}
+1 -4
View File
@@ -1,10 +1,7 @@
#pragma once
#include "../Common/ShaderParam.h"
#include "GLHelpers.h"
#include "../Common/GLSLCommon.h"
#include <ostream>
std::string getFloatTypeNameImpl(size_t elementCount);
std::string getFunctionImpl(FUNCTION f);
std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::string &Op1);
void insert_glsl_legacy_function(std::ostream& OS, gl::glsl::program_domain domain);
+25 -44
View File
@@ -3,13 +3,13 @@
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "GLFragmentProgram.h"
#include "../Common/ProgramStateCache.h"
#include "GLCommonDecompiler.h"
#include "../GCM.h"
std::string GLFragmentDecompilerThread::getFloatTypeName(size_t elementCount)
{
return getFloatTypeNameImpl(elementCount);
return glsl::getFloatTypeNameImpl(elementCount);
}
std::string GLFragmentDecompilerThread::getFunction(FUNCTION f)
@@ -24,7 +24,7 @@ std::string GLFragmentDecompilerThread::saturate(const std::string & code)
std::string GLFragmentDecompilerThread::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1)
{
return compareFunctionImpl(f, Op0, Op1);
return glsl::compareFunctionImpl(f, Op0, Op1);
}
void GLFragmentDecompilerThread::insertHeader(std::stringstream & OS)
@@ -145,45 +145,16 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS)
OS << " float fog_param1;\n";
OS << " uint alpha_test;\n";
OS << " float alpha_ref;\n";
OS << " uint alpha_func;\n";
OS << " uint fog_mode;\n";
OS << " uint window_origin;\n";
OS << " uint window_height;\n";
OS << " vec4 texture_parameters[16];\n"; //sampling: x,y scaling and (unused) offsets data
OS << "};\n";
}
namespace
{
// Note: It's not clear whether fog is computed per pixel or per vertex.
// But it makes more sense to compute exp of interpoled value than to interpolate exp values.
void insert_fog_declaration(std::stringstream & OS, rsx::fog_mode mode)
{
switch (mode)
{
case rsx::fog_mode::linear:
OS << " vec4 fogc = vec4(fog_param1 * fog_c.x + (fog_param0 - 1.), fog_param1 * fog_c.x + (fog_param0 - 1.), 0., 0.);\n";
break;
case rsx::fog_mode::exponential:
OS << " vec4 fogc = vec4(11.084 * (fog_param1 * fog_c.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * fog_c.x + fog_param0 - 1.5)), 0., 0.);\n";
break;
case rsx::fog_mode::exponential2:
OS << " vec4 fogc = vec4(4.709 * (fog_param1 * fog_c.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * fog_c.x + fog_param0 - 1.5), 2.)), 0., 0.);\n";
break;
case rsx::fog_mode::linear_abs:
OS << " vec4 fogc = vec4(fog_param1 * abs(fog_c.x) + (fog_param0 - 1.), fog_param1 * abs(fog_c.x) + (fog_param0 - 1.), 0., 0.);\n";
break;
case rsx::fog_mode::exponential_abs:
OS << " vec4 fogc = vec4(11.084 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5)), 0., 0.);\n";
break;
case rsx::fog_mode::exponential2_abs:
OS << " vec4 fogc = vec4(4.709 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), 2.)), 0., 0.);\n";
break;
default:
OS << " vec4 fogc = vec4(0.);\n";
return;
}
OS << " fogc.y = clamp(fogc.y, 0., 1.);\n";
}
void insert_texture_scale(std::stringstream & OS, const RSXFragmentProgram& prog, int index)
{
std::string vec_type = "vec2";
@@ -221,7 +192,20 @@ namespace
void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
{
insert_glsl_legacy_function(OS, gl::glsl::glsl_fragment_program);
glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program);
//TODO: Generate input mask during parse stage to avoid this
for (const ParamType& PT : m_parr.params[PF_PARAM_IN])
{
for (const ParamItem& PI : PT.items)
{
if (PI.name == "fogc")
{
glsl::insert_fog_declaration(OS);
break;
}
}
}
const std::set<std::string> output_values =
{
@@ -241,6 +225,7 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
}
}
OS << "//FP_HASH=" << fmt::format("%llX", program_hash_util::fragment_program_hash()(m_prog)) << "\n";
OS << "void fs_main(" << parameters << ")\n";
OS << "{\n";
@@ -261,11 +246,7 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n";
OS << " vec4 wpos = gl_FragCoord;\n";
//Flip wpos in Y
//We could optionally export wpos from the VS, but this is so much easier
if (m_prog.origin_mode == rsx::window_origin::bottom)
OS << " wpos.y = " << std::to_string(m_prog.height) << " - wpos.y;\n";
OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n";
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
{
@@ -326,7 +307,7 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
if (PI.name == "fogc")
{
insert_fog_declaration(OS, m_prog.fog_equation);
OS << " vec4 fogc = fetch_fog_value(fog_mode);\n";
continue;
}
}
@@ -394,7 +375,7 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
}
}
OS << make_comparison_test(m_prog.alpha_func, "alpha_test != 0 && ", first_output_name + ".a", "alpha_ref");
OS << " if (alpha_test != 0 && !comparison_passes(" << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n";
}
OS << "}\n\n";
+378 -160
View File
@@ -24,8 +24,7 @@ namespace
GLGSRender::GLGSRender() : GSRender()
{
//TODO
//shaders_cache.load(rsx::old_shaders_cache::shader_language::glsl);
m_shaders_cache.reset(new gl::shader_cache(m_prog_buffer, "opengl", "v1"));
if (g_cfg.video.disable_vertex_cache)
m_vertex_cache.reset(new gl::null_vertex_cache());
@@ -33,34 +32,6 @@ GLGSRender::GLGSRender() : GSRender()
m_vertex_cache.reset(new gl::weak_vertex_cache());
}
u32 GLGSRender::enable(u32 condition, u32 cap)
{
if (condition)
{
glEnable(cap);
}
else
{
glDisable(cap);
}
return condition;
}
u32 GLGSRender::enable(u32 condition, u32 cap, u32 index)
{
if (condition)
{
glEnablei(cap, index);
}
else
{
glDisablei(cap, index);
}
return condition;
}
extern CellGcmContextData current_context;
namespace
@@ -194,6 +165,9 @@ void GLGSRender::begin()
if (skip_frame)
return;
if (conditional_render_enabled && conditional_render_test_failed)
return;
init_buffers();
if (!framebuffer_status_valid)
@@ -206,87 +180,105 @@ void GLGSRender::begin()
bool color_mask_r = rsx::method_registers.color_mask_r();
bool color_mask_a = rsx::method_registers.color_mask_a();
__glcheck glColorMask(color_mask_r, color_mask_g, color_mask_b, color_mask_a);
__glcheck glDepthMask(rsx::method_registers.depth_write_enabled());
__glcheck glStencilMask(rsx::method_registers.stencil_mask());
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 (__glcheck enable(rsx::method_registers.depth_test_enabled(), GL_DEPTH_TEST))
if (gl_state.enable(rsx::method_registers.depth_test_enabled(), GL_DEPTH_TEST))
{
__glcheck glDepthFunc(comparison_op(rsx::method_registers.depth_func()));
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();
if (g_cfg.video.strict_rendering_mode)
gl_state.depth_range(range_near, range_far);
else
{
//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 && (__glcheck enable(rsx::method_registers.depth_bounds_test_enabled(), GL_DEPTH_BOUNDS_TEST_EXT)))
if (glDepthBoundsEXT && (gl_state.enable(rsx::method_registers.depth_bounds_test_enabled(), GL_DEPTH_BOUNDS_TEST_EXT)))
{
__glcheck glDepthBoundsEXT(rsx::method_registers.depth_bounds_min(), rsx::method_registers.depth_bounds_max());
gl_state.depth_bounds(rsx::method_registers.depth_bounds_min(), rsx::method_registers.depth_bounds_max());
}
//__glcheck glDepthRange(rsx::method_registers.clip_min(), rsx::method_registers.clip_max());
__glcheck enable(rsx::method_registers.dither_enabled(), GL_DITHER);
gl_state.enable(rsx::method_registers.dither_enabled(), GL_DITHER);
if (__glcheck enable(rsx::method_registers.blend_enabled(), GL_BLEND))
if (gl_state.enable(rsx::method_registers.blend_enabled(), GL_BLEND))
{
__glcheck glBlendFuncSeparate(blend_factor(rsx::method_registers.blend_func_sfactor_rgb()),
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();
__glcheck glBlendColor(blend_colors[0], blend_colors[1], blend_colors[2], blend_colors[3]);
glBlendColor(blend_colors[0], blend_colors[1], blend_colors[2], blend_colors[3]);
__glcheck glBlendEquationSeparate(blend_equation(rsx::method_registers.blend_equation_rgb()),
glBlendEquationSeparate(blend_equation(rsx::method_registers.blend_equation_rgb()),
blend_equation(rsx::method_registers.blend_equation_a()));
}
if (__glcheck enable(rsx::method_registers.stencil_test_enabled(), GL_STENCIL_TEST))
if (gl_state.enable(rsx::method_registers.stencil_test_enabled(), GL_STENCIL_TEST))
{
__glcheck glStencilFunc(comparison_op(rsx::method_registers.stencil_func()), rsx::method_registers.stencil_func_ref(),
glStencilFunc(comparison_op(rsx::method_registers.stencil_func()),
rsx::method_registers.stencil_func_ref(),
rsx::method_registers.stencil_func_mask());
__glcheck glStencilOp(stencil_op(rsx::method_registers.stencil_op_fail()), stencil_op(rsx::method_registers.stencil_op_zfail()),
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())
{
__glcheck glStencilMaskSeparate(GL_BACK, rsx::method_registers.back_stencil_mask());
__glcheck glStencilFuncSeparate(GL_BACK, comparison_op(rsx::method_registers.back_stencil_func()),
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());
__glcheck glStencilOpSeparate(GL_BACK, stencil_op(rsx::method_registers.back_stencil_op_fail()),
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()));
}
}
__glcheck enable(rsx::method_registers.blend_enabled_surface_1(), GL_BLEND, 1);
__glcheck enable(rsx::method_registers.blend_enabled_surface_2(), GL_BLEND, 2);
__glcheck enable(rsx::method_registers.blend_enabled_surface_3(), GL_BLEND, 3);
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 (__glcheck enable(rsx::method_registers.logic_op_enabled(), GL_COLOR_LOGIC_OP))
if (gl_state.enable(rsx::method_registers.logic_op_enabled(), GL_COLOR_LOGIC_OP))
{
__glcheck glLogicOp(logic_op(rsx::method_registers.logic_operation()));
gl_state.logic_op(logic_op(rsx::method_registers.logic_operation()));
}
__glcheck glLineWidth(rsx::method_registers.line_width());
__glcheck enable(rsx::method_registers.line_smooth_enabled(), GL_LINE_SMOOTH);
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);
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
__glcheck enable(rsx::method_registers.poly_offset_point_enabled(), GL_POLYGON_OFFSET_POINT);
__glcheck enable(rsx::method_registers.poly_offset_line_enabled(), GL_POLYGON_OFFSET_LINE);
__glcheck enable(rsx::method_registers.poly_offset_fill_enabled(), GL_POLYGON_OFFSET_FILL);
__glcheck glPolygonOffset(rsx::method_registers.poly_offset_scale(),
rsx::method_registers.poly_offset_bias());
//NV4097_SET_SPECULAR_ENABLE
//NV4097_SET_TWO_SIDE_LIGHT_EN
//NV4097_SET_FLAT_SHADE_OP
//NV4097_SET_EDGE_FLAG
if (__glcheck enable(rsx::method_registers.cull_face_enabled(), GL_CULL_FACE))
{
__glcheck glCullFace(cull_face(rsx::method_registers.cull_face_mode()));
}
__glcheck glFrontFace(front_face(rsx::method_registers.front_face_mode()));
//NV4097_SET_COLOR_KEY_COLOR
//NV4097_SET_SHADER_CONTROL
@@ -327,18 +319,12 @@ namespace
void GLGSRender::end()
{
std::chrono::time_point<steady_clock> program_start = steady_clock::now();
//Load program here since it is dependent on vertex state
if (skip_frame || !framebuffer_status_valid || !load_program())
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> program_stop = steady_clock::now();
m_begin_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count();
if (manually_flush_ring_buffers)
{
//Use approximations to reseve space. This path is mostly for debug purposes anyway
@@ -350,6 +336,32 @@ void GLGSRender::end()
m_index_ring_buffer->reserve_storage_on_heap(16 * 1024);
}
//Do vertex upload before RTT prep / texture lookups to give the driver time to push data
u32 vertex_draw_count;
u32 actual_vertex_count;
u32 vertex_base;
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();
std::chrono::time_point<steady_clock> program_start = steady_clock::now();
//Load program here since it is dependent on vertex state
load_program(vertex_base, actual_vertex_count);
std::chrono::time_point<steady_clock> program_stop = steady_clock::now();
m_begin_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count();
if (manually_flush_ring_buffers)
{
m_attrib_ring_buffer->unmap();
m_index_ring_buffer->unmap();
}
else
{
//DMA push; not needed with MAP_COHERENT
//glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
}
//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)
@@ -398,9 +410,9 @@ void GLGSRender::end()
if (clear_depth)
{
glDepthMask(GL_TRUE);
glClearDepth(1.0);
glClearStencil(255);
gl_state.depth_mask(GL_TRUE);
gl_state.clear_depth(1.0);
gl_state.clear_stencil(255);
mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
}
@@ -418,7 +430,7 @@ void GLGSRender::end()
}
if (clear_depth)
glDepthMask(rsx::method_registers.depth_write_enabled());
gl_state.depth_mask(rsx::method_registers.depth_write_enabled());
ds->set_cleared();
}
@@ -474,12 +486,12 @@ void GLGSRender::end()
int texture_index = i + rsx::limits::fragment_textures_count;
int location;
/* if (!rsx::method_registers.vertex_textures[i].enabled())
if (!rsx::method_registers.vertex_textures[i].enabled())
{
glActiveTexture(GL_TEXTURE0 + texture_index);
glBindTexture(GL_TEXTURE_2D, 0);
//glActiveTexture(GL_TEXTURE0 + texture_index);
//glBindTexture(GL_TEXTURE_2D, 0);
continue;
} */
}
if (m_program->uniforms.has_location("vtex" + std::to_string(i), &location))
{
@@ -491,20 +503,6 @@ void GLGSRender::end()
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();
u32 vertex_draw_count = m_last_vertex_count;
std::optional<std::tuple<GLenum, u32> > indexed_draw_info;
bool skip_upload = false;
if (!is_probable_instanced_draw())
{
std::tie(vertex_draw_count, indexed_draw_info) = set_vertex_buffer();
m_last_vertex_count = vertex_draw_count;
}
else
{
skip_upload = true;
}
std::chrono::time_point<steady_clock> draw_start = steady_clock::now();
if (g_cfg.video.debug_output)
@@ -512,49 +510,38 @@ void GLGSRender::end()
m_program->validate();
}
if (manually_flush_ring_buffers)
if (indexed_draw_info)
{
m_attrib_ring_buffer->unmap();
m_index_ring_buffer->unmap();
}
const GLenum index_type = std::get<0>(indexed_draw_info.value());
const u32 index_offset = std::get<1>(indexed_draw_info.value());
if (indexed_draw_info || (skip_upload && m_last_draw_indexed == true))
{
if (__glcheck enable(rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART))
if (__glcheck gl_state.enable(rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART))
{
GLenum index_type = (skip_upload)? m_last_ib_type: std::get<0>(indexed_draw_info.value());
__glcheck glPrimitiveRestartIndex((index_type == GL_UNSIGNED_SHORT)? 0xffff: 0xffffffff);
}
m_last_draw_indexed = true;
if (!skip_upload)
{
m_last_ib_type = std::get<0>(indexed_draw_info.value());
m_last_index_offset = std::get<1>(indexed_draw_info.value());
}
__glcheck glDrawElements(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), vertex_draw_count, m_last_ib_type, (GLvoid *)(std::ptrdiff_t)m_last_index_offset);
__glcheck glDrawElements(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), vertex_draw_count, index_type, (GLvoid *)(uintptr_t)index_offset);
}
else
{
draw_fbo.draw_arrays(rsx::method_registers.current_draw_clause.primitive, vertex_draw_count);
m_last_draw_indexed = false;
glDrawArrays(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), 0, vertex_draw_count);
}
m_attrib_ring_buffer->notify();
m_index_ring_buffer->notify();
m_scale_offset_buffer->notify();
m_vertex_state_buffer->notify();
m_fragment_constants_buffer->notify();
m_transform_constants_buffer->notify();
std::chrono::time_point<steady_clock> draw_end = steady_clock::now();
m_draw_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(draw_end - draw_start).count();
m_draw_calls++;
synchronize_buffers();
if (zcull_task_queue.active_query &&
zcull_task_queue.active_query->active)
zcull_task_queue.active_query->num_draws++;
synchronize_buffers();
rsx::thread::end();
}
@@ -593,6 +580,9 @@ void GLGSRender::on_init_thread()
gl::init();
//Enable adaptive vsync if vsync is requested
gl::set_swapinterval(g_cfg.video.vsync ? -1 : 0);
if (g_cfg.video.debug_output)
gl::enable_debugging();
@@ -637,13 +627,21 @@ void GLGSRender::on_init_thread()
const u32 texture_index_offset = rsx::limits::fragment_textures_count + rsx::limits::vertex_textures_count;
for (int index = 0; index < rsx::limits::vertex_count; ++index)
//Array stream buffer
{
auto &tex = m_gl_attrib_buffers[index];
auto &tex = m_gl_persistent_stream_buffer;
tex.create();
tex.set_target(gl::texture::target::textureBuffer);
glActiveTexture(GL_TEXTURE0 + texture_index_offset);
tex.bind();
}
glActiveTexture(GL_TEXTURE0 + texture_index_offset + index);
//Register stream buffer
{
auto &tex = m_gl_volatile_stream_buffer;
tex.create();
tex.set_target(gl::texture::target::textureBuffer);
glActiveTexture(GL_TEXTURE0 + texture_index_offset + 1);
tex.bind();
}
@@ -662,7 +660,7 @@ void GLGSRender::on_init_thread()
m_attrib_ring_buffer.reset(new gl::legacy_ring_buffer());
m_transform_constants_buffer.reset(new gl::legacy_ring_buffer());
m_fragment_constants_buffer.reset(new gl::legacy_ring_buffer());
m_scale_offset_buffer.reset(new gl::legacy_ring_buffer());
m_vertex_state_buffer.reset(new gl::legacy_ring_buffer());
m_index_ring_buffer.reset(new gl::legacy_ring_buffer());
}
else
@@ -670,7 +668,7 @@ void GLGSRender::on_init_thread()
m_attrib_ring_buffer.reset(new gl::ring_buffer());
m_transform_constants_buffer.reset(new gl::ring_buffer());
m_fragment_constants_buffer.reset(new gl::ring_buffer());
m_scale_offset_buffer.reset(new gl::ring_buffer());
m_vertex_state_buffer.reset(new gl::ring_buffer());
m_index_ring_buffer.reset(new gl::ring_buffer());
}
@@ -678,7 +676,7 @@ void GLGSRender::on_init_thread()
m_index_ring_buffer->create(gl::buffer::target::element_array, 64 * 0x100000);
m_transform_constants_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
m_fragment_constants_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
m_scale_offset_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
m_vertex_state_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
m_vao.element_array_buffer = *m_index_ring_buffer;
@@ -697,6 +695,17 @@ void GLGSRender::on_init_thread()
m_gl_sampler_states[i].bind(i);
}
//Occlusion query
for (u32 i = 0; i < occlusion_query_count; ++i)
{
auto &query = occlusion_query_data[i];
glGenQueries(1, &query.handle);
query.pending = false;
query.active = false;
query.result = 0;
}
//Clip planes are shader controlled; enable all planes driver-side
glEnable(GL_CLIP_DISTANCE0 + 0);
glEnable(GL_CLIP_DISTANCE0 + 1);
@@ -706,11 +715,13 @@ void GLGSRender::on_init_thread()
glEnable(GL_CLIP_DISTANCE0 + 5);
m_gl_texture_cache.initialize(this);
m_shaders_cache->load();
}
void GLGSRender::on_exit()
{
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
glFinish();
m_prog_buffer.clear();
@@ -734,10 +745,8 @@ void GLGSRender::on_exit()
m_vao.remove();
}
for (gl::texture &tex : m_gl_attrib_buffers)
{
tex.remove();
}
m_gl_persistent_stream_buffer.remove();
m_gl_volatile_stream_buffer.remove();
for (auto &sampler : m_gl_sampler_states)
{
@@ -759,9 +768,9 @@ void GLGSRender::on_exit()
m_fragment_constants_buffer->remove();
}
if (m_scale_offset_buffer)
if (m_vertex_state_buffer)
{
m_scale_offset_buffer->remove();
m_vertex_state_buffer->remove();
}
if (m_index_ring_buffer)
@@ -772,6 +781,15 @@ void GLGSRender::on_exit()
m_text_printer.close();
m_gl_texture_cache.close();
for (u32 i = 0; i < occlusion_query_count; ++i)
{
auto &query = occlusion_query_data[i];
query.active = false;
query.pending = false;
glDeleteQueries(1, &query.handle);
}
return GSRender::on_exit();
}
@@ -790,8 +808,8 @@ void GLGSRender::clear_surface(u32 arg)
u32 max_depth_value = get_max_depth_value(surface_depth_format);
u32 clear_depth = rsx::method_registers.z_clear_value(surface_depth_format == rsx::surface_depth_format::z24s8);
glDepthMask(GL_TRUE);
glClearDepth(double(clear_depth) / max_depth_value);
gl_state.depth_mask(GL_TRUE);
gl_state.clear_depth(f32(clear_depth) / max_depth_value);
mask |= GLenum(gl::buffers::depth);
gl::render_target *ds = std::get<1>(m_rtts.m_bound_depth_stencil);
@@ -806,8 +824,8 @@ void GLGSRender::clear_surface(u32 arg)
{
u8 clear_stencil = rsx::method_registers.stencil_clear_value();
__glcheck glStencilMask(rsx::method_registers.stencil_mask());
glClearStencil(clear_stencil);
gl_state.stencil_mask(rsx::method_registers.stencil_mask());
gl_state.clear_stencil(clear_stencil);
mask |= GLenum(gl::buffers::stencil);
}
@@ -819,8 +837,8 @@ void GLGSRender::clear_surface(u32 arg)
u8 clear_g = rsx::method_registers.clear_color_g();
u8 clear_b = rsx::method_registers.clear_color_b();
glColorMask(((arg & 0x20) ? 1 : 0), ((arg & 0x40) ? 1 : 0), ((arg & 0x80) ? 1 : 0), ((arg & 0x10) ? 1 : 0));
glClearColor(clear_r / 255.f, clear_g / 255.f, clear_b / 255.f, clear_a / 255.f);
gl_state.color_mask(arg & 0xf0);
gl_state.clear_color(clear_r, clear_g, clear_b, clear_a);
mask |= GLenum(gl::buffers::color);
@@ -853,6 +871,12 @@ bool GLGSRender::do_method(u32 cmd, u32 arg)
return true;
}
case NV4097_CLEAR_ZCULL_SURFACE:
{
// NOP
// Clearing zcull memory does not modify depth/stencil buffers 'bound' to the zcull region
return true;
}
case NV4097_TEXTURE_READ_SEMAPHORE_RELEASE:
case NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE:
flush_draw_buffers = true;
@@ -862,7 +886,7 @@ bool GLGSRender::do_method(u32 cmd, u32 arg)
return false;
}
bool GLGSRender::load_program()
bool GLGSRender::check_program_state()
{
auto rtt_lookup_func = [this](u32 texaddr, rsx::fragment_texture &tex, bool is_depth) -> std::tuple<bool, u16>
{
@@ -884,12 +908,19 @@ bool GLGSRender::load_program()
return std::make_tuple(true, surface->get_native_pitch());
};
RSXFragmentProgram fragment_program = get_current_fragment_program(rtt_lookup_func);
if (!fragment_program.valid) return false;
get_current_fragment_program(rtt_lookup_func);
RSXVertexProgram vertex_program = get_current_vertex_program();
if (current_fragment_program.valid == false)
return false;
u32 unnormalized_rtts = 0;
get_current_vertex_program();
return true;
}
void GLGSRender::load_program(u32 vertex_base, u32 vertex_count)
{
auto &fragment_program = current_fragment_program;
auto &vertex_program = current_vertex_program;
for (auto &vtx : vertex_program.rsx_vertex_inputs)
{
@@ -903,31 +934,39 @@ bool GLGSRender::load_program()
}
}
auto old_program = m_program;
m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr);
vertex_program.skip_vertex_input_check = true; //not needed for us since decoding is done server side
void* pipeline_properties = nullptr;
m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, pipeline_properties);
m_program->use();
if (m_prog_buffer.check_cache_missed())
m_shaders_cache->store(pipeline_properties, vertex_program, fragment_program);
u8 *buf;
u32 scale_offset_offset;
u32 vertex_state_offset;
u32 vertex_constants_offset;
u32 fragment_constants_offset;
const u32 fragment_constants_size = (const u32)m_prog_buffer.get_fragment_constants_buffer_size(fragment_program);
const u32 fragment_buffer_size = fragment_constants_size + (17 * 4 * sizeof(float));
const u32 fragment_buffer_size = fragment_constants_size + (18 * 4 * sizeof(float));
if (manually_flush_ring_buffers)
{
m_scale_offset_buffer->reserve_storage_on_heap(512);
m_vertex_state_buffer->reserve_storage_on_heap(512);
m_fragment_constants_buffer->reserve_storage_on_heap(align(fragment_buffer_size, 256));
if (m_transform_constants_dirty) m_transform_constants_buffer->reserve_storage_on_heap(8192);
}
// Scale offset
auto mapping = m_scale_offset_buffer->alloc_from_heap(512, m_uniform_buffer_offset_align);
// Vertex state
auto mapping = m_vertex_state_buffer->alloc_from_heap(512, m_uniform_buffer_offset_align);
buf = static_cast<u8*>(mapping.first);
scale_offset_offset = mapping.second;
vertex_state_offset = mapping.second;
fill_scale_offset_data(buf, false);
fill_user_clip_data((char *)buf + 64);
fill_user_clip_data(buf + 64);
*(reinterpret_cast<u32*>(buf + 128)) = rsx::method_registers.transform_branch_bits();
*(reinterpret_cast<u32*>(buf + 132)) = vertex_base;
fill_vertex_layout_state(m_vertex_layout, vertex_count, reinterpret_cast<s32*>(buf + 144));
if (m_transform_constants_dirty)
{
@@ -936,7 +975,6 @@ bool GLGSRender::load_program()
buf = static_cast<u8*>(mapping.first);
vertex_constants_offset = mapping.second;
fill_vertex_program_constants_data(buf);
*(reinterpret_cast<u32*>(buf + (468 * 4 * sizeof(float)))) = rsx::method_registers.transform_branch_bits();
}
// Fragment constants
@@ -949,21 +987,20 @@ bool GLGSRender::load_program()
// Fragment state
fill_fragment_state_buffer(buf+fragment_constants_size, fragment_program);
m_scale_offset_buffer->bind_range(0, scale_offset_offset, 512);
m_vertex_state_buffer->bind_range(0, vertex_state_offset, 512);
m_fragment_constants_buffer->bind_range(2, fragment_constants_offset, fragment_buffer_size);
if (m_transform_constants_dirty) m_transform_constants_buffer->bind_range(1, vertex_constants_offset, 8192);
if (manually_flush_ring_buffers)
{
m_scale_offset_buffer->unmap();
m_vertex_state_buffer->unmap();
m_fragment_constants_buffer->unmap();
if (m_transform_constants_dirty) m_transform_constants_buffer->unmap();
}
m_transform_constants_dirty = false;
return true;
}
void GLGSRender::flip(int buffer)
@@ -1064,10 +1101,8 @@ void GLGSRender::flip(int buffer)
}
// Blit source image to the screen
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Disable scissor test (affects blit)
glDisable(GL_SCISSOR_TEST);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
gl::screen.clear(gl::buffers::color_depth_stencil);
__glcheck m_flip_fbo.blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical(), gl::buffers::color, gl::filter::linear);
@@ -1126,6 +1161,12 @@ bool GLGSRender::on_access_violation(u32 address, bool is_writing)
return m_gl_texture_cache.flush_section(address);
}
void GLGSRender::on_notify_memory_unmapped(u32 address_base, u32 size)
{
if (m_gl_texture_cache.invalidate_range(address_base, size, false))
m_gl_texture_cache.purge_dirty();
}
void GLGSRender::do_local_task()
{
std::lock_guard<std::mutex> lock(queue_guard);
@@ -1183,3 +1224,180 @@ bool GLGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst
{
return m_gl_texture_cache.upload_scaled_image(src, dst, interpolate, m_rtts);
}
void GLGSRender::check_zcull_status(bool framebuffer_swap, bool force_read)
{
if (g_cfg.video.disable_zcull_queries)
return;
bool testing_enabled = zcull_pixel_cnt_enabled || zcull_stats_enabled;
if (framebuffer_swap)
{
zcull_surface_active = false;
const u32 zeta_address = depth_surface_info.address;
if (zeta_address)
{
//Find zeta address in bound zculls
for (int i = 0; i < rsx::limits::zculls_count; i++)
{
if (zculls[i].binded)
{
const u32 rsx_address = rsx::get_address(zculls[i].offset, CELL_GCM_LOCATION_LOCAL);
if (rsx_address == zeta_address)
{
zcull_surface_active = true;
break;
}
}
}
}
}
occlusion_query_info* query = nullptr;
if (zcull_task_queue.task_stack.size() > 0)
query = zcull_task_queue.active_query;
if (query && query->active)
{
if (force_read || (!zcull_rendering_enabled || !testing_enabled || !zcull_surface_active))
{
glEndQuery(GL_ANY_SAMPLES_PASSED);
query->active = false;
query->pending = true;
}
}
else
{
if (zcull_rendering_enabled && testing_enabled && zcull_surface_active)
{
//Find query
u32 free_index = synchronize_zcull_stats();
query = &occlusion_query_data[free_index];
zcull_task_queue.add(query);
glBeginQuery(GL_ANY_SAMPLES_PASSED, query->handle);
query->active = true;
query->result = 0;
query->num_draws = 0;
}
}
}
void GLGSRender::clear_zcull_stats(u32 type)
{
if (g_cfg.video.disable_zcull_queries)
return;
if (type == CELL_GCM_ZPASS_PIXEL_CNT)
{
if (zcull_task_queue.active_query &&
zcull_task_queue.active_query->active &&
zcull_task_queue.active_query->num_draws > 0)
{
//discard active query results
check_zcull_status(false, true);
zcull_task_queue.active_query->pending = false;
//re-enable cull stats if stats are enabled
check_zcull_status(false, false);
zcull_task_queue.active_query->num_draws = 0;
}
current_zcull_stats.clear();
}
}
u32 GLGSRender::get_zcull_stats(u32 type)
{
if (g_cfg.video.disable_zcull_queries)
return 0u;
if (zcull_task_queue.active_query &&
zcull_task_queue.active_query->active &&
current_zcull_stats.zpass_pixel_cnt == 0 &&
type == CELL_GCM_ZPASS_PIXEL_CNT)
{
//The zcull unit is still bound as the read is happening and there are no results ready
check_zcull_status(false, true); //close current query
check_zcull_status(false, false); //start new query since stat counting is still active
}
switch (type)
{
case CELL_GCM_ZPASS_PIXEL_CNT:
{
if (current_zcull_stats.zpass_pixel_cnt > 0)
return UINT16_MAX;
synchronize_zcull_stats(true);
return (current_zcull_stats.zpass_pixel_cnt > 0)? UINT16_MAX : 0;
}
case CELL_GCM_ZCULL_STATS:
case CELL_GCM_ZCULL_STATS1:
case CELL_GCM_ZCULL_STATS2:
//TODO
return UINT16_MAX;
case CELL_GCM_ZCULL_STATS3:
{
//Some kind of inverse value
if (current_zcull_stats.zpass_pixel_cnt > 0)
return 0;
synchronize_zcull_stats(true);
return (current_zcull_stats.zpass_pixel_cnt > 0) ? 0 : UINT16_MAX;
}
default:
LOG_ERROR(RSX, "Unknown zcull stat type %d", type);
return 0;
}
}
u32 GLGSRender::synchronize_zcull_stats(bool hard_sync)
{
if (!zcull_rendering_enabled || zcull_task_queue.pending == 0)
return 0;
u32 result = UINT16_MAX;
GLint count, status;
for (auto &query : zcull_task_queue.task_stack)
{
if (query == nullptr || query->active)
continue;
glGetQueryObjectiv(query->handle, GL_QUERY_RESULT_AVAILABLE, &status);
if (status == GL_FALSE && !hard_sync)
continue;
glGetQueryObjectiv(query->handle, GL_QUERY_RESULT, &count);
query->pending = false;
query = nullptr;
current_zcull_stats.zpass_pixel_cnt += count;
zcull_task_queue.pending--;
}
for (u32 i = 0; i < occlusion_query_count; ++i)
{
auto &query = occlusion_query_data[i];
if (!query.pending && !query.active)
{
result = i;
break;
}
}
if (result == UINT16_MAX && !hard_sync)
return synchronize_zcull_stats(true);
return result;
}
void GLGSRender::notify_zcull_info_changed()
{
check_zcull_status(false, false);
}
+304 -12
View File
@@ -19,6 +19,8 @@ namespace gl
using vertex_cache = rsx::vertex_cache::default_vertex_cache<rsx::vertex_cache::uploaded_range<GLenum>, GLenum>;
using weak_vertex_cache = rsx::vertex_cache::weak_vertex_cache<GLenum>;
using null_vertex_cache = vertex_cache;
using shader_cache = rsx::shaders_cache<void*, GLProgramBuffer>;
}
struct work_item
@@ -50,12 +52,13 @@ private:
gl::texture_cache m_gl_texture_cache;
gl::texture m_gl_attrib_buffers[rsx::limits::vertex_count];
gl::texture m_gl_persistent_stream_buffer;
gl::texture m_gl_volatile_stream_buffer;
std::unique_ptr<gl::ring_buffer> m_attrib_ring_buffer;
std::unique_ptr<gl::ring_buffer> m_fragment_constants_buffer;
std::unique_ptr<gl::ring_buffer> m_transform_constants_buffer;
std::unique_ptr<gl::ring_buffer> m_scale_offset_buffer;
std::unique_ptr<gl::ring_buffer> m_vertex_state_buffer;
std::unique_ptr<gl::ring_buffer> m_index_ring_buffer;
u32 m_draw_calls = 0;
@@ -65,6 +68,7 @@ private:
s64 m_textures_upload_time = 0;
std::unique_ptr<gl::vertex_cache> m_vertex_cache;
std::unique_ptr<gl::shader_cache> m_shaders_cache;
GLint m_min_texbuffer_alignment = 256;
GLint m_uniform_buffer_offset_align = 256;
@@ -83,11 +87,6 @@ private:
bool flush_draw_buffers = false;
bool m_last_draw_indexed;
GLenum m_last_ib_type;
size_t m_last_index_offset;
u32 m_last_vertex_count;
public:
gl::fbo draw_fbo;
@@ -101,21 +100,306 @@ private:
//vaos are mandatory for core profile
gl::vao m_vao;
//occlusion query
bool zcull_surface_active = false;
struct occlusion_query_info
{
GLuint handle;
GLint result;
GLint num_draws;
bool pending;
bool active;
};
struct
{
u32 zpass_pixel_cnt;
u32 zcull_stats;
u32 zcull_stats1;
u32 zcull_stats2;
u32 zcull_stats3;
void clear()
{
zpass_pixel_cnt = zcull_stats = zcull_stats1 = zcull_stats2 = zcull_stats3 = 0;
}
}
current_zcull_stats;
struct occlusion_task
{
std::vector<occlusion_query_info*> task_stack;
occlusion_query_info* active_query = nullptr;
u32 pending = 0;
//Add one query to the task
void add(occlusion_query_info* query)
{
active_query = query;
if (task_stack.size() > 0 && pending == 0)
task_stack.resize(0);
const auto empty_slots = task_stack.size() - pending;
if (empty_slots >= 4)
{
for (auto &_query : task_stack)
{
if (_query == nullptr)
{
_query = query;
pending++;
return;
}
}
}
task_stack.push_back(query);
pending++;
}
}
zcull_task_queue = {};
const u32 occlusion_query_count = 128;
std::array<occlusion_query_info, 128> occlusion_query_data = {};
public:
GLGSRender();
private:
static u32 enable(u32 enable, u32 cap);
static u32 enable(u32 enable, u32 cap, u32 index);
struct
{
const u32 DEPTH_BOUNDS_MIN = 0xFFFF0001;
const u32 DEPTH_BOUNDS_MAX = 0xFFFF0002;
const u32 DEPTH_RANGE_MIN = 0xFFFF0003;
const u32 DEPTH_RANGE_MAX = 0xFFFF0004;
std::unordered_map<GLenum, u32> properties = {};
std::unordered_map<GLenum, std::array<u32, 4>> indexed_properties = {};
bool enable(u32 test, GLenum cap)
{
auto found = properties.find(cap);
if (found != properties.end() && found->second == test)
return !!test;
properties[cap] = test;
if (test)
glEnable(cap);
else
glDisable(cap);
return !!test;
}
bool enablei(u32 test, GLenum cap, u32 index)
{
auto found = indexed_properties.find(cap);
const bool exists = found != indexed_properties.end();
if (!exists)
{
indexed_properties[cap] = {};
indexed_properties[cap][index] = test;
}
else
{
if (found->second[index] == test)
return !!test;
found->second[index] = test;
}
if (test)
glEnablei(cap, index);
else
glDisablei(cap, index);
return !!test;
}
const bool test_property(GLenum property, u32 test) const
{
auto found = properties.find(property);
if (found == properties.end())
return false;
return (found->second == test);
}
void depth_func(GLenum func)
{
if (!test_property(GL_DEPTH_FUNC, func))
{
glDepthFunc(func);
properties[GL_DEPTH_FUNC] = func;
}
}
void depth_mask(GLboolean mask)
{
if (!test_property(GL_DEPTH_WRITEMASK, mask))
{
glDepthMask(mask);
properties[GL_DEPTH_WRITEMASK] = mask;
}
}
void clear_depth(GLfloat depth)
{
u32 value = (u32&)depth;
if (!test_property(GL_DEPTH_CLEAR_VALUE, value))
{
glClearDepth(depth);
properties[GL_DEPTH_CLEAR_VALUE] = value;
}
}
void stencil_mask(GLuint mask)
{
if (!test_property(GL_STENCIL_WRITEMASK, mask))
{
glStencilMask(mask);
properties[GL_STENCIL_WRITEMASK] = mask;
}
}
void clear_stencil(GLint stencil)
{
u32 value = (u32&)stencil;
if (!test_property(GL_STENCIL_CLEAR_VALUE, value))
{
glClearStencil(stencil);
properties[GL_STENCIL_CLEAR_VALUE] = value;
}
}
void color_mask(u32 mask)
{
if (!test_property(GL_COLOR_WRITEMASK, mask))
{
glColorMask(((mask & 0x20) ? 1 : 0), ((mask & 0x40) ? 1 : 0), ((mask & 0x80) ? 1 : 0), ((mask & 0x10) ? 1 : 0));
properties[GL_COLOR_WRITEMASK] = mask;
}
}
void color_mask(bool r, bool g, bool b, bool a)
{
u32 mask = 0;
if (r) mask |= 0x20;
if (g) mask |= 0x40;
if (b) mask |= 0x80;
if (a) mask |= 0x10;
color_mask(mask);
}
void clear_color(u8 r, u8 g, u8 b, u8 a)
{
u32 value = (u32)r | (u32)g << 8 | (u32)b << 16 | (u32)a << 24;
if (!test_property(GL_COLOR_CLEAR_VALUE, value))
{
glClearColor(r / 255.f, g / 255.f, b / 255.f, a / 255.f);
properties[GL_COLOR_CLEAR_VALUE] = value;
}
}
void depth_bounds(float min, float max)
{
u32 depth_min = (u32&)min;
u32 depth_max = (u32&)max;
if (!test_property(DEPTH_BOUNDS_MIN, depth_min) || !test_property(DEPTH_BOUNDS_MAX, depth_max))
{
glDepthBoundsEXT(min, max);
properties[DEPTH_BOUNDS_MIN] = depth_min;
properties[DEPTH_BOUNDS_MAX] = depth_max;
}
}
void depth_range(float min, float max)
{
u32 depth_min = (u32&)min;
u32 depth_max = (u32&)max;
if (!test_property(DEPTH_RANGE_MIN, depth_min) || !test_property(DEPTH_RANGE_MAX, depth_max))
{
glDepthRange(min, max);
properties[DEPTH_RANGE_MIN] = depth_min;
properties[DEPTH_RANGE_MAX] = depth_max;
}
}
void logic_op(GLenum op)
{
if (!test_property(GL_COLOR_LOGIC_OP, op))
{
glLogicOp(op);
properties[GL_COLOR_LOGIC_OP] = op;
}
}
void line_width(GLfloat width)
{
u32 value = (u32&)width;
if (!test_property(GL_LINE_WIDTH, value))
{
glLineWidth(width);
properties[GL_LINE_WIDTH] = value;
}
}
void front_face(GLenum face)
{
if (!test_property(GL_FRONT_FACE, face))
{
glFrontFace(face);
properties[GL_FRONT_FACE] = face;
}
}
void cull_face(GLenum mode)
{
if (!test_property(GL_CULL_FACE_MODE, mode))
{
glCullFace(mode);
properties[GL_CULL_FACE_MODE] = mode;
}
}
void polygon_offset(float factor, float units)
{
u32 _units = (u32&)units;
u32 _factor = (u32&)factor;
if (!test_property(GL_POLYGON_OFFSET_UNITS, _units) || !test_property(GL_POLYGON_OFFSET_FACTOR, _factor))
{
glPolygonOffset(factor, units);
properties[GL_POLYGON_OFFSET_UNITS] = _units;
properties[GL_POLYGON_OFFSET_FACTOR] = _factor;
}
}
}
gl_state;
// Return element to draw and in case of indexed draw index type and offset in index buffer
std::tuple<u32, std::optional<std::tuple<GLenum, u32> > > set_vertex_buffer();
std::tuple<u32, u32, u32, std::optional<std::tuple<GLenum, u32> > > set_vertex_buffer();
rsx::vertex_input_layout m_vertex_layout = {};
void clear_surface(u32 arg);
void init_buffers(bool skip_reading = false);
bool check_program_state();
void load_program(u32 vertex_base, u32 vertex_count);
public:
bool load_program();
void init_buffers(bool skip_reading = false);
void read_buffers();
void write_buffers();
void set_viewport();
@@ -124,6 +408,9 @@ public:
work_item& post_flush_request(u32 address, gl::texture_cache::cached_texture_section *section);
bool scaled_image_from_memory(rsx::blit_src_info& src_info, rsx::blit_dst_info& dst_info, bool interpolate) override;
void check_zcull_status(bool framebuffer_swap, bool force_read);
u32 synchronize_zcull_stats(bool hard_sync = false);
protected:
void begin() override;
@@ -137,7 +424,12 @@ protected:
void do_local_task() override;
void notify_zcull_info_changed() override;
void clear_zcull_stats(u32 type) override;
u32 get_zcull_stats(u32 type) override;
bool on_access_violation(u32 address, bool is_writing) override;
void on_notify_memory_unmapped(u32 address_base, u32 size) 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;
+2 -2
View File
@@ -19,7 +19,7 @@ namespace gl
case rsx::primitive_type::triangle_strip: return GL_TRIANGLE_STRIP;
case rsx::primitive_type::triangle_fan: return GL_TRIANGLE_FAN;
case rsx::primitive_type::quads: return GL_TRIANGLES;
case rsx::primitive_type::quad_strip: return GL_TRIANGLES;
case rsx::primitive_type::quad_strip: return GL_TRIANGLE_STRIP;
case rsx::primitive_type::polygon: return GL_TRIANGLES;
}
fmt::throw_exception("unknow primitive type" HERE);
@@ -543,9 +543,9 @@ namespace gl
case rsx::primitive_type::triangles:
case rsx::primitive_type::triangle_strip:
case rsx::primitive_type::triangle_fan:
case rsx::primitive_type::quad_strip:
return true;
case rsx::primitive_type::quads:
case rsx::primitive_type::quad_strip:
case rsx::primitive_type::polygon:
return false;
}
+16 -10
View File
@@ -82,6 +82,7 @@ namespace gl
bool ARB_texture_barrier_supported = false;
bool NV_texture_barrier_supported = false;
bool initialized = false;
bool vendor_INTEL = false;
void initialize()
{
@@ -154,8 +155,17 @@ namespace gl
}
//Workaround for intel drivers which have terrible capability reporting
std::string vendor_string = (const char*)glGetString(GL_VENDOR);
std::transform(vendor_string.begin(), vendor_string.end(), vendor_string.begin(), ::tolower);
std::string vendor_string;
if (const char* raw_string = (const char*)glGetString(GL_VENDOR))
{
vendor_string = raw_string;
std::transform(vendor_string.begin(), vendor_string.end(), vendor_string.begin(), ::tolower);
}
else
{
LOG_ERROR(RSX, "Failed to get vendor string from driver. Are we missing a context?");
vendor_string = "intel"; //lowest acceptable value
}
if (vendor_string.find("intel") != std::string::npos)
{
@@ -165,6 +175,8 @@ namespace gl
glGetIntegerv(GL_MAJOR_VERSION, &version_major);
glGetIntegerv(GL_MINOR_VERSION, &version_minor);
vendor_INTEL = true;
//Texture buffers moved into core at GL 3.3
if (version_major > 3 || (version_major == 3 && version_minor >= 3))
ARB_texture_buffer_supported = true;
@@ -826,7 +838,7 @@ namespace gl
buffer::create();
glBindBuffer((GLenum)m_target, m_id);
glBufferStorage((GLenum)m_target, size, data, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
glBufferStorage((GLenum)m_target, size, data, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT);
m_memory_mapping = glMapBufferRange((GLenum)m_target, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
verify(HERE), m_memory_mapping != nullptr;
@@ -2034,12 +2046,6 @@ namespace gl
namespace glsl
{
enum program_domain
{
glsl_vertex_program = 0,
glsl_fragment_program = 1
};
class compilation_exception : public exception
{
public:
@@ -2538,7 +2544,7 @@ namespace gl
error_msg = buf.get();
}
throw validation_exception(error_msg);
LOG_ERROR(RSX, "Validation failed: %s", error_msg.c_str());
}
}
+9
View File
@@ -183,6 +183,13 @@ OPENGL_PROC(PFNGLSAMPLERPARAMETERIPROC, SamplerParameteri);
OPENGL_PROC(PFNGLSAMPLERPARAMETERFPROC, SamplerParameterf);
OPENGL_PROC(PFNGLSAMPLERPARAMETERFVPROC, SamplerParameterfv);
//Occlusion Query
OPENGL_PROC(PFNGLGENQUERIESPROC, GenQueries);
OPENGL_PROC(PFNGLDELETEQUERIESPROC, DeleteQueries);
OPENGL_PROC(PFNGLGETQUERYOBJECTIVPROC, GetQueryObjectiv);
OPENGL_PROC(PFNGLBEGINQUERYPROC, BeginQuery);
OPENGL_PROC(PFNGLENDQUERYPROC, EndQuery);
//Texture Buffers
OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEEXTPROC, TextureBufferRangeEXT);
OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEPROC, TextureBufferRange);
@@ -212,6 +219,8 @@ OPENGL_PROC(PFNGLTEXTUREBARRIERPROC, TextureBarrier);
OPENGL_PROC(PFNGLTEXTUREBARRIERNVPROC, TextureBarrierNV);
//...
WGL_PROC(PFNWGLSWAPINTERVALEXTPROC, SwapIntervalEXT);
#if !defined(__GNUG__) || defined(__MINGW32__)
OPENGL_PROC(PFNGLBLENDCOLORPROC, BlendColor);
OPENGL_PROC(PFNGLBLENDEQUATIONPROC, BlendEquation);

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