Compare commits

..

374 Commits

Author SHA1 Message Date
Evan Husted
c8b12ee3ec .NET 9 2024-12-23 20:15:36 -06:00
Evan Husted
4937b9ee7f Merge branch 'master' into metal 2024-12-23 20:12:55 -06:00
Isaac Marovitz
1c6636d3cd Make resource encoding less stupid 2024-09-30 17:52:07 +02:00
Isaac Marovitz
e60b90fc47 Set correct maximum supported anisotropy 2024-09-29 01:17:21 +02:00
Isaac Marovitz
cedc8e00df GAL Changes 2024-09-29 01:06:10 +02:00
Isaac Marovitz
0ca4c03af4 Updates 2024-09-28 19:03:01 -04:00
Isaac Marovitz
7d86cb8d7f GAL Changes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
f58920b944 Check for null resources before declaring them resident 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ca30248d97 Fix null sampler crash 2024-09-28 19:03:01 -04:00
Isaac Marovitz
6fed9b51b5 Fix counted indirect draws
Fixes Monster Hunter Rise and Apollo Justice
2024-09-28 19:03:01 -04:00
Isaac Marovitz
bb917a4aa4 Program hash set 2024-09-28 19:03:01 -04:00
Isaac Marovitz
7245193f08 Auto-backed samplers 2024-09-28 19:03:01 -04:00
Isaac Marovitz
2f0235fc37 Refactor binding logic + Bind image arrays 2024-09-28 19:03:01 -04:00
Isaac Marovitz
04c0090653 Fix primitive id in shader gen
Fixes Dark Souls
2024-09-28 19:03:01 -04:00
Isaac Marovitz
d5502b02b1 Fix cubemap array length
Fixes crash in Sonic Frontiers
2024-09-28 19:03:01 -04:00
Isaac Marovitz
691b0de6e1 Properly create stencil views of combined formats
Fixes Link’s Awakening
2024-09-28 19:03:01 -04:00
Isaac Marovitz
b43ff78ba1 Add missing set texture for depth stencil blit
Mostly fixes Sonic Frontiers & Link’s Awakening
2024-09-28 19:03:01 -04:00
Isaac Marovitz
16eb005e8b Fix typo in stride change shader
Fixes Castlevania Dominus Collection
2024-09-28 19:03:01 -04:00
Isaac Marovitz
ce23bff285 Fix invalid depth stencil state when no depth stencil is present
Partially fixes Sonic Frontiers and Castlevania Dominus Collection
2024-09-28 19:03:01 -04:00
Isaac Marovitz
6b2bc16dc3 Style 2024-09-28 19:03:01 -04:00
Isaac Marovitz
302ee73f34 Metal: Unsupported topology indexed draw conversion (#40)
* Convert unsupported indexed buffer topologies

* Fix index count and dispatch size

* Cleanup

* Fix typos
2024-09-28 19:03:01 -04:00
Isaac Marovitz
6a46943af9 Fix null resources breaking arg buffer alignment 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a968ec71fd Remove RenderPipelineDescriptorResult 2024-09-28 19:03:01 -04:00
Isaac Marovitz
d7c71c8a7b D32FS8 to D24S8 Conversion 2024-09-28 19:03:01 -04:00
Isaac Marovitz
f06c869df1 Upstream changes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8a579b64be Logic Operations 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e928ec9708 Fix array size query 2024-09-28 19:03:01 -04:00
Isaac Marovitz
c7c80dc2fb Debug Groups 2024-09-28 19:03:01 -04:00
Isaac Marovitz
fc581cf707 IaIndexing
Fixes shader problems in Donkey Kong Country Tropical Freeze, and Fire Emblem: Three Houses
2024-09-28 19:03:01 -04:00
Isaac Marovitz
bdb00f3981 Rasterizer Discard + Multisample State 2024-09-28 19:03:01 -04:00
Isaac Marovitz
6e3aaa6360 Metal: Argument Buffer Pre-Pass (#38)
* Init

* Fix missing flags

* Cleanup
2024-09-28 19:03:01 -04:00
riperiperi
fff3a4f8f8 Patch some leaks and only perform copies on valid textures (#37) 2024-09-28 19:03:01 -04:00
Isaac Marovitz
01f41b8b0e Get render command encoder after finalising buffers
Fixes crash in Fire Emblem: Houses
2024-09-28 19:03:01 -04:00
Isaac Marovitz
080af8db24 Format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
29e6f17978 Fix non atomic image loads again 2024-09-28 19:03:01 -04:00
Isaac Marovitz
068a83bdfb Finally fix (most) image atomics 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8fa8f3a390 Precise Float Fixes
Fixes artifacts in TOTK
2024-09-28 19:03:01 -04:00
Isaac Marovitz
3360740250 Fix image atomics 2024-09-28 19:03:01 -04:00
Isaac Marovitz
c77f3b90a9 Fix Non-Float Textures + Image Read + FSI Buffers
Fixes Mario Party Superstars
2024-09-28 19:03:01 -04:00
Isaac Marovitz
d5e19a70bd Image Constant Fixes
Allows Mario Party Superstars to boot
2024-09-28 19:03:01 -04:00
Isaac Marovitz
245778bc7e Helper Shader fixes for non float formats 2024-09-28 19:03:01 -04:00
Isaac Marovitz
4cd15cb1a6 Shader Extra Set Support + Cleanup (#36)
Separate samplers are now supported and arrays in constant sets are bound
2024-09-28 19:03:01 -04:00
Isaac Marovitz
d9025904a7 InstGenMemory Refactor + Bindless Support 2024-09-28 19:03:01 -04:00
Isaac Marovitz
47b99e6bc3 TextureArray & ImageArray Creation + State 2024-09-28 19:03:01 -04:00
Isaac Marovitz
d07f6ed38e Fix hex number type ambiguity
Fixes cutscenes in Super Mario Sunshine
2024-09-28 19:03:01 -04:00
Isaac Marovitz
7490afbdc3 Use RGBA8Unorm for R4G4B4A4Unorm
Gets SM64 to boot
2024-09-28 19:03:01 -04:00
Isaac Marovitz
62b8d25315 Dual Source Blend Support in Shader
Fixes Super Mario Galaxy and The Legend of Zelda: Skyward Sword HD
2024-09-28 19:03:01 -04:00
Isaac Marovitz
911389db63 Get Tomb Raider working 2024-09-28 19:03:01 -04:00
Isaac Marovitz
4f6860cfd4 Remove DummyBufferTextures
Mostly gets VTG on Compute working again
2024-09-28 19:03:01 -04:00
Isaac Marovitz
e8dda2d5ef Properly register TextureBuffer usage + Store Auto ref 2024-09-28 19:03:01 -04:00
Isaac Marovitz
810b5792a8 Partial indirect draw support 2024-09-28 19:03:01 -04:00
Gabriel A
1b9377023a Fixes 2024-09-28 19:03:01 -04:00
Gabriel A
29cca80d9f Start building more accurate vertex as compute usage info 2024-09-28 19:03:01 -04:00
Isaac Marovitz
3214a4cf8e Bind TextureBuffers 2024-09-28 19:03:01 -04:00
Isaac Marovitz
62602e58b7 Remove ClearSegments for now
Currently unimplemented and issues are arising with building BindingSegments in general.
2024-09-28 19:03:01 -04:00
Isaac Marovitz
997e8d11f7 Fix compute generation failure in NieR 2024-09-28 19:03:01 -04:00
Isaac Marovitz
42c6611563 Some debug improvements 2024-09-28 19:03:01 -04:00
Isaac Marovitz
3d12f7ef74 Stop complaining about clip distance 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e42e4931a8 Shader Gen Fixes
Fixes Luigi’s Mansion 2 HD
2024-09-28 19:03:01 -04:00
Isaac Marovitz
3a04d72686 DepthStencil Blits 2024-09-28 19:03:01 -04:00
Isaac Marovitz
aa6e87e8a6 Multisample Blits
Partially fixes Sonic Colors Ultimate
2024-09-28 19:03:01 -04:00
Isaac Marovitz
b434cae2c2 Fix image bindings 2024-09-28 19:03:01 -04:00
Isaac Marovitz
2b919493e3 FSI (with raster order groups) 2024-09-28 19:03:01 -04:00
Isaac Marovitz
fdf7578928 SwizzleAdd (NOT TESTED) 2024-09-28 19:03:01 -04:00
Isaac Marovitz
558752594c Consolodate barriers 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a31e461db8 Shader Memory Barriers
Fixes some of the shader generation failures in Sonic Frontiers
2024-09-28 19:03:01 -04:00
Isaac Marovitz
650f309b58 Image binding support
Kirby still has a problem with NaN 3D Texture
2024-09-28 19:03:01 -04:00
Isaac Marovitz
4e5cf38009 Image shader gen support 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b44167d12a Shader cache support 2024-09-28 19:03:01 -04:00
Isaac Marovitz
eb2dae561f Make dotnet format happy 2024-09-28 19:03:01 -04:00
Isaac Marovitz
1287098b8b GAL ResourceUsage Changes
TODO: Guest Barrier Defer
2024-09-28 19:03:01 -04:00
Isaac Marovitz
9f2c99fcfa Better vertex buffer management 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a6f5f2f82b Fix LOD 2024-09-28 19:03:01 -04:00
Isaac Marovitz
655823ecc7 Better index buffer management 2024-09-28 19:03:01 -04:00
Isaac Marovitz
18a1741348 Formatting cleanup 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b734c81683 Formatting 2024-09-28 19:03:01 -04:00
Isaac Marovitz
6e80cc6caa Update binding model description comment 2024-09-28 19:03:01 -04:00
riperiperi
ea30e543e6 Fix preload cbs optimization (for real) (#34)
* Mostly fix preload cbs. There seems to be some random flickering...

* fix index buffer usage range

* fix missing preflush submit before present
2024-09-28 19:03:01 -04:00
Isaac Marovitz
e3468d35b6 Fix invariant position not doing its job 2024-09-28 19:03:01 -04:00
riperiperi
d22feff1d2 implement compressed/uncompressed copy, fix other copies, fix int/uint output shaders (#33) 2024-09-28 19:03:01 -04:00
Isaac Marovitz
9d866ff282 Fix blend state optimisation breaking attachments
Fixes SM3DW
2024-09-28 19:03:01 -04:00
riperiperi
fd0329f2eb Fix warnings 2024-09-28 19:03:01 -04:00
riperiperi
468ab8242f Maintain identity swizzle view of textures for rendering 2024-09-28 19:03:01 -04:00
riperiperi
7b9b23e500 Fix a bunch of issues with texture copy and flush (#32)
* Fix a bunch of issues with texture copy and flush

* TextureCopy helper class, fix clear bug
2024-09-28 19:03:01 -04:00
Isaac Marovitz
0c1acb5107 Cleanup + Format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8e8dcf0d7f Fix trying to reserve size 0 in staging buffer 2024-09-28 19:03:01 -04:00
Isaac Marovitz
9f0a468f55 Fix zero buff not being reset 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ab79959975 Dirty Arg Buffers on Program Change 2024-09-28 19:03:01 -04:00
Isaac Marovitz
de5bf3a141 Least allocations in the west 2024-09-28 19:03:01 -04:00
Isaac Marovitz
5e8606c89a Don’t use Enum.HasFlag 2024-09-28 19:03:01 -04:00
Isaac Marovitz
daee63c451 Metal: Better Bindings (#29)
* Tell GAL to use Vk model (and break everything)

* ResourceBindingSegments

* Set information on backend caps

* Get ready to break everything

* Refactor EncoderStateManager

* Remove padding from helper shaders

* Fix ref array sizes

* Seperate vert & frag buffers

* Shader-side changes

* Fixes

* Fix some helper shader resource layouts

* Sort by binding id

* Fix helper shader layouts

* Don’t do inline vertex buffer updates

* Check for null storage
2024-09-28 19:03:01 -04:00
Isaac Marovitz
971c270bcf Update comment for Metal 2024-09-28 19:03:01 -04:00
Isaac Marovitz
6aff6401fb Don’t do inline vertex buffer updates
Somehow broke zero buff MTLVertexDescriptor, but fixes broken geoemtry so I’m pushing anyway
2024-09-28 19:03:01 -04:00
riperiperi
6f6ccb7898 Create command buffers when rented rather than in advance (#31)
* Make it less likely to freeze, but the creation of the command buffer should probably be moved

* Create command buffers as they're rented rather than in advance
2024-09-28 19:03:01 -04:00
riperiperi
2511bf1e4c Preload command speedup, Texture/buffer data flush, blit shader fix (#30)
* Move encoder state to be tied to command buffer, so preload and background cbs have their own encoder state

* Texture buffer/data flush, blit shader fix
2024-09-28 19:03:01 -04:00
Isaac Marovitz
80f9a5d0da Dont bind images in texture slots 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ed4f7a5602 Stop depth/stencil blits from crashing everything 2024-09-28 19:03:01 -04:00
riperiperi
edceb1607f Fix Geometry/TFB on compute, Buffer Textures, add Window Resizing (#28) 2024-09-28 19:03:01 -04:00
riperiperi
e02df72323 State and cache optimization (#27)
* WIP pipeline/depth state cache rework

* Fix some issues

* Fix some more default values

* Reduce allocations for state changes

* fix helpershader stuff

* explanation comment

* fix depth bias
2024-09-28 19:03:01 -04:00
Isaac Marovitz
9d26aa8d06 Fragment input interpolation qualifiers
Fixes Mario’s shadow in SMO
2024-09-28 19:03:01 -04:00
Isaac Marovitz
c8c4fd730d CommandBufferBarrier 2024-09-28 19:03:01 -04:00
riperiperi
e27ade5aee Add constrained border colours to samplers (#26) 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b33c1ae22f Don’t bind byte format converted index buffers at requested index 2024-09-28 19:03:01 -04:00
Isaac Marovitz
242fcc2481 Render target deduplication
not sure if this is working
2024-09-28 19:03:01 -04:00
Isaac Marovitz
ef4a2fb3b5 Fix CBP not doing its job
Thanks peri (again)
2024-09-28 19:03:01 -04:00
Isaac Marovitz
c4731c0555 Fix blend descriptors not dirting render pipeline
Thanks peri
2024-09-28 19:03:01 -04:00
Isaac Marovitz
0c562a2c50 Support non-index quad draws
Fixes Deltarune
2024-09-28 19:03:01 -04:00
Isaac Marovitz
ab1e02c56a Be better about memory 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a264d9273d Fix stencil clears 2024-09-28 19:03:01 -04:00
Isaac Marovitz
05189c7749 Enable Alpha Test workaround on Metal 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b7ddb693bc Fix Cull FrontAndBack 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a60643620d Warning about host map buffer creation 2024-09-28 19:03:01 -04:00
Isaac Marovitz
113e721cce Fix fragment point_coord in 2024-09-28 19:03:01 -04:00
Isaac Marovitz
c8308d27f1 Argument Buffers (#24)
* Stuff

* More arg buffer stuff

* Fixes

* Rebase

* Pass storage buffers to inline functions

* Fix binding

* Fix typo + Fix a couple shaders

* Enforce ids

* Dispose

* Mark used buffers as resident

* Update depth clear shader

* Fix non-contiguous struct defs

* Update ChangeBufferStride

* Fix StorageBuffer assignments

* Fix odyssey crash

* Retain buffer bindings

* Pad Std140

* Set texture data with safe buffers

* Clone buffers

* Always declare vert in

* Stop clears from breaking OpenGL games

* Fix depth clear

* Use invariant position

* Horribly inefficient texture & sampler arg buffers

* Fix missing struct access

* Minimise rebinds as much as possible

* Build arg buffers on staging buffer
2024-09-28 19:03:01 -04:00
Isaac Marovitz
a71b5f1a3a VoteAllEqual, FindLSB/MSB 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b094d34575 Fix vertex “built-ins”
Only declare main func out in main

Fix simd_ballot

Fix thread_index_in_simdgroup outside of compute

Fix atomic operations

instance_index
2024-09-28 19:03:01 -04:00
Isaac Marovitz
4578ee53d3 Actually clear the right render target 2024-09-28 19:03:01 -04:00
Isaac Marovitz
72cbb41609 Big GetData()
Co-authored-by: riperiperi <rhy3756547@hotmail.com>
2024-09-28 19:03:01 -04:00
Isaac Marovitz
e7fab91c69 Fix Animal Crossing Crash 2024-09-28 19:03:01 -04:00
Isaac Marovitz
97a36298fa Instruction.Barrier
Whoops

Fix inline functions in compute stage

Fix regression

Declare SharedMemories + Only Declare Memories on Main Func

Lowecase struct

Avoid magic strings

Make function signatures readable

Change how unsized arrays are indexed

Use string builder

Fix shuffle instructions

Cleanup NumberFormater

Bunch of Subgroup I/O Vars

Will probably need further refinement

Fix point_coord type

Fix support buffer declaration

Fix point_coord
2024-09-28 19:03:01 -04:00
Isaac Marovitz
03161d8048 PreloadCbs + FlushCommandsIfWeightExceeding 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b1928461bb Cleanup Pipeline
Housekeeping

More housekeeping
2024-09-28 19:03:01 -04:00
Isaac Marovitz
30b50a99e4 PersistentFlushBuffer + BackgroundResources 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a638060dee Match S8UintD24Unorm to Depth24UnormStencil8
Kind of works for es2gears
2024-09-28 19:03:01 -04:00
Isaac Marovitz
49781fde65 Fix FEZ not showing anything
Does not fix the underlying shortcomings of the cache system
2024-09-28 19:03:01 -04:00
Isaac Marovitz
84f3b4a3e1 Clear cached converted buffers on signaled write 2024-09-28 19:03:01 -04:00
Isaac Marovitz
2c511cdf4f FIx regression 2024-09-28 19:03:01 -04:00
Isaac Marovitz
17cfcf07d2 Helper shader cleanup 2024-09-28 19:03:01 -04:00
Isaac Marovitz
410287aba2 Use buffer manager for color blit 2024-09-28 19:03:01 -04:00
Isaac Marovitz
6ebe5bb406 Buffer Conversions (#23)
* Why is this not working

* Revert helper shader changes for now

* Byte Index Buffer Restride
2024-09-28 19:03:01 -04:00
riperiperi
02de48a6f2 don't recreate render pipeline unless we're about to draw, pass view depth properly (#22) 2024-09-28 19:03:01 -04:00
Isaac Marovitz
58b3e2e82b Metal: Buffers Take 2 (#21)
* Basic BufferManager

* Start Scoped Command Buffers

* Fences stuff

* Remember to cleanup sync manager

* Auto, Command Buffer Dependants

* Cleanup

* Cleanup + Fix Texture->Buffer Copies

* Slow buffer upload

* Cleanup + Rework TextureBuffer

* Don’t get unsafe

* Cleanup

* Goddamn it

* Staging Buffer + Interrupt Action + Flush
2024-09-28 19:03:01 -04:00
Isaac Marovitz
d0946213fa Log failed format conversions 2024-09-28 19:03:01 -04:00
Isaac Marovitz
66e2533c90 Print shader code involved in failed linking 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b821cb1739 Don’t use DidModifyRange 2024-09-28 19:03:01 -04:00
Isaac Marovitz
122f0f45c8 Fix sample compare 2024-09-28 19:03:01 -04:00
Isaac Marovitz
9a6759d1e5 Depth Bias 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e97c9bc959 Map R5G5B5A1Unorm 2024-09-28 19:03:01 -04:00
Samuliak
bc5df02d7d override Equals for render pipeline hash 2024-09-28 19:03:01 -04:00
Isaac Marovitz
1c5937c40b Disable scaled vertex formats 2024-09-28 19:03:01 -04:00
Isaac Marovitz
4bb736d70a Disable Vector Indexing Bug Workaround 2024-09-28 19:03:01 -04:00
Isaac Marovitz
efb7baf15c Fix modulo operator
Support sample offsets

Include FragmentIn as additional arg

Always declare frag output struct

SubgroupLaneId
2024-09-28 19:03:01 -04:00
Isaac Marovitz
fad653c12e Workaround for Wonder 2024-09-28 19:03:01 -04:00
Isaac Marovitz
bb4cb531f2 Fix 3D -> 3D Texture Copies 2024-09-28 19:03:01 -04:00
Isaac Marovitz
3c188718c4 Fix Clear Viewport 2024-09-28 19:03:01 -04:00
Isaac Marovitz
362672ae12 Fix sample-less reads with lod 2024-09-28 19:03:01 -04:00
Isaac Marovitz
970914e2b4 Fix Pack and UnpackHalf2x16 2024-09-28 19:03:01 -04:00
Isaac Marovitz
f7e97a30af Handle Array Format SetData 2024-09-28 19:03:01 -04:00
Isaac Marovitz
aae9dc0c2e Cleanup 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b0ba5d5da1 Implement IoVariable.FrontFacing 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a6de2c9274 Fix LOD sample typo 2024-09-28 19:03:01 -04:00
Isaac Marovitz
d323a8d44a Rebase Changes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ba07a8c603 More cleanup 2024-09-28 19:03:01 -04:00
Isaac Marovitz
362746887e Cleanup + Format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b064d76a4f Metal: Compute Shaders (#19)
* check for too bix texture bindings

* implement lod query

* print shader stage name

* always have fragment input

* resolve merge conflicts

* fix: lod query

* fix: casting texture coords

* support non-array memories

* use structure types for buffers

* implement compute pipeline cache

* compute dispatch

* improve error message

* rebind compute state

* bind compute textures

* pass local size as an argument to dispatch

* implement texture buffers

* hack: change vertex index to vertex id

* pass support buffer as an argument to every function

* return at the end of function

* fix: certain missing compute bindings

* implement texture base

* improve texture binding system

* remove useless exception

* move texture handle to texture base

* fix: segfault when using disposed textures

---------

Co-authored-by: Samuliak <samuliak77@gmail.com>
Co-authored-by: SamoZ256 <96914946+SamoZ256@users.noreply.github.com>
2024-09-28 19:03:01 -04:00
Isaac Marovitz
131ab75d55 Handle stride 0 on regular buffers 2024-09-28 19:03:01 -04:00
Isaac Marovitz
65149cfe9f Buffer Descriptor Step Functions 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a435d94fae Sample LOD Level 2024-09-28 19:03:01 -04:00
Isaac Marovitz
88dd2984be Fix FragmentOutputColor Type 2024-09-28 19:03:01 -04:00
Isaac Marovitz
43460186a8 Stencil Ref Value 2024-09-28 19:03:01 -04:00
Isaac Marovitz
0a6f11d247 Stencil Fixes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
1b86360a61 RenderTargetColorMasks 2024-09-28 19:03:01 -04:00
Isaac Marovitz
dc01de61cd Make dotnet format happy 2024-09-28 19:03:01 -04:00
SamoZ256
e423f81155 Zero vertex buffer (#17)
* cast src size to float

* implement zero buffers
2024-09-28 19:03:01 -04:00
Isaac Marovitz
35f68c1b31 Implement Texture CopyTo 2024-09-28 19:03:01 -04:00
Isaac Marovitz
cb8fdeafbc Cleanup present 2024-09-28 19:03:01 -04:00
Isaac Marovitz
1f29a76ea3 Metal: Advanced Present (#6)
* Initial DrawTexture support & Advanced Present

* TODO: Get Scissors Working

* Chnage scissor state management

* Rebase problems…

* Rebase fixes again

* Update DrawTexture + Fix Topology

* Fix flipping

* Add clear action support

* Cleanup
2024-09-28 19:03:01 -04:00
SamoZ256
1f91c74a95 Clone the state & flip viewport vertically (#16)
* implement texture get data

* reset all state before blit & clone state

* format

* support blit regions

* implement source region for blit

* replace bottom with top

* account for 0 size

* support image flipping

* revert presentation fixes & y flip

* revert

* flip viewport vertically

* switch face winding

* comment

* use SetBytes for texture clear

* implement missing compute builtins

* change storage and texture buffer alignment

* correct compute builtins

* don't use nullable for textures and samplers

* remove incorrect texture get data implementation

* Cleanup IntPtrs

---------

Co-authored-by: Isaac Marovitz <isaacryu@icloud.com>
2024-09-28 19:03:01 -04:00
SamoZ256
20b1f6a6ee Fix Scott Pilgrim (#15)
* check for null vertex functions

* format

* Format

---------

Co-authored-by: Isaac Marovitz <isaacryu@icloud.com>
2024-09-28 19:03:01 -04:00
Isaac Marovitz
8b7ac4e87f Suppress GC Finalize on StateCache 2024-09-28 19:03:01 -04:00
Isaac Marovitz
bbcd05aacf Use Stack instead of List 2024-09-28 19:03:01 -04:00
Isaac Marovitz
0e095c778a Whitespace formatting 2024-09-28 19:03:01 -04:00
Samuliak
2833642858 dispose all temporary buffers 2024-09-28 19:03:01 -04:00
Samuliak
f470430c2f dispose temporary metal buffer 2024-09-28 19:03:01 -04:00
Samuliak
051bd144e1 dispose drawable texture view 2024-09-28 19:03:01 -04:00
Samuliak
68f6c08287 implement texture get data 2024-09-28 19:03:01 -04:00
Samuliak
704a78c11f fix: don't dispose stencil state before using 2024-09-28 19:03:01 -04:00
Samuliak
acce02bdf5 allow null depth stencil render targets 2024-09-28 19:03:01 -04:00
Samuliak
8d7be4fe25 reset certain state before doing blit or clear 2024-09-28 19:03:01 -04:00
Samuliak
57a173a671 reset viewport before blit 2024-09-28 19:03:01 -04:00
Samuliak
e6e898b297 dispose encoder state manager 2024-09-28 19:03:01 -04:00
Samuliak
7654f0b16c dispose all objects in encoder state manager 2024-09-28 19:03:01 -04:00
Samuliak
c26df1f7a3 dispose caches 2024-09-28 19:03:01 -04:00
Samuliak
41fb433495 warn about barriers 2024-09-28 19:03:01 -04:00
Samuliak
1a0b928c35 do memory barriers 2024-09-28 19:03:01 -04:00
Samuliak
17334b2131 remove useless parameters 2024-09-28 19:03:01 -04:00
Samuliak
be9f5dcf69 set the inline state after restoring state 2024-09-28 19:03:01 -04:00
Samuliak
f08d6c1cad make states private 2024-09-28 19:03:01 -04:00
Samuliak
8eba42447f fix: incorrect merge stuff 2024-09-28 19:03:01 -04:00
Samuliak
3ec45f73f4 don't interrupt render pass before color clear 2024-09-28 19:03:01 -04:00
Samuliak
b475a44941 implement save and restore state system 2024-09-28 19:03:01 -04:00
Samuliak
295845e6e3 revert deferred clears 2024-09-28 19:03:01 -04:00
Samuliak
79acae3709 prepare for deferred clears 2024-09-28 19:03:01 -04:00
Samuliak
d423a53595 resolve merge conflicts 2024-09-28 19:03:01 -04:00
Isaac Marovitz
f4190bd95a Rebase 2024-09-28 19:03:01 -04:00
Isaac Marovitz
997393bc65 Cleanup + Format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
937d84018e Start Proper Dispose 2024-09-28 19:03:01 -04:00
Samuliak
4bbf7b67d4 do texture barrier tiled 2024-09-28 19:03:01 -04:00
Samuliak
b1549be8c3 do texture barrier 2024-09-28 19:03:01 -04:00
Samuliak
0d15f0fc90 implement depth stencil cache 2024-09-28 19:03:01 -04:00
Isaac Marovitz
20beb2e250 Fix typo in SamplerType.TextureBuffer 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e1279f67fe Fix StoreActions & Don’t Clamp Scissor for Now 2024-09-28 19:03:01 -04:00
Isaac Marovitz
bd3df5f26a Depth Clear 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8feee9c005 Shitty Clears + Inline Buffer Improvements? 2024-09-28 19:03:01 -04:00
Isaac Marovitz
087bf71a13 FragmentOutputDepth Fixes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
3e1f624308 Depth Sampler Fixes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8b2cc4ccf1 Revert position changes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
1aa2b793eb Nvm it should be in.position 2024-09-28 19:03:01 -04:00
Isaac Marovitz
6f44dcc416 More shader fixes 2024-09-28 19:03:01 -04:00
Samuliak
bd14efb220 fix: incorrect layer count of texture view 2024-09-28 19:03:01 -04:00
Samuliak
f5cffa0b46 don't use mask on size query 2024-09-28 19:03:01 -04:00
Samuliak
979da4c1ab declare local memory 2024-09-28 19:03:01 -04:00
Samuliak
f08d3a7517 support multiple render targets & fix: incorrect texture name 2024-09-28 19:03:01 -04:00
Samuliak
21029e895a put render pipeline cache into a separate file 2024-09-28 19:03:01 -04:00
Samuliak
bab9542020 implement pipeline cache 2024-09-28 19:03:01 -04:00
Isaac Marovitz
f2490347af Use return value of BeginRenderPass 2024-09-28 19:03:01 -04:00
Isaac Marovitz
684e025d61 Cleanup 2024-09-28 19:03:01 -04:00
Samuliak
7983bc062b remove outdated comment 2024-09-28 19:03:01 -04:00
Isaac Marovitz
fe2337d61a Fix table 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e72c69cf19 Dont hardcode Vertex Format 2024-09-28 19:03:01 -04:00
Samuliak
9ecaacc977 style 2024-09-28 19:03:01 -04:00
Samuliak
d04e24c382 bring back inline updates for some state 2024-09-28 19:03:01 -04:00
Samuliak
bb425bf640 fix: don't rebind pipeline unless dirty 2024-09-28 19:03:01 -04:00
Samuliak
0444e43654 don't bind null vertex buffers 2024-09-28 19:03:01 -04:00
Samuliak
ccce85e1bb mark state as dirty 2024-09-28 19:03:01 -04:00
Samuliak
348a37a355 add todo notice 2024-09-28 19:03:01 -04:00
Samuliak
918e1c16b7 don't end render pass when not neccessary 2024-09-28 19:03:01 -04:00
Isaac Marovitz
2abadbd649 Remove rebase garbage 2024-09-28 19:03:01 -04:00
Isaac Marovitz
14c58f62eb Be smart and use a bitmask not a list 2024-09-28 19:03:01 -04:00
Isaac Marovitz
102c87e623 Cleanup 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a7e5c26011 Fix Vertex Attributes in Wonder & Kirby 2024-09-28 19:03:01 -04:00
Isaac Marovitz
20e1d1cd33 Implement SetDepthClamp 2024-09-28 19:03:01 -04:00
Isaac Marovitz
f98d9bae24 Implement SetBlendState 2024-09-28 19:03:01 -04:00
Isaac Marovitz
1db8decd12 Be consistent with things that lack support 2024-09-28 19:03:01 -04:00
Isaac Marovitz
71ccb7eaef Ignore SetDepthMode 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e6c2e5873c Make Texture Volatile on dispose 2024-09-28 19:03:01 -04:00
Isaac Marovitz
c97e7d621b Format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
45b533b23b Fix present 2024-09-28 19:03:01 -04:00
Isaac Marovitz
fbe275204b Fix Depth/Stencil attachments 2024-09-28 19:03:01 -04:00
Isaac Marovitz
738227519d Break everything :D 2024-09-28 19:03:01 -04:00
Isaac Marovitz
de86f20b94 Clamp ScissorRect 2024-09-28 19:03:01 -04:00
Isaac Marovitz
fcc7cb55df Set DepthAttachmentPixelFormat 2024-09-28 19:03:01 -04:00
Isaac Marovitz
4e6abb0191 Set Depth Attachment Texture 2024-09-28 19:03:01 -04:00
Isaac Marovitz
35b0436a2b Clamp Viewport ZNear & ZFar 2024-09-28 19:03:01 -04:00
Samuliak
e99f9e2af0 format 2024-09-28 19:03:01 -04:00
Samuliak
bc3fd22f05 use 0 instead of undef 2024-09-28 19:03:01 -04:00
Samuliak
fefdabf257 fix: pass array index as an additional argument to sample 2024-09-28 19:03:01 -04:00
Samuliak
73bb0712a8 don't declare samplers for separate textures 2024-09-28 19:03:01 -04:00
Samuliak
75781ba698 don't hardcode texture type 2024-09-28 19:03:01 -04:00
Samuliak
262452f586 offset storage buffer bindings by 15 2024-09-28 19:03:01 -04:00
Samuliak
f56117a5c7 fix: incorrect abs instruction 2024-09-28 19:03:01 -04:00
Samuliak
aff8fdb2f8 add: vertex and instance id arguments 2024-09-28 19:03:01 -04:00
Samuliak
3651e8ea32 determine type of buffer by its field types 2024-09-28 19:03:01 -04:00
Isaac Marovitz
2d609ad57b Rebase + Format 2024-09-28 19:03:01 -04:00
Samuliak
559122f591 use unknown texture usage 2024-09-28 19:03:01 -04:00
Samuliak
64005ba9ee don't hardcode render pipeline attachments 2024-09-28 19:03:01 -04:00
Samuliak
a11247b72d create GetSwizzle helper function 2024-09-28 19:03:01 -04:00
Samuliak
320c317113 add: textures and samplers as shader arguments & fix: issue with casting 2024-09-28 19:03:01 -04:00
Samuliak
6295153a28 support fragment coord as an input to a shader 2024-09-28 19:03:01 -04:00
Samuliak
e638172753 support texture views 2024-09-28 19:03:01 -04:00
Isaac Marovitz
32db6cc281 Format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
722aa4e45d Rebase + GAL Changes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
00b99770a2 Remove TODOs 2024-09-28 19:03:01 -04:00
Isaac Marovitz
df6821d023 Fix Scissor/Viewport state & Validation Error 2024-09-28 19:03:01 -04:00
Isaac Marovitz
17aa3c6d0f Require Argument Buffers Tier 2 2024-09-28 19:03:01 -04:00
Isaac Marovitz
5a320cca19 Buffer bindings in shader…
Will need to be reworked
2024-09-28 19:03:01 -04:00
Isaac Marovitz
192a84aa2d Bind Uniform & Storage Buffers 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ebc53d7961 Fix buffer access syntax 2024-09-28 19:03:01 -04:00
Isaac Marovitz
4d063f80b8 Dispose pipeline before window 2024-09-28 19:03:01 -04:00
Isaac Marovitz
316fea1fa9 Set scissors & viewports 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a9db9f5b27 Format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
009f791879 Format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
c0bb55cf5e Fix some crashes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
54c8dabadc Fix Cubemap & Array Texture Creation 2024-09-28 19:03:01 -04:00
Isaac Marovitz
04ca284e14 Properly check for 3D 2024-09-28 19:03:01 -04:00
Isaac Marovitz
d58f79ae0f Fix swizzle for certain formats 2024-09-28 19:03:01 -04:00
Isaac Marovitz
cd7d62542a Blit at the end of the render 2024-09-28 19:03:01 -04:00
Isaac Marovitz
72209ba2a6 Load attachments 2024-09-28 19:03:01 -04:00
Isaac Marovitz
70ba3506b0 Cleanup Shader I/O 2024-09-28 19:03:01 -04:00
Isaac Marovitz
35cc208435 Fix fragment shader bindings 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8dca53685a Fix VertexBuffers
Naive non-managed approach
2024-09-28 19:03:01 -04:00
Isaac Marovitz
e517cfeb8f Fix some shader gen problems… 2024-09-28 19:03:01 -04:00
Isaac Marovitz
4a30b58e0b Formatting 2024-09-28 19:03:01 -04:00
Isaac Marovitz
bdd9ede4fd Make TypeConversion failure an error 2024-09-28 19:03:01 -04:00
Isaac Marovitz
84a8edf675 Fix MSL Reinterpret Casts 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e8a2637d46 Dont set Vertex Attributes for now 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e4a14dd23a Remove capture code 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ffb7423260 Bind Textures & Samplers 2024-09-28 19:03:01 -04:00
Isaac Marovitz
80340c98d3 Revise ISampler 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b8c60e993a Try again 2024-09-28 19:03:01 -04:00
Isaac Marovitz
d88314424b Resolve warning 2024-09-28 19:03:01 -04:00
Isaac Marovitz
df8fca012f Formatting 2024-09-28 19:03:01 -04:00
Isaac Marovitz
3d897c4f9a FIx build 2024-09-28 19:03:01 -04:00
Isaac Marovitz
62bf395970 Fix some rebase errors 2024-09-28 19:03:01 -04:00
Isaac Marovitz
bb742f64c6 End Pass on Dispose 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a669592651 Don’t change Render State if Vertex Function is Invalid 2024-09-28 19:03:01 -04:00
Isaac Marovitz
eb5fa2b546 “Report” Driver 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8e99199e19 Adjust function signature 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b439a52ac7 Get it building again 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b9c4a23f22 Render Targets 2024-09-28 19:03:01 -04:00
Isaac Marovitz
64c95bd8d8 format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
264742f085 Formatting 2024-09-28 19:03:01 -04:00
Isaac Marovitz
64d12e8d23 smh 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a9e9819b33 Dont specify [[stage_in]] on fragment 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a58d1cffe4 If one shader fails, whole program fails 2024-09-28 19:03:01 -04:00
Isaac Marovitz
511db833db Fix fragment shaders (and fuck everything up) 2024-09-28 19:03:01 -04:00
Isaac Marovitz
2890fc1069 Vertex buffer data 2024-09-28 19:03:01 -04:00
Isaac Marovitz
7f41e7dbd4 Dont be stupid 2024-09-28 19:03:01 -04:00
Isaac Marovitz
c58cc76b39 Dont set 0 attributes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8232ce7d72 Reset Descriptor instead of making a new object 2024-09-28 19:03:01 -04:00
Isaac Marovitz
db9de66437 Set Vertex Descriptor properly 2024-09-28 19:03:01 -04:00
Isaac Marovitz
5c9d1bd0da Start vertex descriptor work 2024-09-28 19:03:01 -04:00
Isaac Marovitz
fb5402ce81 Implement CreateProgram 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ed11cdda8d Fix fragment output color 2024-09-28 19:03:01 -04:00
Isaac Marovitz
6017c225b2 Set TargetLanguage for Metal to MSL 2024-09-28 19:03:01 -04:00
Isaac Marovitz
98e2ab5a49 Fix IoMap variable names
Output struct

Lazy Vertex IO

Output fixes

Fix output struct definition

MSL Binding Model description

Might need tweaks/adjustments

Cleanup

Typo + Format
2024-09-28 19:03:01 -04:00
Isaac Marovitz
d5758cb310 Fix ETC2 PTA formats
Format
2024-09-28 19:03:01 -04:00
Isaac Marovitz
81b1ae4bcf Partial TextureQuerySamples 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ce5f383f5d Fix instructions 2024-09-28 19:03:01 -04:00
Isaac Marovitz
d2ec22a01b LDR ASTC 2024-09-28 19:03:01 -04:00
Isaac Marovitz
53b886d893 Get build working again (values likely wrong) 2024-09-28 19:03:01 -04:00
Isaac Marovitz
29ef76f153 dotnet format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a1b314acd2 Back to where we were
First special instruction

Start Load/Store implementation

Start TextureSample

Sample progress

I/O Load/Store Progress

Rest of load/store

TODO: Currently, the generator still assumes the GLSL style of I/O attributres. On MSL, the vertex function should output a struct which contains a float4 with the required position attribute.

TextureSize and VectorExtract

Fix UserDefined IO Vars

Fix stage input struct names
2024-09-28 19:03:01 -04:00
Isaac Marovitz
5198fcb881 Boot TOTK 2024-09-28 19:03:01 -04:00
Isaac Marovitz
b37c109673 Boot Sonic Mania 2024-09-28 19:03:01 -04:00
Isaac Marovitz
163be0a159 Update for new Shader IR format 2024-09-28 19:03:01 -04:00
Isaac Marovitz
1f8ae7e5b1 Update src/Ryujinx.Graphics.Metal/Pipeline.cs
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
2024-09-28 19:03:01 -04:00
Isaac Marovitz
bbc2ac2e9b Vertex Input Attributes 2024-09-28 19:03:01 -04:00
Isaac Marovitz
f07327166c More Shader Gen Stuff
Mostly copied from GLSL since in terms of syntax within blocks they’re pretty similar. Likely the result will need tweaking…

Isn’t that conveniant?

“Do the simd_shuffle”

atomics

Remaining instructions

Remove removed special instructions

Getting somewhere…
2024-09-28 19:03:01 -04:00
Isaac Marovitz
1790050a14 Fix Metal Validation Error 2024-09-28 19:03:01 -04:00
Isaac Marovitz
f2c090fe55 SDL2 Headless Metal Backend support 2024-09-28 19:03:01 -04:00
Isaac Marovitz
fd0eaaafc1 Easier capture stuff 2024-09-28 19:03:01 -04:00
Isaac Marovitz
0233a0d35a Define MaxFramesPerCapture 2024-09-28 19:03:01 -04:00
Isaac Marovitz
61910fe342 Cleanup encoder getting + Fix capture overflow 2024-09-28 19:03:01 -04:00
Isaac Marovitz
1cb2ec7ebc Formatting 2024-09-28 19:03:01 -04:00
Isaac Marovitz
4ec37d1798 Start of MSL instructions
Remaining functions
2024-09-28 19:03:01 -04:00
Isaac Marovitz
27effab989 Warn when generating unsupported shader 2024-09-28 19:03:01 -04:00
Isaac Marovitz
d0d5c76f06 Pass sampler to Blit shader 2024-09-28 19:03:01 -04:00
Isaac Marovitz
a03471a8ab Shader comments 2024-09-28 19:03:01 -04:00
Isaac Marovitz
93c71110e1 HelperShaders class 2024-09-28 19:03:01 -04:00
Isaac Marovitz
00fce5a51d Undertale boots 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ce5f5a6442 Check if packed depth is supported 2024-09-28 19:03:01 -04:00
Isaac Marovitz
541cdfebb7 Fix RGB Seizure 2024-09-28 19:03:01 -04:00
Isaac Marovitz
07be20c369 Barry is here mashallah 2024-09-28 19:03:01 -04:00
Isaac Marovitz
aaa140e510 Seizure my beloved is working 2024-09-28 19:03:01 -04:00
Isaac Marovitz
6d722d83ba SetData 2024-09-28 19:03:01 -04:00
Isaac Marovitz
6c3435aaac Look ma no crash 2024-09-28 19:03:01 -04:00
Isaac Marovitz
425177a876 Whitespace 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e3da359acf TODO 2024-09-28 19:03:01 -04:00
Isaac Marovitz
96bbc86331 BeginComputePass 2024-09-28 19:03:01 -04:00
Isaac Marovitz
3d42543f03 SetDepthTest 2024-09-28 19:03:01 -04:00
Isaac Marovitz
0f52165e86 SetStencilTest 2024-09-28 19:03:01 -04:00
Isaac Marovitz
628772f685 Forgot depth 2024-09-28 19:03:01 -04:00
Isaac Marovitz
118d10bc32 Texture usage 2024-09-28 19:03:01 -04:00
Isaac Marovitz
33a986317b CopyBuffer to Buffer 2024-09-28 19:03:01 -04:00
Isaac Marovitz
7a2ab77b4d CopyTo Buffer 2024-09-28 19:03:01 -04:00
Isaac Marovitz
08126b26b1 SetData without region 2024-09-28 19:03:01 -04:00
Isaac Marovitz
abcd2b2754 Rewrite SetData for GPU 2024-09-28 19:03:01 -04:00
Isaac Marovitz
d076a70816 Clear Buffer 2024-09-28 19:03:01 -04:00
Isaac Marovitz
28da4248ae Use Ryujinx Logger 2024-09-28 19:03:01 -04:00
Isaac Marovitz
f4aea9b7ec One encoder at a time 2024-09-28 19:03:01 -04:00
Isaac Marovitz
e269d1605d Fix byte alignment 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8b21447018 Finish SetData /w region 2024-09-28 19:03:01 -04:00
Isaac Marovitz
66d575965c Spoof Counters 2024-09-28 19:03:01 -04:00
Isaac Marovitz
4104af65a3 BufferAccess 2024-09-28 19:03:01 -04:00
Isaac Marovitz
8da7c42cf8 Delete and Get Data from Buffer 2024-09-28 19:03:01 -04:00
Isaac Marovitz
da9a194023 Bump SharpMetal 2024-09-28 19:03:01 -04:00
Isaac Marovitz
5dd444f605 Start Texture region-based CopyTo 2024-09-28 19:03:01 -04:00
Isaac Marovitz
0f3358b931 IoMap 2024-09-28 19:03:01 -04:00
Isaac Marovitz
177303d223 Fix error 2024-09-28 19:03:01 -04:00
Isaac Marovitz
0eaee442c7 Renderer cleanup 2024-09-28 19:03:01 -04:00
Isaac Marovitz
70f54f23c9 Texture Copys 2024-09-28 19:03:01 -04:00
Isaac Marovitz
1e36815713 Texture, Pipeline, Sample, Renderer Improvements 2024-09-28 19:03:01 -04:00
Isaac Marovitz
ebaf1d8258 Start Metal Backend
Revert build yml changes
2024-09-28 19:03:01 -04:00
221 changed files with 4204 additions and 4194 deletions

View File

@@ -64,9 +64,14 @@ jobs:
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
- name: Publish Ryujinx.Headless.SDL2
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
- name: Set executable bit
run: |
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
- name: Build AppImage
@@ -114,6 +119,13 @@ jobs:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}-AppImage
path: publish_appimage
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v4
with:
name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
path: publish_sdl2_headless
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
build_macos:
name: macOS Universal (${{ matrix.configuration }})
runs-on: ubuntu-latest
@@ -159,9 +171,20 @@ jobs:
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Upload Ryujinx artifact
uses: actions/upload-artifact@v4
with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish/*.tar.gz"
if: github.event_name == 'pull_request'
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v4
with:
name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish_headless/*.tar.gz"
if: github.event_name == 'pull_request'

View File

@@ -21,9 +21,9 @@ env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.2"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "canary"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryubing"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "GreemDev"
RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO: "Ryujinx"
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Canary-Releases"
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx-Canary"
RELEASE: 1
jobs:
@@ -43,8 +43,8 @@ jobs:
with:
script: |
github.rest.git.createRef({
owner: "${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}",
repo: "${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}",
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'refs/tags/Canary-${{ steps.version_info.outputs.build_version }}',
sha: context.sha
})
@@ -64,7 +64,7 @@ jobs:
| Windows 64-bit | [Canary Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
| Linux 64-bit | [Canary Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
| Linux ARM 64-bit | [Canary Linux ARM Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
| macOS | [Canary macOS Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
| macOS | [Canary macOS artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}
omitBodyDuringUpdate: true
@@ -116,6 +116,7 @@ jobs:
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
@@ -124,6 +125,11 @@ jobs:
rm publish/libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
popd
pushd publish_sdl2_headless
rm publish/libarmeilleure-jitsupport.dylib
7z a ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
popd
shell: bash
- name: Packing Linux builds
@@ -134,6 +140,12 @@ jobs:
chmod +x publish/Ryujinx.sh publish/Ryujinx
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
popd
pushd publish_sdl2_headless
rm publish/libarmeilleure-jitsupport.dylib
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
tar -czvf ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
popd
shell: bash
#- name: Build AppImage (Linux)
@@ -179,21 +191,21 @@ jobs:
with:
name: ${{ steps.version_info.outputs.build_version }}
artifacts: "release_output/*.tar.gz,release_output/*.zip"
#artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
#artifacts: "release_output/*.tar.gz,release_output/*.zip/*AppImage*"
tag: ${{ steps.version_info.outputs.build_version }}
body: |
# Canary builds:
These builds are experimental and may sometimes not work, use [regular builds](https://github.com/${{ github.repository }}/releases/latest) instead if that sounds like something you don't want to deal with.
These builds are experimental and may sometimes not work, use [regular builds](https://github.com/GreemDev/Ryujinx/releases/latest) instead if that sounds like something you don't want to deal with.
| Platform | Artifact |
|--|--|
| Windows 64-bit | [Canary Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
| Linux 64-bit | [Canary Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
| Linux ARM 64-bit | [Canary Linux ARM Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
| macOS | [Canary macOS Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
| Windows 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip |
| Linux 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz |
| Linux ARM 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz |
| macOS | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz |
**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}
"**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}"
omitBodyDuringUpdate: true
allowUpdates: true
replacesArtifacts: true
@@ -250,11 +262,15 @@ jobs:
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: "Canary ${{ steps.version_info.outputs.build_version }}"
artifacts: "publish_ava/*.tar.gz"
artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }}
body: ""
omitBodyDuringUpdate: true

View File

@@ -37,17 +37,21 @@ jobs:
if (!artifacts.length) {
return core.error(`No artifacts found`);
}
let body = `*You need to be logged into GitHub to download these files.*\n\nDownload the artifacts for this pull request:\n`;
let body = `Download the artifacts for this pull request:\n`;
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less</summary>\n`;
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
for (const art of artifacts) {
const url = `https://github.com/Ryubing/Ryujinx/actions/runs/${run_id}/artifacts/${art.id}`;
if(art.name.includes('Debug')) {
hidden_debug_artifacts += `\n* [${art.name}](${url})`;
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('nogui-ryujinx')) {
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else {
body += `\n* [${art.name}](${url})`;
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
}
}
hidden_headless_artifacts += `\n</details>`;
hidden_debug_artifacts += `\n</details>`;
body += hidden_headless_artifacts;
body += hidden_debug_artifacts;
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});

View File

@@ -21,7 +21,7 @@ env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.2"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "release"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryubing"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "GreemDev"
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx"
RELEASE: 1
@@ -42,8 +42,8 @@ jobs:
with:
script: |
github.rest.git.createRef({
owner: "${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}",
repo: "${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}",
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'refs/tags/${{ steps.version_info.outputs.build_version }}',
sha: context.sha
})
@@ -54,13 +54,13 @@ jobs:
name: ${{ steps.version_info.outputs.build_version }}
tag: ${{ steps.version_info.outputs.build_version }}
body: |
# Stable builds:
# Regular builds:
| Platform | Artifact |
|--|--|
| Windows 64-bit | [Stable Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
| Linux 64-bit | [Stable Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
| Linux ARM 64-bit | [Stable Linux ARM Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
| macOS | [Stable macOS Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
| Windows 64-bit | [Release Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
| Linux 64-bit | [Release Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
| Linux ARM 64-bit | [Release Linux ARM Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
| macOS | [Release macOS Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}
omitBodyDuringUpdate: true
@@ -112,6 +112,7 @@ jobs:
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
@@ -120,6 +121,11 @@ jobs:
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
pushd publish_sdl2_headless
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
shell: bash
- name: Build AppImage (Linux)
@@ -166,6 +172,11 @@ jobs:
chmod +x Ryujinx.sh Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd
pushd publish_sdl2_headless
chmod +x Ryujinx.sh Ryujinx.Headless.SDL2
tar -czvf ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd
shell: bash
- name: Pushing new release
@@ -175,15 +186,15 @@ jobs:
artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
tag: ${{ steps.version_info.outputs.build_version }}
body: |
# Stable builds:
# Regular builds:
| Platform | Artifact |
|--|--|
| Windows 64-bit | [Stable Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
| Linux 64-bit | [Stable Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
| Linux ARM 64-bit | [Stable Linux ARM Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
| macOS | [Stable macOS Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}
| Windows 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip |
| Linux 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz |
| Linux ARM 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz |
| macOS | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz |
"**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}"
omitBodyDuringUpdate: true
allowUpdates: true
replacesArtifacts: true
@@ -240,11 +251,15 @@ jobs:
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: ${{ steps.version_info.outputs.build_version }}
artifacts: "publish/*.tar.gz"
artifacts: "publish/*.tar.gz, publish_headless/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }}
body: ""
omitBodyDuringUpdate: true

View File

@@ -17,7 +17,6 @@
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.0"/>
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0"/>
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
<PackageVersion Include="Concentus" Version="2.2.0" />
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageVersion Include="DynamicData" Version="9.0.4" />
@@ -42,10 +41,10 @@
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
<PackageVersion Include="Gommon" Version="2.7.0.1" />
<PackageVersion Include="Gommon" Version="2.6.8" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpMetal" Version="1.0.0-preview21" />
<PackageVersion Include="SharpMetal" Version="1.0.0-preview20" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />

View File

@@ -57,10 +57,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "src\Ryujinx.Headless.SDL2\Ryujinx.Headless.SDL2.csproj", "{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "src\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj", "{D4D09B08-D580-4D69-B886-C35D2853F6C8}"
@@ -76,16 +80,11 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal", "src\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj", "{C08931FA-1191-417A-864F-3882D93E683B}"
ProjectSection(ProjectDependencies) = postProject
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E} = {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal.SharpMetalExtensions", "src/Ryujinx.Graphics.Metal.SharpMetalExtensions\Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj", "{81EA598C-DBA1-40B0-8DA4-4796B78F2037}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
@@ -95,6 +94,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.github\workflows\release.yml = .github\workflows\release.yml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -209,6 +210,10 @@ Global
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -217,6 +222,10 @@ Global
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -254,11 +263,8 @@ Global
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -13,7 +13,7 @@ mkdir -p AppDir/usr/bin
cp distribution/linux/Ryujinx.desktop AppDir/Ryujinx.desktop
cp distribution/linux/appimage/AppRun AppDir/AppRun
cp distribution/misc/Logo.svg AppDir/Ryujinx.svg
cp src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png AppDir/Ryujinx.svg
cp -r "$BUILDDIR"/* AppDir/usr/bin/

View File

@@ -1,5 +1,4 @@
using ARMeilleure.State;
using Humanizer;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Memory;
@@ -59,8 +58,8 @@ namespace ARMeilleure.Translation.PTC
{
_ptc = ptc;
_timer = new Timer(SaveInterval.Seconds());
_timer.Elapsed += TimerElapsed;
_timer = new Timer(SaveInterval * 1000d);
_timer.Elapsed += PreSave;
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
@@ -73,9 +72,6 @@ namespace ARMeilleure.Translation.PTC
Enabled = false;
}
private void TimerElapsed(object _, ElapsedEventArgs __)
=> new Thread(PreSave) { Name = "Ptc.DiskWriter" }.Start();
public void AddEntry(ulong address, ExecutionMode mode, bool highCq)
{
if (IsAddressInStaticCodeRange(address))
@@ -266,7 +262,7 @@ namespace ARMeilleure.Translation.PTC
compressedStream.SetLength(0L);
}
private void PreSave()
private void PreSave(object source, ElapsedEventArgs e)
{
_waitEvent.Reset();
@@ -432,7 +428,7 @@ namespace ARMeilleure.Translation.PTC
{
_disposed = true;
_timer.Elapsed -= TimerElapsed;
_timer.Elapsed -= PreSave;
_timer.Dispose();
Wait();

View File

@@ -9,12 +9,20 @@ namespace Ryujinx.Audio.Backends.Dummy
{
public class DummyHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ManualResetEvent _updateRequiredEvent = new(false);
private readonly ManualResetEvent _pauseEvent = new(true);
private readonly ManualResetEvent _updateRequiredEvent;
private readonly ManualResetEvent _pauseEvent;
public static bool IsSupported => true;
public float Volume { get; set; } = 1f;
public float Volume { get; set; }
public DummyHardwareDeviceDriver()
{
_updateRequiredEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
Volume = 1f;
}
public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount)
{
@@ -52,7 +60,7 @@ namespace Ryujinx.Audio.Backends.Dummy
Dispose(true);
}
private void Dispose(bool disposing)
protected virtual void Dispose(bool disposing)
{
if (disposing)
{

View File

@@ -1,7 +0,0 @@
namespace Ryujinx.BuildValidationTasks
{
public interface IValidationTask
{
public bool Execute(string projectPath, bool isGitRunner);
}
}

View File

@@ -0,0 +1,73 @@
using System;
using Microsoft.Build.Utilities;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Newtonsoft.Json;
using Microsoft.Build.Framework;
namespace Ryujinx.BuildValidationTasks
{
public class LocaleValidationTask : Task
{
public override bool Execute()
{
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
if (path.Split(["src"], StringSplitOptions.None).Length == 1)
{
//i assume that we are in a build directory in the solution dir
path = new FileInfo(path).Directory!.Parent!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
}
else
{
path = path.Split(["src"], StringSplitOptions.None)[0];
path = new FileInfo(path).Directory!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
}
string data;
using (StreamReader sr = new(path))
{
data = sr.ReadToEnd();
}
LocalesJson json = JsonConvert.DeserializeObject<LocalesJson>(data);
for (int i = 0; i < json.Locales.Count; i++)
{
LocalesEntry locale = json.Locales[i];
foreach (string langCode in json.Languages.Where(it => !locale.Translations.ContainsKey(it)))
{
locale.Translations.Add(langCode, string.Empty);
Log.LogMessage(MessageImportance.High, $"Added '{langCode}' to Locale '{locale.ID}'");
}
locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
json.Locales[i] = locale;
}
string jsonString = JsonConvert.SerializeObject(json, Formatting.Indented);
using (StreamWriter sw = new(path))
{
sw.Write(jsonString);
}
return true;
}
struct LocalesJson
{
public List<string> Languages { get; set; }
public List<LocalesEntry> Locales { get; set; }
}
struct LocalesEntry
{
public string ID { get; set; }
public Dictionary<string, string> Translations { get; set; }
}
}
}

View File

@@ -1,117 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text.Json;
using System.Text.Encodings.Web;
namespace Ryujinx.BuildValidationTasks
{
public class LocalesValidationTask : IValidationTask
{
public LocalesValidationTask() { }
public bool Execute(string projectPath, bool isGitRunner)
{
Console.WriteLine("Running Locale Validation Task...");
string path = projectPath + "src/Ryujinx/Assets/locales.json";
string data;
using (StreamReader sr = new(path))
{
data = sr.ReadToEnd();
}
LocalesJson json;
if (isGitRunner && data.Contains("\r\n"))
throw new FormatException("locales.json is using CRLF line endings! It should be using LF line endings, build locally to fix...");
try
{
json = JsonSerializer.Deserialize<LocalesJson>(data);
}
catch (JsonException e)
{
throw new JsonException(e.Message); //shorter and easier stacktrace
}
bool encounteredIssue = false;
for (int i = 0; i < json.Locales.Count; i++)
{
LocalesEntry locale = json.Locales[i];
foreach (string langCode in json.Languages.Where(lang => !locale.Translations.ContainsKey(lang)))
{
encounteredIssue = true;
if (!isGitRunner)
{
locale.Translations.Add(langCode, string.Empty);
Console.WriteLine($"Added '{langCode}' to Locale '{locale.ID}'");
}
else
{
Console.WriteLine($"Missing '{langCode}' in Locale '{locale.ID}'!");
}
}
foreach (string langCode in json.Languages.Where(lang => locale.Translations.ContainsKey(lang) && lang != "en_US" && locale.Translations[lang] == locale.Translations["en_US"]))
{
encounteredIssue = true;
if (!isGitRunner)
{
locale.Translations[langCode] = string.Empty;
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'! Resetting it...");
}
else
{
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'!");
}
}
locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
json.Locales[i] = locale;
}
if (isGitRunner && encounteredIssue)
throw new JsonException("1 or more locales are invalid!");
JsonSerializerOptions jsonOptions = new JsonSerializerOptions()
{
WriteIndented = true,
NewLine = "\n",
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
string jsonString = JsonSerializer.Serialize(json, jsonOptions);
using (StreamWriter sw = new(path))
{
sw.Write(jsonString);
}
Console.WriteLine("Finished Locale Validation Task!");
return true;
}
struct LocalesJson
{
public List<string> Languages { get; set; }
public List<LocalesEntry> Locales { get; set; }
}
struct LocalesEntry
{
public string ID { get; set; }
public Dictionary<string, string> Translations { get; set; }
}
}
}

View File

@@ -1,37 +0,0 @@
using System;
using System.IO;
using System.Linq;
namespace Ryujinx.BuildValidationTasks
{
public class Program
{
static void Main(string[] args)
{
// Display the number of command line arguments.
if (args.Length == 0)
throw new ArgumentException("Error: too few arguments!");
string path = args[0];
if (string.IsNullOrEmpty(path))
throw new ArgumentException("Error: path is null or empty!");
if (!Path.Exists(path))
throw new FileLoadException($"path {{{path}}} does not exist!");
path = Path.GetFullPath(path);
if (!Directory.GetDirectories(path).Contains($"{path}src"))
throw new FileLoadException($"path {{{path}}} is not a valid ryujinx project!");
bool isGitRunner = path.Contains("runner") || path.Contains("D:\\a\\Ryujinx\\Ryujinx");
if (isGitRunner)
Console.WriteLine("Is Git Runner!");
// Run tasks
// Pass extra info needed in the task constructors
new LocalesValidationTask().Execute(path, isGitRunner);
}
}
}

View File

@@ -1,17 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<Target Name="PostBuildTarget" AfterTargets="AfterBuild">
<Message Text="Running Validation Project" Importance="high" />
<ItemGroup>
<PackageReference Include="Microsoft.Build.Utilities.Core" />
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>
<Exec WorkingDirectory="$(ProjectDir)bin\Debug\$(TargetFramework)\"
Command="dotnet Ryujinx.BuildValidationTasks.dll &quot;$(ProjectDir)..\..\\&quot;"
ConsoleToMsBuild="true"
Condition="'$(RuntimeIdentifier)' == ''"
/>
<UsingTask TaskName="Ryujinx.BuildValidationTasks.LocaleValidationTask" TaskFactory="TaskHostFactory" AssemblyFile="$(OutDir)Ryujinx.BuildValidationTasks.dll" />
<Target Name="LocalesJsonValidation" AfterTargets="AfterRebuild">
<LocaleValidationTask />
</Target>
</Project>
</Project>

View File

@@ -35,8 +35,6 @@ namespace Ryujinx.Common.Configuration
#pragma warning restore IDE0055
};
}
public static float ToFloatY(this AspectRatio aspectRatio)
{

View File

@@ -1,60 +0,0 @@
using Gommon;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Ryujinx.Common.Configuration
{
[Flags]
public enum DirtyHack : byte
{
Xc2MenuSoftlockFix = 1,
ShaderTranslationDelay = 2
}
public readonly struct EnabledDirtyHack(DirtyHack hack, int value)
{
public DirtyHack Hack => hack;
public int Value => value;
public ulong Pack() => Raw.PackBitFields(PackedFormat);
public static EnabledDirtyHack Unpack(ulong packedHack)
{
var unpackedFields = packedHack.UnpackBitFields(PackedFormat);
if (unpackedFields is not [var hack, var value])
throw new ArgumentException(nameof(packedHack));
return new EnabledDirtyHack((DirtyHack)hack, (int)value);
}
private uint[] Raw => [(uint)Hack, (uint)Value.CoerceAtLeast(0)];
public static readonly byte[] PackedFormat = [8, 32];
}
public class DirtyHacks : Dictionary<DirtyHack, int>
{
public DirtyHacks(IEnumerable<EnabledDirtyHack> hacks)
=> hacks.ForEach(edh => Add(edh.Hack, edh.Value));
public DirtyHacks(ulong[] packedHacks) : this(packedHacks.Select(EnabledDirtyHack.Unpack)) {}
public ulong[] PackEntries()
=> Entries.Select(it => it.Pack()).ToArray();
public EnabledDirtyHack[] Entries
=> this
.Select(it => new EnabledDirtyHack(it.Key, it.Value))
.ToArray();
public static implicit operator DirtyHacks(EnabledDirtyHack[] hacks) => new(hacks);
public static implicit operator DirtyHacks(ulong[] packedHacks) => new(packedHacks);
public new int this[DirtyHack hack] => TryGetValue(hack, out var value) ? value : -1;
public bool IsEnabled(DirtyHack hack) => ContainsKey(hack);
}
}

View File

@@ -6,7 +6,6 @@ namespace Ryujinx.Common.Configuration
[JsonConverter(typeof(TypedStringEnumConverter<GraphicsBackend>))]
public enum GraphicsBackend
{
Auto,
Vulkan,
OpenGl,
Metal

View File

@@ -9,6 +9,5 @@ namespace Ryujinx.Common.Configuration
Bilinear,
Nearest,
Fsr,
Area,
}
}

View File

@@ -8,10 +8,10 @@ namespace Ryujinx.Common
public static class StreamExtensions
{
/// <summary>
/// Writes an int span to this stream.
/// Writes a <see cref="ReadOnlySpan{int}" /> to this stream.
///
/// This default implementation converts each buffer value to a stack-allocated
/// byte array, then writes it to the Stream using <see cref="Stream.Write(ReadOnlySpan{byte})" />.
/// byte array, then writes it to the Stream using <cref="System.Stream.Write(byte[])" />.
/// </summary>
/// <param name="stream">The stream to be written to</param>
/// <param name="buffer">The buffer of values to be written</param>

View File

@@ -4,7 +4,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -158,16 +157,21 @@ namespace Ryujinx.Common.Logging
_time.Restart();
}
private static ILogTarget GetTarget(string targetName)
=> _logTargets.FirstOrDefault(target => target.Name.Equals(targetName));
private static ILogTarget GetTarget(string targetName)
{
foreach (var target in _logTargets)
{
if (target.Name.Equals(targetName))
{
return target;
}
}
return null;
}
public static void AddTarget(ILogTarget target)
{
if (_logTargets.Any(t => t.Name == target.Name))
{
return;
}
_logTargets.Add(target);
Updated += target.Log;

View File

@@ -27,7 +27,11 @@ namespace Ryujinx.Common.Logging.Targets
private readonly int _overflowTimeout;
string ILogTarget.Name => _target.Name;
string ILogTarget.Name { get => _target.Name; }
public AsyncLogTargetWrapper(ILogTarget target)
: this(target, -1)
{ }
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit = -1, AsyncLogTargetOverflowAction overflowAction = AsyncLogTargetOverflowAction.Block)
{

View File

@@ -40,35 +40,5 @@ namespace Ryujinx.Common
return (value >> 32) | (value << 32);
}
// Never actually written bit packing logic before, so I looked it up.
// This code is from https://gist.github.com/Alan-FGR/04938e93e2bffdf5802ceb218a37c195
public static ulong PackBitFields(this uint[] values, byte[] bitFields)
{
ulong retVal = values[0]; //we set the first value right away
for (int f = 1; f < values.Length; f++)
{
retVal <<= bitFields[f]; // we shift the previous value
retVal += values[f];// and add our current value
}
return retVal;
}
public static uint[] UnpackBitFields(this ulong packed, byte[] bitFields)
{
int fields = bitFields.Length - 1; // number of fields to unpack
uint[] retArr = new uint[fields + 1]; // init return array
int curPos = 0; // current field bit position (start)
int lastEnd; // position where last field ended
for (int f = fields; f >= 0; f--) // loop from last
{
lastEnd = curPos; // we store where the last value ended
curPos += bitFields[f]; // we get where the current value starts
int leftShift = 64 - curPos; // we figure how much left shift we gotta apply for the other numbers to overflow into oblivion
retArr[f] = (uint)((packed << leftShift) >> leftShift + lastEnd); // we do magic
}
return retArr;
}
}
}

View File

@@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.GAL
{
public enum AntiAliasing
{
None,
Fxaa,
SmaaLow,
SmaaMedium,
SmaaHigh,
SmaaUltra,
}
}

View File

@@ -1,4 +1,3 @@
using Ryujinx.Common.Configuration;
using System;
namespace Ryujinx.Graphics.GAL

View File

@@ -1,4 +1,3 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Window;
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;

View File

@@ -0,0 +1,10 @@
namespace Ryujinx.Graphics.GAL
{
public enum ScalingFilter
{
Bilinear,
Nearest,
Fsr,
Area,
}
}

View File

@@ -0,0 +1,9 @@
namespace Ryujinx.Graphics.GAL
{
public enum VSyncMode
{
Switch,
Unbounded,
Custom
}
}

View File

@@ -1,5 +1,4 @@
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
@@ -91,13 +90,6 @@ namespace Ryujinx.Graphics.Gpu
/// Support buffer updater.
/// </summary>
internal SupportBufferUpdater SupportBufferUpdater { get; }
/// <summary>
/// Enabled dirty hacks.
/// Used for workarounds to emulator bugs we can't fix/don't know how to fix yet.
/// </summary>
internal DirtyHacks DirtyHacks { get; }
/// <summary>
/// Host hardware capabilities.
@@ -121,7 +113,7 @@ namespace Ryujinx.Graphics.Gpu
/// Creates a new instance of the GPU emulation context.
/// </summary>
/// <param name="renderer">Host renderer</param>
public GpuContext(IRenderer renderer, DirtyHacks hacks)
public GpuContext(IRenderer renderer)
{
Renderer = renderer;
@@ -144,8 +136,6 @@ namespace Ryujinx.Graphics.Gpu
SupportBufferUpdater = new SupportBufferUpdater(renderer);
DirtyHacks = hacks;
_firstTimestamp = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds);
}

View File

@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Gpu
/// Enables or disables high-level emulation of common GPU Macro code.
/// </summary>
public static bool EnableMacroHLE = true;
/// <summary>
/// Title id of the current running game.
/// Used by the shader cache.

View File

@@ -1,4 +1,3 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
@@ -367,9 +366,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
try
{
if (_context.DirtyHacks.IsEnabled(DirtyHack.ShaderTranslationDelay))
Thread.Sleep(_context.DirtyHacks[DirtyHack.ShaderTranslationDelay]);
AsyncProgramTranslation asyncTranslation = new(guestShaders, specState, programIndex, isCompute);
_asyncTranslationQueue.Add(asyncTranslation, _cancellationToken);
}

View File

@@ -1,4 +1,3 @@
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
@@ -839,7 +838,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
TargetApi.OpenGL => TargetLanguage.Glsl,
TargetApi.Vulkan => GraphicsConfig.EnableSpirvCompilationOnVulkan ? TargetLanguage.Spirv : TargetLanguage.Glsl,
TargetApi.Metal => TargetLanguage.Msl,
_ => throw new NotImplementedException()
};
return new TranslationOptions(lang, api, flags);

View File

@@ -1,22 +0,0 @@
using SharpMetal;
using SharpMetal.Foundation;
using SharpMetal.ObjectiveCCore;
using SharpMetal.QuartzCore;
using System.Runtime.Versioning;
// ReSharper disable InconsistentNaming
namespace Ryujinx.Graphics.Metal.SharpMetalExtensions
{
[SupportedOSPlatform("macOS")]
public static class CAMetalLayerExtensions
{
private static readonly Selector sel_developerHUDProperties = "developerHUDProperties";
private static readonly Selector sel_setDeveloperHUDProperties = "setDeveloperHUDProperties:";
public static NSDictionary GetDeveloperHudProperties(this CAMetalLayer metalLayer)
=> new(ObjectiveCRuntime.IntPtr_objc_msgSend(metalLayer.NativePtr, sel_developerHUDProperties));
public static void SetDeveloperHudProperties(this CAMetalLayer metalLayer, NSDictionary dictionary)
=> ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDeveloperHUDProperties, dictionary);
}
}

View File

@@ -1,32 +0,0 @@
using SharpMetal.Foundation;
using SharpMetal.ObjectiveCCore;
using System.Runtime.Versioning;
// ReSharper disable InconsistentNaming
namespace Ryujinx.Graphics.Metal.SharpMetalExtensions
{
[SupportedOSPlatform("macOS")]
public static class NSHelper
{
private static readonly Selector sel_getCStringMaxLengthEncoding = "getCString:maxLength:encoding:";
private static readonly Selector sel_stringWithUTF8String = "stringWithUTF8String:";
public static unsafe string ToDotNetString(this NSString source)
{
char[] sourceBuffer = new char[source.Length];
fixed (char* pSourceBuffer = sourceBuffer)
{
ObjectiveC.bool_objc_msgSend(source,
sel_getCStringMaxLengthEncoding,
pSourceBuffer,
source.MaximumLengthOfBytes(NSStringEncoding.UTF16) + 1,
(ulong)NSStringEncoding.UTF16);
}
return new string(sourceBuffer);
}
public static NSString ToNSString(this string source)
=> new(ObjectiveC.IntPtr_objc_msgSend(new ObjectiveCClass(nameof(NSString)), sel_stringWithUTF8String, source));
}
}

View File

@@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SharpMetal" />
</ItemGroup>
</Project>

View File

@@ -1767,7 +1767,6 @@ namespace Ryujinx.Graphics.Metal
Constants.StorageBuffersSetIndex => Constants.StorageBuffersIndex,
Constants.TexturesSetIndex => Constants.TexturesIndex,
Constants.ImagesSetIndex => Constants.ImagesIndex,
_ => throw new NotImplementedException()
};
}

View File

@@ -20,13 +20,8 @@ namespace Ryujinx.Graphics.Metal
private Pipeline _pipeline;
private Window _window;
public uint ProgramCount { get; set; }
#pragma warning disable CS0067 // The event is never used
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
#pragma warning restore CS0067
public bool PreferThreading => true;
public IPipeline Pipeline => _pipeline;
public IWindow Window => _window;
@@ -107,7 +102,6 @@ namespace Ryujinx.Graphics.Metal
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
{
ProgramCount++;
return new Program(this, _device, shaders, info.ResourceLayout, info.ComputeLocalSize);
}

View File

@@ -5,9 +5,12 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Metal.SharpMetalExtensions\Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SharpMetal" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,4 +1,3 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Metal.Effects;
@@ -15,22 +14,20 @@ namespace Ryujinx.Graphics.Metal
public bool ScreenCaptureRequested { get; set; }
private readonly MetalRenderer _renderer;
private CAMetalLayer _metalLayer;
private readonly CAMetalLayer _metalLayer;
private int _width;
private int _height;
private int _requestedWidth;
private int _requestedHeight;
// private bool _vsyncEnabled;
private AntiAliasing _currentAntiAliasing;
private bool _updateEffect;
private IPostProcessingEffect _effect;
private IScalingFilter _scalingFilter;
private bool _isLinear;
public bool IsVSyncEnabled => _metalLayer.DisplaySyncEnabled;
// private float _scalingFilterLevel;
private bool _updateScalingFilter;
private ScalingFilter _currentScalingFilter;
@@ -42,7 +39,7 @@ namespace Ryujinx.Graphics.Metal
_metalLayer = metalLayer;
}
private void ResizeIfNeeded()
private unsafe void ResizeIfNeeded()
{
if (_requestedWidth != 0 && _requestedHeight != 0)
{
@@ -56,7 +53,7 @@ namespace Ryujinx.Graphics.Metal
}
}
public void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
public unsafe void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
{
if (_renderer.Pipeline is Pipeline pipeline && texture is Texture tex)
{
@@ -140,10 +137,10 @@ namespace Ryujinx.Graphics.Metal
_requestedWidth = width;
_requestedHeight = height;
}
public void ChangeVSyncMode(VSyncMode vSyncMode)
public void ChangeVSyncMode(bool vsyncEnabled)
{
_metalLayer.DisplaySyncEnabled = vSyncMode is VSyncMode.Switch;
// _vsyncEnabled = vsyncEnabled;
}
public void SetAntiAliasing(AntiAliasing effect)

View File

@@ -2,8 +2,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{
internal enum BitDepth
{
Bits8 = 8, // < 8 bits
Bits10 = 10, // < 10 bits
Bits12 = 12, // < 12 bits
Bits8 = 8, /**< 8 bits */
Bits10 = 10, /**< 10 bits */
Bits12 = 12, /**< 12 bits */
}
}

View File

@@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
_current = new CounterQueueEvent(this, glType, 0);
_consumerThread = new Thread(EventConsumer) { Name = "CPU.CounterQueue." + (int)type };
_consumerThread = new Thread(EventConsumer);
_consumerThread.Start();
}

View File

@@ -1,5 +1,4 @@
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.OpenGL.Effects;
using Ryujinx.Graphics.OpenGL.Effects.Smaa;

View File

@@ -125,7 +125,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
Instruction.Add => "PreciseFAdd",
Instruction.Subtract => "PreciseFSub",
Instruction.Multiply => "PreciseFMul",
_ => throw new NotImplementedException()
};
return $"{func}({expr[0]}, {expr[1]})";

View File

@@ -52,7 +52,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
_current = new CounterQueueEvent(this, type, 0);
_consumerThread = new Thread(EventConsumer) { Name = "CPU.CounterQueue." + (int)type };
_consumerThread = new Thread(EventConsumer);
_consumerThread.Start();
}

View File

@@ -1,4 +1,3 @@
using Gommon;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
@@ -891,12 +890,7 @@ namespace Ryujinx.Graphics.Vulkan
private void PrintGpuInformation()
{
string gpuInfoMessage = $"{GpuRenderer} ({GpuVersion})";
if (!GpuRenderer.StartsWithIgnoreCase(GpuVendor))
gpuInfoMessage = gpuInfoMessage.Prepend(GpuVendor);
Logger.Notice.Print(LogClass.Gpu, gpuInfoMessage);
Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})");
Logger.Notice.Print(LogClass.Gpu, $"GPU Memory: {GetTotalGPUMemory() / (1024 * 1024)} MiB");
}

View File

@@ -1,4 +1,3 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Vulkan.Effects;
using Silk.NET.Vulkan;

View File

@@ -1,4 +1,3 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL;
using System;

View File

@@ -1034,16 +1034,16 @@ namespace Ryujinx.HLE.FileSystem
switch (fileName)
{
case "prod.keys":
verified = VerifyKeys(lines, genericPattern);
verified = verifyKeys(lines, genericPattern);
break;
case "title.keys":
verified = VerifyKeys(lines, titlePattern);
verified = verifyKeys(lines, titlePattern);
break;
case "console.keys":
verified = VerifyKeys(lines, genericPattern);
verified = verifyKeys(lines, genericPattern);
break;
case "dev.keys":
verified = VerifyKeys(lines, genericPattern);
verified = verifyKeys(lines, genericPattern);
break;
default:
throw new FormatException($"Keys file name \"{fileName}\" not supported. Only \"prod.keys\", \"title.keys\", \"console.keys\", \"dev.keys\" are supported.");
@@ -1056,22 +1056,20 @@ namespace Ryujinx.HLE.FileSystem
{
throw new FileNotFoundException($"Keys file not found at \"{filePath}\".");
}
return;
bool VerifyKeys(string[] lines, string regex)
{
foreach (string line in lines)
{
if (!Regex.IsMatch(line, regex))
{
return false;
}
}
return true;
}
}
private bool verifyKeys(string[] lines, string regex)
{
foreach (string line in lines)
{
if (!Regex.IsMatch(line, regex))
{
return false;
}
}
return true;
}
public bool AreKeysAlredyPresent(string pathToCheck)
{
string[] fileNames = { "prod.keys", "title.keys", "console.keys", "dev.keys" };

View File

@@ -9,6 +9,7 @@ using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.UI;
using System;
using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
namespace Ryujinx.HLE
{
@@ -188,11 +189,6 @@ namespace Ryujinx.HLE
/// An action called when HLE force a refresh of output after docked mode changed.
/// </summary>
public Action RefreshInputConfig { internal get; set; }
/// <summary>
/// The desired hacky workarounds.
/// </summary>
public EnabledDirtyHack[] Hacks { internal get; set; }
public HLEConfiguration(VirtualFileSystem virtualFileSystem,
LibHacHorizonManager libHacHorizonManager,
@@ -223,8 +219,7 @@ namespace Ryujinx.HLE
bool multiplayerDisableP2p,
string multiplayerLdnPassphrase,
string multiplayerLdnServer,
int customVSyncInterval,
EnabledDirtyHack[] dirtyHacks = null)
int customVSyncInterval)
{
VirtualFileSystem = virtualFileSystem;
LibHacHorizonManager = libHacHorizonManager;
@@ -256,7 +251,6 @@ namespace Ryujinx.HLE
MultiplayerDisableP2p = multiplayerDisableP2p;
MultiplayerLdnPassphrase = multiplayerLdnPassphrase;
MultiplayerLdnServer = multiplayerLdnServer;
Hacks = dirtyHacks ?? [];
}
}
}

View File

@@ -181,7 +181,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
is64Bits = true;
}
HostThread = new Thread(ThreadStart) { Name = "HLE.KThread" };
HostThread = new Thread(ThreadStart);
Context = owner?.CreateExecutionContext() ?? new ProcessExecutionContext();

View File

@@ -1,4 +1,3 @@
using Gommon;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
@@ -7,13 +6,12 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Ryujinx.HLE.HOS.Services.Account.Acc
{
public class AccountSaveDataManager
class AccountSaveDataManager
{
private static readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
private readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
private static readonly ProfilesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@@ -51,16 +49,6 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
}
}
public static Optional<UserProfile> GetLastUsedUser()
{
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson);
return profilesJson.Profiles
.FindFirst(profile => profile.AccountState == AccountState.Open)
.Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name,
profileJson.Image, profileJson.LastModifiedTimestamp));
}
public void Save(ConcurrentDictionary<string, UserProfile> profiles)
{
ProfilesJson profilesJson = new()

View File

@@ -1,9 +1,6 @@
using LibHac;
using LibHac.Common;
using LibHac.Sf;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using System.Threading;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{
@@ -16,8 +13,6 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
_baseStorage = SharedRef<LibHac.FsSrv.Sf.IStorage>.CreateMove(ref baseStorage);
}
private const string Xc2TitleId = "0100e95004038000";
[CommandCmif(0)]
// Read(u64 offset, u64 length) -> buffer<u8, 0x46, 0> buffer
public ResultCode Read(ServiceCtx context)
@@ -38,13 +33,6 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
using var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true);
Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(region.Memory.Span), (long)size);
if (context.Device.DirtyHacks.IsEnabled(DirtyHack.Xc2MenuSoftlockFix) && TitleIDs.CurrentApplication.Value == Xc2TitleId)
{
// Add a load-bearing sleep to avoid XC2 softlock
// https://web.archive.org/web/20240728045136/https://github.com/Ryujinx/Ryujinx/issues/2357
Thread.Sleep(2);
}
return (ResultCode)result.Value;
}

View File

@@ -114,10 +114,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
}
}
string usedCharacterStr = Convert.ToHexString(usedCharacter);
string variationStr = Convert.ToHexString(variation);
string amiiboIDStr = Convert.ToHexString(amiiboID);
string setIDStr = Convert.ToHexString(setID);
string usedCharacterStr = BitConverter.ToString(usedCharacter).Replace("-", "");
string variationStr = BitConverter.ToString(variation).Replace("-", "");
string amiiboIDStr = BitConverter.ToString(amiiboID).Replace("-", "");
string setIDStr = BitConverter.ToString(setID).Replace("-", "");
string head = usedCharacterStr + variationStr;
string tail = amiiboIDStr + setIDStr + "02";
string finalID = head + tail;
@@ -289,8 +289,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
private static void LogFinalData(byte[] titleId, byte[] appId, string head, string tail, string finalID, string nickName, DateTime initDateTime, DateTime writeDateTime, ushort settingsValue, ushort writeCounterValue, byte[] applicationAreas)
{
Logger.Debug?.Print(LogClass.ServiceNfp, $"Title ID: 0x{Convert.ToHexString(titleId)}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Application Program ID: 0x{Convert.ToHexString(appId)}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Title ID: 0x{BitConverter.ToString(titleId).Replace("-", "")}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Application Program ID: 0x{BitConverter.ToString(appId).Replace("-", "")}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Head: {head}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Tail: {tail}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Final ID: {finalID}");

View File

@@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{

View File

@@ -4,10 +4,8 @@ using LibHac.Fs.Fsa;
using LibHac.Loader;
using LibHac.Ns;
using LibHac.Tools.FsSystem;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.Memory;
using System;
@@ -104,7 +102,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
}
// Initialize GPU.
GraphicsConfig.TitleId = programId.ToString("X16");
Graphics.Gpu.GraphicsConfig.TitleId = $"{programId:x16}";
device.Gpu.HostInitalized.Set();
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))

View File

@@ -6,9 +6,7 @@ using LibHac.Ns;
using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Loaders.Processes.Extensions;
using System;
@@ -61,8 +59,6 @@ namespace Ryujinx.HLE.Loaders.Processes
{
_latestPid = processResult.ProcessId;
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
return true;
}
}
@@ -90,8 +86,6 @@ namespace Ryujinx.HLE.Loaders.Processes
{
_latestPid = processResult.ProcessId;
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
return true;
}
}
@@ -119,8 +113,6 @@ namespace Ryujinx.HLE.Loaders.Processes
if (processResult.ProgramId > 0x01000000000007FF)
{
_latestPid = processResult.ProcessId;
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
}
return true;
@@ -140,8 +132,6 @@ namespace Ryujinx.HLE.Loaders.Processes
{
_latestPid = processResult.ProcessId;
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
return true;
}
}
@@ -193,17 +183,14 @@ namespace Ryujinx.HLE.Loaders.Processes
if (nacpData.Value.PresenceGroupId != 0)
{
programId = nacpData.Value.PresenceGroupId;
TitleIDs.CurrentApplication.Value = programId.ToString("X16");
}
else if (nacpData.Value.SaveDataOwnerId != 0)
{
programId = nacpData.Value.SaveDataOwnerId;
TitleIDs.CurrentApplication.Value = programId.ToString("X16");
}
else if (nacpData.Value.AddOnContentBaseId != 0)
{
programId = nacpData.Value.AddOnContentBaseId - 0x1000;
TitleIDs.CurrentApplication.Value = programId.ToString("X16");
}
}
@@ -217,7 +204,7 @@ namespace Ryujinx.HLE.Loaders.Processes
}
// Explicitly null TitleId to disable the shader cache.
GraphicsConfig.TitleId = null;
Graphics.Gpu.GraphicsConfig.TitleId = null;
_device.Gpu.HostInitalized.Set();
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,

View File

@@ -2,7 +2,6 @@ using LibHac.Common;
using LibHac.Ns;
using Ryujinx.Audio.Backends.CompatLayer;
using Ryujinx.Audio.Integration;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.FileSystem;
@@ -18,8 +17,6 @@ namespace Ryujinx.HLE
{
public class Switch : IDisposable
{
public static Switch Shared { get; private set; }
public HLEConfiguration Configuration { get; }
public IHardwareDeviceDriver AudioDeviceDriver { get; }
public MemoryBlock Memory { get; }
@@ -40,8 +37,6 @@ namespace Ryujinx.HLE
public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable;
public DirtyHacks DirtyHacks { get; }
public Switch(HLEConfiguration configuration)
{
ArgumentNullException.ThrowIfNull(configuration.GpuRenderer);
@@ -57,10 +52,9 @@ namespace Ryujinx.HLE
: MemoryAllocationFlags.Reserve | MemoryAllocationFlags.Mirrorable;
#pragma warning disable IDE0055 // Disable formatting
DirtyHacks = new DirtyHacks(Configuration.Hacks);
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver);
Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), memoryAllocationFlags);
Gpu = new GpuContext(Configuration.GpuRenderer, DirtyHacks);
Gpu = new GpuContext(Configuration.GpuRenderer);
System = new HOS.Horizon(this);
Statistics = new PerformanceStatistics();
Hid = new Hid(this, System.HidStorage);
@@ -78,11 +72,8 @@ namespace Ryujinx.HLE
System.EnablePtc = Configuration.EnablePtc;
System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
UpdateVSyncInterval();
#pragma warning restore IDE0055
Shared = this;
}
public void ProcessFrame()
@@ -151,9 +142,6 @@ namespace Ryujinx.HLE
AudioDeviceDriver.Dispose();
FileSystem.Dispose();
Memory.Dispose();
TitleIDs.CurrentApplication.Value = null;
Shared = null;
}
}
}

View File

@@ -2,7 +2,7 @@ using Ryujinx.HLE.UI;
using System.Threading;
using System.Threading.Tasks;
namespace Ryujinx.Headless
namespace Ryujinx.Headless.SDL2
{
/// <summary>
/// Headless text processing class, right now there is no way to forward the input to it.

View File

@@ -1,6 +1,6 @@
using Ryujinx.HLE.UI;
namespace Ryujinx.Headless
namespace Ryujinx.Headless.SDL2
{
internal class HeadlessHostUiTheme : IHostUITheme
{

View File

@@ -5,7 +5,7 @@ using SharpMetal.QuartzCore;
using System.Runtime.Versioning;
using static SDL2.SDL;
namespace Ryujinx.Headless
namespace Ryujinx.Headless.SDL2.Metal
{
[SupportedOSPlatform("macos")]
class MetalWindow : WindowBase
@@ -22,9 +22,8 @@ namespace Ryujinx.Headless
GraphicsDebugLevel glLogLevel,
AspectRatio aspectRatio,
bool enableMouse,
HideCursorMode hideCursorMode,
bool ignoreControllerApplet)
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet) { }
HideCursorMode hideCursorMode)
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode) { }
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_METAL;

View File

@@ -7,7 +7,7 @@ using Ryujinx.Input.HLE;
using System;
using static SDL2.SDL;
namespace Ryujinx.Headless
namespace Ryujinx.Headless.SDL2.OpenGL
{
class OpenGLWindow : WindowBase
{

View File

@@ -1,168 +1,13 @@
using CommandLine;
using Gommon;
using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.HLE;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Ryujinx.Headless
namespace Ryujinx.Headless.SDL2
{
public class Options
{
public void InheritMainConfig(string[] originalArgs, ConfigurationState configurationState, out bool needsProfileSet)
{
needsProfileSet = NeedsOverride(nameof(UserProfile));
if (NeedsOverride(nameof(IsFullscreen)))
IsFullscreen = configurationState.UI.StartFullscreen;
if (NeedsOverride(nameof(EnableKeyboard)))
EnableKeyboard = configurationState.Hid.EnableKeyboard;
if (NeedsOverride(nameof(EnableMouse)))
EnableMouse = configurationState.Hid.EnableMouse;
if (NeedsOverride(nameof(HideCursorMode)))
HideCursorMode = configurationState.HideCursor;
if (NeedsOverride(nameof(DisablePTC)))
DisablePTC = !configurationState.System.EnablePtc;
if (NeedsOverride(nameof(EnableInternetAccess)))
EnableInternetAccess = configurationState.System.EnableInternetAccess;
if (NeedsOverride(nameof(DisableFsIntegrityChecks)))
DisableFsIntegrityChecks = configurationState.System.EnableFsIntegrityChecks;
if (NeedsOverride(nameof(FsGlobalAccessLogMode)))
FsGlobalAccessLogMode = configurationState.System.FsGlobalAccessLogMode;
if (NeedsOverride(nameof(VSyncMode)))
VSyncMode = configurationState.Graphics.VSyncMode;
if (NeedsOverride(nameof(CustomVSyncInterval)))
CustomVSyncInterval = configurationState.Graphics.CustomVSyncInterval;
if (NeedsOverride(nameof(DisableShaderCache)))
DisableShaderCache = !configurationState.Graphics.EnableShaderCache;
if (NeedsOverride(nameof(EnableTextureRecompression)))
EnableTextureRecompression = configurationState.Graphics.EnableTextureRecompression;
if (NeedsOverride(nameof(DisableDockedMode)))
DisableDockedMode = !configurationState.System.EnableDockedMode;
if (NeedsOverride(nameof(SystemLanguage)))
SystemLanguage = (SystemLanguage)(int)configurationState.System.Language.Value;
if (NeedsOverride(nameof(SystemRegion)))
SystemRegion = (RegionCode)(int)configurationState.System.Region.Value;
if (NeedsOverride(nameof(SystemTimeZone)))
SystemTimeZone = configurationState.System.TimeZone;
if (NeedsOverride(nameof(SystemTimeOffset)))
SystemTimeOffset = configurationState.System.SystemTimeOffset;
if (NeedsOverride(nameof(MemoryManagerMode)))
MemoryManagerMode = configurationState.System.MemoryManagerMode;
if (NeedsOverride(nameof(AudioVolume)))
AudioVolume = configurationState.System.AudioVolume;
if (NeedsOverride(nameof(UseHypervisor)) && OperatingSystem.IsMacOS())
UseHypervisor = configurationState.System.UseHypervisor;
if (NeedsOverride(nameof(MultiplayerLanInterfaceId)))
MultiplayerLanInterfaceId = configurationState.Multiplayer.LanInterfaceId;
if (NeedsOverride(nameof(DisableFileLog)))
DisableFileLog = !configurationState.Logger.EnableFileLog;
if (NeedsOverride(nameof(LoggingEnableDebug)))
LoggingEnableDebug = configurationState.Logger.EnableDebug;
if (NeedsOverride(nameof(LoggingDisableStub)))
LoggingDisableStub = !configurationState.Logger.EnableStub;
if (NeedsOverride(nameof(LoggingDisableInfo)))
LoggingDisableInfo = !configurationState.Logger.EnableInfo;
if (NeedsOverride(nameof(LoggingDisableWarning)))
LoggingDisableWarning = !configurationState.Logger.EnableWarn;
if (NeedsOverride(nameof(LoggingDisableError)))
LoggingDisableError = !configurationState.Logger.EnableError;
if (NeedsOverride(nameof(LoggingEnableTrace)))
LoggingEnableTrace = configurationState.Logger.EnableTrace;
if (NeedsOverride(nameof(LoggingDisableGuest)))
LoggingDisableGuest = !configurationState.Logger.EnableGuest;
if (NeedsOverride(nameof(LoggingEnableFsAccessLog)))
LoggingEnableFsAccessLog = configurationState.Logger.EnableFsAccessLog;
if (NeedsOverride(nameof(LoggingGraphicsDebugLevel)))
LoggingGraphicsDebugLevel = configurationState.Logger.GraphicsDebugLevel;
if (NeedsOverride(nameof(ResScale)))
ResScale = configurationState.Graphics.ResScale;
if (NeedsOverride(nameof(MaxAnisotropy)))
MaxAnisotropy = configurationState.Graphics.MaxAnisotropy;
if (NeedsOverride(nameof(AspectRatio)))
AspectRatio = configurationState.Graphics.AspectRatio;
if (NeedsOverride(nameof(BackendThreading)))
BackendThreading = configurationState.Graphics.BackendThreading;
if (NeedsOverride(nameof(DisableMacroHLE)))
DisableMacroHLE = !configurationState.Graphics.EnableMacroHLE;
if (NeedsOverride(nameof(GraphicsShadersDumpPath)))
GraphicsShadersDumpPath = configurationState.Graphics.ShadersDumpPath;
if (NeedsOverride(nameof(GraphicsBackend)))
GraphicsBackend = configurationState.Graphics.GraphicsBackend;
if (NeedsOverride(nameof(AntiAliasing)))
AntiAliasing = configurationState.Graphics.AntiAliasing;
if (NeedsOverride(nameof(ScalingFilter)))
ScalingFilter = configurationState.Graphics.ScalingFilter;
if (NeedsOverride(nameof(ScalingFilterLevel)))
ScalingFilterLevel = configurationState.Graphics.ScalingFilterLevel;
if (NeedsOverride(nameof(DramSize)))
DramSize = configurationState.System.DramSize;
if (NeedsOverride(nameof(IgnoreMissingServices)))
IgnoreMissingServices = configurationState.System.IgnoreMissingServices;
if (NeedsOverride(nameof(IgnoreControllerApplet)))
IgnoreControllerApplet = configurationState.IgnoreApplet;
return;
bool NeedsOverride(string argKey) => originalArgs.None(arg => arg.TrimStart('-').EqualsIgnoreCase(OptionName(argKey)));
string OptionName(string propertyName) =>
typeof(Options)!.GetProperty(propertyName)!.GetCustomAttribute<OptionAttribute>()!.LongName;
}
// General
[Option("use-main-config", Required = false, Default = false, HelpText = "Use the settings from what was configured via the UI.")]
public bool InheritConfig { get; set; }
[Option("root-data-dir", Required = false, HelpText = "Set the custom folder path for Ryujinx data.")]
public string BaseDataDir { get; set; }
@@ -250,10 +95,10 @@ namespace Ryujinx.Headless
[Option("hide-cursor", Required = false, Default = HideCursorMode.OnIdle, HelpText = "Change when the cursor gets hidden.")]
public HideCursorMode HideCursorMode { get; set; }
[Option("list-input-profiles", Required = false, HelpText = "List input profiles.")]
[Option("list-input-profiles", Required = false, HelpText = "List inputs profiles.")]
public bool ListInputProfiles { get; set; }
[Option("list-input-ids", Required = false, HelpText = "List input IDs.")]
[Option("list-inputs-ids", Required = false, HelpText = "List inputs ids.")]
public bool ListInputIds { get; set; }
// System
@@ -327,7 +172,7 @@ namespace Ryujinx.Headless
public bool LoggingDisableWarning { get; set; }
[Option("disable-error-logs", Required = false, HelpText = "Disables printing error log messages.")]
public bool LoggingDisableError { get; set; }
public bool LoggingEnableError { get; set; }
[Option("enable-trace-logs", Required = false, Default = false, HelpText = "Enables printing trace log messages.")]
public bool LoggingEnableTrace { get; set; }
@@ -370,7 +215,7 @@ namespace Ryujinx.Headless
[Option("anti-aliasing", Required = false, Default = AntiAliasing.None, HelpText = "Set the type of anti aliasing being used. [None|Fxaa|SmaaLow|SmaaMedium|SmaaHigh|SmaaUltra]")]
public AntiAliasing AntiAliasing { get; set; }
[Option("scaling-filter", Required = false, Default = ScalingFilter.Bilinear, HelpText = "Set the scaling filter. [Bilinear|Nearest|Fsr|Area]")]
[Option("scaling-filter", Required = false, Default = ScalingFilter.Bilinear, HelpText = "Set the scaling filter. [Bilinear|Nearest|Fsr]")]
public ScalingFilter ScalingFilter { get; set; }
[Option("scaling-filter-level", Required = false, Default = 0, HelpText = "Set the scaling filter intensity (currently only applies to FSR). [0-100]")]

View File

@@ -1,10 +1,13 @@
using CommandLine;
using Gommon;
using Ryujinx.Ava;
using Ryujinx.Ava.Utilities.Configuration;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.SDL2;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Logging.Targets;
@@ -12,9 +15,16 @@ using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.Utilities;
using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Metal;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.Headless.SDL2.Metal;
using Ryujinx.Headless.SDL2.OpenGL;
using Ryujinx.Headless.SDL2.Vulkan;
using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
@@ -23,15 +33,22 @@ using Ryujinx.Input;
using Ryujinx.Input.HLE;
using Ryujinx.Input.SDL2;
using Ryujinx.SDL2.Common;
using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading;
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Headless
namespace Ryujinx.Headless.SDL2
{
public partial class HeadlessRyujinx
class Program
{
public static string Version { get; private set; }
private static VirtualFileSystem _virtualFileSystem;
private static ContentManager _contentManager;
private static AccountManager _accountManager;
@@ -41,18 +58,20 @@ namespace Ryujinx.Headless
private static Switch _emulationContext;
private static WindowBase _window;
private static WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
private static List<InputConfig> _inputConfiguration = [];
private static List<InputConfig> _inputConfiguration;
private static bool _enableKeyboard;
private static bool _enableMouse;
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public static void Entrypoint(string[] args)
static void Main(string[] args)
{
Version = ReleaseInformation.Version;
// Make process DPI aware for proper window sizing on high-res screens.
ForceDpiAware.Windows();
Console.Title = $"Ryujinx Console {Program.Version} (Headless)";
Console.Title = $"Ryujinx Console {Version} (Headless SDL2)";
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
{
@@ -80,7 +99,7 @@ namespace Ryujinx.Headless
}
Parser.Default.ParseArguments<Options>(args)
.WithParsed(options => Load(args, options))
.WithParsed(Load)
.WithNotParsed(errors =>
{
Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:");
@@ -88,81 +107,239 @@ namespace Ryujinx.Headless
errors.ForEach(err => Logger.Error?.PrintMsg(LogClass.Application, $" - {err.Tag}"));
});
}
public static void ReloadConfig(string customConfigPath = null)
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
{
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
string configurationPath = null;
// Now load the configuration as the other subsystems are now registered
if (customConfigPath != null && File.Exists(customConfigPath))
if (inputId == null)
{
configurationPath = customConfigPath;
}
else if (File.Exists(localConfigurationPath))
{
configurationPath = localConfigurationPath;
}
else if (File.Exists(appDataConfigurationPath))
{
configurationPath = appDataConfigurationPath;
}
if (configurationPath == null)
{
// No configuration, we load the default values and save it to disk
configurationPath = appDataConfigurationPath;
Logger.Notice.Print(LogClass.Application, $"No configuration file found. Saving default configuration to: {configurationPath}");
ConfigurationState.Instance.LoadDefault();
ConfigurationState.Instance.ToFileFormat().SaveConfig(configurationPath);
}
else
{
Logger.Notice.Print(LogClass.Application, $"Loading configuration from: {configurationPath}");
if (ConfigurationFileFormat.TryLoad(configurationPath, out ConfigurationFileFormat configurationFileFormat))
if (index == PlayerIndex.Player1)
{
ConfigurationState.Instance.Load(configurationFileFormat, configurationPath);
Logger.Info?.Print(LogClass.Application, $"{index} not configured, defaulting to default keyboard.");
// Default to keyboard
inputId = "0";
}
else
{
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location: {configurationPath}");
Logger.Info?.Print(LogClass.Application, $"{index} not configured");
ConfigurationState.Instance.LoadDefault();
return null;
}
}
IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
bool isKeyboard = true;
if (gamepad == null)
{
gamepad = _inputManager.GamepadDriver.GetGamepad(inputId);
isKeyboard = false;
if (gamepad == null)
{
Logger.Error?.Print(LogClass.Application, $"{index} gamepad not found (\"{inputId}\")");
return null;
}
}
string gamepadName = gamepad.Name;
gamepad.Dispose();
InputConfig config;
if (inputProfileName == null || inputProfileName.Equals("default"))
{
if (isKeyboard)
{
config = new StandardKeyboardInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.WindowKeyboard,
Id = null,
ControllerType = ControllerType.JoyconPair,
LeftJoycon = new LeftJoyconCommonConfig<Key>
{
DpadUp = Key.Up,
DpadDown = Key.Down,
DpadLeft = Key.Left,
DpadRight = Key.Right,
ButtonMinus = Key.Minus,
ButtonL = Key.E,
ButtonZl = Key.Q,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound,
},
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
{
StickUp = Key.W,
StickDown = Key.S,
StickLeft = Key.A,
StickRight = Key.D,
StickButton = Key.F,
},
RightJoycon = new RightJoyconCommonConfig<Key>
{
ButtonA = Key.Z,
ButtonB = Key.X,
ButtonX = Key.C,
ButtonY = Key.V,
ButtonPlus = Key.Plus,
ButtonR = Key.U,
ButtonZr = Key.O,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound,
},
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
{
StickUp = Key.I,
StickDown = Key.K,
StickLeft = Key.J,
StickRight = Key.L,
StickButton = Key.H,
},
};
}
else
{
bool isNintendoStyle = gamepadName.Contains("Nintendo");
config = new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.GamepadSDL2,
Id = null,
ControllerType = ControllerType.JoyconPair,
DeadzoneLeft = 0.1f,
DeadzoneRight = 0.1f,
RangeLeft = 1.0f,
RangeRight = 1.0f,
TriggerThreshold = 0.5f,
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
{
DpadUp = ConfigGamepadInputId.DpadUp,
DpadDown = ConfigGamepadInputId.DpadDown,
DpadLeft = ConfigGamepadInputId.DpadLeft,
DpadRight = ConfigGamepadInputId.DpadRight,
ButtonMinus = ConfigGamepadInputId.Minus,
ButtonL = ConfigGamepadInputId.LeftShoulder,
ButtonZl = ConfigGamepadInputId.LeftTrigger,
ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound,
},
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{
Joystick = ConfigStickInputId.Left,
StickButton = ConfigGamepadInputId.LeftStick,
InvertStickX = false,
InvertStickY = false,
Rotate90CW = false,
},
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
{
ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
ButtonPlus = ConfigGamepadInputId.Plus,
ButtonR = ConfigGamepadInputId.RightShoulder,
ButtonZr = ConfigGamepadInputId.RightTrigger,
ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound,
},
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{
Joystick = ConfigStickInputId.Right,
StickButton = ConfigGamepadInputId.RightStick,
InvertStickX = false,
InvertStickY = false,
Rotate90CW = false,
},
Motion = new StandardMotionConfigController
{
MotionBackend = MotionInputBackendType.GamepadDriver,
EnableMotion = true,
Sensitivity = 100,
GyroDeadzone = 1,
},
Rumble = new RumbleConfigController
{
StrongRumble = 1f,
WeakRumble = 1f,
EnableRumble = false,
},
};
}
}
else
{
string profileBasePath;
if (isKeyboard)
{
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "keyboard");
}
else
{
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "controller");
}
string path = Path.Combine(profileBasePath, inputProfileName + ".json");
if (!File.Exists(path))
{
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" not found for \"{inputId}\"");
return null;
}
try
{
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
}
catch (JsonException)
{
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" parsing failed for \"{inputId}\"");
return null;
}
}
config.Id = inputId;
config.PlayerIndex = index;
string inputTypeName = isKeyboard ? "Keyboard" : "Gamepad";
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} configured with {inputTypeName} \"{config.Id}\"");
// If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
if (config is StandardControllerInputConfig controllerConfig)
{
if (controllerConfig.RangeLeft <= 0.0f && controllerConfig.RangeRight <= 0.0f)
{
controllerConfig.RangeLeft = 1.0f;
controllerConfig.RangeRight = 1.0f;
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
}
}
return config;
}
static void Load(string[] originalArgs, Options option)
static void Load(Options option)
{
Initialize();
bool useLastUsedProfile = false;
if (option.InheritConfig)
{
option.InheritMainConfig(originalArgs, ConfigurationState.Instance, out useLastUsedProfile);
}
AppDataManager.Initialize(option.BaseDataDir);
if (useLastUsedProfile && AccountSaveDataManager.GetLastUsedUser().TryGet(out var profile))
option.UserProfile = profile.Name;
// Check if keys exists.
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
{
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
{
Logger.Error?.Print(LogClass.Application, "Keys not found");
}
}
ReloadConfig();
_virtualFileSystem = VirtualFileSystem.CreateInstance();
_libHacHorizonManager = new LibHacHorizonManager();
@@ -177,7 +354,7 @@ namespace Ryujinx.Headless
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
GraphicsConfig.EnableShaderCache = !option.DisableShaderCache;
GraphicsConfig.EnableShaderCache = true;
if (OperatingSystem.IsMacOS())
{
@@ -188,13 +365,15 @@ namespace Ryujinx.Headless
}
}
IGamepad gamepad;
if (option.ListInputIds)
{
Logger.Info?.Print(LogClass.Application, "Input Ids:");
foreach (string id in _inputManager.KeyboardDriver.GamepadsIds)
{
IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
@@ -203,7 +382,7 @@ namespace Ryujinx.Headless
foreach (string id in _inputManager.GamepadDriver.GamepadsIds)
{
IGamepad gamepad = _inputManager.GamepadDriver.GetGamepad(id);
gamepad = _inputManager.GamepadDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
@@ -220,7 +399,7 @@ namespace Ryujinx.Headless
return;
}
_inputConfiguration ??= [];
_inputConfiguration = new List<InputConfig>();
_enableKeyboard = option.EnableKeyboard;
_enableMouse = option.EnableMouse;
@@ -233,9 +412,9 @@ namespace Ryujinx.Headless
_inputConfiguration.Add(inputConfig);
}
}
LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1);
LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
LoadPlayerConfiguration(option.InputProfile3Name, option.InputId3, PlayerIndex.Player3);
LoadPlayerConfiguration(option.InputProfile4Name, option.InputId4, PlayerIndex.Player4);
LoadPlayerConfiguration(option.InputProfile5Name, option.InputId5, PlayerIndex.Player5);
@@ -243,7 +422,6 @@ namespace Ryujinx.Headless
LoadPlayerConfiguration(option.InputProfile7Name, option.InputId7, PlayerIndex.Player7);
LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8);
LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld);
if (_inputConfiguration.Count == 0)
{
@@ -255,7 +433,7 @@ namespace Ryujinx.Headless
Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub);
Logger.SetEnable(LogLevel.Info, !option.LoggingDisableInfo);
Logger.SetEnable(LogLevel.Warning, !option.LoggingDisableWarning);
Logger.SetEnable(LogLevel.Error, !option.LoggingDisableError);
Logger.SetEnable(LogLevel.Error, option.LoggingEnableError);
Logger.SetEnable(LogLevel.Trace, option.LoggingEnableTrace);
Logger.SetEnable(LogLevel.Guest, !option.LoggingDisableGuest);
Logger.SetEnable(LogLevel.AccessLog, option.LoggingEnableFsAccessLog);
@@ -344,6 +522,88 @@ namespace Ryujinx.Headless
};
}
private static IRenderer CreateRenderer(Options options, WindowBase window)
{
if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
{
string preferredGpuId = string.Empty;
Vk api = Vk.GetApi();
if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
{
string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
var devices = VulkanRenderer.GetPhysicalDevices(api);
foreach (var device in devices)
{
if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
{
preferredGpuId = device.Id;
break;
}
}
}
return new VulkanRenderer(
api,
(instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
vulkanWindow.GetRequiredInstanceExtensions,
preferredGpuId);
}
if (options.GraphicsBackend == GraphicsBackend.Metal && window is MetalWindow metalWindow && OperatingSystem.IsMacOS())
{
return new MetalRenderer(metalWindow.GetLayer);
}
return new OpenGLRenderer();
}
private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)
{
BackendThreading threadingMode = options.BackendThreading;
bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
if (threadedGAL)
{
renderer = new ThreadedRenderer(renderer);
}
HLEConfiguration configuration = new(_virtualFileSystem,
_libHacHorizonManager,
_contentManager,
_accountManager,
_userChannelPersistence,
renderer,
new SDL2HardwareDeviceDriver(),
options.DramSize,
window,
options.SystemLanguage,
options.SystemRegion,
options.VSyncMode,
!options.DisableDockedMode,
!options.DisablePTC,
options.EnableInternetAccess,
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
options.FsGlobalAccessLogMode,
options.SystemTimeOffset,
options.SystemTimeZone,
options.MemoryManagerMode,
options.IgnoreMissingServices,
options.AspectRatio,
options.AudioVolume,
options.UseHypervisor ?? true,
options.MultiplayerLanInterfaceId,
Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
false,
string.Empty,
string.Empty,
options.CustomVSyncInterval);
return new Switch(configuration);
}
private static void ExecutionEntrypoint()
{
if (OperatingSystem.IsWindows())

View File

@@ -0,0 +1,755 @@
using CommandLine;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.SDL2;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Logging.Targets;
using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.Utilities;
using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Metal;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Graphics.Vulkan;
<<<<<<< HEAD
using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.Graphics.Metal;
=======
>>>>>>> 137f5970f (Vertex Input Attributes)
using Ryujinx.Headless.SDL2.Metal;
using Ryujinx.Headless.SDL2.OpenGL;
using Ryujinx.Headless.SDL2.Vulkan;
using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Input;
using Ryujinx.Input.HLE;
using Ryujinx.Input.SDL2;
using Ryujinx.SDL2.Common;
using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading;
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Headless.SDL2
{
class Program
{
public static string Version { get; private set; }
private static VirtualFileSystem _virtualFileSystem;
private static ContentManager _contentManager;
private static AccountManager _accountManager;
private static LibHacHorizonManager _libHacHorizonManager;
private static UserChannelPersistence _userChannelPersistence;
private static InputManager _inputManager;
private static Switch _emulationContext;
private static WindowBase _window;
private static WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
private static List<InputConfig> _inputConfiguration;
private static bool _enableKeyboard;
private static bool _enableMouse;
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
static void Main(string[] args)
{
Version = ReleaseInformation.Version;
// Make process DPI aware for proper window sizing on high-res screens.
ForceDpiAware.Windows();
Console.Title = $"Ryujinx Console {Version} (Headless SDL2)";
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
{
AutoResetEvent invoked = new(false);
// MacOS must perform SDL polls from the main thread.
SDL2Driver.MainThreadDispatcher = action =>
{
invoked.Reset();
WindowBase.QueueMainThreadAction(() =>
{
action();
invoked.Set();
});
invoked.WaitOne();
};
}
if (OperatingSystem.IsMacOS())
{
MVKInitialization.InitializeResolver();
}
Parser.Default.ParseArguments<Options>(args)
.WithParsed(Load)
.WithNotParsed(errors => errors.Output());
}
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
{
if (inputId == null)
{
if (index == PlayerIndex.Player1)
{
Logger.Info?.Print(LogClass.Application, $"{index} not configured, defaulting to default keyboard.");
// Default to keyboard
inputId = "0";
}
else
{
Logger.Info?.Print(LogClass.Application, $"{index} not configured");
return null;
}
}
IGamepad gamepad;
bool isKeyboard = true;
gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
if (gamepad == null)
{
gamepad = _inputManager.GamepadDriver.GetGamepad(inputId);
isKeyboard = false;
if (gamepad == null)
{
Logger.Error?.Print(LogClass.Application, $"{index} gamepad not found (\"{inputId}\")");
return null;
}
}
string gamepadName = gamepad.Name;
gamepad.Dispose();
InputConfig config;
if (inputProfileName == null || inputProfileName.Equals("default"))
{
if (isKeyboard)
{
config = new StandardKeyboardInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.WindowKeyboard,
Id = null,
ControllerType = ControllerType.JoyconPair,
LeftJoycon = new LeftJoyconCommonConfig<Key>
{
DpadUp = Key.Up,
DpadDown = Key.Down,
DpadLeft = Key.Left,
DpadRight = Key.Right,
ButtonMinus = Key.Minus,
ButtonL = Key.E,
ButtonZl = Key.Q,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound,
},
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
{
StickUp = Key.W,
StickDown = Key.S,
StickLeft = Key.A,
StickRight = Key.D,
StickButton = Key.F,
},
RightJoycon = new RightJoyconCommonConfig<Key>
{
ButtonA = Key.Z,
ButtonB = Key.X,
ButtonX = Key.C,
ButtonY = Key.V,
ButtonPlus = Key.Plus,
ButtonR = Key.U,
ButtonZr = Key.O,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound,
},
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
{
StickUp = Key.I,
StickDown = Key.K,
StickLeft = Key.J,
StickRight = Key.L,
StickButton = Key.H,
},
};
}
else
{
bool isNintendoStyle = gamepadName.Contains("Nintendo");
config = new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.GamepadSDL2,
Id = null,
ControllerType = ControllerType.JoyconPair,
DeadzoneLeft = 0.1f,
DeadzoneRight = 0.1f,
RangeLeft = 1.0f,
RangeRight = 1.0f,
TriggerThreshold = 0.5f,
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
{
DpadUp = ConfigGamepadInputId.DpadUp,
DpadDown = ConfigGamepadInputId.DpadDown,
DpadLeft = ConfigGamepadInputId.DpadLeft,
DpadRight = ConfigGamepadInputId.DpadRight,
ButtonMinus = ConfigGamepadInputId.Minus,
ButtonL = ConfigGamepadInputId.LeftShoulder,
ButtonZl = ConfigGamepadInputId.LeftTrigger,
ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound,
},
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{
Joystick = ConfigStickInputId.Left,
StickButton = ConfigGamepadInputId.LeftStick,
InvertStickX = false,
InvertStickY = false,
Rotate90CW = false,
},
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
{
ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
ButtonPlus = ConfigGamepadInputId.Plus,
ButtonR = ConfigGamepadInputId.RightShoulder,
ButtonZr = ConfigGamepadInputId.RightTrigger,
ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound,
},
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{
Joystick = ConfigStickInputId.Right,
StickButton = ConfigGamepadInputId.RightStick,
InvertStickX = false,
InvertStickY = false,
Rotate90CW = false,
},
Motion = new StandardMotionConfigController
{
MotionBackend = MotionInputBackendType.GamepadDriver,
EnableMotion = true,
Sensitivity = 100,
GyroDeadzone = 1,
},
Rumble = new RumbleConfigController
{
StrongRumble = 1f,
WeakRumble = 1f,
EnableRumble = false,
},
};
}
}
else
{
string profileBasePath;
if (isKeyboard)
{
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "keyboard");
}
else
{
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "controller");
}
string path = Path.Combine(profileBasePath, inputProfileName + ".json");
if (!File.Exists(path))
{
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" not found for \"{inputId}\"");
return null;
}
try
{
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
}
catch (JsonException)
{
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" parsing failed for \"{inputId}\"");
return null;
}
}
config.Id = inputId;
config.PlayerIndex = index;
string inputTypeName = isKeyboard ? "Keyboard" : "Gamepad";
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} configured with {inputTypeName} \"{config.Id}\"");
// If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
if (config is StandardControllerInputConfig controllerConfig)
{
if (controllerConfig.RangeLeft <= 0.0f && controllerConfig.RangeRight <= 0.0f)
{
controllerConfig.RangeLeft = 1.0f;
controllerConfig.RangeRight = 1.0f;
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
}
}
return config;
}
static void Load(Options option)
{
AppDataManager.Initialize(option.BaseDataDir);
_virtualFileSystem = VirtualFileSystem.CreateInstance();
_libHacHorizonManager = new LibHacHorizonManager();
_libHacHorizonManager.InitializeFsServer(_virtualFileSystem);
_libHacHorizonManager.InitializeArpServer();
_libHacHorizonManager.InitializeBcatServer();
_libHacHorizonManager.InitializeSystemClients();
_contentManager = new ContentManager(_virtualFileSystem);
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, option.UserProfile);
_userChannelPersistence = new UserChannelPersistence();
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
GraphicsConfig.EnableShaderCache = true;
if (OperatingSystem.IsMacOS())
{
if (option.GraphicsBackend == GraphicsBackend.OpenGl)
{
option.GraphicsBackend = GraphicsBackend.Vulkan;
Logger.Warning?.Print(LogClass.Application, "OpenGL is not supported on macOS, switching to Vulkan!");
}
}
IGamepad gamepad;
if (option.ListInputIds)
{
Logger.Info?.Print(LogClass.Application, "Input Ids:");
foreach (string id in _inputManager.KeyboardDriver.GamepadsIds)
{
gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
gamepad.Dispose();
}
foreach (string id in _inputManager.GamepadDriver.GamepadsIds)
{
gamepad = _inputManager.GamepadDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
gamepad.Dispose();
}
return;
}
if (option.InputPath == null)
{
Logger.Error?.Print(LogClass.Application, "Please provide a file to load");
return;
}
_inputConfiguration = new List<InputConfig>();
_enableKeyboard = option.EnableKeyboard;
_enableMouse = option.EnableMouse;
static void LoadPlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
{
InputConfig inputConfig = HandlePlayerConfiguration(inputProfileName, inputId, index);
if (inputConfig != null)
{
_inputConfiguration.Add(inputConfig);
}
}
LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1);
LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
LoadPlayerConfiguration(option.InputProfile3Name, option.InputId3, PlayerIndex.Player3);
LoadPlayerConfiguration(option.InputProfile4Name, option.InputId4, PlayerIndex.Player4);
LoadPlayerConfiguration(option.InputProfile5Name, option.InputId5, PlayerIndex.Player5);
LoadPlayerConfiguration(option.InputProfile6Name, option.InputId6, PlayerIndex.Player6);
LoadPlayerConfiguration(option.InputProfile7Name, option.InputId7, PlayerIndex.Player7);
LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8);
LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld);
if (_inputConfiguration.Count == 0)
{
return;
}
// Setup logging level
Logger.SetEnable(LogLevel.Debug, option.LoggingEnableDebug);
Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub);
Logger.SetEnable(LogLevel.Info, !option.LoggingDisableInfo);
Logger.SetEnable(LogLevel.Warning, !option.LoggingDisableWarning);
Logger.SetEnable(LogLevel.Error, option.LoggingEnableError);
Logger.SetEnable(LogLevel.Trace, option.LoggingEnableTrace);
Logger.SetEnable(LogLevel.Guest, !option.LoggingDisableGuest);
Logger.SetEnable(LogLevel.AccessLog, option.LoggingEnableFsAccessLog);
if (!option.DisableFileLog)
{
string logDir = AppDataManager.LogsDirPath;
FileStream logFile = null;
if (!string.IsNullOrEmpty(logDir))
{
logFile = FileLogTarget.PrepareLogFile(logDir);
}
if (logFile != null)
{
Logger.AddTarget(new AsyncLogTargetWrapper(
new FileLogTarget("file", logFile),
1000,
AsyncLogTargetOverflowAction.Block
));
}
else
{
Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the Logs directory, Application Data, or the Ryujinx directory is writable.");
}
}
// Setup graphics configuration
GraphicsConfig.EnableShaderCache = !option.DisableShaderCache;
GraphicsConfig.EnableTextureRecompression = option.EnableTextureRecompression;
GraphicsConfig.ResScale = option.ResScale;
GraphicsConfig.MaxAnisotropy = option.MaxAnisotropy;
GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath;
GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE;
DriverUtilities.InitDriverConfig(option.BackendThreading == BackendThreading.Off);
while (true)
{
LoadApplication(option);
if (_userChannelPersistence.PreviousIndex == -1 || !_userChannelPersistence.ShouldRestart)
{
break;
}
_userChannelPersistence.ShouldRestart = false;
}
_inputManager.Dispose();
}
private static void SetupProgressHandler()
{
if (_emulationContext.Processes.ActiveApplication.DiskCacheLoadState != null)
{
_emulationContext.Processes.ActiveApplication.DiskCacheLoadState.StateChanged -= ProgressHandler;
_emulationContext.Processes.ActiveApplication.DiskCacheLoadState.StateChanged += ProgressHandler;
}
_emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler;
_emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
}
private static void ProgressHandler<T>(T state, int current, int total) where T : Enum
{
string label = state switch
{
LoadState => $"PTC : {current}/{total}",
ShaderCacheState => $"Shaders : {current}/{total}",
_ => throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}"),
};
Logger.Info?.Print(LogClass.Application, label);
}
private static WindowBase CreateWindow(Options options)
{
return options.GraphicsBackend switch
{
GraphicsBackend.Vulkan => new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode),
GraphicsBackend.Metal => new MetalWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableKeyboard, options.HideCursorMode),
_ => new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode)
};
}
private static IRenderer CreateRenderer(Options options, WindowBase window)
{
if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
{
string preferredGpuId = string.Empty;
Vk api = Vk.GetApi();
if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
{
string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
var devices = VulkanRenderer.GetPhysicalDevices(api);
foreach (var device in devices)
{
if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
{
preferredGpuId = device.Id;
break;
}
}
}
return new VulkanRenderer(
api,
(instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
vulkanWindow.GetRequiredInstanceExtensions,
preferredGpuId);
}
if (options.GraphicsBackend == GraphicsBackend.Metal && window is MetalWindow metalWindow && OperatingSystem.IsMacOS())
{
return new MetalRenderer(metalWindow.GetLayer);
}
return new OpenGLRenderer();
}
private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)
{
BackendThreading threadingMode = options.BackendThreading;
bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
if (threadedGAL)
{
renderer = new ThreadedRenderer(renderer);
}
HLEConfiguration configuration = new(_virtualFileSystem,
_libHacHorizonManager,
_contentManager,
_accountManager,
_userChannelPersistence,
renderer,
new SDL2HardwareDeviceDriver(),
options.ExpandRAM ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB,
window,
options.SystemLanguage,
options.SystemRegion,
!options.DisableVSync,
!options.DisableDockedMode,
!options.DisablePTC,
options.EnableInternetAccess,
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
options.FsGlobalAccessLogMode,
options.SystemTimeOffset,
options.SystemTimeZone,
options.MemoryManagerMode,
options.IgnoreMissingServices,
options.AspectRatio,
options.AudioVolume,
options.UseHypervisor ?? true,
options.MultiplayerLanInterfaceId,
Common.Configuration.Multiplayer.MultiplayerMode.Disabled);
return new Switch(configuration);
}
private static void ExecutionEntrypoint()
{
if (OperatingSystem.IsWindows())
{
_windowsMultimediaTimerResolution = new WindowsMultimediaTimerResolution(1);
}
DisplaySleep.Prevent();
_window.Initialize(_emulationContext, _inputConfiguration, _enableKeyboard, _enableMouse);
_window.Execute();
_emulationContext.Dispose();
_window.Dispose();
if (OperatingSystem.IsWindows())
{
_windowsMultimediaTimerResolution?.Dispose();
_windowsMultimediaTimerResolution = null;
}
}
private static bool LoadApplication(Options options)
{
string path = options.InputPath;
Logger.RestartTime();
WindowBase window = CreateWindow(options);
IRenderer renderer = CreateRenderer(options, window);
_window = window;
_window.IsFullscreen = options.IsFullscreen;
_window.DisplayId = options.DisplayId;
_window.IsExclusiveFullscreen = options.IsExclusiveFullscreen;
_window.ExclusiveFullscreenWidth = options.ExclusiveFullscreenWidth;
_window.ExclusiveFullscreenHeight = options.ExclusiveFullscreenHeight;
_window.AntiAliasing = options.AntiAliasing;
_window.ScalingFilter = options.ScalingFilter;
_window.ScalingFilterLevel = options.ScalingFilterLevel;
_emulationContext = InitializeEmulationContext(window, renderer, options);
SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion();
Logger.Notice.Print(LogClass.Application, $"Using Firmware Version: {firmwareVersion?.VersionString}");
if (Directory.Exists(path))
{
string[] romFsFiles = Directory.GetFiles(path, "*.istorage");
if (romFsFiles.Length == 0)
{
romFsFiles = Directory.GetFiles(path, "*.romfs");
}
if (romFsFiles.Length > 0)
{
Logger.Info?.Print(LogClass.Application, "Loading as cart with RomFS.");
if (!_emulationContext.LoadCart(path, romFsFiles[0]))
{
_emulationContext.Dispose();
return false;
}
}
else
{
Logger.Info?.Print(LogClass.Application, "Loading as cart WITHOUT RomFS.");
if (!_emulationContext.LoadCart(path))
{
_emulationContext.Dispose();
return false;
}
}
}
else if (File.Exists(path))
{
switch (Path.GetExtension(path).ToLowerInvariant())
{
case ".xci":
Logger.Info?.Print(LogClass.Application, "Loading as XCI.");
if (!_emulationContext.LoadXci(path))
{
_emulationContext.Dispose();
return false;
}
break;
case ".nca":
Logger.Info?.Print(LogClass.Application, "Loading as NCA.");
if (!_emulationContext.LoadNca(path))
{
_emulationContext.Dispose();
return false;
}
break;
case ".nsp":
case ".pfs0":
Logger.Info?.Print(LogClass.Application, "Loading as NSP.");
if (!_emulationContext.LoadNsp(path))
{
_emulationContext.Dispose();
return false;
}
break;
default:
Logger.Info?.Print(LogClass.Application, "Loading as Homebrew.");
try
{
if (!_emulationContext.LoadProgram(path))
{
_emulationContext.Dispose();
return false;
}
}
catch (ArgumentOutOfRangeException)
{
Logger.Error?.Print(LogClass.Application, "The specified file is not supported by Ryujinx.");
_emulationContext.Dispose();
return false;
}
break;
}
}
else
{
Logger.Warning?.Print(LogClass.Application, $"Couldn't load '{options.InputPath}'. Please specify a valid XCI/NCA/NSP/PFS0/NRO file.");
_emulationContext.Dispose();
return false;
}
SetupProgressHandler();
ExecutionEntrypoint();
return true;
}
}
}

View File

@@ -0,0 +1,73 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>1.0.0-dirty</Version>
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
<SigningCertificate Condition=" '$(SigningCertificate)' == '' ">-</SigningCertificate>
<TieredPGO>true</TieredPGO>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.Core" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
<Exec Command="codesign --entitlements '$(ProjectDir)..\..\distribution\macos\entitlements.xml' -f -s $(SigningCertificate) '$(TargetDir)$(TargetName)'" />
</Target>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
<ProjectReference Include="..\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" />
<ProjectReference Include="..\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" />
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64'" />
</ItemGroup>
<ItemGroup>
<Content Include="..\..\distribution\legal\THIRDPARTY.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>THIRDPARTY.md</TargetPath>
</Content>
<Content Include="..\..\LICENSE.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>LICENSE.txt</TargetPath>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm64' OR ('$(RuntimeIdentifier)' == '' AND $([MSBuild]::IsOSPlatform('Linux')))">
<Content Include="..\..\distribution\linux\Ryujinx.sh">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Ryujinx.bmp" />
</ItemGroup>
<!-- Due to .net core 3.1 embedded resource loading -->
<PropertyGroup>
<EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
<ApplicationIcon>..\Ryujinx\Ryujinx.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>partial</TrimMode>
</PropertyGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -1,6 +1,6 @@
using System;
namespace Ryujinx.Headless
namespace Ryujinx.Headless.SDL2
{
class StatusUpdatedEventArgs(
string vSyncMode,

View File

@@ -6,7 +6,7 @@ using System;
using System.Runtime.InteropServices;
using static SDL2.SDL;
namespace Ryujinx.Headless
namespace Ryujinx.Headless.SDL2.Vulkan
{
class VulkanWindow : WindowBase
{

View File

@@ -1,6 +1,5 @@
using Humanizer;
using LibHac.Tools.Fs;
using Ryujinx.Ava;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging;
@@ -27,7 +26,7 @@ using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
using Switch = Ryujinx.HLE.Switch;
namespace Ryujinx.Headless
namespace Ryujinx.Headless.SDL2
{
abstract partial class WindowBase : IHostUIHandler, IDisposable
{
@@ -137,7 +136,7 @@ namespace Ryujinx.Headless
private void SetWindowIcon()
{
Stream iconStream = typeof(Program).Assembly.GetManifestResourceStream("HeadlessLogo");
Stream iconStream = typeof(WindowBase).Assembly.GetManifestResourceStream("Ryujinx.Headless.SDL2.Ryujinx.bmp");
byte[] iconBytes = new byte[iconStream!.Length];
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)
@@ -255,12 +254,12 @@ namespace Ryujinx.Headless
private void SetAntiAliasing()
{
Renderer?.Window.SetAntiAliasing(AntiAliasing);
Renderer?.Window.SetAntiAliasing((Graphics.GAL.AntiAliasing)AntiAliasing);
}
private void SetScalingFilter()
{
Renderer?.Window.SetScalingFilter(ScalingFilter);
Renderer?.Window.SetScalingFilter((Graphics.GAL.ScalingFilter)ScalingFilter);
Renderer?.Window.SetScalingFilterLevel(ScalingFilterLevel);
}
@@ -319,7 +318,7 @@ namespace Ryujinx.Headless
Device.VSyncMode.ToString(),
dockedMode,
Device.Configuration.AspectRatio.ToText(),
$"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
$"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
$"FIFO: {Device.Statistics.GetFifoPercent():0.00} %",
$"GPU: {_gpuDriverName}"));

View File

@@ -1,6 +1,6 @@
using System;
namespace Ryujinx.Ava.Utilities.AppLibrary
namespace Ryujinx.UI.App.Common
{
public class ApplicationCountUpdatedEventArgs : EventArgs
{

View File

@@ -10,14 +10,17 @@ using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.Loaders.Processes.Extensions;
using Ryujinx.UI.Common.Helper;
using System;
using System.IO;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.AppLibrary
namespace Ryujinx.UI.App.Common
{
public class ApplicationData
{
public static Func<string> LocalizedNever { get; set; } = () => "Never";
public bool Favorite { get; set; }
public byte[] Icon { get; set; }
public string Name { get; set; } = "Unknown";
@@ -33,11 +36,9 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public string Path { get; set; }
public BlitStruct<ApplicationControlProperty> ControlHolder { get; set; }
public bool HasControlHolder => ControlHolder.ByteSpan.Length > 0 && !ControlHolder.ByteSpan.IsZeros();
public string TimePlayedString => ValueFormatUtils.FormatTimeSpan(TimePlayed);
public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed)?.Replace(" ", "\n");
public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed)?.Replace(" ", "\n") ?? LocalizedNever();
public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize);

View File

@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.AppLibrary
namespace Ryujinx.UI.App.Common
{
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(ApplicationMetadata))]

View File

@@ -10,10 +10,6 @@ using LibHac.Ns;
using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Ava.Utilities.Configuration.System;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.Logging;
@@ -23,11 +19,16 @@ using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.Loaders.Npdm;
using Ryujinx.HLE.Loaders.Processes.Extensions;
using Ryujinx.HLE.Utilities;
using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Configuration.System;
using Ryujinx.UI.Common.Helper;
using Ryujinx.UI.Common.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading;
@@ -37,7 +38,7 @@ using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
using Path = System.IO.Path;
using TimeSpan = System.TimeSpan;
namespace Ryujinx.Ava.Utilities.AppLibrary
namespace Ryujinx.UI.App.Common
{
public class ApplicationLibrary
{
@@ -75,11 +76,21 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
TitleUpdates = _titleUpdates.AsObservableCache();
DownloadableContents = _downloadableContents.AsObservableCache();
_nspIcon = EmbeddedResources.Read("Ryujinx/Assets.UIImages.Icon_NSP.png");
_xciIcon = EmbeddedResources.Read("Ryujinx/Assets.UIImages.Icon_XCI.png");
_ncaIcon = EmbeddedResources.Read("Ryujinx/Assets.UIImages.Icon_NCA.png");
_nroIcon = EmbeddedResources.Read("Ryujinx/Assets.UIImages.Icon_NRO.png");
_nsoIcon = EmbeddedResources.Read("Ryujinx/Assets.UIImages.Icon_NSO.png");
_nspIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NSP.png");
_xciIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_XCI.png");
_ncaIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NCA.png");
_nroIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NRO.png");
_nsoIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NSO.png");
}
private static byte[] GetResourceBytes(string resourceName)
{
Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName)!;
byte[] resourceByteArray = new byte[resourceStream.Length];
resourceStream.ReadExactly(resourceByteArray);
return resourceByteArray;
}
/// <exception cref="Ryujinx.HLE.Exceptions.InvalidNpdmException">The npdm file doesn't contain valid data.</exception>
@@ -778,15 +789,16 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
using HttpClient httpClient = new HttpClient();
string ldnGameDataArrayString = await httpClient.GetStringAsync($"https://{ldnWebHost}/api/public_games");
ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData);
LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs
var evt = new LdnGameDataReceivedEventArgs
{
LdnData = ldnGameDataArray
});
};
LdnGameDataReceived?.Invoke(null, evt);
}
catch (Exception ex)
{
Logger.Warning?.Print(LogClass.Application, $"Failed to fetch the public games JSON from the API. Player and game count in the game list will be unavailable.\n{ex.Message}");
LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs
LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs()
{
LdnData = Array.Empty<LdnGameData>()
});
@@ -794,7 +806,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
}
else
{
LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs
LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs()
{
LdnData = Array.Empty<LdnGameData>()
});

View File

@@ -1,7 +1,7 @@
using System;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.AppLibrary
namespace Ryujinx.UI.App.Common
{
public class ApplicationMetadata
{

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace Ryujinx.UI.App.Common
{
public struct LdnGameData
{
public string Id { get; set; }
public int PlayerCount { get; set; }
public int MaxPlayerCount { get; set; }
public string GameName { get; set; }
public string TitleId { get; set; }
public string Mode { get; set; }
public string Status { get; set; }
public IEnumerable<string> Players { get; set; }
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
namespace Ryujinx.Ava.Utilities.AppLibrary
namespace Ryujinx.UI.App.Common
{
public class LdnGameDataReceivedEventArgs : EventArgs
{

View File

@@ -1,8 +1,11 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.AppLibrary
namespace Ryujinx.UI.App.Common
{
[JsonSerializable(typeof(IEnumerable<LdnGameData>))]
internal partial class LdnGameDataSerializerContext : JsonSerializerContext;
internal partial class LdnGameDataSerializerContext : JsonSerializerContext
{
}
}

View File

@@ -1,7 +1,7 @@
using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.Configuration
namespace Ryujinx.UI.Common.Configuration
{
[JsonConverter(typeof(TypedStringEnumConverter<AudioBackend>))]
public enum AudioBackend

View File

@@ -1,5 +1,3 @@
using Ryujinx.Ava.Utilities.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
@@ -7,17 +5,19 @@ using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE;
using Ryujinx.UI.Common.Configuration.System;
using Ryujinx.UI.Common.Configuration.UI;
using System.Collections.Generic;
using System.Text.Json.Nodes;
namespace Ryujinx.Ava.Utilities.Configuration
namespace Ryujinx.UI.Common.Configuration
{
public class ConfigurationFileFormat
{
/// <summary>
/// The current version of the file format
/// </summary>
public const int CurrentVersion = 59;
public const int CurrentVersion = 57;
/// <summary>
/// Version of the configuration file format
@@ -272,7 +272,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
public MemoryManagerMode MemoryManagerMode { get; set; }
/// <summary>
/// Expands the RAM amount on the emulated system
/// Expands the RAM amount on the emulated system from 4GiB to 8GiB
/// </summary>
public MemoryConfiguration DramSize { get; set; }
@@ -429,17 +429,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// Uses Hypervisor over JIT if available
/// </summary>
public bool UseHypervisor { get; set; }
/// <summary>
/// Show toggles for dirty hacks in the UI.
/// </summary>
public bool ShowDirtyHacks { get; set; }
/// <summary>
/// The packed values of the enabled dirty hacks.
/// </summary>
public ulong[] DirtyHacks { get; set; }
/// <summary>
/// Loads a configuration file from disk
/// </summary>

View File

@@ -1,6 +1,6 @@
using Ryujinx.Common.Utilities;
namespace Ryujinx.Ava.Utilities.Configuration
namespace Ryujinx.UI.Common.Configuration
{
internal static class ConfigurationFileFormatSettings
{

View File

@@ -1,8 +1,10 @@
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.Configuration
namespace Ryujinx.UI.Common.Configuration
{
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(ConfigurationFileFormat))]
internal partial class ConfigurationJsonSerializerContext : JsonSerializerContext;
internal partial class ConfigurationJsonSerializerContext : JsonSerializerContext
{
}
}

View File

@@ -0,0 +1,747 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.Logging;
using Ryujinx.HLE;
using Ryujinx.UI.Common.Configuration.System;
using Ryujinx.UI.Common.Configuration.UI;
using System;
using System.Collections.Generic;
namespace Ryujinx.UI.Common.Configuration
{
public partial class ConfigurationState
{
public void Load(ConfigurationFileFormat configurationFileFormat, string configurationFilePath)
{
bool configurationFileUpdated = false;
if (configurationFileFormat.Version is < 0 or > ConfigurationFileFormat.CurrentVersion)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Unsupported configuration version {configurationFileFormat.Version}, loading default.");
LoadDefault();
}
if (configurationFileFormat.Version < 2)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 2.");
configurationFileFormat.SystemRegion = Region.USA;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 3)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 3.");
configurationFileFormat.SystemTimeZone = "UTC";
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 4)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 4.");
configurationFileFormat.MaxAnisotropy = -1;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 5)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 5.");
configurationFileFormat.SystemTimeOffset = 0;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 8)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 8.");
configurationFileFormat.EnablePtc = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 9)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 9.");
configurationFileFormat.ColumnSort = new ColumnSort
{
SortColumnId = 0,
SortAscending = false,
};
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = Key.F1,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 10)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 10.");
configurationFileFormat.AudioBackend = AudioBackend.OpenAl;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 11)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 11.");
configurationFileFormat.ResScale = 1;
configurationFileFormat.ResScaleCustom = 1.0f;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 12)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 12.");
configurationFileFormat.LoggingGraphicsDebugLevel = GraphicsDebugLevel.None;
configurationFileUpdated = true;
}
// configurationFileFormat.Version == 13 -> LDN1
if (configurationFileFormat.Version < 14)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 14.");
configurationFileFormat.CheckUpdatesOnStart = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 16)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 16.");
configurationFileFormat.EnableShaderCache = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 17)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 17.");
configurationFileFormat.StartFullscreen = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 18)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 18.");
configurationFileFormat.AspectRatio = AspectRatio.Fixed16x9;
configurationFileUpdated = true;
}
// configurationFileFormat.Version == 19 -> LDN2
if (configurationFileFormat.Version < 20)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 20.");
configurationFileFormat.ShowConfirmExit = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 21)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 21.");
// Initialize network config.
configurationFileFormat.MultiplayerMode = MultiplayerMode.Disabled;
configurationFileFormat.MultiplayerLanInterfaceId = "0";
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 22)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 22.");
configurationFileFormat.HideCursor = HideCursorMode.Never;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 24)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 24.");
configurationFileFormat.InputConfig = new List<InputConfig>
{
new StandardKeyboardInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.WindowKeyboard,
Id = "0",
PlayerIndex = PlayerIndex.Player1,
ControllerType = ControllerType.ProController,
LeftJoycon = new LeftJoyconCommonConfig<Key>
{
DpadUp = Key.Up,
DpadDown = Key.Down,
DpadLeft = Key.Left,
DpadRight = Key.Right,
ButtonMinus = Key.Minus,
ButtonL = Key.E,
ButtonZl = Key.Q,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound,
},
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
{
StickUp = Key.W,
StickDown = Key.S,
StickLeft = Key.A,
StickRight = Key.D,
StickButton = Key.F,
},
RightJoycon = new RightJoyconCommonConfig<Key>
{
ButtonA = Key.Z,
ButtonB = Key.X,
ButtonX = Key.C,
ButtonY = Key.V,
ButtonPlus = Key.Plus,
ButtonR = Key.U,
ButtonZr = Key.O,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound,
},
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
{
StickUp = Key.I,
StickDown = Key.K,
StickLeft = Key.J,
StickRight = Key.L,
StickButton = Key.H,
},
},
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 25)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 25.");
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 26)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 26.");
configurationFileFormat.MemoryManagerMode = MemoryManagerMode.HostMappedUnsafe;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 27)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 27.");
configurationFileFormat.EnableMouse = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 28)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 28.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = Key.F1,
Screenshot = Key.F8,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 29)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 29.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = Key.F1,
Screenshot = Key.F8,
ShowUI = Key.F4,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 30)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 30.");
foreach (InputConfig config in configurationFileFormat.InputConfig)
{
if (config is StandardControllerInputConfig controllerConfig)
{
controllerConfig.Rumble = new RumbleConfigController
{
EnableRumble = false,
StrongRumble = 1f,
WeakRumble = 1f,
};
}
}
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 31)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 31.");
configurationFileFormat.BackendThreading = BackendThreading.Auto;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 32)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 32.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = Key.F5,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 33)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 33.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = configurationFileFormat.Hotkeys.Pause,
ToggleMute = Key.F2,
};
configurationFileFormat.AudioVolume = 1;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 34)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 34.");
configurationFileFormat.EnableInternetAccess = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 35)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 35.");
foreach (InputConfig config in configurationFileFormat.InputConfig)
{
if (config is StandardControllerInputConfig controllerConfig)
{
controllerConfig.RangeLeft = 1.0f;
controllerConfig.RangeRight = 1.0f;
}
}
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 36)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 36.");
configurationFileFormat.LoggingEnableTrace = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 37)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 37.");
configurationFileFormat.ShowConsole = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 38)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 38.");
configurationFileFormat.BaseStyle = "Dark";
configurationFileFormat.GameListViewMode = 0;
configurationFileFormat.ShowNames = true;
configurationFileFormat.GridSize = 2;
configurationFileFormat.LanguageCode = "en_US";
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 39)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 39.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = configurationFileFormat.Hotkeys.Pause,
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
ResScaleUp = Key.Unbound,
ResScaleDown = Key.Unbound,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 40)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 40.");
configurationFileFormat.GraphicsBackend = GraphicsBackend.OpenGl;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 41)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 41.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = configurationFileFormat.Hotkeys.Pause,
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
VolumeUp = Key.Unbound,
VolumeDown = Key.Unbound,
};
}
if (configurationFileFormat.Version < 42)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 42.");
configurationFileFormat.EnableMacroHLE = true;
}
if (configurationFileFormat.Version < 43)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 43.");
configurationFileFormat.UseHypervisor = true;
}
if (configurationFileFormat.Version < 44)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 44.");
configurationFileFormat.AntiAliasing = AntiAliasing.None;
configurationFileFormat.ScalingFilter = ScalingFilter.Bilinear;
configurationFileFormat.ScalingFilterLevel = 80;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 45)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 45.");
configurationFileFormat.ShownFileTypes = new ShownFileTypes
{
NSP = true,
PFS0 = true,
XCI = true,
NCA = true,
NRO = true,
NSO = true,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 46)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 46.");
configurationFileFormat.MultiplayerLanInterfaceId = "0";
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 47)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 47.");
configurationFileFormat.WindowStartup = new WindowStartup
{
WindowPositionX = 0,
WindowPositionY = 0,
WindowSizeHeight = 760,
WindowSizeWidth = 1280,
WindowMaximized = false,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 48)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 48.");
configurationFileFormat.EnableColorSpacePassthrough = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 49)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 49.");
if (OperatingSystem.IsMacOS())
{
AppDataManager.FixMacOSConfigurationFolders();
}
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 50)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 50.");
configurationFileFormat.EnableHardwareAcceleration = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 51)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 51.");
configurationFileFormat.RememberWindowState = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 52)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 52.");
configurationFileFormat.AutoloadDirs = [];
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 53)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 53.");
configurationFileFormat.EnableLowPowerPtc = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 54)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 54.");
configurationFileFormat.DramSize = MemoryConfiguration.MemoryConfiguration4GiB;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 55)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 55.");
configurationFileFormat.IgnoreApplet = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 56)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 56.");
configurationFileFormat.ShowTitleBar = !OperatingSystem.IsWindows();
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 57)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 57.");
configurationFileFormat.VSyncMode = VSyncMode.Switch;
configurationFileFormat.EnableCustomVSyncInterval = false;
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = Key.F1,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = configurationFileFormat.Hotkeys.Pause,
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
VolumeUp = configurationFileFormat.Hotkeys.VolumeUp,
VolumeDown = configurationFileFormat.Hotkeys.VolumeDown,
CustomVSyncIntervalIncrement = Key.Unbound,
CustomVSyncIntervalDecrement = Key.Unbound,
};
configurationFileFormat.CustomVSyncInterval = 120;
configurationFileUpdated = true;
}
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
Graphics.ResScale.Value = configurationFileFormat.ResScale;
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
Graphics.MaxAnisotropy.Value = configurationFileFormat.MaxAnisotropy;
Graphics.AspectRatio.Value = configurationFileFormat.AspectRatio;
Graphics.ShadersDumpPath.Value = configurationFileFormat.GraphicsShadersDumpPath;
Graphics.BackendThreading.Value = configurationFileFormat.BackendThreading;
Graphics.GraphicsBackend.Value = configurationFileFormat.GraphicsBackend;
Graphics.PreferredGpu.Value = configurationFileFormat.PreferredGpu;
Graphics.AntiAliasing.Value = configurationFileFormat.AntiAliasing;
Graphics.ScalingFilter.Value = configurationFileFormat.ScalingFilter;
Graphics.ScalingFilterLevel.Value = configurationFileFormat.ScalingFilterLevel;
Logger.EnableDebug.Value = configurationFileFormat.LoggingEnableDebug;
Logger.EnableStub.Value = configurationFileFormat.LoggingEnableStub;
Logger.EnableInfo.Value = configurationFileFormat.LoggingEnableInfo;
Logger.EnableWarn.Value = configurationFileFormat.LoggingEnableWarn;
Logger.EnableError.Value = configurationFileFormat.LoggingEnableError;
Logger.EnableTrace.Value = configurationFileFormat.LoggingEnableTrace;
Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest;
Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog;
Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses;
Logger.GraphicsDebugLevel.Value = configurationFileFormat.LoggingGraphicsDebugLevel;
System.Language.Value = configurationFileFormat.SystemLanguage;
System.Region.Value = configurationFileFormat.SystemRegion;
System.TimeZone.Value = configurationFileFormat.SystemTimeZone;
System.SystemTimeOffset.Value = configurationFileFormat.SystemTimeOffset;
System.EnableDockedMode.Value = configurationFileFormat.DockedMode;
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart;
ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit;
IgnoreApplet.Value = configurationFileFormat.IgnoreApplet;
RememberWindowState.Value = configurationFileFormat.RememberWindowState;
ShowTitleBar.Value = configurationFileFormat.ShowTitleBar;
EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration;
HideCursor.Value = configurationFileFormat.HideCursor;
Graphics.VSyncMode.Value = configurationFileFormat.VSyncMode;
Graphics.EnableCustomVSyncInterval.Value = configurationFileFormat.EnableCustomVSyncInterval;
Graphics.CustomVSyncInterval.Value = configurationFileFormat.CustomVSyncInterval;
Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache;
Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression;
Graphics.EnableMacroHLE.Value = configurationFileFormat.EnableMacroHLE;
Graphics.EnableColorSpacePassthrough.Value = configurationFileFormat.EnableColorSpacePassthrough;
System.EnablePtc.Value = configurationFileFormat.EnablePtc;
System.EnableLowPowerPtc.Value = configurationFileFormat.EnableLowPowerPtc;
System.EnableInternetAccess.Value = configurationFileFormat.EnableInternetAccess;
System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks;
System.FsGlobalAccessLogMode.Value = configurationFileFormat.FsGlobalAccessLogMode;
System.AudioBackend.Value = configurationFileFormat.AudioBackend;
System.AudioVolume.Value = configurationFileFormat.AudioVolume;
System.MemoryManagerMode.Value = configurationFileFormat.MemoryManagerMode;
System.DramSize.Value = configurationFileFormat.DramSize;
System.IgnoreMissingServices.Value = configurationFileFormat.IgnoreMissingServices;
System.UseHypervisor.Value = configurationFileFormat.UseHypervisor;
UI.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn;
UI.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn;
UI.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn;
UI.GuiColumns.DevColumn.Value = configurationFileFormat.GuiColumns.DevColumn;
UI.GuiColumns.VersionColumn.Value = configurationFileFormat.GuiColumns.VersionColumn;
UI.GuiColumns.TimePlayedColumn.Value = configurationFileFormat.GuiColumns.TimePlayedColumn;
UI.GuiColumns.LastPlayedColumn.Value = configurationFileFormat.GuiColumns.LastPlayedColumn;
UI.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn;
UI.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn;
UI.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn;
UI.ColumnSort.SortColumnId.Value = configurationFileFormat.ColumnSort.SortColumnId;
UI.ColumnSort.SortAscending.Value = configurationFileFormat.ColumnSort.SortAscending;
UI.GameDirs.Value = configurationFileFormat.GameDirs;
UI.AutoloadDirs.Value = configurationFileFormat.AutoloadDirs ?? [];
UI.ShownFileTypes.NSP.Value = configurationFileFormat.ShownFileTypes.NSP;
UI.ShownFileTypes.PFS0.Value = configurationFileFormat.ShownFileTypes.PFS0;
UI.ShownFileTypes.XCI.Value = configurationFileFormat.ShownFileTypes.XCI;
UI.ShownFileTypes.NCA.Value = configurationFileFormat.ShownFileTypes.NCA;
UI.ShownFileTypes.NRO.Value = configurationFileFormat.ShownFileTypes.NRO;
UI.ShownFileTypes.NSO.Value = configurationFileFormat.ShownFileTypes.NSO;
UI.LanguageCode.Value = configurationFileFormat.LanguageCode;
UI.BaseStyle.Value = configurationFileFormat.BaseStyle;
UI.GameListViewMode.Value = configurationFileFormat.GameListViewMode;
UI.ShowNames.Value = configurationFileFormat.ShowNames;
UI.IsAscendingOrder.Value = configurationFileFormat.IsAscendingOrder;
UI.GridSize.Value = configurationFileFormat.GridSize;
UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort;
UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
UI.ShowConsole.Value = configurationFileFormat.ShowConsole;
UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth;
UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight;
UI.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX;
UI.WindowStartup.WindowPositionY.Value = configurationFileFormat.WindowStartup.WindowPositionY;
UI.WindowStartup.WindowMaximized.Value = configurationFileFormat.WindowStartup.WindowMaximized;
Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
Hid.EnableMouse.Value = configurationFileFormat.EnableMouse;
Hid.Hotkeys.Value = configurationFileFormat.Hotkeys;
Hid.InputConfig.Value = configurationFileFormat.InputConfig ?? [];
Multiplayer.LanInterfaceId.Value = configurationFileFormat.MultiplayerLanInterfaceId;
Multiplayer.Mode.Value = configurationFileFormat.MultiplayerMode;
Multiplayer.DisableP2p.Value = configurationFileFormat.MultiplayerDisableP2p;
Multiplayer.LdnPassphrase.Value = configurationFileFormat.MultiplayerLdnPassphrase;
Multiplayer.LdnServer.Value = configurationFileFormat.LdnServer;
if (configurationFileUpdated)
{
ToFileFormat().SaveConfig(configurationFilePath);
Ryujinx.Common.Logging.Logger.Notice.Print(LogClass.Application, $"Configuration file updated to version {ConfigurationFileFormat.CurrentVersion}");
}
}
}
}

View File

@@ -1,18 +1,15 @@
using ARMeilleure;
using Gommon;
using Ryujinx.Ava.Utilities.Configuration.System;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging;
using Ryujinx.HLE;
using Ryujinx.UI.Common.Configuration.System;
using Ryujinx.UI.Common.Helper;
using System.Collections.Generic;
using System.Linq;
using RyuLogger = Ryujinx.Common.Logging.Logger;
namespace Ryujinx.Ava.Utilities.Configuration
namespace Ryujinx.UI.Common.Configuration
{
public partial class ConfigurationState
{
@@ -620,70 +617,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
}
}
public class HacksSection
{
/// <summary>
/// Show toggles for dirty hacks in the UI.
/// </summary>
public ReactiveObject<bool> ShowDirtyHacks { get; private set; }
public ReactiveObject<bool> Xc2MenuSoftlockFix { get; private set; }
public ReactiveObject<bool> EnableShaderTranslationDelay { get; private set; }
public ReactiveObject<int> ShaderTranslationDelay { get; private set; }
public HacksSection()
{
ShowDirtyHacks = new ReactiveObject<bool>();
Xc2MenuSoftlockFix = new ReactiveObject<bool>();
Xc2MenuSoftlockFix.Event += HackChanged;
EnableShaderTranslationDelay = new ReactiveObject<bool>();
EnableShaderTranslationDelay.Event += HackChanged;
ShaderTranslationDelay = new ReactiveObject<int>();
}
private void HackChanged(object sender, ReactiveEventArgs<bool> rxe)
{
if (!ShowDirtyHacks)
return;
var newHacks = EnabledHacks.Select(x => x.Hack)
.JoinToString(", ");
if (newHacks != _lastHackCollection)
{
RyuLogger.Info?.Print(LogClass.Configuration,
$"EnabledDirtyHacks set to: [{newHacks}]", "LogValueChange");
_lastHackCollection = newHacks;
}
}
private static string _lastHackCollection;
public EnabledDirtyHack[] EnabledHacks
{
get
{
List<EnabledDirtyHack> enabledHacks = [];
if (Xc2MenuSoftlockFix)
Apply(DirtyHack.Xc2MenuSoftlockFix);
if (EnableShaderTranslationDelay)
Apply(DirtyHack.ShaderTranslationDelay, ShaderTranslationDelay);
return enabledHacks.ToArray();
void Apply(DirtyHack hack, int value = 0)
{
enabledHacks.Add(new EnabledDirtyHack(hack, value));
}
}
}
}
/// <summary>
/// The default configuration instance
/// </summary>
@@ -718,11 +651,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// The Multiplayer section
/// </summary>
public MultiplayerSection Multiplayer { get; private set; }
/// <summary>
/// The Dirty Hacks section
/// </summary>
public HacksSection Hacks { get; private set; }
/// <summary>
/// Enables or disables Discord Rich Presence
@@ -772,7 +700,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
Graphics = new GraphicsSection();
Hid = new HidSection();
Multiplayer = new MultiplayerSection();
Hacks = new HacksSection();
EnableDiscordIntegration = new ReactiveObject<bool>();
CheckUpdatesOnStart = new ReactiveObject<bool>();
ShowConfirmExit = new ReactiveObject<bool>();

View File

@@ -1,15 +1,14 @@
using Ryujinx.Ava.Utilities.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE;
using Ryujinx.UI.Common.Configuration.System;
using Ryujinx.UI.Common.Configuration.UI;
using System;
using System.Linq;
namespace Ryujinx.Ava.Utilities.Configuration
namespace Ryujinx.UI.Common.Configuration
{
public partial class ConfigurationState
{
@@ -139,8 +138,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
MultiplayerDisableP2p = Multiplayer.DisableP2p,
MultiplayerLdnPassphrase = Multiplayer.LdnPassphrase,
LdnServer = Multiplayer.LdnServer,
ShowDirtyHacks = Hacks.ShowDirtyHacks,
DirtyHacks = Hacks.EnabledHacks.Select(it => it.Pack()).ToArray(),
};
return configurationFile;
@@ -308,15 +305,14 @@ namespace Ryujinx.Ava.Utilities.Configuration
private static GraphicsBackend DefaultGraphicsBackend()
{
// Any system running macOS should default to auto, so it uses Vulkan everywhere and Metal in games where it works well.
if (OperatingSystem.IsMacOS())
return GraphicsBackend.Auto;
// Any system returning any amount of valid Vulkan devices should default to Vulkan.
// Any system running macOS or returning any amount of valid Vulkan devices should default to Vulkan.
// Checks for if the Vulkan version and featureset is compatible should be performed within VulkanRenderer.
return VulkanRenderer.GetPhysicalDevices().Length > 0
? GraphicsBackend.Vulkan
: GraphicsBackend.OpenGl;
if (OperatingSystem.IsMacOS() || VulkanRenderer.GetPhysicalDevices().Length > 0)
{
return GraphicsBackend.Vulkan;
}
return GraphicsBackend.OpenGl;
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
namespace Ryujinx.UI.Common
{
public enum FileTypes
{
NSP,
PFS0,
XCI,
NCA,
NRO,
NSO
}
}

View File

@@ -4,7 +4,7 @@ using Ryujinx.Common.Logging.Targets;
using System;
using System.IO;
namespace Ryujinx.Ava.Utilities.Configuration
namespace Ryujinx.UI.Common.Configuration
{
public static class LoggerModule
{

View File

@@ -1,7 +1,7 @@
using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.Configuration.System
namespace Ryujinx.UI.Common.Configuration.System
{
[JsonConverter(typeof(TypedStringEnumConverter<Language>))]
public enum Language

View File

@@ -1,7 +1,7 @@
using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.Configuration.System
namespace Ryujinx.UI.Common.Configuration.System
{
[JsonConverter(typeof(TypedStringEnumConverter<Region>))]
public enum Region

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Utilities.Configuration.UI
namespace Ryujinx.UI.Common.Configuration.UI
{
public struct ColumnSort
{

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Utilities.Configuration.UI
namespace Ryujinx.UI.Common.Configuration.UI
{
public struct GuiColumns
{

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Utilities.Configuration.UI
namespace Ryujinx.UI.Common.Configuration.UI
{
public struct ShownFileTypes
{

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Utilities.Configuration.UI
namespace Ryujinx.UI.Common.Configuration.UI
{
public struct WindowStartup
{

View File

@@ -1,51 +1,129 @@
using Gommon;
using Ryujinx.Common.Configuration;
using System;
using DiscordRPC;
using Humanizer;
using Humanizer.Localisation;
using Ryujinx.Common;
using Ryujinx.HLE.Loaders.Processes;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common.Configuration;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace Ryujinx.Common
namespace Ryujinx.UI.Common
{
public static class TitleIDs
public static class DiscordIntegrationModule
{
public static ReactiveObject<Optional<string>> CurrentApplication { get; set; } = new();
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
public static Timestamps StartedAt { get; set; }
private static string VersionString
=> (ReleaseInformation.IsCanaryBuild ? "Canary " : string.Empty) + $"v{ReleaseInformation.Version}";
private static readonly string _description =
ReleaseInformation.IsValid
? $"{VersionString} {ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelSourceRepo}@{ReleaseInformation.BuildGitHash}"
: "dev build";
private const string ApplicationId = "1293250299716173864";
private const int ApplicationByteLimit = 128;
private const string Ellipsis = "…";
private static DiscordRpcClient _discordClient;
private static RichPresence _discordPresenceMain;
public static void Initialize()
{
switch (currentBackend)
_discordPresenceMain = new RichPresence
{
case GraphicsBackend.OpenGl when OperatingSystem.IsMacOS():
return GraphicsBackend.Vulkan;
case GraphicsBackend.Vulkan or GraphicsBackend.OpenGl or GraphicsBackend.Metal:
return currentBackend;
Assets = new Assets
{
LargeImageKey = "ryujinx",
LargeImageText = TruncateToByteLength(_description)
},
Details = "Main Menu",
State = "Idling",
Timestamps = StartedAt
};
ConfigurationState.Instance.EnableDiscordIntegration.Event += Update;
}
private static void Update(object sender, ReactiveEventArgs<bool> evnt)
{
if (evnt.OldValue != evnt.NewValue)
{
// If the integration was active, disable it and unload everything
if (evnt.OldValue)
{
_discordClient?.Dispose();
_discordClient = null;
}
// If we need to activate it and the client isn't active, initialize it
if (evnt.NewValue && _discordClient == null)
{
_discordClient = new DiscordRpcClient(ApplicationId);
_discordClient.Initialize();
_discordClient.SetPresence(_discordPresenceMain);
}
}
}
public static void SwitchToPlayingState(ApplicationMetadata appMeta, ProcessResult procRes)
{
_discordClient?.SetPresence(new RichPresence
{
Assets = new Assets
{
LargeImageKey = _discordGameAssetKeys.Contains(procRes.ProgramIdText) ? procRes.ProgramIdText : "game",
LargeImageText = TruncateToByteLength($"{appMeta.Title} (v{procRes.DisplayVersion})"),
SmallImageKey = "ryujinx",
SmallImageText = TruncateToByteLength(_description)
},
Details = TruncateToByteLength($"Playing {appMeta.Title}"),
State = appMeta.LastPlayed.HasValue && appMeta.TimePlayed.TotalSeconds > 5
? $"Total play time: {appMeta.TimePlayed.Humanize(2, false, maxUnit: TimeUnit.Hour)}"
: "Never played",
Timestamps = Timestamps.Now
});
}
public static void SwitchToMainState() => _discordClient?.SetPresence(_discordPresenceMain);
private static string TruncateToByteLength(string input)
{
if (Encoding.UTF8.GetByteCount(input) <= ApplicationByteLimit)
{
return input;
}
if (!(OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture is Architecture.Arm64))
return GraphicsBackend.Vulkan;
// Find the length to trim the string to guarantee we have space for the trailing ellipsis.
int trimLimit = ApplicationByteLimit - Encoding.UTF8.GetByteCount(Ellipsis);
return GreatMetalTitles.ContainsIgnoreCase(titleId) ? GraphicsBackend.Metal : GraphicsBackend.Vulkan;
// Make sure the string is long enough to perform the basic trim.
// Amount of bytes != Length of the string
if (input.Length > trimLimit)
{
// Basic trim to best case scenario of 1 byte characters.
input = input[..trimLimit];
}
while (Encoding.UTF8.GetByteCount(input) > trimLimit)
{
// Remove one character from the end of the string at a time.
input = input[..^1];
}
return input.TrimEnd() + Ellipsis;
}
public static readonly string[] GreatMetalTitles =
[
"01006f8002326000", // Animal Crossings: New Horizons
"01009bf0072d4000", // Captain Toad: Treasure Tracker
"0100a5c00d162000", // Cuphead
"010023800d64a000", // Deltarune
"010028600EBDA000", // Mario 3D World
"0100152000022000", // Mario Kart 8 Deluxe
"01005CA01580E000", // Persona 5
"0100187003A36000", // Pokémon: Let's Go, Evoli!
"010003f003a34000", // Pokémon: Let's Go, Pikachu!
"01008C0016544000", // Sea of Stars
"01006A800016E000", // Smash Ultimate
"0100000000010000", // Super Mario Odyessy
];
public static string GetDiscordGameAsset(string titleId)
=> DiscordGameAssetKeys.Contains(titleId) ? titleId : "game";
public static readonly string[] DiscordGameAssetKeys =
public static void Exit()
{
_discordClient?.Dispose();
}
private static readonly string[] _discordGameAssetKeys =
[
"010055d009f78000", // Fire Emblem: Three Houses
"0100a12011cc8000", // Fire Emblem: Shadow Dragon

View File

@@ -1,19 +1,8 @@
using System;
using static Ryujinx.UI.Common.Configuration.ConfigurationState.UISection;
using static Ryujinx.Ava.Utilities.Configuration.ConfigurationState.UISection;
namespace Ryujinx.Ava.Utilities.Configuration
namespace Ryujinx.UI.Common
{
public enum FileTypes
{
NSP,
PFS0,
XCI,
NCA,
NRO,
NSO
}
public static class FileTypesExtensions
{
/// <summary>
@@ -21,7 +10,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary>
/// <param name="type">The name of the <see cref="ShownFileTypeSettings"/> parameter to get the value of.</param>
/// <param name="config">The config instance to get the value from.</param>
/// <returns>The current value of the setting. Value is <see langword="true"/> if the file type is to be shown on the games list, <see langword="false"/> otherwise.</returns>
/// <returns>The current value of the setting. Value is <see langword="true"/> if the file type is the be shown on the games list, <see langword="false"/> otherwise.</returns>
public static bool GetConfigValue(this FileTypes type, ShownFileTypeSettings config) => type switch
{
FileTypes.NSP => config.NSP.Value,

View File

@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using System.Collections.Generic;
namespace Ryujinx.Ava.Utilities
namespace Ryujinx.UI.Common.Helper
{
public static class CommandLineState
{

View File

@@ -3,7 +3,7 @@ using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Common.Helper
namespace Ryujinx.UI.Common.Helper
{
public static partial class ConsoleHelper
{

View File

@@ -3,18 +3,18 @@ using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Models;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.Utilities;
using Ryujinx.UI.Common.Models;
using System;
using System.Collections.Generic;
using System.IO;
using Path = System.IO.Path;
namespace Ryujinx.Ava.Utilities
namespace Ryujinx.UI.Common.Helper
{
public static class DownloadableContentsHelper
{

View File

@@ -8,7 +8,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Common.Helper
namespace Ryujinx.UI.Common.Helper
{
public static partial class FileAssociationHelper
{
@@ -132,7 +132,7 @@ namespace Ryujinx.Common.Helper
if (uninstall)
{
// If the types don't already exist, there's nothing to do, and we can call this operation successful.
// If the types don't already exist, there's nothing to do and we can call this operation successful.
if (!AreMimeTypesRegisteredWindows())
{
return true;

View File

@@ -3,7 +3,7 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.Versioning;
namespace Ryujinx.Common.Helper
namespace Ryujinx.UI.Common.Helper
{
[SupportedOSPlatform("linux")]
public static class LinuxHelper

View File

@@ -2,7 +2,7 @@ using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Common.Helper
namespace Ryujinx.UI.Common.Helper
{
[SupportedOSPlatform("macos")]
public static partial class ObjectiveC

View File

@@ -5,7 +5,7 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace Ryujinx.Common.Helper
namespace Ryujinx.UI.Common.Helper
{
public static partial class OpenHelper
{

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