SDL_gpu_metal.m 145 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "SDL_internal.h"
  19. #if SDL_GPU_METAL
  20. #include <Metal/Metal.h>
  21. #include <QuartzCore/CoreAnimation.h>
  22. #include "../SDL_sysgpu.h"
  23. // Defines
  24. #define METAL_MAX_BUFFER_COUNT 31
  25. #define WINDOW_PROPERTY_DATA "SDL_GPUMetalWindowPropertyData"
  26. #define SDL_GPU_SHADERSTAGE_COMPUTE 2
  27. #define TRACK_RESOURCE(resource, type, array, count, capacity) \
  28. Uint32 i; \
  29. \
  30. for (i = 0; i < commandBuffer->count; i += 1) { \
  31. if (commandBuffer->array[i] == resource) { \
  32. return; \
  33. } \
  34. } \
  35. \
  36. if (commandBuffer->count == commandBuffer->capacity) { \
  37. commandBuffer->capacity += 1; \
  38. commandBuffer->array = SDL_realloc( \
  39. commandBuffer->array, \
  40. commandBuffer->capacity * sizeof(type)); \
  41. } \
  42. commandBuffer->array[commandBuffer->count] = resource; \
  43. commandBuffer->count += 1; \
  44. SDL_AtomicIncRef(&resource->referenceCount);
  45. // Blit Shaders
  46. #include "Metal_Blit.h"
  47. // Forward Declarations
  48. static void METAL_Wait(SDL_GPURenderer *driverData);
  49. static void METAL_ReleaseWindow(
  50. SDL_GPURenderer *driverData,
  51. SDL_Window *window);
  52. static void METAL_INTERNAL_DestroyBlitResources(SDL_GPURenderer *driverData);
  53. // Conversions
  54. static MTLPixelFormat SDLToMetal_SurfaceFormat[] = {
  55. MTLPixelFormatRGBA8Unorm, // R8G8B8A8_UNORM
  56. MTLPixelFormatBGRA8Unorm, // B8G8R8A8_UNORM
  57. MTLPixelFormatB5G6R5Unorm, // B5G6R5_UNORM
  58. MTLPixelFormatBGR5A1Unorm, // B5G5R5A1_UNORM
  59. MTLPixelFormatABGR4Unorm, // B4G4R4A4_UNORM
  60. MTLPixelFormatRGB10A2Unorm, // A2R10G10B10_UNORM
  61. MTLPixelFormatRG16Unorm, // R16G16_UNORM
  62. MTLPixelFormatRGBA16Unorm, // R16G16B16A16_UNORM
  63. MTLPixelFormatR8Unorm, // R8_UNORM
  64. MTLPixelFormatA8Unorm, // A8_UNORM
  65. #ifdef SDL_PLATFORM_MACOS
  66. MTLPixelFormatBC1_RGBA, // BC1_UNORM
  67. MTLPixelFormatBC2_RGBA, // BC2_UNORM
  68. MTLPixelFormatBC3_RGBA, // BC3_UNORM
  69. MTLPixelFormatBC7_RGBAUnorm, // BC7_UNORM
  70. #else
  71. MTLPixelFormatInvalid, // BC1_UNORM
  72. MTLPixelFormatInvalid, // BC2_UNORM
  73. MTLPixelFormatInvalid, // BC3_UNORM
  74. MTLPixelFormatInvalid, // BC7_UNORM
  75. #endif
  76. MTLPixelFormatRG8Snorm, // R8G8_SNORM
  77. MTLPixelFormatRGBA8Snorm, // R8G8B8A8_SNORM
  78. MTLPixelFormatR16Float, // R16_FLOAT
  79. MTLPixelFormatRG16Float, // R16G16_FLOAT
  80. MTLPixelFormatRGBA16Float, // R16G16B16A16_FLOAT
  81. MTLPixelFormatR32Float, // R32_FLOAT
  82. MTLPixelFormatRG32Float, // R32G32_FLOAT
  83. MTLPixelFormatRGBA32Float, // R32G32B32A32_FLOAT
  84. MTLPixelFormatR8Uint, // R8_UINT
  85. MTLPixelFormatRG8Uint, // R8G8_UINT
  86. MTLPixelFormatRGBA8Uint, // R8G8B8A8_UINT
  87. MTLPixelFormatR16Uint, // R16_UINT
  88. MTLPixelFormatRG16Uint, // R16G16_UINT
  89. MTLPixelFormatRGBA16Uint, // R16G16B16A16_UINT
  90. MTLPixelFormatRGBA8Unorm_sRGB, // R8G8B8A8_UNORM_SRGB
  91. MTLPixelFormatBGRA8Unorm_sRGB, // B8G8R8A8_UNORM_SRGB
  92. #ifdef SDL_PLATFORM_MACOS
  93. MTLPixelFormatBC3_RGBA_sRGB, // BC3_UNORM_SRGB
  94. MTLPixelFormatBC7_RGBAUnorm_sRGB, // BC7_UNORM_SRGB
  95. #else
  96. MTLPixelFormatInvalid, // BC3_UNORM_SRGB
  97. MTLPixelFormatInvalid, // BC7_UNORM_SRGB
  98. #endif
  99. MTLPixelFormatDepth16Unorm, // D16_UNORM
  100. #ifdef SDL_PLATFORM_MACOS
  101. MTLPixelFormatDepth24Unorm_Stencil8, // D24_UNORM
  102. #else
  103. MTLPixelFormatInvalid, // D24_UNORM
  104. #endif
  105. MTLPixelFormatDepth32Float, // D32_FLOAT
  106. #ifdef SDL_PLATFORM_MACOS
  107. MTLPixelFormatDepth24Unorm_Stencil8, // D24_UNORM_S8_UINT
  108. #else
  109. MTLPixelFormatInvalid, // D24_UNORM_S8_UINT
  110. #endif
  111. MTLPixelFormatDepth32Float_Stencil8, // D32_FLOAT_S8_UINT
  112. };
  113. SDL_COMPILE_TIME_ASSERT(SDLToMetal_SurfaceFormat, SDL_arraysize(SDLToMetal_SurfaceFormat) == SDL_GPU_TEXTUREFORMAT_MAX);
  114. static MTLVertexFormat SDLToMetal_VertexFormat[] = {
  115. MTLVertexFormatInt, // INT
  116. MTLVertexFormatInt2, // INT2
  117. MTLVertexFormatInt3, // INT3
  118. MTLVertexFormatInt4, // INT4
  119. MTLVertexFormatUInt, // UINT
  120. MTLVertexFormatUInt2, // UINT2
  121. MTLVertexFormatUInt3, // UINT3
  122. MTLVertexFormatUInt4, // UINT4
  123. MTLVertexFormatFloat, // FLOAT
  124. MTLVertexFormatFloat2, // FLOAT2
  125. MTLVertexFormatFloat3, // FLOAT3
  126. MTLVertexFormatFloat4, // FLOAT4
  127. MTLVertexFormatChar2, // BYTE2
  128. MTLVertexFormatChar4, // BYTE4
  129. MTLVertexFormatUChar2, // UBYTE2
  130. MTLVertexFormatUChar4, // UBYTE4
  131. MTLVertexFormatChar2Normalized, // BYTE2_NORM
  132. MTLVertexFormatChar4Normalized, // BYTE4_NORM
  133. MTLVertexFormatUChar2Normalized, // UBYTE2_NORM
  134. MTLVertexFormatUChar4Normalized, // UBYTE4_NORM
  135. MTLVertexFormatShort2, // SHORT2
  136. MTLVertexFormatShort4, // SHORT4
  137. MTLVertexFormatUShort2, // USHORT2
  138. MTLVertexFormatUShort4, // USHORT4
  139. MTLVertexFormatShort2Normalized, // SHORT2_NORM
  140. MTLVertexFormatShort4Normalized, // SHORT4_NORM
  141. MTLVertexFormatUShort2Normalized, // USHORT2_NORM
  142. MTLVertexFormatUShort4Normalized, // USHORT4_NORM
  143. MTLVertexFormatHalf2, // HALF2
  144. MTLVertexFormatHalf4 // HALF4
  145. };
  146. static MTLIndexType SDLToMetal_IndexType[] = {
  147. MTLIndexTypeUInt16, // 16BIT
  148. MTLIndexTypeUInt32, // 32BIT
  149. };
  150. static MTLPrimitiveType SDLToMetal_PrimitiveType[] = {
  151. MTLPrimitiveTypePoint, // POINTLIST
  152. MTLPrimitiveTypeLine, // LINELIST
  153. MTLPrimitiveTypeLineStrip, // LINESTRIP
  154. MTLPrimitiveTypeTriangle, // TRIANGLELIST
  155. MTLPrimitiveTypeTriangleStrip // TRIANGLESTRIP
  156. };
  157. static MTLTriangleFillMode SDLToMetal_PolygonMode[] = {
  158. MTLTriangleFillModeFill, // FILL
  159. MTLTriangleFillModeLines, // LINE
  160. };
  161. static MTLCullMode SDLToMetal_CullMode[] = {
  162. MTLCullModeNone, // NONE
  163. MTLCullModeFront, // FRONT
  164. MTLCullModeBack, // BACK
  165. };
  166. static MTLWinding SDLToMetal_FrontFace[] = {
  167. MTLWindingCounterClockwise, // COUNTER_CLOCKWISE
  168. MTLWindingClockwise, // CLOCKWISE
  169. };
  170. static MTLBlendFactor SDLToMetal_BlendFactor[] = {
  171. MTLBlendFactorZero, // ZERO
  172. MTLBlendFactorOne, // ONE
  173. MTLBlendFactorSourceColor, // SRC_COLOR
  174. MTLBlendFactorOneMinusSourceColor, // ONE_MINUS_SRC_COLOR
  175. MTLBlendFactorDestinationColor, // DST_COLOR
  176. MTLBlendFactorOneMinusDestinationColor, // ONE_MINUS_DST_COLOR
  177. MTLBlendFactorSourceAlpha, // SRC_ALPHA
  178. MTLBlendFactorOneMinusSourceAlpha, // ONE_MINUS_SRC_ALPHA
  179. MTLBlendFactorDestinationAlpha, // DST_ALPHA
  180. MTLBlendFactorOneMinusDestinationAlpha, // ONE_MINUS_DST_ALPHA
  181. MTLBlendFactorBlendColor, // CONSTANT_COLOR
  182. MTLBlendFactorOneMinusBlendColor, // ONE_MINUS_CONSTANT_COLOR
  183. MTLBlendFactorSourceAlphaSaturated, // SRC_ALPHA_SATURATE
  184. };
  185. static MTLBlendOperation SDLToMetal_BlendOp[] = {
  186. MTLBlendOperationAdd, // ADD
  187. MTLBlendOperationSubtract, // SUBTRACT
  188. MTLBlendOperationReverseSubtract, // REVERSE_SUBTRACT
  189. MTLBlendOperationMin, // MIN
  190. MTLBlendOperationMax, // MAX
  191. };
  192. static MTLCompareFunction SDLToMetal_CompareOp[] = {
  193. MTLCompareFunctionNever, // NEVER
  194. MTLCompareFunctionLess, // LESS
  195. MTLCompareFunctionEqual, // EQUAL
  196. MTLCompareFunctionLessEqual, // LESS_OR_EQUAL
  197. MTLCompareFunctionGreater, // GREATER
  198. MTLCompareFunctionNotEqual, // NOT_EQUAL
  199. MTLCompareFunctionGreaterEqual, // GREATER_OR_EQUAL
  200. MTLCompareFunctionAlways, // ALWAYS
  201. };
  202. static MTLStencilOperation SDLToMetal_StencilOp[] = {
  203. MTLStencilOperationKeep, // KEEP
  204. MTLStencilOperationZero, // ZERO
  205. MTLStencilOperationReplace, // REPLACE
  206. MTLStencilOperationIncrementClamp, // INCREMENT_AND_CLAMP
  207. MTLStencilOperationDecrementClamp, // DECREMENT_AND_CLAMP
  208. MTLStencilOperationInvert, // INVERT
  209. MTLStencilOperationIncrementWrap, // INCREMENT_AND_WRAP
  210. MTLStencilOperationDecrementWrap, // DECREMENT_AND_WRAP
  211. };
  212. static MTLSamplerAddressMode SDLToMetal_SamplerAddressMode[] = {
  213. MTLSamplerAddressModeRepeat, // REPEAT
  214. MTLSamplerAddressModeMirrorRepeat, // MIRRORED_REPEAT
  215. MTLSamplerAddressModeClampToEdge // CLAMP_TO_EDGE
  216. };
  217. static MTLSamplerMinMagFilter SDLToMetal_MinMagFilter[] = {
  218. MTLSamplerMinMagFilterNearest, // NEAREST
  219. MTLSamplerMinMagFilterLinear, // LINEAR
  220. };
  221. static MTLSamplerMipFilter SDLToMetal_MipFilter[] = {
  222. MTLSamplerMipFilterNearest, // NEAREST
  223. MTLSamplerMipFilterLinear, // LINEAR
  224. };
  225. static MTLLoadAction SDLToMetal_LoadOp[] = {
  226. MTLLoadActionLoad, // LOAD
  227. MTLLoadActionClear, // CLEAR
  228. MTLLoadActionDontCare, // DONT_CARE
  229. };
  230. static MTLVertexStepFunction SDLToMetal_StepFunction[] = {
  231. MTLVertexStepFunctionPerVertex,
  232. MTLVertexStepFunctionPerInstance,
  233. };
  234. static NSUInteger SDLToMetal_SampleCount[] = {
  235. 1, // SDL_GPU_SAMPLECOUNT_1
  236. 2, // SDL_GPU_SAMPLECOUNT_2
  237. 4, // SDL_GPU_SAMPLECOUNT_4
  238. 8 // SDL_GPU_SAMPLECOUNT_8
  239. };
  240. static MTLTextureType SDLToMetal_TextureType[] = {
  241. MTLTextureType2D, // SDL_GPU_TEXTURETYPE_2D
  242. MTLTextureType2DArray, // SDL_GPU_TEXTURETYPE_2D_ARRAY
  243. MTLTextureType3D, // SDL_GPU_TEXTURETYPE_3D
  244. MTLTextureTypeCube // SDL_GPU_TEXTURETYPE_CUBE
  245. };
  246. static SDL_GPUTextureFormat SwapchainCompositionToFormat[] = {
  247. SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM, // SDR
  248. SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB, // SDR_LINEAR
  249. SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR
  250. SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM, // HDR10_ST2048
  251. };
  252. static CFStringRef SwapchainCompositionToColorSpace[4]; // initialized on device creation
  253. static MTLStoreAction SDLToMetal_StoreOp(
  254. SDL_GPUStoreOp storeOp,
  255. Uint8 isMultisample)
  256. {
  257. if (isMultisample) {
  258. if (storeOp == SDL_GPU_STOREOP_STORE) {
  259. return MTLStoreActionStoreAndMultisampleResolve;
  260. } else {
  261. return MTLStoreActionMultisampleResolve;
  262. }
  263. } else {
  264. if (storeOp == SDL_GPU_STOREOP_STORE) {
  265. return MTLStoreActionStore;
  266. } else {
  267. return MTLStoreActionDontCare;
  268. }
  269. }
  270. };
  271. static MTLColorWriteMask SDLToMetal_ColorWriteMask(
  272. SDL_GPUColorComponentFlagBits mask)
  273. {
  274. MTLColorWriteMask result = 0;
  275. if (mask & SDL_GPU_COLORCOMPONENT_R_BIT) {
  276. result |= MTLColorWriteMaskRed;
  277. }
  278. if (mask & SDL_GPU_COLORCOMPONENT_G_BIT) {
  279. result |= MTLColorWriteMaskGreen;
  280. }
  281. if (mask & SDL_GPU_COLORCOMPONENT_B_BIT) {
  282. result |= MTLColorWriteMaskBlue;
  283. }
  284. if (mask & SDL_GPU_COLORCOMPONENT_A_BIT) {
  285. result |= MTLColorWriteMaskAlpha;
  286. }
  287. return result;
  288. }
  289. // Structs
  290. typedef struct MetalTexture
  291. {
  292. id<MTLTexture> handle;
  293. id<MTLTexture> msaaHandle;
  294. SDL_AtomicInt referenceCount;
  295. } MetalTexture;
  296. typedef struct MetalTextureContainer
  297. {
  298. TextureCommonHeader header;
  299. MetalTexture *activeTexture;
  300. Uint8 canBeCycled;
  301. Uint32 textureCapacity;
  302. Uint32 textureCount;
  303. MetalTexture **textures;
  304. char *debugName;
  305. } MetalTextureContainer;
  306. typedef struct MetalFence
  307. {
  308. SDL_AtomicInt complete;
  309. } MetalFence;
  310. typedef struct MetalWindowData
  311. {
  312. SDL_Window *window;
  313. SDL_MetalView view;
  314. CAMetalLayer *layer;
  315. id<CAMetalDrawable> drawable;
  316. MetalTexture texture;
  317. MetalTextureContainer textureContainer;
  318. } MetalWindowData;
  319. typedef struct MetalShader
  320. {
  321. id<MTLLibrary> library;
  322. id<MTLFunction> function;
  323. Uint32 samplerCount;
  324. Uint32 uniformBufferCount;
  325. Uint32 storageBufferCount;
  326. Uint32 storageTextureCount;
  327. } MetalShader;
  328. typedef struct MetalGraphicsPipeline
  329. {
  330. id<MTLRenderPipelineState> handle;
  331. float blendConstants[4];
  332. Uint32 sampleMask;
  333. SDL_GPURasterizerState rasterizerState;
  334. SDL_GPUPrimitiveType primitiveType;
  335. id<MTLDepthStencilState> depthStencilState;
  336. Uint8 stencilReference;
  337. Uint32 vertexSamplerCount;
  338. Uint32 vertexUniformBufferCount;
  339. Uint32 vertexStorageBufferCount;
  340. Uint32 vertexStorageTextureCount;
  341. Uint32 fragmentSamplerCount;
  342. Uint32 fragmentUniformBufferCount;
  343. Uint32 fragmentStorageBufferCount;
  344. Uint32 fragmentStorageTextureCount;
  345. } MetalGraphicsPipeline;
  346. typedef struct MetalComputePipeline
  347. {
  348. id<MTLComputePipelineState> handle;
  349. Uint32 readOnlyStorageTextureCount;
  350. Uint32 writeOnlyStorageTextureCount;
  351. Uint32 readOnlyStorageBufferCount;
  352. Uint32 writeOnlyStorageBufferCount;
  353. Uint32 uniformBufferCount;
  354. Uint32 threadCountX;
  355. Uint32 threadCountY;
  356. Uint32 threadCountZ;
  357. } MetalComputePipeline;
  358. typedef struct MetalBuffer
  359. {
  360. id<MTLBuffer> handle;
  361. SDL_AtomicInt referenceCount;
  362. } MetalBuffer;
  363. typedef struct MetalBufferContainer
  364. {
  365. MetalBuffer *activeBuffer;
  366. Uint32 size;
  367. Uint32 bufferCapacity;
  368. Uint32 bufferCount;
  369. MetalBuffer **buffers;
  370. bool isPrivate;
  371. bool isWriteOnly;
  372. char *debugName;
  373. } MetalBufferContainer;
  374. typedef struct MetalUniformBuffer
  375. {
  376. id<MTLBuffer> handle;
  377. Uint32 writeOffset;
  378. Uint32 drawOffset;
  379. } MetalUniformBuffer;
  380. typedef struct MetalRenderer MetalRenderer;
  381. typedef struct MetalCommandBuffer
  382. {
  383. CommandBufferCommonHeader common;
  384. MetalRenderer *renderer;
  385. // Native Handle
  386. id<MTLCommandBuffer> handle;
  387. // Presentation
  388. MetalWindowData **windowDatas;
  389. Uint32 windowDataCount;
  390. Uint32 windowDataCapacity;
  391. // Render Pass
  392. id<MTLRenderCommandEncoder> renderEncoder;
  393. MetalGraphicsPipeline *graphicsPipeline;
  394. MetalBuffer *indexBuffer;
  395. Uint32 indexBufferOffset;
  396. SDL_GPUIndexElementSize indexElementSize;
  397. // Copy Pass
  398. id<MTLBlitCommandEncoder> blitEncoder;
  399. // Compute Pass
  400. id<MTLComputeCommandEncoder> computeEncoder;
  401. MetalComputePipeline *computePipeline;
  402. // Resource slot state
  403. bool needVertexSamplerBind;
  404. bool needVertexStorageTextureBind;
  405. bool needVertexStorageBufferBind;
  406. bool needVertexUniformBind;
  407. bool needFragmentSamplerBind;
  408. bool needFragmentStorageTextureBind;
  409. bool needFragmentStorageBufferBind;
  410. bool needFragmentUniformBind;
  411. bool needComputeTextureBind;
  412. bool needComputeBufferBind;
  413. bool needComputeUniformBind;
  414. id<MTLSamplerState> vertexSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE];
  415. id<MTLTexture> vertexTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
  416. id<MTLTexture> vertexStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
  417. id<MTLBuffer> vertexStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
  418. id<MTLSamplerState> fragmentSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE];
  419. id<MTLTexture> fragmentTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE];
  420. id<MTLTexture> fragmentStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
  421. id<MTLBuffer> fragmentStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
  422. id<MTLTexture> computeReadOnlyTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
  423. id<MTLBuffer> computeReadOnlyBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
  424. id<MTLTexture> computeWriteOnlyTextures[MAX_COMPUTE_WRITE_TEXTURES];
  425. id<MTLBuffer> computeWriteOnlyBuffers[MAX_COMPUTE_WRITE_BUFFERS];
  426. // Uniform buffers
  427. MetalUniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
  428. MetalUniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
  429. MetalUniformBuffer *computeUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
  430. MetalUniformBuffer **usedUniformBuffers;
  431. Uint32 usedUniformBufferCount;
  432. Uint32 usedUniformBufferCapacity;
  433. // Fences
  434. MetalFence *fence;
  435. Uint8 autoReleaseFence;
  436. // Reference Counting
  437. MetalBuffer **usedBuffers;
  438. Uint32 usedBufferCount;
  439. Uint32 usedBufferCapacity;
  440. MetalTexture **usedTextures;
  441. Uint32 usedTextureCount;
  442. Uint32 usedTextureCapacity;
  443. } MetalCommandBuffer;
  444. typedef struct MetalSampler
  445. {
  446. id<MTLSamplerState> handle;
  447. } MetalSampler;
  448. typedef struct BlitPipeline
  449. {
  450. SDL_GPUGraphicsPipeline *pipeline;
  451. SDL_GPUTextureFormat format;
  452. } BlitPipeline;
  453. struct MetalRenderer
  454. {
  455. // Reference to the parent device
  456. SDL_GPUDevice *sdlGPUDevice;
  457. id<MTLDevice> device;
  458. id<MTLCommandQueue> queue;
  459. bool debugMode;
  460. MetalWindowData **claimedWindows;
  461. Uint32 claimedWindowCount;
  462. Uint32 claimedWindowCapacity;
  463. MetalCommandBuffer **availableCommandBuffers;
  464. Uint32 availableCommandBufferCount;
  465. Uint32 availableCommandBufferCapacity;
  466. MetalCommandBuffer **submittedCommandBuffers;
  467. Uint32 submittedCommandBufferCount;
  468. Uint32 submittedCommandBufferCapacity;
  469. MetalFence **availableFences;
  470. Uint32 availableFenceCount;
  471. Uint32 availableFenceCapacity;
  472. MetalUniformBuffer **uniformBufferPool;
  473. Uint32 uniformBufferPoolCount;
  474. Uint32 uniformBufferPoolCapacity;
  475. MetalBufferContainer **bufferContainersToDestroy;
  476. Uint32 bufferContainersToDestroyCount;
  477. Uint32 bufferContainersToDestroyCapacity;
  478. MetalTextureContainer **textureContainersToDestroy;
  479. Uint32 textureContainersToDestroyCount;
  480. Uint32 textureContainersToDestroyCapacity;
  481. // Blit
  482. SDL_GPUShader *blitVertexShader;
  483. SDL_GPUShader *blitFrom2DShader;
  484. SDL_GPUShader *blitFrom2DArrayShader;
  485. SDL_GPUShader *blitFrom3DShader;
  486. SDL_GPUShader *blitFromCubeShader;
  487. SDL_GPUSampler *blitNearestSampler;
  488. SDL_GPUSampler *blitLinearSampler;
  489. BlitPipelineCacheEntry *blitPipelines;
  490. Uint32 blitPipelineCount;
  491. Uint32 blitPipelineCapacity;
  492. // Mutexes
  493. SDL_Mutex *submitLock;
  494. SDL_Mutex *acquireCommandBufferLock;
  495. SDL_Mutex *acquireUniformBufferLock;
  496. SDL_Mutex *disposeLock;
  497. SDL_Mutex *fenceLock;
  498. SDL_Mutex *windowLock;
  499. };
  500. // Helper Functions
  501. static Uint32 METAL_INTERNAL_GetVertexBufferIndex(Uint32 binding)
  502. {
  503. return METAL_MAX_BUFFER_COUNT - 1 - binding;
  504. }
  505. // FIXME: This should be moved into SDL_sysgpu.h
  506. static inline Uint32 METAL_INTERNAL_NextHighestAlignment(
  507. Uint32 n,
  508. Uint32 align)
  509. {
  510. return align * ((n + align - 1) / align);
  511. }
  512. // Quit
  513. static void METAL_DestroyDevice(SDL_GPUDevice *device)
  514. {
  515. MetalRenderer *renderer = (MetalRenderer *)device->driverData;
  516. // Flush any remaining GPU work...
  517. METAL_Wait(device->driverData);
  518. // Release the window data
  519. for (Sint32 i = renderer->claimedWindowCount - 1; i >= 0; i -= 1) {
  520. METAL_ReleaseWindow(device->driverData, renderer->claimedWindows[i]->window);
  521. }
  522. SDL_free(renderer->claimedWindows);
  523. // Release the blit resources
  524. METAL_INTERNAL_DestroyBlitResources(device->driverData);
  525. // Release uniform buffers
  526. for (Uint32 i = 0; i < renderer->uniformBufferPoolCount; i += 1) {
  527. renderer->uniformBufferPool[i]->handle = nil;
  528. SDL_free(renderer->uniformBufferPool[i]);
  529. }
  530. SDL_free(renderer->uniformBufferPool);
  531. // Release destroyed resource lists
  532. SDL_free(renderer->bufferContainersToDestroy);
  533. SDL_free(renderer->textureContainersToDestroy);
  534. // Release command buffer infrastructure
  535. for (Uint32 i = 0; i < renderer->availableCommandBufferCount; i += 1) {
  536. MetalCommandBuffer *commandBuffer = renderer->availableCommandBuffers[i];
  537. SDL_free(commandBuffer->usedBuffers);
  538. SDL_free(commandBuffer->usedTextures);
  539. SDL_free(commandBuffer->usedUniformBuffers);
  540. SDL_free(commandBuffer->windowDatas);
  541. SDL_free(commandBuffer);
  542. }
  543. SDL_free(renderer->availableCommandBuffers);
  544. SDL_free(renderer->submittedCommandBuffers);
  545. // Release fence infrastructure
  546. for (Uint32 i = 0; i < renderer->availableFenceCount; i += 1) {
  547. SDL_free(renderer->availableFences[i]);
  548. }
  549. SDL_free(renderer->availableFences);
  550. // Release the mutexes
  551. SDL_DestroyMutex(renderer->submitLock);
  552. SDL_DestroyMutex(renderer->acquireCommandBufferLock);
  553. SDL_DestroyMutex(renderer->acquireUniformBufferLock);
  554. SDL_DestroyMutex(renderer->disposeLock);
  555. SDL_DestroyMutex(renderer->fenceLock);
  556. SDL_DestroyMutex(renderer->windowLock);
  557. // Release the command queue
  558. renderer->queue = nil;
  559. // Free the primary structures
  560. SDL_free(renderer);
  561. SDL_free(device);
  562. }
  563. // Resource tracking
  564. static void METAL_INTERNAL_TrackBuffer(
  565. MetalCommandBuffer *commandBuffer,
  566. MetalBuffer *buffer)
  567. {
  568. TRACK_RESOURCE(
  569. buffer,
  570. MetalBuffer *,
  571. usedBuffers,
  572. usedBufferCount,
  573. usedBufferCapacity);
  574. }
  575. static void METAL_INTERNAL_TrackTexture(
  576. MetalCommandBuffer *commandBuffer,
  577. MetalTexture *texture)
  578. {
  579. TRACK_RESOURCE(
  580. texture,
  581. MetalTexture *,
  582. usedTextures,
  583. usedTextureCount,
  584. usedTextureCapacity);
  585. }
  586. static void METAL_INTERNAL_TrackUniformBuffer(
  587. MetalCommandBuffer *commandBuffer,
  588. MetalUniformBuffer *uniformBuffer)
  589. {
  590. Uint32 i;
  591. for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) {
  592. if (commandBuffer->usedUniformBuffers[i] == uniformBuffer) {
  593. return;
  594. }
  595. }
  596. if (commandBuffer->usedUniformBufferCount == commandBuffer->usedUniformBufferCapacity) {
  597. commandBuffer->usedUniformBufferCapacity += 1;
  598. commandBuffer->usedUniformBuffers = SDL_realloc(
  599. commandBuffer->usedUniformBuffers,
  600. commandBuffer->usedUniformBufferCapacity * sizeof(MetalUniformBuffer *));
  601. }
  602. commandBuffer->usedUniformBuffers[commandBuffer->usedUniformBufferCount] = uniformBuffer;
  603. commandBuffer->usedUniformBufferCount += 1;
  604. }
  605. // Shader Compilation
  606. typedef struct MetalLibraryFunction
  607. {
  608. id<MTLLibrary> library;
  609. id<MTLFunction> function;
  610. } MetalLibraryFunction;
  611. // This function assumes that it's called from within an autorelease pool
  612. static MetalLibraryFunction METAL_INTERNAL_CompileShader(
  613. MetalRenderer *renderer,
  614. SDL_GPUShaderFormat format,
  615. const Uint8 *code,
  616. size_t codeSize,
  617. const char *entryPointName)
  618. {
  619. MetalLibraryFunction libraryFunction = { nil, nil };
  620. id<MTLLibrary> library;
  621. NSError *error;
  622. dispatch_data_t data;
  623. id<MTLFunction> function;
  624. if (format == SDL_GPU_SHADERFORMAT_MSL) {
  625. library = [renderer->device
  626. newLibraryWithSource:@((const char *)code)
  627. options:nil
  628. error:&error];
  629. } else if (format == SDL_GPU_SHADERFORMAT_METALLIB) {
  630. data = dispatch_data_create(
  631. code,
  632. codeSize,
  633. dispatch_get_global_queue(0, 0),
  634. ^{ /* do nothing */ });
  635. library = [renderer->device newLibraryWithData:data error:&error];
  636. } else {
  637. SDL_assert(!"SDL_gpu.c should have already validated this!");
  638. return libraryFunction;
  639. }
  640. if (library == nil) {
  641. SDL_LogError(
  642. SDL_LOG_CATEGORY_GPU,
  643. "Creating MTLLibrary failed: %s",
  644. [[error description] cStringUsingEncoding:[NSString defaultCStringEncoding]]);
  645. return libraryFunction;
  646. } else if (error != nil) {
  647. SDL_LogWarn(
  648. SDL_LOG_CATEGORY_GPU,
  649. "Creating MTLLibrary failed: %s",
  650. [[error description] cStringUsingEncoding:[NSString defaultCStringEncoding]]);
  651. }
  652. function = [library newFunctionWithName:@(entryPointName)];
  653. if (function == nil) {
  654. SDL_LogError(
  655. SDL_LOG_CATEGORY_GPU,
  656. "Creating MTLFunction failed");
  657. return libraryFunction;
  658. }
  659. libraryFunction.library = library;
  660. libraryFunction.function = function;
  661. return libraryFunction;
  662. }
  663. // Disposal
  664. static void METAL_INTERNAL_DestroyTextureContainer(
  665. MetalTextureContainer *container)
  666. {
  667. for (Uint32 i = 0; i < container->textureCount; i += 1) {
  668. container->textures[i]->handle = nil;
  669. container->textures[i]->msaaHandle = nil;
  670. SDL_free(container->textures[i]);
  671. }
  672. if (container->debugName != NULL) {
  673. SDL_free(container->debugName);
  674. }
  675. SDL_free(container->textures);
  676. SDL_free(container);
  677. }
  678. static void METAL_ReleaseTexture(
  679. SDL_GPURenderer *driverData,
  680. SDL_GPUTexture *texture)
  681. {
  682. MetalRenderer *renderer = (MetalRenderer *)driverData;
  683. MetalTextureContainer *container = (MetalTextureContainer *)texture;
  684. SDL_LockMutex(renderer->disposeLock);
  685. EXPAND_ARRAY_IF_NEEDED(
  686. renderer->textureContainersToDestroy,
  687. MetalTextureContainer *,
  688. renderer->textureContainersToDestroyCount + 1,
  689. renderer->textureContainersToDestroyCapacity,
  690. renderer->textureContainersToDestroyCapacity + 1);
  691. renderer->textureContainersToDestroy[renderer->textureContainersToDestroyCount] = container;
  692. renderer->textureContainersToDestroyCount += 1;
  693. SDL_UnlockMutex(renderer->disposeLock);
  694. }
  695. static void METAL_ReleaseSampler(
  696. SDL_GPURenderer *driverData,
  697. SDL_GPUSampler *sampler)
  698. {
  699. @autoreleasepool {
  700. MetalSampler *metalSampler = (MetalSampler *)sampler;
  701. metalSampler->handle = nil;
  702. SDL_free(metalSampler);
  703. }
  704. }
  705. static void METAL_INTERNAL_DestroyBufferContainer(
  706. MetalBufferContainer *container)
  707. {
  708. for (Uint32 i = 0; i < container->bufferCount; i += 1) {
  709. container->buffers[i]->handle = nil;
  710. SDL_free(container->buffers[i]);
  711. }
  712. if (container->debugName != NULL) {
  713. SDL_free(container->debugName);
  714. }
  715. SDL_free(container->buffers);
  716. SDL_free(container);
  717. }
  718. static void METAL_ReleaseBuffer(
  719. SDL_GPURenderer *driverData,
  720. SDL_GPUBuffer *buffer)
  721. {
  722. MetalRenderer *renderer = (MetalRenderer *)driverData;
  723. MetalBufferContainer *container = (MetalBufferContainer *)buffer;
  724. SDL_LockMutex(renderer->disposeLock);
  725. EXPAND_ARRAY_IF_NEEDED(
  726. renderer->bufferContainersToDestroy,
  727. MetalBufferContainer *,
  728. renderer->bufferContainersToDestroyCount + 1,
  729. renderer->bufferContainersToDestroyCapacity,
  730. renderer->bufferContainersToDestroyCapacity + 1);
  731. renderer->bufferContainersToDestroy[renderer->bufferContainersToDestroyCount] = container;
  732. renderer->bufferContainersToDestroyCount += 1;
  733. SDL_UnlockMutex(renderer->disposeLock);
  734. }
  735. static void METAL_ReleaseTransferBuffer(
  736. SDL_GPURenderer *driverData,
  737. SDL_GPUTransferBuffer *transferBuffer)
  738. {
  739. METAL_ReleaseBuffer(
  740. driverData,
  741. (SDL_GPUBuffer *)transferBuffer);
  742. }
  743. static void METAL_ReleaseShader(
  744. SDL_GPURenderer *driverData,
  745. SDL_GPUShader *shader)
  746. {
  747. @autoreleasepool {
  748. MetalShader *metalShader = (MetalShader *)shader;
  749. metalShader->function = nil;
  750. metalShader->library = nil;
  751. SDL_free(metalShader);
  752. }
  753. }
  754. static void METAL_ReleaseComputePipeline(
  755. SDL_GPURenderer *driverData,
  756. SDL_GPUComputePipeline *computePipeline)
  757. {
  758. @autoreleasepool {
  759. MetalComputePipeline *metalComputePipeline = (MetalComputePipeline *)computePipeline;
  760. metalComputePipeline->handle = nil;
  761. SDL_free(metalComputePipeline);
  762. }
  763. }
  764. static void METAL_ReleaseGraphicsPipeline(
  765. SDL_GPURenderer *driverData,
  766. SDL_GPUGraphicsPipeline *graphicsPipeline)
  767. {
  768. @autoreleasepool {
  769. MetalGraphicsPipeline *metalGraphicsPipeline = (MetalGraphicsPipeline *)graphicsPipeline;
  770. metalGraphicsPipeline->handle = nil;
  771. metalGraphicsPipeline->depthStencilState = nil;
  772. SDL_free(metalGraphicsPipeline);
  773. }
  774. }
  775. // Pipeline Creation
  776. static SDL_GPUComputePipeline *METAL_CreateComputePipeline(
  777. SDL_GPURenderer *driverData,
  778. SDL_GPUComputePipelineCreateInfo *pipelineCreateInfo)
  779. {
  780. @autoreleasepool {
  781. MetalRenderer *renderer = (MetalRenderer *)driverData;
  782. MetalLibraryFunction libraryFunction;
  783. id<MTLComputePipelineState> handle;
  784. MetalComputePipeline *pipeline;
  785. NSError *error;
  786. libraryFunction = METAL_INTERNAL_CompileShader(
  787. renderer,
  788. pipelineCreateInfo->format,
  789. pipelineCreateInfo->code,
  790. pipelineCreateInfo->codeSize,
  791. pipelineCreateInfo->entryPointName);
  792. if (libraryFunction.library == nil || libraryFunction.function == nil) {
  793. return NULL;
  794. }
  795. handle = [renderer->device newComputePipelineStateWithFunction:libraryFunction.function error:&error];
  796. if (error != NULL) {
  797. SDL_LogError(
  798. SDL_LOG_CATEGORY_GPU,
  799. "Creating compute pipeline failed: %s", [[error description] UTF8String]);
  800. return NULL;
  801. }
  802. pipeline = SDL_malloc(sizeof(MetalComputePipeline));
  803. pipeline->handle = handle;
  804. pipeline->readOnlyStorageTextureCount = pipelineCreateInfo->readOnlyStorageTextureCount;
  805. pipeline->writeOnlyStorageTextureCount = pipelineCreateInfo->writeOnlyStorageTextureCount;
  806. pipeline->readOnlyStorageBufferCount = pipelineCreateInfo->readOnlyStorageBufferCount;
  807. pipeline->writeOnlyStorageBufferCount = pipelineCreateInfo->writeOnlyStorageBufferCount;
  808. pipeline->uniformBufferCount = pipelineCreateInfo->uniformBufferCount;
  809. pipeline->threadCountX = pipelineCreateInfo->threadCountX;
  810. pipeline->threadCountY = pipelineCreateInfo->threadCountY;
  811. pipeline->threadCountZ = pipelineCreateInfo->threadCountZ;
  812. return (SDL_GPUComputePipeline *)pipeline;
  813. }
  814. }
  815. static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline(
  816. SDL_GPURenderer *driverData,
  817. SDL_GPUGraphicsPipelineCreateInfo *pipelineCreateInfo)
  818. {
  819. @autoreleasepool {
  820. MetalRenderer *renderer = (MetalRenderer *)driverData;
  821. MetalShader *vertexShader = (MetalShader *)pipelineCreateInfo->vertexShader;
  822. MetalShader *fragmentShader = (MetalShader *)pipelineCreateInfo->fragmentShader;
  823. MTLRenderPipelineDescriptor *pipelineDescriptor;
  824. SDL_GPUColorAttachmentBlendState *blendState;
  825. MTLVertexDescriptor *vertexDescriptor;
  826. Uint32 binding;
  827. MTLDepthStencilDescriptor *depthStencilDescriptor;
  828. MTLStencilDescriptor *frontStencilDescriptor = NULL;
  829. MTLStencilDescriptor *backStencilDescriptor = NULL;
  830. id<MTLDepthStencilState> depthStencilState = nil;
  831. id<MTLRenderPipelineState> pipelineState = nil;
  832. NSError *error = NULL;
  833. MetalGraphicsPipeline *result = NULL;
  834. pipelineDescriptor = [MTLRenderPipelineDescriptor new];
  835. // Blend
  836. for (Uint32 i = 0; i < pipelineCreateInfo->attachmentInfo.colorAttachmentCount; i += 1) {
  837. blendState = &pipelineCreateInfo->attachmentInfo.colorAttachmentDescriptions[i].blendState;
  838. pipelineDescriptor.colorAttachments[i].pixelFormat = SDLToMetal_SurfaceFormat[pipelineCreateInfo->attachmentInfo.colorAttachmentDescriptions[i].format];
  839. pipelineDescriptor.colorAttachments[i].writeMask = SDLToMetal_ColorWriteMask(blendState->colorWriteMask);
  840. pipelineDescriptor.colorAttachments[i].blendingEnabled = blendState->blendEnable;
  841. pipelineDescriptor.colorAttachments[i].rgbBlendOperation = SDLToMetal_BlendOp[blendState->colorBlendOp];
  842. pipelineDescriptor.colorAttachments[i].alphaBlendOperation = SDLToMetal_BlendOp[blendState->alphaBlendOp];
  843. pipelineDescriptor.colorAttachments[i].sourceRGBBlendFactor = SDLToMetal_BlendFactor[blendState->srcColorBlendFactor];
  844. pipelineDescriptor.colorAttachments[i].sourceAlphaBlendFactor = SDLToMetal_BlendFactor[blendState->srcAlphaBlendFactor];
  845. pipelineDescriptor.colorAttachments[i].destinationRGBBlendFactor = SDLToMetal_BlendFactor[blendState->dstColorBlendFactor];
  846. pipelineDescriptor.colorAttachments[i].destinationAlphaBlendFactor = SDLToMetal_BlendFactor[blendState->dstAlphaBlendFactor];
  847. }
  848. // Multisample
  849. pipelineDescriptor.rasterSampleCount = SDLToMetal_SampleCount[pipelineCreateInfo->multisampleState.sampleCount];
  850. // Depth Stencil
  851. if (pipelineCreateInfo->attachmentInfo.hasDepthStencilAttachment) {
  852. pipelineDescriptor.depthAttachmentPixelFormat = SDLToMetal_SurfaceFormat[pipelineCreateInfo->attachmentInfo.depthStencilFormat];
  853. if (pipelineCreateInfo->depthStencilState.stencilTestEnable) {
  854. pipelineDescriptor.stencilAttachmentPixelFormat = SDLToMetal_SurfaceFormat[pipelineCreateInfo->attachmentInfo.depthStencilFormat];
  855. frontStencilDescriptor = [MTLStencilDescriptor new];
  856. frontStencilDescriptor.stencilCompareFunction = SDLToMetal_CompareOp[pipelineCreateInfo->depthStencilState.frontStencilState.compareOp];
  857. frontStencilDescriptor.stencilFailureOperation = SDLToMetal_StencilOp[pipelineCreateInfo->depthStencilState.frontStencilState.failOp];
  858. frontStencilDescriptor.depthStencilPassOperation = SDLToMetal_StencilOp[pipelineCreateInfo->depthStencilState.frontStencilState.passOp];
  859. frontStencilDescriptor.depthFailureOperation = SDLToMetal_StencilOp[pipelineCreateInfo->depthStencilState.frontStencilState.depthFailOp];
  860. frontStencilDescriptor.readMask = pipelineCreateInfo->depthStencilState.compareMask;
  861. frontStencilDescriptor.writeMask = pipelineCreateInfo->depthStencilState.writeMask;
  862. backStencilDescriptor = [MTLStencilDescriptor new];
  863. backStencilDescriptor.stencilCompareFunction = SDLToMetal_CompareOp[pipelineCreateInfo->depthStencilState.backStencilState.compareOp];
  864. backStencilDescriptor.stencilFailureOperation = SDLToMetal_StencilOp[pipelineCreateInfo->depthStencilState.backStencilState.failOp];
  865. backStencilDescriptor.depthStencilPassOperation = SDLToMetal_StencilOp[pipelineCreateInfo->depthStencilState.backStencilState.passOp];
  866. backStencilDescriptor.depthFailureOperation = SDLToMetal_StencilOp[pipelineCreateInfo->depthStencilState.backStencilState.depthFailOp];
  867. backStencilDescriptor.readMask = pipelineCreateInfo->depthStencilState.compareMask;
  868. backStencilDescriptor.writeMask = pipelineCreateInfo->depthStencilState.writeMask;
  869. }
  870. depthStencilDescriptor = [MTLDepthStencilDescriptor new];
  871. depthStencilDescriptor.depthCompareFunction = pipelineCreateInfo->depthStencilState.depthTestEnable ? SDLToMetal_CompareOp[pipelineCreateInfo->depthStencilState.compareOp] : MTLCompareFunctionAlways;
  872. depthStencilDescriptor.depthWriteEnabled = pipelineCreateInfo->depthStencilState.depthWriteEnable;
  873. depthStencilDescriptor.frontFaceStencil = frontStencilDescriptor;
  874. depthStencilDescriptor.backFaceStencil = backStencilDescriptor;
  875. depthStencilState = [renderer->device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
  876. }
  877. // Shaders
  878. pipelineDescriptor.vertexFunction = vertexShader->function;
  879. pipelineDescriptor.fragmentFunction = fragmentShader->function;
  880. // Vertex Descriptor
  881. if (pipelineCreateInfo->vertexInputState.vertexBindingCount > 0) {
  882. vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
  883. for (Uint32 i = 0; i < pipelineCreateInfo->vertexInputState.vertexAttributeCount; i += 1) {
  884. Uint32 loc = pipelineCreateInfo->vertexInputState.vertexAttributes[i].location;
  885. vertexDescriptor.attributes[loc].format = SDLToMetal_VertexFormat[pipelineCreateInfo->vertexInputState.vertexAttributes[i].format];
  886. vertexDescriptor.attributes[loc].offset = pipelineCreateInfo->vertexInputState.vertexAttributes[i].offset;
  887. vertexDescriptor.attributes[loc].bufferIndex = METAL_INTERNAL_GetVertexBufferIndex(pipelineCreateInfo->vertexInputState.vertexAttributes[i].binding);
  888. }
  889. for (Uint32 i = 0; i < pipelineCreateInfo->vertexInputState.vertexBindingCount; i += 1) {
  890. binding = METAL_INTERNAL_GetVertexBufferIndex(pipelineCreateInfo->vertexInputState.vertexBindings[i].binding);
  891. vertexDescriptor.layouts[binding].stepFunction = SDLToMetal_StepFunction[pipelineCreateInfo->vertexInputState.vertexBindings[i].inputRate];
  892. vertexDescriptor.layouts[binding].stepRate = (pipelineCreateInfo->vertexInputState.vertexBindings[i].inputRate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) ? pipelineCreateInfo->vertexInputState.vertexBindings[i].instanceStepRate : 1;
  893. vertexDescriptor.layouts[binding].stride = pipelineCreateInfo->vertexInputState.vertexBindings[i].stride;
  894. }
  895. pipelineDescriptor.vertexDescriptor = vertexDescriptor;
  896. }
  897. // Create the graphics pipeline
  898. pipelineState = [renderer->device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
  899. if (error != NULL) {
  900. SDL_LogError(
  901. SDL_LOG_CATEGORY_GPU,
  902. "Creating render pipeline failed: %s", [[error description] UTF8String]);
  903. return NULL;
  904. }
  905. result = SDL_malloc(sizeof(MetalGraphicsPipeline));
  906. result->handle = pipelineState;
  907. result->blendConstants[0] = pipelineCreateInfo->blendConstants[0];
  908. result->blendConstants[1] = pipelineCreateInfo->blendConstants[1];
  909. result->blendConstants[2] = pipelineCreateInfo->blendConstants[2];
  910. result->blendConstants[3] = pipelineCreateInfo->blendConstants[3];
  911. result->sampleMask = pipelineCreateInfo->multisampleState.sampleMask;
  912. result->depthStencilState = depthStencilState;
  913. result->stencilReference = pipelineCreateInfo->depthStencilState.reference;
  914. result->rasterizerState = pipelineCreateInfo->rasterizerState;
  915. result->primitiveType = pipelineCreateInfo->primitiveType;
  916. result->vertexSamplerCount = vertexShader->samplerCount;
  917. result->vertexUniformBufferCount = vertexShader->uniformBufferCount;
  918. result->vertexStorageBufferCount = vertexShader->storageBufferCount;
  919. result->vertexStorageTextureCount = vertexShader->storageTextureCount;
  920. result->fragmentSamplerCount = fragmentShader->samplerCount;
  921. result->fragmentUniformBufferCount = fragmentShader->uniformBufferCount;
  922. result->fragmentStorageBufferCount = fragmentShader->storageBufferCount;
  923. result->fragmentStorageTextureCount = fragmentShader->storageTextureCount;
  924. return (SDL_GPUGraphicsPipeline *)result;
  925. }
  926. }
  927. // Debug Naming
  928. static void METAL_SetBufferName(
  929. SDL_GPURenderer *driverData,
  930. SDL_GPUBuffer *buffer,
  931. const char *text)
  932. {
  933. @autoreleasepool {
  934. MetalRenderer *renderer = (MetalRenderer *)driverData;
  935. MetalBufferContainer *container = (MetalBufferContainer *)buffer;
  936. size_t textLength = SDL_strlen(text) + 1;
  937. if (renderer->debugMode) {
  938. container->debugName = SDL_realloc(
  939. container->debugName,
  940. textLength);
  941. SDL_utf8strlcpy(
  942. container->debugName,
  943. text,
  944. textLength);
  945. for (Uint32 i = 0; i < container->bufferCount; i += 1) {
  946. container->buffers[i]->handle.label = @(text);
  947. }
  948. }
  949. }
  950. }
  951. static void METAL_SetTextureName(
  952. SDL_GPURenderer *driverData,
  953. SDL_GPUTexture *texture,
  954. const char *text)
  955. {
  956. @autoreleasepool {
  957. MetalRenderer *renderer = (MetalRenderer *)driverData;
  958. MetalTextureContainer *container = (MetalTextureContainer *)texture;
  959. size_t textLength = SDL_strlen(text) + 1;
  960. if (renderer->debugMode) {
  961. container->debugName = SDL_realloc(
  962. container->debugName,
  963. textLength);
  964. SDL_utf8strlcpy(
  965. container->debugName,
  966. text,
  967. textLength);
  968. for (Uint32 i = 0; i < container->textureCount; i += 1) {
  969. container->textures[i]->handle.label = @(text);
  970. }
  971. }
  972. }
  973. }
  974. static void METAL_InsertDebugLabel(
  975. SDL_GPUCommandBuffer *commandBuffer,
  976. const char *text)
  977. {
  978. @autoreleasepool {
  979. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  980. NSString *label = @(text);
  981. if (metalCommandBuffer->renderEncoder) {
  982. [metalCommandBuffer->renderEncoder insertDebugSignpost:label];
  983. } else if (metalCommandBuffer->blitEncoder) {
  984. [metalCommandBuffer->blitEncoder insertDebugSignpost:label];
  985. } else if (metalCommandBuffer->computeEncoder) {
  986. [metalCommandBuffer->computeEncoder insertDebugSignpost:label];
  987. } else {
  988. // Metal doesn't have insertDebugSignpost for command buffers...
  989. [metalCommandBuffer->handle pushDebugGroup:label];
  990. [metalCommandBuffer->handle popDebugGroup];
  991. }
  992. }
  993. }
  994. static void METAL_PushDebugGroup(
  995. SDL_GPUCommandBuffer *commandBuffer,
  996. const char *name)
  997. {
  998. @autoreleasepool {
  999. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1000. NSString *label = @(name);
  1001. if (metalCommandBuffer->renderEncoder) {
  1002. [metalCommandBuffer->renderEncoder pushDebugGroup:label];
  1003. } else if (metalCommandBuffer->blitEncoder) {
  1004. [metalCommandBuffer->blitEncoder pushDebugGroup:label];
  1005. } else if (metalCommandBuffer->computeEncoder) {
  1006. [metalCommandBuffer->computeEncoder pushDebugGroup:label];
  1007. } else {
  1008. [metalCommandBuffer->handle pushDebugGroup:label];
  1009. }
  1010. }
  1011. }
  1012. static void METAL_PopDebugGroup(
  1013. SDL_GPUCommandBuffer *commandBuffer)
  1014. {
  1015. @autoreleasepool {
  1016. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1017. if (metalCommandBuffer->renderEncoder) {
  1018. [metalCommandBuffer->renderEncoder popDebugGroup];
  1019. } else if (metalCommandBuffer->blitEncoder) {
  1020. [metalCommandBuffer->blitEncoder popDebugGroup];
  1021. } else if (metalCommandBuffer->computeEncoder) {
  1022. [metalCommandBuffer->computeEncoder popDebugGroup];
  1023. } else {
  1024. [metalCommandBuffer->handle popDebugGroup];
  1025. }
  1026. }
  1027. }
  1028. // Resource Creation
  1029. static SDL_GPUSampler *METAL_CreateSampler(
  1030. SDL_GPURenderer *driverData,
  1031. SDL_GPUSamplerCreateInfo *samplerCreateInfo)
  1032. {
  1033. @autoreleasepool {
  1034. MetalRenderer *renderer = (MetalRenderer *)driverData;
  1035. MTLSamplerDescriptor *samplerDesc = [MTLSamplerDescriptor new];
  1036. id<MTLSamplerState> sampler;
  1037. MetalSampler *metalSampler;
  1038. samplerDesc.rAddressMode = SDLToMetal_SamplerAddressMode[samplerCreateInfo->addressModeU];
  1039. samplerDesc.sAddressMode = SDLToMetal_SamplerAddressMode[samplerCreateInfo->addressModeV];
  1040. samplerDesc.tAddressMode = SDLToMetal_SamplerAddressMode[samplerCreateInfo->addressModeW];
  1041. samplerDesc.minFilter = SDLToMetal_MinMagFilter[samplerCreateInfo->minFilter];
  1042. samplerDesc.magFilter = SDLToMetal_MinMagFilter[samplerCreateInfo->magFilter];
  1043. samplerDesc.mipFilter = SDLToMetal_MipFilter[samplerCreateInfo->mipmapMode]; // FIXME: Is this right with non-mipmapped samplers?
  1044. samplerDesc.lodMinClamp = samplerCreateInfo->minLod;
  1045. samplerDesc.lodMaxClamp = samplerCreateInfo->maxLod;
  1046. samplerDesc.maxAnisotropy = (NSUInteger)((samplerCreateInfo->anisotropyEnable) ? samplerCreateInfo->maxAnisotropy : 1);
  1047. samplerDesc.compareFunction = (samplerCreateInfo->compareEnable) ? SDLToMetal_CompareOp[samplerCreateInfo->compareOp] : MTLCompareFunctionAlways;
  1048. samplerDesc.borderColor = MTLSamplerBorderColorTransparentBlack; // arbitrary, unused
  1049. sampler = [renderer->device newSamplerStateWithDescriptor:samplerDesc];
  1050. if (sampler == NULL) {
  1051. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create sampler");
  1052. return NULL;
  1053. }
  1054. metalSampler = (MetalSampler *)SDL_malloc(sizeof(MetalSampler));
  1055. metalSampler->handle = sampler;
  1056. return (SDL_GPUSampler *)metalSampler;
  1057. }
  1058. }
  1059. static SDL_GPUShader *METAL_CreateShader(
  1060. SDL_GPURenderer *driverData,
  1061. SDL_GPUShaderCreateInfo *shaderCreateInfo)
  1062. {
  1063. @autoreleasepool {
  1064. MetalLibraryFunction libraryFunction;
  1065. MetalShader *result;
  1066. libraryFunction = METAL_INTERNAL_CompileShader(
  1067. (MetalRenderer *)driverData,
  1068. shaderCreateInfo->format,
  1069. shaderCreateInfo->code,
  1070. shaderCreateInfo->codeSize,
  1071. shaderCreateInfo->entryPointName);
  1072. if (libraryFunction.library == nil || libraryFunction.function == nil) {
  1073. return NULL;
  1074. }
  1075. result = SDL_malloc(sizeof(MetalShader));
  1076. result->library = libraryFunction.library;
  1077. result->function = libraryFunction.function;
  1078. result->samplerCount = shaderCreateInfo->samplerCount;
  1079. result->storageBufferCount = shaderCreateInfo->storageBufferCount;
  1080. result->storageTextureCount = shaderCreateInfo->storageTextureCount;
  1081. result->uniformBufferCount = shaderCreateInfo->uniformBufferCount;
  1082. return (SDL_GPUShader *)result;
  1083. }
  1084. }
  1085. // This function assumes that it's called from within an autorelease pool
  1086. static MetalTexture *METAL_INTERNAL_CreateTexture(
  1087. MetalRenderer *renderer,
  1088. SDL_GPUTextureCreateInfo *textureCreateInfo)
  1089. {
  1090. MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor new];
  1091. id<MTLTexture> texture;
  1092. id<MTLTexture> msaaTexture = NULL;
  1093. MetalTexture *metalTexture;
  1094. textureDescriptor.textureType = SDLToMetal_TextureType[textureCreateInfo->type];
  1095. textureDescriptor.pixelFormat = SDLToMetal_SurfaceFormat[textureCreateInfo->format];
  1096. // This format isn't natively supported so let's swizzle!
  1097. if (textureCreateInfo->format == SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM) {
  1098. textureDescriptor.swizzle = MTLTextureSwizzleChannelsMake(
  1099. MTLTextureSwizzleBlue,
  1100. MTLTextureSwizzleGreen,
  1101. MTLTextureSwizzleRed,
  1102. MTLTextureSwizzleAlpha);
  1103. }
  1104. textureDescriptor.width = textureCreateInfo->width;
  1105. textureDescriptor.height = textureCreateInfo->height;
  1106. textureDescriptor.depth = (textureCreateInfo->type == SDL_GPU_TEXTURETYPE_3D) ? textureCreateInfo->layerCountOrDepth : 1;
  1107. textureDescriptor.mipmapLevelCount = textureCreateInfo->levelCount;
  1108. textureDescriptor.sampleCount = 1;
  1109. textureDescriptor.arrayLength = (textureCreateInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) ? textureCreateInfo->layerCountOrDepth : 1;
  1110. textureDescriptor.storageMode = MTLStorageModePrivate;
  1111. textureDescriptor.usage = 0;
  1112. if (textureCreateInfo->usageFlags & (SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT |
  1113. SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET_BIT)) {
  1114. textureDescriptor.usage |= MTLTextureUsageRenderTarget;
  1115. }
  1116. if (textureCreateInfo->usageFlags & (SDL_GPU_TEXTUREUSAGE_SAMPLER_BIT |
  1117. SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ_BIT |
  1118. SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ_BIT)) {
  1119. textureDescriptor.usage |= MTLTextureUsageShaderRead;
  1120. }
  1121. if (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE_BIT) {
  1122. textureDescriptor.usage |= MTLTextureUsageShaderWrite;
  1123. }
  1124. texture = [renderer->device newTextureWithDescriptor:textureDescriptor];
  1125. if (texture == NULL) {
  1126. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create MTLTexture!");
  1127. return NULL;
  1128. }
  1129. // Create the MSAA texture, if needed
  1130. if (textureCreateInfo->sampleCount > SDL_GPU_SAMPLECOUNT_1 && textureCreateInfo->type == SDL_GPU_TEXTURETYPE_2D) {
  1131. textureDescriptor.textureType = MTLTextureType2DMultisample;
  1132. textureDescriptor.sampleCount = SDLToMetal_SampleCount[textureCreateInfo->sampleCount];
  1133. textureDescriptor.usage = MTLTextureUsageRenderTarget;
  1134. msaaTexture = [renderer->device newTextureWithDescriptor:textureDescriptor];
  1135. if (msaaTexture == NULL) {
  1136. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create MSAA MTLTexture!");
  1137. return NULL;
  1138. }
  1139. }
  1140. metalTexture = (MetalTexture *)SDL_malloc(sizeof(MetalTexture));
  1141. metalTexture->handle = texture;
  1142. metalTexture->msaaHandle = msaaTexture;
  1143. SDL_AtomicSet(&metalTexture->referenceCount, 0);
  1144. return metalTexture;
  1145. }
  1146. static bool METAL_SupportsSampleCount(
  1147. SDL_GPURenderer *driverData,
  1148. SDL_GPUTextureFormat format,
  1149. SDL_GPUSampleCount sampleCount)
  1150. {
  1151. @autoreleasepool {
  1152. MetalRenderer *renderer = (MetalRenderer *)driverData;
  1153. NSUInteger mtlSampleCount = SDLToMetal_SampleCount[sampleCount];
  1154. return [renderer->device supportsTextureSampleCount:mtlSampleCount];
  1155. }
  1156. }
  1157. static SDL_GPUTexture *METAL_CreateTexture(
  1158. SDL_GPURenderer *driverData,
  1159. SDL_GPUTextureCreateInfo *textureCreateInfo)
  1160. {
  1161. @autoreleasepool {
  1162. MetalRenderer *renderer = (MetalRenderer *)driverData;
  1163. MetalTextureContainer *container;
  1164. MetalTexture *texture;
  1165. texture = METAL_INTERNAL_CreateTexture(
  1166. renderer,
  1167. textureCreateInfo);
  1168. if (texture == NULL) {
  1169. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create texture!");
  1170. return NULL;
  1171. }
  1172. container = SDL_malloc(sizeof(MetalTextureContainer));
  1173. container->canBeCycled = 1;
  1174. container->header.info = *textureCreateInfo;
  1175. container->activeTexture = texture;
  1176. container->textureCapacity = 1;
  1177. container->textureCount = 1;
  1178. container->textures = SDL_malloc(
  1179. container->textureCapacity * sizeof(MetalTexture *));
  1180. container->textures[0] = texture;
  1181. container->debugName = NULL;
  1182. return (SDL_GPUTexture *)container;
  1183. }
  1184. }
  1185. // This function assumes that it's called from within an autorelease pool
  1186. static MetalTexture *METAL_INTERNAL_PrepareTextureForWrite(
  1187. MetalRenderer *renderer,
  1188. MetalTextureContainer *container,
  1189. bool cycle)
  1190. {
  1191. Uint32 i;
  1192. // Cycle the active texture handle if needed
  1193. if (cycle && container->canBeCycled) {
  1194. for (i = 0; i < container->textureCount; i += 1) {
  1195. if (SDL_AtomicGet(&container->textures[i]->referenceCount) == 0) {
  1196. container->activeTexture = container->textures[i];
  1197. return container->activeTexture;
  1198. }
  1199. }
  1200. EXPAND_ARRAY_IF_NEEDED(
  1201. container->textures,
  1202. MetalTexture *,
  1203. container->textureCount + 1,
  1204. container->textureCapacity,
  1205. container->textureCapacity + 1);
  1206. container->textures[container->textureCount] = METAL_INTERNAL_CreateTexture(
  1207. renderer,
  1208. &container->header.info);
  1209. container->textureCount += 1;
  1210. container->activeTexture = container->textures[container->textureCount - 1];
  1211. if (renderer->debugMode && container->debugName != NULL) {
  1212. container->activeTexture->handle.label = @(container->debugName);
  1213. }
  1214. }
  1215. return container->activeTexture;
  1216. }
  1217. // This function assumes that it's called from within an autorelease pool
  1218. static MetalBuffer *METAL_INTERNAL_CreateBuffer(
  1219. MetalRenderer *renderer,
  1220. Uint32 sizeInBytes,
  1221. MTLResourceOptions resourceOptions)
  1222. {
  1223. id<MTLBuffer> bufferHandle;
  1224. MetalBuffer *metalBuffer;
  1225. // Storage buffers have to be 4-aligned, so might as well align them all
  1226. sizeInBytes = METAL_INTERNAL_NextHighestAlignment(sizeInBytes, 4);
  1227. bufferHandle = [renderer->device newBufferWithLength:sizeInBytes options:resourceOptions];
  1228. if (bufferHandle == NULL) {
  1229. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create buffer");
  1230. return NULL;
  1231. }
  1232. metalBuffer = SDL_malloc(sizeof(MetalBuffer));
  1233. metalBuffer->handle = bufferHandle;
  1234. SDL_AtomicSet(&metalBuffer->referenceCount, 0);
  1235. return metalBuffer;
  1236. }
  1237. // This function assumes that it's called from within an autorelease pool
  1238. static MetalBufferContainer *METAL_INTERNAL_CreateBufferContainer(
  1239. MetalRenderer *renderer,
  1240. Uint32 sizeInBytes,
  1241. bool isPrivate,
  1242. bool isWriteOnly)
  1243. {
  1244. MetalBufferContainer *container = SDL_malloc(sizeof(MetalBufferContainer));
  1245. MTLResourceOptions resourceOptions;
  1246. container->size = sizeInBytes;
  1247. container->bufferCapacity = 1;
  1248. container->bufferCount = 1;
  1249. container->buffers = SDL_malloc(
  1250. container->bufferCapacity * sizeof(MetalBuffer *));
  1251. container->isPrivate = isPrivate;
  1252. container->isWriteOnly = isWriteOnly;
  1253. container->debugName = NULL;
  1254. if (isPrivate) {
  1255. resourceOptions = MTLResourceStorageModePrivate;
  1256. } else {
  1257. if (isWriteOnly) {
  1258. resourceOptions = MTLResourceCPUCacheModeWriteCombined;
  1259. } else {
  1260. resourceOptions = MTLResourceCPUCacheModeDefaultCache;
  1261. }
  1262. }
  1263. container->buffers[0] = METAL_INTERNAL_CreateBuffer(
  1264. renderer,
  1265. sizeInBytes,
  1266. resourceOptions);
  1267. container->activeBuffer = container->buffers[0];
  1268. return container;
  1269. }
  1270. static SDL_GPUBuffer *METAL_CreateBuffer(
  1271. SDL_GPURenderer *driverData,
  1272. SDL_GPUBufferUsageFlags usageFlags,
  1273. Uint32 sizeInBytes)
  1274. {
  1275. @autoreleasepool {
  1276. return (SDL_GPUBuffer *)METAL_INTERNAL_CreateBufferContainer(
  1277. (MetalRenderer *)driverData,
  1278. sizeInBytes,
  1279. true,
  1280. false);
  1281. }
  1282. }
  1283. static SDL_GPUTransferBuffer *METAL_CreateTransferBuffer(
  1284. SDL_GPURenderer *driverData,
  1285. SDL_GPUTransferBufferUsage usage,
  1286. Uint32 sizeInBytes)
  1287. {
  1288. @autoreleasepool {
  1289. return (SDL_GPUTransferBuffer *)METAL_INTERNAL_CreateBufferContainer(
  1290. (MetalRenderer *)driverData,
  1291. sizeInBytes,
  1292. false,
  1293. usage == SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD);
  1294. }
  1295. }
  1296. // This function assumes that it's called from within an autorelease pool
  1297. static MetalUniformBuffer *METAL_INTERNAL_CreateUniformBuffer(
  1298. MetalRenderer *renderer,
  1299. Uint32 sizeInBytes)
  1300. {
  1301. MetalUniformBuffer *uniformBuffer;
  1302. id<MTLBuffer> bufferHandle;
  1303. bufferHandle = [renderer->device newBufferWithLength:sizeInBytes options:MTLResourceCPUCacheModeWriteCombined];
  1304. if (bufferHandle == nil) {
  1305. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create uniform buffer");
  1306. return NULL;
  1307. }
  1308. uniformBuffer = SDL_malloc(sizeof(MetalUniformBuffer));
  1309. uniformBuffer->handle = bufferHandle;
  1310. uniformBuffer->writeOffset = 0;
  1311. uniformBuffer->drawOffset = 0;
  1312. return uniformBuffer;
  1313. }
  1314. // This function assumes that it's called from within an autorelease pool
  1315. static MetalBuffer *METAL_INTERNAL_PrepareBufferForWrite(
  1316. MetalRenderer *renderer,
  1317. MetalBufferContainer *container,
  1318. bool cycle)
  1319. {
  1320. MTLResourceOptions resourceOptions;
  1321. Uint32 i;
  1322. // Cycle if needed
  1323. if (cycle && SDL_AtomicGet(&container->activeBuffer->referenceCount) > 0) {
  1324. for (i = 0; i < container->bufferCount; i += 1) {
  1325. if (SDL_AtomicGet(&container->buffers[i]->referenceCount) == 0) {
  1326. container->activeBuffer = container->buffers[i];
  1327. return container->activeBuffer;
  1328. }
  1329. }
  1330. EXPAND_ARRAY_IF_NEEDED(
  1331. container->buffers,
  1332. MetalBuffer *,
  1333. container->bufferCount + 1,
  1334. container->bufferCapacity,
  1335. container->bufferCapacity + 1);
  1336. if (container->isPrivate) {
  1337. resourceOptions = MTLResourceStorageModePrivate;
  1338. } else {
  1339. if (container->isWriteOnly) {
  1340. resourceOptions = MTLResourceCPUCacheModeWriteCombined;
  1341. } else {
  1342. resourceOptions = MTLResourceCPUCacheModeDefaultCache;
  1343. }
  1344. }
  1345. container->buffers[container->bufferCount] = METAL_INTERNAL_CreateBuffer(
  1346. renderer,
  1347. container->size,
  1348. resourceOptions);
  1349. container->bufferCount += 1;
  1350. container->activeBuffer = container->buffers[container->bufferCount - 1];
  1351. if (renderer->debugMode && container->debugName != NULL) {
  1352. container->activeBuffer->handle.label = @(container->debugName);
  1353. }
  1354. }
  1355. return container->activeBuffer;
  1356. }
  1357. // TransferBuffer Data
  1358. static void *METAL_MapTransferBuffer(
  1359. SDL_GPURenderer *driverData,
  1360. SDL_GPUTransferBuffer *transferBuffer,
  1361. bool cycle)
  1362. {
  1363. @autoreleasepool {
  1364. MetalRenderer *renderer = (MetalRenderer *)driverData;
  1365. MetalBufferContainer *container = (MetalBufferContainer *)transferBuffer;
  1366. MetalBuffer *buffer = METAL_INTERNAL_PrepareBufferForWrite(renderer, container, cycle);
  1367. return [buffer->handle contents];
  1368. }
  1369. }
  1370. static void METAL_UnmapTransferBuffer(
  1371. SDL_GPURenderer *driverData,
  1372. SDL_GPUTransferBuffer *transferBuffer)
  1373. {
  1374. #ifdef SDL_PLATFORM_MACOS
  1375. @autoreleasepool {
  1376. // FIXME: Is this necessary?
  1377. MetalBufferContainer *container = (MetalBufferContainer *)transferBuffer;
  1378. MetalBuffer *buffer = container->activeBuffer;
  1379. if (buffer->handle.storageMode == MTLStorageModeManaged) {
  1380. [buffer->handle didModifyRange:NSMakeRange(0, container->size)];
  1381. }
  1382. }
  1383. #endif
  1384. }
  1385. // Copy Pass
  1386. static void METAL_BeginCopyPass(
  1387. SDL_GPUCommandBuffer *commandBuffer)
  1388. {
  1389. @autoreleasepool {
  1390. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1391. metalCommandBuffer->blitEncoder = [metalCommandBuffer->handle blitCommandEncoder];
  1392. }
  1393. }
  1394. static void METAL_UploadToTexture(
  1395. SDL_GPUCommandBuffer *commandBuffer,
  1396. SDL_GPUTextureTransferInfo *source,
  1397. SDL_GPUTextureRegion *destination,
  1398. bool cycle)
  1399. {
  1400. @autoreleasepool {
  1401. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1402. MetalRenderer *renderer = metalCommandBuffer->renderer;
  1403. MetalBufferContainer *bufferContainer = (MetalBufferContainer *)source->transferBuffer;
  1404. MetalTextureContainer *textureContainer = (MetalTextureContainer *)destination->texture;
  1405. MetalTexture *metalTexture = METAL_INTERNAL_PrepareTextureForWrite(renderer, textureContainer, cycle);
  1406. [metalCommandBuffer->blitEncoder
  1407. copyFromBuffer:bufferContainer->activeBuffer->handle
  1408. sourceOffset:source->offset
  1409. sourceBytesPerRow:BytesPerRow(destination->w, textureContainer->header.info.format)
  1410. sourceBytesPerImage:BytesPerImage(destination->w, destination->h, textureContainer->header.info.format)
  1411. sourceSize:MTLSizeMake(destination->w, destination->h, destination->d)
  1412. toTexture:metalTexture->handle
  1413. destinationSlice:destination->layer
  1414. destinationLevel:destination->mipLevel
  1415. destinationOrigin:MTLOriginMake(destination->x, destination->y, destination->z)];
  1416. METAL_INTERNAL_TrackTexture(metalCommandBuffer, metalTexture);
  1417. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, bufferContainer->activeBuffer);
  1418. }
  1419. }
  1420. static void METAL_UploadToBuffer(
  1421. SDL_GPUCommandBuffer *commandBuffer,
  1422. SDL_GPUTransferBufferLocation *source,
  1423. SDL_GPUBufferRegion *destination,
  1424. bool cycle)
  1425. {
  1426. @autoreleasepool {
  1427. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1428. MetalRenderer *renderer = metalCommandBuffer->renderer;
  1429. MetalBufferContainer *transferContainer = (MetalBufferContainer *)source->transferBuffer;
  1430. MetalBufferContainer *bufferContainer = (MetalBufferContainer *)destination->buffer;
  1431. MetalBuffer *metalBuffer = METAL_INTERNAL_PrepareBufferForWrite(
  1432. renderer,
  1433. bufferContainer,
  1434. cycle);
  1435. [metalCommandBuffer->blitEncoder
  1436. copyFromBuffer:transferContainer->activeBuffer->handle
  1437. sourceOffset:source->offset
  1438. toBuffer:metalBuffer->handle
  1439. destinationOffset:destination->offset
  1440. size:destination->size];
  1441. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, metalBuffer);
  1442. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, transferContainer->activeBuffer);
  1443. }
  1444. }
  1445. static void METAL_CopyTextureToTexture(
  1446. SDL_GPUCommandBuffer *commandBuffer,
  1447. SDL_GPUTextureLocation *source,
  1448. SDL_GPUTextureLocation *destination,
  1449. Uint32 w,
  1450. Uint32 h,
  1451. Uint32 d,
  1452. bool cycle)
  1453. {
  1454. @autoreleasepool {
  1455. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1456. MetalRenderer *renderer = metalCommandBuffer->renderer;
  1457. MetalTextureContainer *srcContainer = (MetalTextureContainer *)source->texture;
  1458. MetalTextureContainer *dstContainer = (MetalTextureContainer *)destination->texture;
  1459. MetalTexture *srcTexture = srcContainer->activeTexture;
  1460. MetalTexture *dstTexture = METAL_INTERNAL_PrepareTextureForWrite(
  1461. renderer,
  1462. dstContainer,
  1463. cycle);
  1464. [metalCommandBuffer->blitEncoder
  1465. copyFromTexture:srcTexture->handle
  1466. sourceSlice:source->layer
  1467. sourceLevel:source->mipLevel
  1468. sourceOrigin:MTLOriginMake(source->x, source->y, source->z)
  1469. sourceSize:MTLSizeMake(w, h, d)
  1470. toTexture:dstTexture->handle
  1471. destinationSlice:destination->layer
  1472. destinationLevel:destination->mipLevel
  1473. destinationOrigin:MTLOriginMake(destination->x, destination->y, destination->z)];
  1474. METAL_INTERNAL_TrackTexture(metalCommandBuffer, srcTexture);
  1475. METAL_INTERNAL_TrackTexture(metalCommandBuffer, dstTexture);
  1476. }
  1477. }
  1478. static void METAL_CopyBufferToBuffer(
  1479. SDL_GPUCommandBuffer *commandBuffer,
  1480. SDL_GPUBufferLocation *source,
  1481. SDL_GPUBufferLocation *destination,
  1482. Uint32 size,
  1483. bool cycle)
  1484. {
  1485. @autoreleasepool {
  1486. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1487. MetalRenderer *renderer = metalCommandBuffer->renderer;
  1488. MetalBufferContainer *srcContainer = (MetalBufferContainer *)source->buffer;
  1489. MetalBufferContainer *dstContainer = (MetalBufferContainer *)destination->buffer;
  1490. MetalBuffer *srcBuffer = srcContainer->activeBuffer;
  1491. MetalBuffer *dstBuffer = METAL_INTERNAL_PrepareBufferForWrite(
  1492. renderer,
  1493. dstContainer,
  1494. cycle);
  1495. [metalCommandBuffer->blitEncoder
  1496. copyFromBuffer:srcBuffer->handle
  1497. sourceOffset:source->offset
  1498. toBuffer:dstBuffer->handle
  1499. destinationOffset:destination->offset
  1500. size:size];
  1501. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, srcBuffer);
  1502. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, dstBuffer);
  1503. }
  1504. }
  1505. static void METAL_DownloadFromTexture(
  1506. SDL_GPUCommandBuffer *commandBuffer,
  1507. SDL_GPUTextureRegion *source,
  1508. SDL_GPUTextureTransferInfo *destination)
  1509. {
  1510. @autoreleasepool {
  1511. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1512. MetalRenderer *renderer = metalCommandBuffer->renderer;
  1513. MetalTextureContainer *textureContainer = (MetalTextureContainer *)source->texture;
  1514. MetalTexture *metalTexture = textureContainer->activeTexture;
  1515. MetalBufferContainer *bufferContainer = (MetalBufferContainer *)destination->transferBuffer;
  1516. Uint32 bufferStride = destination->imagePitch;
  1517. Uint32 bufferImageHeight = destination->imageHeight;
  1518. Uint32 bytesPerRow, bytesPerDepthSlice;
  1519. MetalBuffer *dstBuffer = METAL_INTERNAL_PrepareBufferForWrite(
  1520. renderer,
  1521. bufferContainer,
  1522. false);
  1523. MTLOrigin regionOrigin = MTLOriginMake(
  1524. source->x,
  1525. source->y,
  1526. source->z);
  1527. MTLSize regionSize = MTLSizeMake(
  1528. source->w,
  1529. source->h,
  1530. source->d);
  1531. if (bufferStride == 0 || bufferImageHeight == 0) {
  1532. bufferStride = source->w;
  1533. bufferImageHeight = source->h;
  1534. }
  1535. bytesPerRow = BytesPerRow(bufferStride, textureContainer->header.info.format);
  1536. bytesPerDepthSlice = bytesPerRow * bufferImageHeight;
  1537. [metalCommandBuffer->blitEncoder
  1538. copyFromTexture:metalTexture->handle
  1539. sourceSlice:source->layer
  1540. sourceLevel:source->mipLevel
  1541. sourceOrigin:regionOrigin
  1542. sourceSize:regionSize
  1543. toBuffer:dstBuffer->handle
  1544. destinationOffset:destination->offset
  1545. destinationBytesPerRow:bytesPerRow
  1546. destinationBytesPerImage:bytesPerDepthSlice];
  1547. METAL_INTERNAL_TrackTexture(metalCommandBuffer, metalTexture);
  1548. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, dstBuffer);
  1549. }
  1550. }
  1551. static void METAL_DownloadFromBuffer(
  1552. SDL_GPUCommandBuffer *commandBuffer,
  1553. SDL_GPUBufferRegion *source,
  1554. SDL_GPUTransferBufferLocation *destination)
  1555. {
  1556. SDL_GPUBufferLocation sourceLocation;
  1557. sourceLocation.buffer = source->buffer;
  1558. sourceLocation.offset = source->offset;
  1559. METAL_CopyBufferToBuffer(
  1560. commandBuffer,
  1561. &sourceLocation,
  1562. (SDL_GPUBufferLocation *)destination,
  1563. source->size,
  1564. false);
  1565. }
  1566. static void METAL_EndCopyPass(
  1567. SDL_GPUCommandBuffer *commandBuffer)
  1568. {
  1569. @autoreleasepool {
  1570. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1571. [metalCommandBuffer->blitEncoder endEncoding];
  1572. metalCommandBuffer->blitEncoder = nil;
  1573. }
  1574. }
  1575. static void METAL_GenerateMipmaps(
  1576. SDL_GPUCommandBuffer *commandBuffer,
  1577. SDL_GPUTexture *texture)
  1578. {
  1579. @autoreleasepool {
  1580. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1581. MetalTextureContainer *container = (MetalTextureContainer *)texture;
  1582. MetalTexture *metalTexture = container->activeTexture;
  1583. METAL_BeginCopyPass(commandBuffer);
  1584. [metalCommandBuffer->blitEncoder
  1585. generateMipmapsForTexture:metalTexture->handle];
  1586. METAL_EndCopyPass(commandBuffer);
  1587. METAL_INTERNAL_TrackTexture(metalCommandBuffer, metalTexture);
  1588. }
  1589. }
  1590. // Graphics State
  1591. static void METAL_INTERNAL_AllocateCommandBuffers(
  1592. MetalRenderer *renderer,
  1593. Uint32 allocateCount)
  1594. {
  1595. MetalCommandBuffer *commandBuffer;
  1596. renderer->availableCommandBufferCapacity += allocateCount;
  1597. renderer->availableCommandBuffers = SDL_realloc(
  1598. renderer->availableCommandBuffers,
  1599. sizeof(MetalCommandBuffer *) * renderer->availableCommandBufferCapacity);
  1600. for (Uint32 i = 0; i < allocateCount; i += 1) {
  1601. commandBuffer = SDL_calloc(1, sizeof(MetalCommandBuffer));
  1602. commandBuffer->renderer = renderer;
  1603. // The native Metal command buffer is created in METAL_AcquireCommandBuffer
  1604. commandBuffer->windowDataCapacity = 1;
  1605. commandBuffer->windowDataCount = 0;
  1606. commandBuffer->windowDatas = SDL_malloc(
  1607. commandBuffer->windowDataCapacity * sizeof(MetalWindowData *));
  1608. // Reference Counting
  1609. commandBuffer->usedBufferCapacity = 4;
  1610. commandBuffer->usedBufferCount = 0;
  1611. commandBuffer->usedBuffers = SDL_malloc(
  1612. commandBuffer->usedBufferCapacity * sizeof(MetalBuffer *));
  1613. commandBuffer->usedTextureCapacity = 4;
  1614. commandBuffer->usedTextureCount = 0;
  1615. commandBuffer->usedTextures = SDL_malloc(
  1616. commandBuffer->usedTextureCapacity * sizeof(MetalTexture *));
  1617. renderer->availableCommandBuffers[renderer->availableCommandBufferCount] = commandBuffer;
  1618. renderer->availableCommandBufferCount += 1;
  1619. }
  1620. }
  1621. static MetalCommandBuffer *METAL_INTERNAL_GetInactiveCommandBufferFromPool(
  1622. MetalRenderer *renderer)
  1623. {
  1624. MetalCommandBuffer *commandBuffer;
  1625. if (renderer->availableCommandBufferCount == 0) {
  1626. METAL_INTERNAL_AllocateCommandBuffers(
  1627. renderer,
  1628. renderer->availableCommandBufferCapacity);
  1629. }
  1630. commandBuffer = renderer->availableCommandBuffers[renderer->availableCommandBufferCount - 1];
  1631. renderer->availableCommandBufferCount -= 1;
  1632. return commandBuffer;
  1633. }
  1634. static Uint8 METAL_INTERNAL_CreateFence(
  1635. MetalRenderer *renderer)
  1636. {
  1637. MetalFence *fence;
  1638. fence = SDL_malloc(sizeof(MetalFence));
  1639. SDL_AtomicSet(&fence->complete, 0);
  1640. // Add it to the available pool
  1641. // FIXME: Should this be EXPAND_IF_NEEDED?
  1642. if (renderer->availableFenceCount >= renderer->availableFenceCapacity) {
  1643. renderer->availableFenceCapacity *= 2;
  1644. renderer->availableFences = SDL_realloc(
  1645. renderer->availableFences,
  1646. sizeof(MetalFence *) * renderer->availableFenceCapacity);
  1647. }
  1648. renderer->availableFences[renderer->availableFenceCount] = fence;
  1649. renderer->availableFenceCount += 1;
  1650. return 1;
  1651. }
  1652. static Uint8 METAL_INTERNAL_AcquireFence(
  1653. MetalRenderer *renderer,
  1654. MetalCommandBuffer *commandBuffer)
  1655. {
  1656. MetalFence *fence;
  1657. // Acquire a fence from the pool
  1658. SDL_LockMutex(renderer->fenceLock);
  1659. if (renderer->availableFenceCount == 0) {
  1660. if (!METAL_INTERNAL_CreateFence(renderer)) {
  1661. SDL_UnlockMutex(renderer->fenceLock);
  1662. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create fence!");
  1663. return 0;
  1664. }
  1665. }
  1666. fence = renderer->availableFences[renderer->availableFenceCount - 1];
  1667. renderer->availableFenceCount -= 1;
  1668. SDL_UnlockMutex(renderer->fenceLock);
  1669. // Associate the fence with the command buffer
  1670. commandBuffer->fence = fence;
  1671. SDL_AtomicSet(&fence->complete, 0); // FIXME: Is this right?
  1672. return 1;
  1673. }
  1674. static SDL_GPUCommandBuffer *METAL_AcquireCommandBuffer(
  1675. SDL_GPURenderer *driverData)
  1676. {
  1677. @autoreleasepool {
  1678. MetalRenderer *renderer = (MetalRenderer *)driverData;
  1679. MetalCommandBuffer *commandBuffer;
  1680. SDL_LockMutex(renderer->acquireCommandBufferLock);
  1681. commandBuffer = METAL_INTERNAL_GetInactiveCommandBufferFromPool(renderer);
  1682. commandBuffer->handle = [renderer->queue commandBuffer];
  1683. commandBuffer->graphicsPipeline = NULL;
  1684. commandBuffer->computePipeline = NULL;
  1685. for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
  1686. commandBuffer->vertexUniformBuffers[i] = NULL;
  1687. commandBuffer->fragmentUniformBuffers[i] = NULL;
  1688. commandBuffer->computeUniformBuffers[i] = NULL;
  1689. }
  1690. // FIXME: Do we actually need to set this?
  1691. commandBuffer->needVertexSamplerBind = true;
  1692. commandBuffer->needVertexStorageTextureBind = true;
  1693. commandBuffer->needVertexStorageBufferBind = true;
  1694. commandBuffer->needVertexUniformBind = true;
  1695. commandBuffer->needFragmentSamplerBind = true;
  1696. commandBuffer->needFragmentStorageTextureBind = true;
  1697. commandBuffer->needFragmentStorageBufferBind = true;
  1698. commandBuffer->needFragmentUniformBind = true;
  1699. commandBuffer->needComputeBufferBind = true;
  1700. commandBuffer->needComputeTextureBind = true;
  1701. commandBuffer->needComputeUniformBind = true;
  1702. METAL_INTERNAL_AcquireFence(renderer, commandBuffer);
  1703. commandBuffer->autoReleaseFence = 1;
  1704. SDL_UnlockMutex(renderer->acquireCommandBufferLock);
  1705. return (SDL_GPUCommandBuffer *)commandBuffer;
  1706. }
  1707. }
  1708. // This function assumes that it's called from within an autorelease pool
  1709. static MetalUniformBuffer *METAL_INTERNAL_AcquireUniformBufferFromPool(
  1710. MetalCommandBuffer *commandBuffer)
  1711. {
  1712. MetalRenderer *renderer = commandBuffer->renderer;
  1713. MetalUniformBuffer *uniformBuffer;
  1714. SDL_LockMutex(renderer->acquireUniformBufferLock);
  1715. if (renderer->uniformBufferPoolCount > 0) {
  1716. uniformBuffer = renderer->uniformBufferPool[renderer->uniformBufferPoolCount - 1];
  1717. renderer->uniformBufferPoolCount -= 1;
  1718. } else {
  1719. uniformBuffer = METAL_INTERNAL_CreateUniformBuffer(
  1720. renderer,
  1721. UNIFORM_BUFFER_SIZE);
  1722. }
  1723. SDL_UnlockMutex(renderer->acquireUniformBufferLock);
  1724. METAL_INTERNAL_TrackUniformBuffer(commandBuffer, uniformBuffer);
  1725. return uniformBuffer;
  1726. }
  1727. static void METAL_INTERNAL_ReturnUniformBufferToPool(
  1728. MetalRenderer *renderer,
  1729. MetalUniformBuffer *uniformBuffer)
  1730. {
  1731. if (renderer->uniformBufferPoolCount >= renderer->uniformBufferPoolCapacity) {
  1732. renderer->uniformBufferPoolCapacity *= 2;
  1733. renderer->uniformBufferPool = SDL_realloc(
  1734. renderer->uniformBufferPool,
  1735. renderer->uniformBufferPoolCapacity * sizeof(MetalUniformBuffer *));
  1736. }
  1737. renderer->uniformBufferPool[renderer->uniformBufferPoolCount] = uniformBuffer;
  1738. renderer->uniformBufferPoolCount += 1;
  1739. uniformBuffer->writeOffset = 0;
  1740. uniformBuffer->drawOffset = 0;
  1741. }
  1742. static void METAL_BeginRenderPass(
  1743. SDL_GPUCommandBuffer *commandBuffer,
  1744. SDL_GPUColorAttachmentInfo *colorAttachmentInfos,
  1745. Uint32 colorAttachmentCount,
  1746. SDL_GPUDepthStencilAttachmentInfo *depthStencilAttachmentInfo)
  1747. {
  1748. @autoreleasepool {
  1749. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1750. MetalRenderer *renderer = metalCommandBuffer->renderer;
  1751. MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
  1752. Uint32 vpWidth = UINT_MAX;
  1753. Uint32 vpHeight = UINT_MAX;
  1754. MTLViewport viewport;
  1755. MTLScissorRect scissorRect;
  1756. for (Uint32 i = 0; i < colorAttachmentCount; i += 1) {
  1757. MetalTextureContainer *container = (MetalTextureContainer *)colorAttachmentInfos[i].texture;
  1758. MetalTexture *texture = METAL_INTERNAL_PrepareTextureForWrite(
  1759. renderer,
  1760. container,
  1761. colorAttachmentInfos[i].cycle);
  1762. if (texture->msaaHandle) {
  1763. passDescriptor.colorAttachments[i].texture = texture->msaaHandle;
  1764. passDescriptor.colorAttachments[i].resolveTexture = texture->handle;
  1765. } else {
  1766. passDescriptor.colorAttachments[i].texture = texture->handle;
  1767. }
  1768. passDescriptor.colorAttachments[i].level = colorAttachmentInfos[i].mipLevel;
  1769. if (container->header.info.type == SDL_GPU_TEXTURETYPE_3D) {
  1770. passDescriptor.colorAttachments[i].depthPlane = colorAttachmentInfos[i].layerOrDepthPlane;
  1771. } else {
  1772. passDescriptor.colorAttachments[i].slice = colorAttachmentInfos[i].layerOrDepthPlane;
  1773. }
  1774. passDescriptor.colorAttachments[i].clearColor = MTLClearColorMake(
  1775. colorAttachmentInfos[i].clearColor.r,
  1776. colorAttachmentInfos[i].clearColor.g,
  1777. colorAttachmentInfos[i].clearColor.b,
  1778. colorAttachmentInfos[i].clearColor.a);
  1779. passDescriptor.colorAttachments[i].loadAction = SDLToMetal_LoadOp[colorAttachmentInfos[i].loadOp];
  1780. passDescriptor.colorAttachments[i].storeAction = SDLToMetal_StoreOp(
  1781. colorAttachmentInfos[i].storeOp,
  1782. texture->msaaHandle ? 1 : 0);
  1783. METAL_INTERNAL_TrackTexture(metalCommandBuffer, texture);
  1784. }
  1785. if (depthStencilAttachmentInfo != NULL) {
  1786. MetalTextureContainer *container = (MetalTextureContainer *)depthStencilAttachmentInfo->texture;
  1787. MetalTexture *texture = METAL_INTERNAL_PrepareTextureForWrite(
  1788. renderer,
  1789. container,
  1790. depthStencilAttachmentInfo->cycle);
  1791. if (texture->msaaHandle) {
  1792. passDescriptor.depthAttachment.texture = texture->msaaHandle;
  1793. passDescriptor.depthAttachment.resolveTexture = texture->handle;
  1794. } else {
  1795. passDescriptor.depthAttachment.texture = texture->handle;
  1796. }
  1797. passDescriptor.depthAttachment.loadAction = SDLToMetal_LoadOp[depthStencilAttachmentInfo->loadOp];
  1798. passDescriptor.depthAttachment.storeAction = SDLToMetal_StoreOp(
  1799. depthStencilAttachmentInfo->storeOp,
  1800. texture->msaaHandle ? 1 : 0);
  1801. passDescriptor.depthAttachment.clearDepth = depthStencilAttachmentInfo->depthStencilClearValue.depth;
  1802. if (IsStencilFormat(container->header.info.format)) {
  1803. if (texture->msaaHandle) {
  1804. passDescriptor.stencilAttachment.texture = texture->msaaHandle;
  1805. passDescriptor.stencilAttachment.resolveTexture = texture->handle;
  1806. } else {
  1807. passDescriptor.stencilAttachment.texture = texture->handle;
  1808. }
  1809. passDescriptor.stencilAttachment.loadAction = SDLToMetal_LoadOp[depthStencilAttachmentInfo->loadOp];
  1810. passDescriptor.stencilAttachment.storeAction = SDLToMetal_StoreOp(
  1811. depthStencilAttachmentInfo->storeOp,
  1812. texture->msaaHandle ? 1 : 0);
  1813. passDescriptor.stencilAttachment.clearStencil = depthStencilAttachmentInfo->depthStencilClearValue.stencil;
  1814. }
  1815. METAL_INTERNAL_TrackTexture(metalCommandBuffer, texture);
  1816. }
  1817. metalCommandBuffer->renderEncoder = [metalCommandBuffer->handle renderCommandEncoderWithDescriptor:passDescriptor];
  1818. // The viewport cannot be larger than the smallest attachment.
  1819. for (Uint32 i = 0; i < colorAttachmentCount; i += 1) {
  1820. MetalTextureContainer *container = (MetalTextureContainer *)colorAttachmentInfos[i].texture;
  1821. Uint32 w = container->header.info.width >> colorAttachmentInfos[i].mipLevel;
  1822. Uint32 h = container->header.info.height >> colorAttachmentInfos[i].mipLevel;
  1823. if (w < vpWidth) {
  1824. vpWidth = w;
  1825. }
  1826. if (h < vpHeight) {
  1827. vpHeight = h;
  1828. }
  1829. }
  1830. if (depthStencilAttachmentInfo != NULL) {
  1831. MetalTextureContainer *container = (MetalTextureContainer *)depthStencilAttachmentInfo->texture;
  1832. Uint32 w = container->header.info.width;
  1833. Uint32 h = container->header.info.height;
  1834. if (w < vpWidth) {
  1835. vpWidth = w;
  1836. }
  1837. if (h < vpHeight) {
  1838. vpHeight = h;
  1839. }
  1840. }
  1841. // Set default viewport and scissor state
  1842. viewport.originX = 0;
  1843. viewport.originY = 0;
  1844. viewport.width = vpWidth;
  1845. viewport.height = vpHeight;
  1846. viewport.znear = 0;
  1847. viewport.zfar = 1;
  1848. [metalCommandBuffer->renderEncoder setViewport:viewport];
  1849. scissorRect.x = 0;
  1850. scissorRect.y = 0;
  1851. scissorRect.width = vpWidth;
  1852. scissorRect.height = vpHeight;
  1853. [metalCommandBuffer->renderEncoder setScissorRect:scissorRect];
  1854. }
  1855. }
  1856. static void METAL_BindGraphicsPipeline(
  1857. SDL_GPUCommandBuffer *commandBuffer,
  1858. SDL_GPUGraphicsPipeline *graphicsPipeline)
  1859. {
  1860. @autoreleasepool {
  1861. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1862. MetalGraphicsPipeline *metalGraphicsPipeline = (MetalGraphicsPipeline *)graphicsPipeline;
  1863. SDL_GPURasterizerState *rast = &metalGraphicsPipeline->rasterizerState;
  1864. metalCommandBuffer->graphicsPipeline = metalGraphicsPipeline;
  1865. [metalCommandBuffer->renderEncoder setRenderPipelineState:metalGraphicsPipeline->handle];
  1866. // Apply rasterizer state
  1867. [metalCommandBuffer->renderEncoder setTriangleFillMode:SDLToMetal_PolygonMode[metalGraphicsPipeline->rasterizerState.fillMode]];
  1868. [metalCommandBuffer->renderEncoder setCullMode:SDLToMetal_CullMode[metalGraphicsPipeline->rasterizerState.cullMode]];
  1869. [metalCommandBuffer->renderEncoder setFrontFacingWinding:SDLToMetal_FrontFace[metalGraphicsPipeline->rasterizerState.frontFace]];
  1870. [metalCommandBuffer->renderEncoder
  1871. setDepthBias:((rast->depthBiasEnable) ? rast->depthBiasConstantFactor : 0)
  1872. slopeScale:((rast->depthBiasEnable) ? rast->depthBiasSlopeFactor : 0)
  1873. clamp:((rast->depthBiasEnable) ? rast->depthBiasClamp : 0)];
  1874. // Apply blend constants
  1875. [metalCommandBuffer->renderEncoder
  1876. setBlendColorRed:metalGraphicsPipeline->blendConstants[0]
  1877. green:metalGraphicsPipeline->blendConstants[1]
  1878. blue:metalGraphicsPipeline->blendConstants[2]
  1879. alpha:metalGraphicsPipeline->blendConstants[3]];
  1880. // Apply depth-stencil state
  1881. if (metalGraphicsPipeline->depthStencilState != NULL) {
  1882. [metalCommandBuffer->renderEncoder
  1883. setDepthStencilState:metalGraphicsPipeline->depthStencilState];
  1884. [metalCommandBuffer->renderEncoder
  1885. setStencilReferenceValue:metalGraphicsPipeline->stencilReference];
  1886. }
  1887. for (Uint32 i = 0; i < metalGraphicsPipeline->vertexUniformBufferCount; i += 1) {
  1888. if (metalCommandBuffer->vertexUniformBuffers[i] == NULL) {
  1889. metalCommandBuffer->vertexUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
  1890. metalCommandBuffer);
  1891. }
  1892. }
  1893. for (Uint32 i = 0; i < metalGraphicsPipeline->fragmentUniformBufferCount; i += 1) {
  1894. if (metalCommandBuffer->fragmentUniformBuffers[i] == NULL) {
  1895. metalCommandBuffer->fragmentUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
  1896. metalCommandBuffer);
  1897. }
  1898. }
  1899. metalCommandBuffer->needVertexUniformBind = true;
  1900. metalCommandBuffer->needFragmentUniformBind = true;
  1901. }
  1902. }
  1903. static void METAL_SetViewport(
  1904. SDL_GPUCommandBuffer *commandBuffer,
  1905. SDL_GPUViewport *viewport)
  1906. {
  1907. @autoreleasepool {
  1908. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1909. MTLViewport metalViewport;
  1910. metalViewport.originX = viewport->x;
  1911. metalViewport.originY = viewport->y;
  1912. metalViewport.width = viewport->w;
  1913. metalViewport.height = viewport->h;
  1914. metalViewport.znear = viewport->minDepth;
  1915. metalViewport.zfar = viewport->maxDepth;
  1916. [metalCommandBuffer->renderEncoder setViewport:metalViewport];
  1917. }
  1918. }
  1919. static void METAL_SetScissor(
  1920. SDL_GPUCommandBuffer *commandBuffer,
  1921. SDL_Rect *scissor)
  1922. {
  1923. @autoreleasepool {
  1924. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1925. MTLScissorRect metalScissor;
  1926. metalScissor.x = scissor->x;
  1927. metalScissor.y = scissor->y;
  1928. metalScissor.width = scissor->w;
  1929. metalScissor.height = scissor->h;
  1930. [metalCommandBuffer->renderEncoder setScissorRect:metalScissor];
  1931. }
  1932. }
  1933. static void METAL_BindVertexBuffers(
  1934. SDL_GPUCommandBuffer *commandBuffer,
  1935. Uint32 firstBinding,
  1936. SDL_GPUBufferBinding *pBindings,
  1937. Uint32 bindingCount)
  1938. {
  1939. @autoreleasepool {
  1940. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1941. id<MTLBuffer> metalBuffers[MAX_BUFFER_BINDINGS];
  1942. NSUInteger bufferOffsets[MAX_BUFFER_BINDINGS];
  1943. NSRange range = NSMakeRange(METAL_INTERNAL_GetVertexBufferIndex(firstBinding), bindingCount);
  1944. if (range.length == 0) {
  1945. return;
  1946. }
  1947. for (Uint32 i = 0; i < range.length; i += 1) {
  1948. MetalBuffer *currentBuffer = ((MetalBufferContainer *)pBindings[i].buffer)->activeBuffer;
  1949. NSUInteger bindingIndex = range.length - 1 - i;
  1950. metalBuffers[bindingIndex] = currentBuffer->handle;
  1951. bufferOffsets[bindingIndex] = pBindings[i].offset;
  1952. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, currentBuffer);
  1953. }
  1954. [metalCommandBuffer->renderEncoder setVertexBuffers:metalBuffers offsets:bufferOffsets withRange:range];
  1955. }
  1956. }
  1957. static void METAL_BindIndexBuffer(
  1958. SDL_GPUCommandBuffer *commandBuffer,
  1959. SDL_GPUBufferBinding *pBinding,
  1960. SDL_GPUIndexElementSize indexElementSize)
  1961. {
  1962. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1963. metalCommandBuffer->indexBuffer = ((MetalBufferContainer *)pBinding->buffer)->activeBuffer;
  1964. metalCommandBuffer->indexBufferOffset = pBinding->offset;
  1965. metalCommandBuffer->indexElementSize = indexElementSize;
  1966. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, metalCommandBuffer->indexBuffer);
  1967. }
  1968. static void METAL_BindVertexSamplers(
  1969. SDL_GPUCommandBuffer *commandBuffer,
  1970. Uint32 firstSlot,
  1971. SDL_GPUTextureSamplerBinding *textureSamplerBindings,
  1972. Uint32 bindingCount)
  1973. {
  1974. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1975. MetalTextureContainer *textureContainer;
  1976. for (Uint32 i = 0; i < bindingCount; i += 1) {
  1977. textureContainer = (MetalTextureContainer *)textureSamplerBindings[i].texture;
  1978. METAL_INTERNAL_TrackTexture(
  1979. metalCommandBuffer,
  1980. textureContainer->activeTexture);
  1981. metalCommandBuffer->vertexSamplers[firstSlot + i] =
  1982. ((MetalSampler *)textureSamplerBindings[i].sampler)->handle;
  1983. metalCommandBuffer->vertexTextures[firstSlot + i] =
  1984. textureContainer->activeTexture->handle;
  1985. }
  1986. metalCommandBuffer->needVertexSamplerBind = true;
  1987. }
  1988. static void METAL_BindVertexStorageTextures(
  1989. SDL_GPUCommandBuffer *commandBuffer,
  1990. Uint32 firstSlot,
  1991. SDL_GPUTexture **storageTextures,
  1992. Uint32 bindingCount)
  1993. {
  1994. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  1995. MetalTextureContainer *textureContainer;
  1996. for (Uint32 i = 0; i < bindingCount; i += 1) {
  1997. textureContainer = (MetalTextureContainer *)storageTextures[i];
  1998. METAL_INTERNAL_TrackTexture(
  1999. metalCommandBuffer,
  2000. textureContainer->activeTexture);
  2001. metalCommandBuffer->vertexStorageTextures[firstSlot + i] =
  2002. textureContainer->activeTexture->handle;
  2003. }
  2004. metalCommandBuffer->needVertexStorageTextureBind = true;
  2005. }
  2006. static void METAL_BindVertexStorageBuffers(
  2007. SDL_GPUCommandBuffer *commandBuffer,
  2008. Uint32 firstSlot,
  2009. SDL_GPUBuffer **storageBuffers,
  2010. Uint32 bindingCount)
  2011. {
  2012. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2013. MetalBufferContainer *bufferContainer;
  2014. for (Uint32 i = 0; i < bindingCount; i += 1) {
  2015. bufferContainer = (MetalBufferContainer *)storageBuffers[i];
  2016. METAL_INTERNAL_TrackBuffer(
  2017. metalCommandBuffer,
  2018. bufferContainer->activeBuffer);
  2019. metalCommandBuffer->vertexStorageBuffers[firstSlot + i] =
  2020. bufferContainer->activeBuffer->handle;
  2021. }
  2022. metalCommandBuffer->needVertexStorageBufferBind = true;
  2023. }
  2024. static void METAL_BindFragmentSamplers(
  2025. SDL_GPUCommandBuffer *commandBuffer,
  2026. Uint32 firstSlot,
  2027. SDL_GPUTextureSamplerBinding *textureSamplerBindings,
  2028. Uint32 bindingCount)
  2029. {
  2030. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2031. MetalTextureContainer *textureContainer;
  2032. for (Uint32 i = 0; i < bindingCount; i += 1) {
  2033. textureContainer = (MetalTextureContainer *)textureSamplerBindings[i].texture;
  2034. METAL_INTERNAL_TrackTexture(
  2035. metalCommandBuffer,
  2036. textureContainer->activeTexture);
  2037. metalCommandBuffer->fragmentSamplers[firstSlot + i] =
  2038. ((MetalSampler *)textureSamplerBindings[i].sampler)->handle;
  2039. metalCommandBuffer->fragmentTextures[firstSlot + i] =
  2040. textureContainer->activeTexture->handle;
  2041. }
  2042. metalCommandBuffer->needFragmentSamplerBind = true;
  2043. }
  2044. static void METAL_BindFragmentStorageTextures(
  2045. SDL_GPUCommandBuffer *commandBuffer,
  2046. Uint32 firstSlot,
  2047. SDL_GPUTexture **storageTextures,
  2048. Uint32 bindingCount)
  2049. {
  2050. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2051. MetalTextureContainer *textureContainer;
  2052. for (Uint32 i = 0; i < bindingCount; i += 1) {
  2053. textureContainer = (MetalTextureContainer *)storageTextures[i];
  2054. METAL_INTERNAL_TrackTexture(
  2055. metalCommandBuffer,
  2056. textureContainer->activeTexture);
  2057. metalCommandBuffer->fragmentStorageTextures[firstSlot + i] =
  2058. textureContainer->activeTexture->handle;
  2059. }
  2060. metalCommandBuffer->needFragmentStorageTextureBind = true;
  2061. }
  2062. static void METAL_BindFragmentStorageBuffers(
  2063. SDL_GPUCommandBuffer *commandBuffer,
  2064. Uint32 firstSlot,
  2065. SDL_GPUBuffer **storageBuffers,
  2066. Uint32 bindingCount)
  2067. {
  2068. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2069. MetalBufferContainer *bufferContainer;
  2070. for (Uint32 i = 0; i < bindingCount; i += 1) {
  2071. bufferContainer = (MetalBufferContainer *)storageBuffers[i];
  2072. METAL_INTERNAL_TrackBuffer(
  2073. metalCommandBuffer,
  2074. bufferContainer->activeBuffer);
  2075. metalCommandBuffer->fragmentStorageBuffers[firstSlot + i] =
  2076. bufferContainer->activeBuffer->handle;
  2077. }
  2078. metalCommandBuffer->needFragmentStorageBufferBind = true;
  2079. }
  2080. // This function assumes that it's called from within an autorelease pool
  2081. static void METAL_INTERNAL_BindGraphicsResources(
  2082. MetalCommandBuffer *commandBuffer)
  2083. {
  2084. MetalGraphicsPipeline *graphicsPipeline = commandBuffer->graphicsPipeline;
  2085. NSUInteger offsets[MAX_STORAGE_BUFFERS_PER_STAGE] = { 0 };
  2086. // Vertex Samplers+Textures
  2087. if (graphicsPipeline->vertexSamplerCount > 0 && commandBuffer->needVertexSamplerBind) {
  2088. [commandBuffer->renderEncoder setVertexSamplerStates:commandBuffer->vertexSamplers
  2089. withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)];
  2090. [commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexTextures
  2091. withRange:NSMakeRange(0, graphicsPipeline->vertexSamplerCount)];
  2092. commandBuffer->needVertexSamplerBind = false;
  2093. }
  2094. // Vertex Storage Textures
  2095. if (graphicsPipeline->vertexStorageTextureCount > 0 && commandBuffer->needVertexStorageTextureBind) {
  2096. [commandBuffer->renderEncoder setVertexTextures:commandBuffer->vertexStorageTextures
  2097. withRange:NSMakeRange(graphicsPipeline->vertexSamplerCount,
  2098. graphicsPipeline->vertexStorageTextureCount)];
  2099. commandBuffer->needVertexStorageTextureBind = false;
  2100. }
  2101. // Vertex Storage Buffers
  2102. if (graphicsPipeline->vertexStorageBufferCount > 0 && commandBuffer->needVertexStorageBufferBind) {
  2103. [commandBuffer->renderEncoder setVertexBuffers:commandBuffer->vertexStorageBuffers
  2104. offsets:offsets
  2105. withRange:NSMakeRange(graphicsPipeline->vertexUniformBufferCount,
  2106. graphicsPipeline->vertexStorageBufferCount)];
  2107. commandBuffer->needVertexStorageBufferBind = false;
  2108. }
  2109. // Vertex Uniform Buffers
  2110. if (graphicsPipeline->vertexUniformBufferCount > 0 && commandBuffer->needVertexUniformBind) {
  2111. for (Uint32 i = 0; i < graphicsPipeline->vertexUniformBufferCount; i += 1) {
  2112. [commandBuffer->renderEncoder
  2113. setVertexBuffer:commandBuffer->vertexUniformBuffers[i]->handle
  2114. offset:commandBuffer->vertexUniformBuffers[i]->drawOffset
  2115. atIndex:i];
  2116. }
  2117. commandBuffer->needVertexUniformBind = false;
  2118. }
  2119. // Fragment Samplers+Textures
  2120. if (graphicsPipeline->fragmentSamplerCount > 0 && commandBuffer->needFragmentSamplerBind) {
  2121. [commandBuffer->renderEncoder setFragmentSamplerStates:commandBuffer->fragmentSamplers
  2122. withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)];
  2123. [commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentTextures
  2124. withRange:NSMakeRange(0, graphicsPipeline->fragmentSamplerCount)];
  2125. commandBuffer->needFragmentSamplerBind = false;
  2126. }
  2127. // Fragment Storage Textures
  2128. if (graphicsPipeline->fragmentStorageTextureCount > 0 && commandBuffer->needFragmentStorageTextureBind) {
  2129. [commandBuffer->renderEncoder setFragmentTextures:commandBuffer->fragmentStorageTextures
  2130. withRange:NSMakeRange(graphicsPipeline->fragmentSamplerCount,
  2131. graphicsPipeline->fragmentStorageTextureCount)];
  2132. commandBuffer->needFragmentStorageTextureBind = false;
  2133. }
  2134. // Fragment Storage Buffers
  2135. if (graphicsPipeline->fragmentStorageBufferCount > 0 && commandBuffer->needFragmentStorageBufferBind) {
  2136. [commandBuffer->renderEncoder setFragmentBuffers:commandBuffer->fragmentStorageBuffers
  2137. offsets:offsets
  2138. withRange:NSMakeRange(graphicsPipeline->fragmentUniformBufferCount,
  2139. graphicsPipeline->fragmentStorageBufferCount)];
  2140. commandBuffer->needFragmentStorageBufferBind = false;
  2141. }
  2142. // Fragment Uniform Buffers
  2143. if (graphicsPipeline->fragmentUniformBufferCount > 0 && commandBuffer->needFragmentUniformBind) {
  2144. for (Uint32 i = 0; i < graphicsPipeline->fragmentUniformBufferCount; i += 1) {
  2145. [commandBuffer->renderEncoder
  2146. setFragmentBuffer:commandBuffer->fragmentUniformBuffers[i]->handle
  2147. offset:commandBuffer->fragmentUniformBuffers[i]->drawOffset
  2148. atIndex:i];
  2149. }
  2150. commandBuffer->needFragmentUniformBind = false;
  2151. }
  2152. }
  2153. // This function assumes that it's called from within an autorelease pool
  2154. static void METAL_INTERNAL_BindComputeResources(
  2155. MetalCommandBuffer *commandBuffer)
  2156. {
  2157. MetalComputePipeline *computePipeline = commandBuffer->computePipeline;
  2158. NSUInteger offsets[MAX_STORAGE_BUFFERS_PER_STAGE] = { 0 }; // 8 is the max for both read and write-only
  2159. if (commandBuffer->needComputeTextureBind) {
  2160. // Bind read-only textures
  2161. if (computePipeline->readOnlyStorageTextureCount > 0) {
  2162. [commandBuffer->computeEncoder setTextures:commandBuffer->computeReadOnlyTextures
  2163. withRange:NSMakeRange(0, computePipeline->readOnlyStorageTextureCount)];
  2164. }
  2165. // Bind write-only textures
  2166. if (computePipeline->writeOnlyStorageTextureCount > 0) {
  2167. [commandBuffer->computeEncoder setTextures:commandBuffer->computeWriteOnlyTextures
  2168. withRange:NSMakeRange(
  2169. computePipeline->readOnlyStorageTextureCount,
  2170. computePipeline->writeOnlyStorageTextureCount)];
  2171. }
  2172. commandBuffer->needComputeTextureBind = false;
  2173. }
  2174. if (commandBuffer->needComputeBufferBind) {
  2175. // Bind read-only buffers
  2176. if (computePipeline->readOnlyStorageBufferCount > 0) {
  2177. [commandBuffer->computeEncoder setBuffers:commandBuffer->computeReadOnlyBuffers
  2178. offsets:offsets
  2179. withRange:NSMakeRange(computePipeline->uniformBufferCount,
  2180. computePipeline->readOnlyStorageBufferCount)];
  2181. }
  2182. // Bind write-only buffers
  2183. if (computePipeline->writeOnlyStorageBufferCount > 0) {
  2184. [commandBuffer->computeEncoder setBuffers:commandBuffer->computeWriteOnlyBuffers
  2185. offsets:offsets
  2186. withRange:NSMakeRange(
  2187. computePipeline->uniformBufferCount +
  2188. computePipeline->readOnlyStorageBufferCount,
  2189. computePipeline->writeOnlyStorageBufferCount)];
  2190. }
  2191. commandBuffer->needComputeBufferBind = false;
  2192. }
  2193. if (commandBuffer->needComputeUniformBind) {
  2194. for (Uint32 i = 0; i < computePipeline->uniformBufferCount; i += 1) {
  2195. [commandBuffer->computeEncoder
  2196. setBuffer:commandBuffer->computeUniformBuffers[i]->handle
  2197. offset:commandBuffer->computeUniformBuffers[i]->drawOffset
  2198. atIndex:i];
  2199. }
  2200. commandBuffer->needComputeUniformBind = false;
  2201. }
  2202. }
  2203. static void METAL_DrawIndexedPrimitives(
  2204. SDL_GPUCommandBuffer *commandBuffer,
  2205. Uint32 indexCount,
  2206. Uint32 instanceCount,
  2207. Uint32 firstIndex,
  2208. Sint32 vertexOffset,
  2209. Uint32 firstInstance)
  2210. {
  2211. @autoreleasepool {
  2212. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2213. SDL_GPUPrimitiveType primitiveType = metalCommandBuffer->graphicsPipeline->primitiveType;
  2214. Uint32 indexSize = IndexSize(metalCommandBuffer->indexElementSize);
  2215. METAL_INTERNAL_BindGraphicsResources(metalCommandBuffer);
  2216. [metalCommandBuffer->renderEncoder
  2217. drawIndexedPrimitives:SDLToMetal_PrimitiveType[primitiveType]
  2218. indexCount:indexCount
  2219. indexType:SDLToMetal_IndexType[metalCommandBuffer->indexElementSize]
  2220. indexBuffer:metalCommandBuffer->indexBuffer->handle
  2221. indexBufferOffset:metalCommandBuffer->indexBufferOffset + (firstIndex * indexSize)
  2222. instanceCount:instanceCount
  2223. baseVertex:vertexOffset
  2224. baseInstance:firstInstance];
  2225. }
  2226. }
  2227. static void METAL_DrawPrimitives(
  2228. SDL_GPUCommandBuffer *commandBuffer,
  2229. Uint32 vertexCount,
  2230. Uint32 instanceCount,
  2231. Uint32 firstVertex,
  2232. Uint32 firstInstance)
  2233. {
  2234. @autoreleasepool {
  2235. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2236. SDL_GPUPrimitiveType primitiveType = metalCommandBuffer->graphicsPipeline->primitiveType;
  2237. METAL_INTERNAL_BindGraphicsResources(metalCommandBuffer);
  2238. [metalCommandBuffer->renderEncoder
  2239. drawPrimitives:SDLToMetal_PrimitiveType[primitiveType]
  2240. vertexStart:firstVertex
  2241. vertexCount:vertexCount
  2242. instanceCount:instanceCount
  2243. baseInstance:firstInstance];
  2244. }
  2245. }
  2246. static void METAL_DrawPrimitivesIndirect(
  2247. SDL_GPUCommandBuffer *commandBuffer,
  2248. SDL_GPUBuffer *buffer,
  2249. Uint32 offsetInBytes,
  2250. Uint32 drawCount,
  2251. Uint32 stride)
  2252. {
  2253. @autoreleasepool {
  2254. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2255. MetalBuffer *metalBuffer = ((MetalBufferContainer *)buffer)->activeBuffer;
  2256. SDL_GPUPrimitiveType primitiveType = metalCommandBuffer->graphicsPipeline->primitiveType;
  2257. METAL_INTERNAL_BindGraphicsResources(metalCommandBuffer);
  2258. /* Metal: "We have multi-draw at home!"
  2259. * Multi-draw at home:
  2260. */
  2261. for (Uint32 i = 0; i < drawCount; i += 1) {
  2262. [metalCommandBuffer->renderEncoder
  2263. drawPrimitives:SDLToMetal_PrimitiveType[primitiveType]
  2264. indirectBuffer:metalBuffer->handle
  2265. indirectBufferOffset:offsetInBytes + (stride * i)];
  2266. }
  2267. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, metalBuffer);
  2268. }
  2269. }
  2270. static void METAL_DrawIndexedPrimitivesIndirect(
  2271. SDL_GPUCommandBuffer *commandBuffer,
  2272. SDL_GPUBuffer *buffer,
  2273. Uint32 offsetInBytes,
  2274. Uint32 drawCount,
  2275. Uint32 stride)
  2276. {
  2277. @autoreleasepool {
  2278. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2279. MetalBuffer *metalBuffer = ((MetalBufferContainer *)buffer)->activeBuffer;
  2280. SDL_GPUPrimitiveType primitiveType = metalCommandBuffer->graphicsPipeline->primitiveType;
  2281. METAL_INTERNAL_BindGraphicsResources(metalCommandBuffer);
  2282. for (Uint32 i = 0; i < drawCount; i += 1) {
  2283. [metalCommandBuffer->renderEncoder
  2284. drawIndexedPrimitives:SDLToMetal_PrimitiveType[primitiveType]
  2285. indexType:SDLToMetal_IndexType[metalCommandBuffer->indexElementSize]
  2286. indexBuffer:metalCommandBuffer->indexBuffer->handle
  2287. indexBufferOffset:metalCommandBuffer->indexBufferOffset
  2288. indirectBuffer:metalBuffer->handle
  2289. indirectBufferOffset:offsetInBytes + (stride * i)];
  2290. }
  2291. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, metalBuffer);
  2292. }
  2293. }
  2294. static void METAL_EndRenderPass(
  2295. SDL_GPUCommandBuffer *commandBuffer)
  2296. {
  2297. @autoreleasepool {
  2298. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2299. [metalCommandBuffer->renderEncoder endEncoding];
  2300. metalCommandBuffer->renderEncoder = nil;
  2301. for (Uint32 i = 0; i < MAX_TEXTURE_SAMPLERS_PER_STAGE; i += 1) {
  2302. metalCommandBuffer->vertexSamplers[i] = nil;
  2303. metalCommandBuffer->vertexTextures[i] = nil;
  2304. metalCommandBuffer->fragmentSamplers[i] = nil;
  2305. metalCommandBuffer->fragmentTextures[i] = nil;
  2306. }
  2307. for (Uint32 i = 0; i < MAX_STORAGE_TEXTURES_PER_STAGE; i += 1) {
  2308. metalCommandBuffer->vertexStorageTextures[i] = nil;
  2309. metalCommandBuffer->fragmentStorageTextures[i] = nil;
  2310. }
  2311. for (Uint32 i = 0; i < MAX_STORAGE_BUFFERS_PER_STAGE; i += 1) {
  2312. metalCommandBuffer->vertexStorageBuffers[i] = nil;
  2313. metalCommandBuffer->fragmentStorageBuffers[i] = nil;
  2314. }
  2315. }
  2316. }
  2317. // This function assumes that it's called from within an autorelease pool
  2318. static void METAL_INTERNAL_PushUniformData(
  2319. MetalCommandBuffer *metalCommandBuffer,
  2320. SDL_GPUShaderStage shaderStage,
  2321. Uint32 slotIndex,
  2322. const void *data,
  2323. Uint32 dataLengthInBytes)
  2324. {
  2325. MetalUniformBuffer *metalUniformBuffer;
  2326. Uint32 alignedDataLength;
  2327. if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) {
  2328. if (metalCommandBuffer->vertexUniformBuffers[slotIndex] == NULL) {
  2329. metalCommandBuffer->vertexUniformBuffers[slotIndex] = METAL_INTERNAL_AcquireUniformBufferFromPool(
  2330. metalCommandBuffer);
  2331. }
  2332. metalUniformBuffer = metalCommandBuffer->vertexUniformBuffers[slotIndex];
  2333. } else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) {
  2334. if (metalCommandBuffer->fragmentUniformBuffers[slotIndex] == NULL) {
  2335. metalCommandBuffer->fragmentUniformBuffers[slotIndex] = METAL_INTERNAL_AcquireUniformBufferFromPool(
  2336. metalCommandBuffer);
  2337. }
  2338. metalUniformBuffer = metalCommandBuffer->fragmentUniformBuffers[slotIndex];
  2339. } else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) {
  2340. if (metalCommandBuffer->computeUniformBuffers[slotIndex] == NULL) {
  2341. metalCommandBuffer->computeUniformBuffers[slotIndex] = METAL_INTERNAL_AcquireUniformBufferFromPool(
  2342. metalCommandBuffer);
  2343. }
  2344. metalUniformBuffer = metalCommandBuffer->computeUniformBuffers[slotIndex];
  2345. } else {
  2346. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!");
  2347. return;
  2348. }
  2349. alignedDataLength = METAL_INTERNAL_NextHighestAlignment(
  2350. dataLengthInBytes,
  2351. 256);
  2352. if (metalUniformBuffer->writeOffset + alignedDataLength >= UNIFORM_BUFFER_SIZE) {
  2353. metalUniformBuffer = METAL_INTERNAL_AcquireUniformBufferFromPool(
  2354. metalCommandBuffer);
  2355. metalUniformBuffer->writeOffset = 0;
  2356. metalUniformBuffer->drawOffset = 0;
  2357. if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) {
  2358. metalCommandBuffer->vertexUniformBuffers[slotIndex] = metalUniformBuffer;
  2359. } else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) {
  2360. metalCommandBuffer->fragmentUniformBuffers[slotIndex] = metalUniformBuffer;
  2361. } else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) {
  2362. metalCommandBuffer->computeUniformBuffers[slotIndex] = metalUniformBuffer;
  2363. } else {
  2364. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!");
  2365. return;
  2366. }
  2367. }
  2368. metalUniformBuffer->drawOffset = metalUniformBuffer->writeOffset;
  2369. SDL_memcpy(
  2370. (metalUniformBuffer->handle).contents + metalUniformBuffer->writeOffset,
  2371. data,
  2372. dataLengthInBytes);
  2373. metalUniformBuffer->writeOffset += alignedDataLength;
  2374. if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) {
  2375. metalCommandBuffer->needVertexUniformBind = true;
  2376. } else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) {
  2377. metalCommandBuffer->needFragmentUniformBind = true;
  2378. } else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) {
  2379. metalCommandBuffer->needComputeUniformBind = true;
  2380. } else {
  2381. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!");
  2382. }
  2383. }
  2384. static void METAL_PushVertexUniformData(
  2385. SDL_GPUCommandBuffer *commandBuffer,
  2386. Uint32 slotIndex,
  2387. const void *data,
  2388. Uint32 dataLengthInBytes)
  2389. {
  2390. @autoreleasepool {
  2391. METAL_INTERNAL_PushUniformData(
  2392. (MetalCommandBuffer *)commandBuffer,
  2393. SDL_GPU_SHADERSTAGE_VERTEX,
  2394. slotIndex,
  2395. data,
  2396. dataLengthInBytes);
  2397. }
  2398. }
  2399. static void METAL_PushFragmentUniformData(
  2400. SDL_GPUCommandBuffer *commandBuffer,
  2401. Uint32 slotIndex,
  2402. const void *data,
  2403. Uint32 dataLengthInBytes)
  2404. {
  2405. @autoreleasepool {
  2406. METAL_INTERNAL_PushUniformData(
  2407. (MetalCommandBuffer *)commandBuffer,
  2408. SDL_GPU_SHADERSTAGE_FRAGMENT,
  2409. slotIndex,
  2410. data,
  2411. dataLengthInBytes);
  2412. }
  2413. }
  2414. // Blit
  2415. static void METAL_Blit(
  2416. SDL_GPUCommandBuffer *commandBuffer,
  2417. SDL_GPUBlitRegion *source,
  2418. SDL_GPUBlitRegion *destination,
  2419. SDL_FlipMode flipMode,
  2420. SDL_GPUFilter filterMode,
  2421. bool cycle)
  2422. {
  2423. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2424. MetalRenderer *renderer = (MetalRenderer *)metalCommandBuffer->renderer;
  2425. SDL_GPU_BlitCommon(
  2426. commandBuffer,
  2427. source,
  2428. destination,
  2429. flipMode,
  2430. filterMode,
  2431. cycle,
  2432. renderer->blitLinearSampler,
  2433. renderer->blitNearestSampler,
  2434. renderer->blitVertexShader,
  2435. renderer->blitFrom2DShader,
  2436. renderer->blitFrom2DArrayShader,
  2437. renderer->blitFrom3DShader,
  2438. renderer->blitFromCubeShader,
  2439. &renderer->blitPipelines,
  2440. &renderer->blitPipelineCount,
  2441. &renderer->blitPipelineCapacity);
  2442. }
  2443. // Compute State
  2444. static void METAL_BeginComputePass(
  2445. SDL_GPUCommandBuffer *commandBuffer,
  2446. SDL_GPUStorageTextureWriteOnlyBinding *storageTextureBindings,
  2447. Uint32 storageTextureBindingCount,
  2448. SDL_GPUStorageBufferWriteOnlyBinding *storageBufferBindings,
  2449. Uint32 storageBufferBindingCount)
  2450. {
  2451. @autoreleasepool {
  2452. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2453. MetalTextureContainer *textureContainer;
  2454. MetalTexture *texture;
  2455. id<MTLTexture> textureView;
  2456. MetalBufferContainer *bufferContainer;
  2457. MetalBuffer *buffer;
  2458. metalCommandBuffer->computeEncoder = [metalCommandBuffer->handle computeCommandEncoder];
  2459. for (Uint32 i = 0; i < storageTextureBindingCount; i += 1) {
  2460. textureContainer = (MetalTextureContainer *)storageTextureBindings[i].texture;
  2461. texture = METAL_INTERNAL_PrepareTextureForWrite(
  2462. metalCommandBuffer->renderer,
  2463. textureContainer,
  2464. storageTextureBindings[i].cycle);
  2465. METAL_INTERNAL_TrackTexture(metalCommandBuffer, texture);
  2466. textureView = [texture->handle newTextureViewWithPixelFormat:SDLToMetal_SurfaceFormat[textureContainer->header.info.format]
  2467. textureType:SDLToMetal_TextureType[textureContainer->header.info.type]
  2468. levels:NSMakeRange(storageTextureBindings[i].mipLevel, 1)
  2469. slices:NSMakeRange(storageTextureBindings[i].layer, 1)];
  2470. metalCommandBuffer->computeWriteOnlyTextures[i] = textureView;
  2471. metalCommandBuffer->needComputeTextureBind = true;
  2472. }
  2473. for (Uint32 i = 0; i < storageBufferBindingCount; i += 1) {
  2474. bufferContainer = (MetalBufferContainer *)storageBufferBindings[i].buffer;
  2475. buffer = METAL_INTERNAL_PrepareBufferForWrite(
  2476. metalCommandBuffer->renderer,
  2477. bufferContainer,
  2478. storageBufferBindings[i].cycle);
  2479. METAL_INTERNAL_TrackBuffer(
  2480. metalCommandBuffer,
  2481. buffer);
  2482. metalCommandBuffer->computeWriteOnlyBuffers[i] = buffer->handle;
  2483. metalCommandBuffer->needComputeBufferBind = true;
  2484. }
  2485. }
  2486. }
  2487. static void METAL_BindComputePipeline(
  2488. SDL_GPUCommandBuffer *commandBuffer,
  2489. SDL_GPUComputePipeline *computePipeline)
  2490. {
  2491. @autoreleasepool {
  2492. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2493. MetalComputePipeline *pipeline = (MetalComputePipeline *)computePipeline;
  2494. metalCommandBuffer->computePipeline = pipeline;
  2495. [metalCommandBuffer->computeEncoder setComputePipelineState:pipeline->handle];
  2496. for (Uint32 i = 0; i < pipeline->uniformBufferCount; i += 1) {
  2497. if (metalCommandBuffer->computeUniformBuffers[i] == NULL) {
  2498. metalCommandBuffer->computeUniformBuffers[i] = METAL_INTERNAL_AcquireUniformBufferFromPool(
  2499. metalCommandBuffer);
  2500. }
  2501. }
  2502. metalCommandBuffer->needComputeUniformBind = true;
  2503. }
  2504. }
  2505. static void METAL_BindComputeStorageTextures(
  2506. SDL_GPUCommandBuffer *commandBuffer,
  2507. Uint32 firstSlot,
  2508. SDL_GPUTexture **storageTextures,
  2509. Uint32 bindingCount)
  2510. {
  2511. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2512. MetalTextureContainer *textureContainer;
  2513. for (Uint32 i = 0; i < bindingCount; i += 1) {
  2514. textureContainer = (MetalTextureContainer *)storageTextures[i];
  2515. METAL_INTERNAL_TrackTexture(
  2516. metalCommandBuffer,
  2517. textureContainer->activeTexture);
  2518. metalCommandBuffer->computeReadOnlyTextures[firstSlot + i] =
  2519. textureContainer->activeTexture->handle;
  2520. }
  2521. metalCommandBuffer->needComputeTextureBind = true;
  2522. }
  2523. static void METAL_BindComputeStorageBuffers(
  2524. SDL_GPUCommandBuffer *commandBuffer,
  2525. Uint32 firstSlot,
  2526. SDL_GPUBuffer **storageBuffers,
  2527. Uint32 bindingCount)
  2528. {
  2529. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2530. MetalBufferContainer *bufferContainer;
  2531. for (Uint32 i = 0; i < bindingCount; i += 1) {
  2532. bufferContainer = (MetalBufferContainer *)storageBuffers[i];
  2533. METAL_INTERNAL_TrackBuffer(
  2534. metalCommandBuffer,
  2535. bufferContainer->activeBuffer);
  2536. metalCommandBuffer->computeReadOnlyBuffers[firstSlot + i] =
  2537. bufferContainer->activeBuffer->handle;
  2538. }
  2539. metalCommandBuffer->needComputeBufferBind = true;
  2540. }
  2541. static void METAL_PushComputeUniformData(
  2542. SDL_GPUCommandBuffer *commandBuffer,
  2543. Uint32 slotIndex,
  2544. const void *data,
  2545. Uint32 dataLengthInBytes)
  2546. {
  2547. @autoreleasepool {
  2548. METAL_INTERNAL_PushUniformData(
  2549. (MetalCommandBuffer *)commandBuffer,
  2550. SDL_GPU_SHADERSTAGE_COMPUTE,
  2551. slotIndex,
  2552. data,
  2553. dataLengthInBytes);
  2554. }
  2555. }
  2556. static void METAL_DispatchCompute(
  2557. SDL_GPUCommandBuffer *commandBuffer,
  2558. Uint32 groupCountX,
  2559. Uint32 groupCountY,
  2560. Uint32 groupCountZ)
  2561. {
  2562. @autoreleasepool {
  2563. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2564. MTLSize threadgroups = MTLSizeMake(groupCountX, groupCountY, groupCountZ);
  2565. MTLSize threadsPerThreadgroup = MTLSizeMake(
  2566. metalCommandBuffer->computePipeline->threadCountX,
  2567. metalCommandBuffer->computePipeline->threadCountY,
  2568. metalCommandBuffer->computePipeline->threadCountZ);
  2569. METAL_INTERNAL_BindComputeResources(metalCommandBuffer);
  2570. [metalCommandBuffer->computeEncoder
  2571. dispatchThreadgroups:threadgroups
  2572. threadsPerThreadgroup:threadsPerThreadgroup];
  2573. }
  2574. }
  2575. static void METAL_DispatchComputeIndirect(
  2576. SDL_GPUCommandBuffer *commandBuffer,
  2577. SDL_GPUBuffer *buffer,
  2578. Uint32 offsetInBytes)
  2579. {
  2580. @autoreleasepool {
  2581. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2582. MetalBuffer *metalBuffer = ((MetalBufferContainer *)buffer)->activeBuffer;
  2583. MTLSize threadsPerThreadgroup = MTLSizeMake(
  2584. metalCommandBuffer->computePipeline->threadCountX,
  2585. metalCommandBuffer->computePipeline->threadCountY,
  2586. metalCommandBuffer->computePipeline->threadCountZ);
  2587. METAL_INTERNAL_BindComputeResources(metalCommandBuffer);
  2588. [metalCommandBuffer->computeEncoder
  2589. dispatchThreadgroupsWithIndirectBuffer:metalBuffer->handle
  2590. indirectBufferOffset:offsetInBytes
  2591. threadsPerThreadgroup:threadsPerThreadgroup];
  2592. METAL_INTERNAL_TrackBuffer(metalCommandBuffer, metalBuffer);
  2593. }
  2594. }
  2595. static void METAL_EndComputePass(
  2596. SDL_GPUCommandBuffer *commandBuffer)
  2597. {
  2598. @autoreleasepool {
  2599. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2600. [metalCommandBuffer->computeEncoder endEncoding];
  2601. metalCommandBuffer->computeEncoder = nil;
  2602. for (Uint32 i = 0; i < MAX_COMPUTE_WRITE_TEXTURES; i += 1) {
  2603. metalCommandBuffer->computeWriteOnlyTextures[i] = nil;
  2604. }
  2605. for (Uint32 i = 0; i < MAX_COMPUTE_WRITE_BUFFERS; i += 1) {
  2606. metalCommandBuffer->computeWriteOnlyBuffers[i] = nil;
  2607. }
  2608. for (Uint32 i = 0; i < MAX_STORAGE_TEXTURES_PER_STAGE; i += 1) {
  2609. metalCommandBuffer->computeReadOnlyTextures[i] = nil;
  2610. }
  2611. for (Uint32 i = 0; i < MAX_STORAGE_BUFFERS_PER_STAGE; i += 1) {
  2612. metalCommandBuffer->computeReadOnlyBuffers[i] = nil;
  2613. }
  2614. }
  2615. }
  2616. // Fence Cleanup
  2617. static void METAL_INTERNAL_ReleaseFenceToPool(
  2618. MetalRenderer *renderer,
  2619. MetalFence *fence)
  2620. {
  2621. SDL_LockMutex(renderer->fenceLock);
  2622. // FIXME: Should this use EXPAND_IF_NEEDED?
  2623. if (renderer->availableFenceCount == renderer->availableFenceCapacity) {
  2624. renderer->availableFenceCapacity *= 2;
  2625. renderer->availableFences = SDL_realloc(
  2626. renderer->availableFences,
  2627. renderer->availableFenceCapacity * sizeof(MetalFence *));
  2628. }
  2629. renderer->availableFences[renderer->availableFenceCount] = fence;
  2630. renderer->availableFenceCount += 1;
  2631. SDL_UnlockMutex(renderer->fenceLock);
  2632. }
  2633. static void METAL_ReleaseFence(
  2634. SDL_GPURenderer *driverData,
  2635. SDL_GPUFence *fence)
  2636. {
  2637. METAL_INTERNAL_ReleaseFenceToPool(
  2638. (MetalRenderer *)driverData,
  2639. (MetalFence *)fence);
  2640. }
  2641. // Cleanup
  2642. static void METAL_INTERNAL_CleanCommandBuffer(
  2643. MetalRenderer *renderer,
  2644. MetalCommandBuffer *commandBuffer)
  2645. {
  2646. Uint32 i;
  2647. // Reference Counting
  2648. for (i = 0; i < commandBuffer->usedBufferCount; i += 1) {
  2649. (void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->referenceCount);
  2650. }
  2651. commandBuffer->usedBufferCount = 0;
  2652. for (i = 0; i < commandBuffer->usedTextureCount; i += 1) {
  2653. (void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->referenceCount);
  2654. }
  2655. commandBuffer->usedTextureCount = 0;
  2656. // Uniform buffers are now available
  2657. SDL_LockMutex(renderer->acquireUniformBufferLock);
  2658. for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) {
  2659. METAL_INTERNAL_ReturnUniformBufferToPool(
  2660. renderer,
  2661. commandBuffer->usedUniformBuffers[i]);
  2662. }
  2663. commandBuffer->usedUniformBufferCount = 0;
  2664. SDL_UnlockMutex(renderer->acquireUniformBufferLock);
  2665. // Reset presentation
  2666. commandBuffer->windowDataCount = 0;
  2667. // Reset bindings
  2668. commandBuffer->indexBuffer = NULL;
  2669. for (i = 0; i < MAX_TEXTURE_SAMPLERS_PER_STAGE; i += 1) {
  2670. commandBuffer->vertexSamplers[i] = nil;
  2671. commandBuffer->vertexTextures[i] = nil;
  2672. commandBuffer->fragmentSamplers[i] = nil;
  2673. commandBuffer->fragmentTextures[i] = nil;
  2674. }
  2675. for (i = 0; i < MAX_STORAGE_TEXTURES_PER_STAGE; i += 1) {
  2676. commandBuffer->vertexStorageTextures[i] = nil;
  2677. commandBuffer->fragmentStorageTextures[i] = nil;
  2678. commandBuffer->computeReadOnlyTextures[i] = nil;
  2679. }
  2680. for (i = 0; i < MAX_STORAGE_BUFFERS_PER_STAGE; i += 1) {
  2681. commandBuffer->vertexStorageBuffers[i] = nil;
  2682. commandBuffer->fragmentStorageBuffers[i] = nil;
  2683. commandBuffer->computeReadOnlyBuffers[i] = nil;
  2684. }
  2685. for (i = 0; i < MAX_COMPUTE_WRITE_TEXTURES; i += 1) {
  2686. commandBuffer->computeWriteOnlyTextures[i] = nil;
  2687. }
  2688. for (i = 0; i < MAX_COMPUTE_WRITE_BUFFERS; i += 1) {
  2689. commandBuffer->computeWriteOnlyBuffers[i] = nil;
  2690. }
  2691. // The fence is now available (unless SubmitAndAcquireFence was called)
  2692. if (commandBuffer->autoReleaseFence) {
  2693. METAL_ReleaseFence(
  2694. (SDL_GPURenderer *)renderer,
  2695. (SDL_GPUFence *)commandBuffer->fence);
  2696. }
  2697. // Return command buffer to pool
  2698. SDL_LockMutex(renderer->acquireCommandBufferLock);
  2699. // FIXME: Should this use EXPAND_IF_NEEDED?
  2700. if (renderer->availableCommandBufferCount == renderer->availableCommandBufferCapacity) {
  2701. renderer->availableCommandBufferCapacity += 1;
  2702. renderer->availableCommandBuffers = SDL_realloc(
  2703. renderer->availableCommandBuffers,
  2704. renderer->availableCommandBufferCapacity * sizeof(MetalCommandBuffer *));
  2705. }
  2706. renderer->availableCommandBuffers[renderer->availableCommandBufferCount] = commandBuffer;
  2707. renderer->availableCommandBufferCount += 1;
  2708. SDL_UnlockMutex(renderer->acquireCommandBufferLock);
  2709. // Remove this command buffer from the submitted list
  2710. for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
  2711. if (renderer->submittedCommandBuffers[i] == commandBuffer) {
  2712. renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1];
  2713. renderer->submittedCommandBufferCount -= 1;
  2714. }
  2715. }
  2716. }
  2717. // This function assumes that it's called from within an autorelease pool
  2718. static void METAL_INTERNAL_PerformPendingDestroys(
  2719. MetalRenderer *renderer)
  2720. {
  2721. Sint32 referenceCount = 0;
  2722. Sint32 i;
  2723. Uint32 j;
  2724. for (i = renderer->bufferContainersToDestroyCount - 1; i >= 0; i -= 1) {
  2725. referenceCount = 0;
  2726. for (j = 0; j < renderer->bufferContainersToDestroy[i]->bufferCount; j += 1) {
  2727. referenceCount += SDL_AtomicGet(&renderer->bufferContainersToDestroy[i]->buffers[j]->referenceCount);
  2728. }
  2729. if (referenceCount == 0) {
  2730. METAL_INTERNAL_DestroyBufferContainer(
  2731. renderer->bufferContainersToDestroy[i]);
  2732. renderer->bufferContainersToDestroy[i] = renderer->bufferContainersToDestroy[renderer->bufferContainersToDestroyCount - 1];
  2733. renderer->bufferContainersToDestroyCount -= 1;
  2734. }
  2735. }
  2736. for (i = renderer->textureContainersToDestroyCount - 1; i >= 0; i -= 1) {
  2737. referenceCount = 0;
  2738. for (j = 0; j < renderer->textureContainersToDestroy[i]->textureCount; j += 1) {
  2739. referenceCount += SDL_AtomicGet(&renderer->textureContainersToDestroy[i]->textures[j]->referenceCount);
  2740. }
  2741. if (referenceCount == 0) {
  2742. METAL_INTERNAL_DestroyTextureContainer(
  2743. renderer->textureContainersToDestroy[i]);
  2744. renderer->textureContainersToDestroy[i] = renderer->textureContainersToDestroy[renderer->textureContainersToDestroyCount - 1];
  2745. renderer->textureContainersToDestroyCount -= 1;
  2746. }
  2747. }
  2748. }
  2749. // Fences
  2750. static void METAL_WaitForFences(
  2751. SDL_GPURenderer *driverData,
  2752. bool waitAll,
  2753. SDL_GPUFence **pFences,
  2754. Uint32 fenceCount)
  2755. {
  2756. @autoreleasepool {
  2757. MetalRenderer *renderer = (MetalRenderer *)driverData;
  2758. bool waiting;
  2759. if (waitAll) {
  2760. for (Uint32 i = 0; i < fenceCount; i += 1) {
  2761. while (!SDL_AtomicGet(&((MetalFence *)pFences[i])->complete)) {
  2762. // Spin!
  2763. }
  2764. }
  2765. } else {
  2766. waiting = 1;
  2767. while (waiting) {
  2768. for (Uint32 i = 0; i < fenceCount; i += 1) {
  2769. if (SDL_AtomicGet(&((MetalFence *)pFences[i])->complete) > 0) {
  2770. waiting = 0;
  2771. break;
  2772. }
  2773. }
  2774. }
  2775. }
  2776. METAL_INTERNAL_PerformPendingDestroys(renderer);
  2777. }
  2778. }
  2779. static bool METAL_QueryFence(
  2780. SDL_GPURenderer *driverData,
  2781. SDL_GPUFence *fence)
  2782. {
  2783. MetalFence *metalFence = (MetalFence *)fence;
  2784. return SDL_AtomicGet(&metalFence->complete) == 1;
  2785. }
  2786. // Window and Swapchain Management
  2787. static MetalWindowData *METAL_INTERNAL_FetchWindowData(SDL_Window *window)
  2788. {
  2789. SDL_PropertiesID properties = SDL_GetWindowProperties(window);
  2790. return (MetalWindowData *)SDL_GetPointerProperty(properties, WINDOW_PROPERTY_DATA, NULL);
  2791. }
  2792. static bool METAL_SupportsSwapchainComposition(
  2793. SDL_GPURenderer *driverData,
  2794. SDL_Window *window,
  2795. SDL_GPUSwapchainComposition swapchainComposition)
  2796. {
  2797. #ifndef SDL_PLATFORM_MACOS
  2798. if (swapchainComposition == SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2048) {
  2799. return false;
  2800. }
  2801. #endif
  2802. if (@available(macOS 11.0, *)) {
  2803. return true;
  2804. } else {
  2805. return swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2048;
  2806. }
  2807. }
  2808. // This function assumes that it's called from within an autorelease pool
  2809. static Uint8 METAL_INTERNAL_CreateSwapchain(
  2810. MetalRenderer *renderer,
  2811. MetalWindowData *windowData,
  2812. SDL_GPUSwapchainComposition swapchainComposition,
  2813. SDL_GPUPresentMode presentMode)
  2814. {
  2815. CGColorSpaceRef colorspace;
  2816. CGSize drawableSize;
  2817. windowData->view = SDL_Metal_CreateView(windowData->window);
  2818. windowData->drawable = nil;
  2819. windowData->layer = (__bridge CAMetalLayer *)(SDL_Metal_GetLayer(windowData->view));
  2820. windowData->layer.device = renderer->device;
  2821. #ifdef SDL_PLATFORM_MACOS
  2822. windowData->layer.displaySyncEnabled = (presentMode != SDL_GPU_PRESENTMODE_IMMEDIATE);
  2823. #endif
  2824. windowData->layer.pixelFormat = SDLToMetal_SurfaceFormat[SwapchainCompositionToFormat[swapchainComposition]];
  2825. #ifndef SDL_PLATFORM_TVOS
  2826. windowData->layer.wantsExtendedDynamicRangeContent = (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR);
  2827. #endif
  2828. colorspace = CGColorSpaceCreateWithName(SwapchainCompositionToColorSpace[swapchainComposition]);
  2829. windowData->layer.colorspace = colorspace;
  2830. CGColorSpaceRelease(colorspace);
  2831. windowData->texture.handle = nil; // This will be set in AcquireSwapchainTexture.
  2832. // Precache blit pipelines for the swapchain format
  2833. for (Uint32 i = 0; i < 4; i += 1) {
  2834. SDL_GPU_FetchBlitPipeline(
  2835. renderer->sdlGPUDevice,
  2836. (SDL_GPUTextureType)i,
  2837. SwapchainCompositionToFormat[swapchainComposition],
  2838. renderer->blitVertexShader,
  2839. renderer->blitFrom2DShader,
  2840. renderer->blitFrom2DArrayShader,
  2841. renderer->blitFrom3DShader,
  2842. renderer->blitFromCubeShader,
  2843. &renderer->blitPipelines,
  2844. &renderer->blitPipelineCount,
  2845. &renderer->blitPipelineCapacity);
  2846. }
  2847. // Set up the texture container
  2848. SDL_zero(windowData->textureContainer);
  2849. windowData->textureContainer.canBeCycled = 0;
  2850. windowData->textureContainer.activeTexture = &windowData->texture;
  2851. windowData->textureContainer.textureCapacity = 1;
  2852. windowData->textureContainer.textureCount = 1;
  2853. windowData->textureContainer.header.info.format = SwapchainCompositionToFormat[swapchainComposition];
  2854. windowData->textureContainer.header.info.levelCount = 1;
  2855. windowData->textureContainer.header.info.layerCountOrDepth = 1;
  2856. windowData->textureContainer.header.info.type = SDL_GPU_TEXTURETYPE_2D;
  2857. windowData->textureContainer.header.info.usageFlags = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT;
  2858. drawableSize = windowData->layer.drawableSize;
  2859. windowData->textureContainer.header.info.width = (Uint32)drawableSize.width;
  2860. windowData->textureContainer.header.info.height = (Uint32)drawableSize.height;
  2861. return 1;
  2862. }
  2863. static bool METAL_SupportsPresentMode(
  2864. SDL_GPURenderer *driverData,
  2865. SDL_Window *window,
  2866. SDL_GPUPresentMode presentMode)
  2867. {
  2868. switch (presentMode) {
  2869. #ifdef SDL_PLATFORM_MACOS
  2870. case SDL_GPU_PRESENTMODE_IMMEDIATE:
  2871. #endif
  2872. case SDL_GPU_PRESENTMODE_VSYNC:
  2873. return true;
  2874. default:
  2875. return false;
  2876. }
  2877. }
  2878. static bool METAL_ClaimWindow(
  2879. SDL_GPURenderer *driverData,
  2880. SDL_Window *window)
  2881. {
  2882. @autoreleasepool {
  2883. MetalRenderer *renderer = (MetalRenderer *)driverData;
  2884. MetalWindowData *windowData = METAL_INTERNAL_FetchWindowData(window);
  2885. if (windowData == NULL) {
  2886. windowData = (MetalWindowData *)SDL_malloc(sizeof(MetalWindowData));
  2887. windowData->window = window;
  2888. if (METAL_INTERNAL_CreateSwapchain(renderer, windowData, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_VSYNC)) {
  2889. SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData);
  2890. SDL_LockMutex(renderer->windowLock);
  2891. if (renderer->claimedWindowCount >= renderer->claimedWindowCapacity) {
  2892. renderer->claimedWindowCapacity *= 2;
  2893. renderer->claimedWindows = SDL_realloc(
  2894. renderer->claimedWindows,
  2895. renderer->claimedWindowCapacity * sizeof(MetalWindowData *));
  2896. }
  2897. renderer->claimedWindows[renderer->claimedWindowCount] = windowData;
  2898. renderer->claimedWindowCount += 1;
  2899. SDL_UnlockMutex(renderer->windowLock);
  2900. return true;
  2901. } else {
  2902. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create swapchain, failed to claim window!");
  2903. SDL_free(windowData);
  2904. return false;
  2905. }
  2906. } else {
  2907. SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Window already claimed!");
  2908. return false;
  2909. }
  2910. }
  2911. }
  2912. static void METAL_ReleaseWindow(
  2913. SDL_GPURenderer *driverData,
  2914. SDL_Window *window)
  2915. {
  2916. @autoreleasepool {
  2917. MetalRenderer *renderer = (MetalRenderer *)driverData;
  2918. MetalWindowData *windowData = METAL_INTERNAL_FetchWindowData(window);
  2919. if (windowData == NULL) {
  2920. return;
  2921. }
  2922. METAL_Wait(driverData);
  2923. SDL_Metal_DestroyView(windowData->view);
  2924. SDL_LockMutex(renderer->windowLock);
  2925. for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) {
  2926. if (renderer->claimedWindows[i]->window == window) {
  2927. renderer->claimedWindows[i] = renderer->claimedWindows[renderer->claimedWindowCount - 1];
  2928. renderer->claimedWindowCount -= 1;
  2929. break;
  2930. }
  2931. }
  2932. SDL_UnlockMutex(renderer->windowLock);
  2933. SDL_free(windowData);
  2934. SDL_ClearProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA);
  2935. }
  2936. }
  2937. static SDL_GPUTexture *METAL_AcquireSwapchainTexture(
  2938. SDL_GPUCommandBuffer *commandBuffer,
  2939. SDL_Window *window,
  2940. Uint32 *pWidth,
  2941. Uint32 *pHeight)
  2942. {
  2943. @autoreleasepool {
  2944. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  2945. MetalWindowData *windowData;
  2946. CGSize drawableSize;
  2947. windowData = METAL_INTERNAL_FetchWindowData(window);
  2948. if (windowData == NULL) {
  2949. return NULL;
  2950. }
  2951. // Get the drawable and its underlying texture
  2952. windowData->drawable = [windowData->layer nextDrawable];
  2953. windowData->texture.handle = [windowData->drawable texture];
  2954. // Update the window size
  2955. drawableSize = windowData->layer.drawableSize;
  2956. windowData->textureContainer.header.info.width = (Uint32)drawableSize.width;
  2957. windowData->textureContainer.header.info.height = (Uint32)drawableSize.height;
  2958. // Send the dimensions to the out parameters.
  2959. *pWidth = (Uint32)drawableSize.width;
  2960. *pHeight = (Uint32)drawableSize.height;
  2961. // Set up presentation
  2962. if (metalCommandBuffer->windowDataCount == metalCommandBuffer->windowDataCapacity) {
  2963. metalCommandBuffer->windowDataCapacity += 1;
  2964. metalCommandBuffer->windowDatas = SDL_realloc(
  2965. metalCommandBuffer->windowDatas,
  2966. metalCommandBuffer->windowDataCapacity * sizeof(MetalWindowData *));
  2967. }
  2968. metalCommandBuffer->windowDatas[metalCommandBuffer->windowDataCount] = windowData;
  2969. metalCommandBuffer->windowDataCount += 1;
  2970. // Return the swapchain texture
  2971. return (SDL_GPUTexture *)&windowData->textureContainer;
  2972. }
  2973. }
  2974. static SDL_GPUTextureFormat METAL_GetSwapchainTextureFormat(
  2975. SDL_GPURenderer *driverData,
  2976. SDL_Window *window)
  2977. {
  2978. MetalWindowData *windowData = METAL_INTERNAL_FetchWindowData(window);
  2979. if (windowData == NULL) {
  2980. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot get swapchain format, window has not been claimed!");
  2981. return 0;
  2982. }
  2983. return windowData->textureContainer.header.info.format;
  2984. }
  2985. static bool METAL_SetSwapchainParameters(
  2986. SDL_GPURenderer *driverData,
  2987. SDL_Window *window,
  2988. SDL_GPUSwapchainComposition swapchainComposition,
  2989. SDL_GPUPresentMode presentMode)
  2990. {
  2991. @autoreleasepool {
  2992. MetalWindowData *windowData = METAL_INTERNAL_FetchWindowData(window);
  2993. CGColorSpaceRef colorspace;
  2994. if (windowData == NULL) {
  2995. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot set swapchain parameters, window has not been claimed!");
  2996. return false;
  2997. }
  2998. if (!METAL_SupportsSwapchainComposition(driverData, window, swapchainComposition)) {
  2999. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Swapchain composition not supported!");
  3000. return false;
  3001. }
  3002. if (!METAL_SupportsPresentMode(driverData, window, presentMode)) {
  3003. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Present mode not supported!");
  3004. return false;
  3005. }
  3006. METAL_Wait(driverData);
  3007. #ifdef SDL_PLATFORM_MACOS
  3008. windowData->layer.displaySyncEnabled = (presentMode != SDL_GPU_PRESENTMODE_IMMEDIATE);
  3009. #endif
  3010. windowData->layer.pixelFormat = SDLToMetal_SurfaceFormat[SwapchainCompositionToFormat[swapchainComposition]];
  3011. #ifndef SDL_PLATFORM_TVOS
  3012. windowData->layer.wantsExtendedDynamicRangeContent = (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR);
  3013. #endif
  3014. colorspace = CGColorSpaceCreateWithName(SwapchainCompositionToColorSpace[swapchainComposition]);
  3015. windowData->layer.colorspace = colorspace;
  3016. CGColorSpaceRelease(colorspace);
  3017. windowData->textureContainer.header.info.format = SwapchainCompositionToFormat[swapchainComposition];
  3018. return true;
  3019. }
  3020. }
  3021. // Submission
  3022. static void METAL_Submit(
  3023. SDL_GPUCommandBuffer *commandBuffer)
  3024. {
  3025. @autoreleasepool {
  3026. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  3027. MetalRenderer *renderer = metalCommandBuffer->renderer;
  3028. SDL_LockMutex(renderer->submitLock);
  3029. // Enqueue present requests, if applicable
  3030. for (Uint32 i = 0; i < metalCommandBuffer->windowDataCount; i += 1) {
  3031. [metalCommandBuffer->handle presentDrawable:metalCommandBuffer->windowDatas[i]->drawable];
  3032. metalCommandBuffer->windowDatas[i]->drawable = nil;
  3033. }
  3034. // Notify the fence when the command buffer has completed
  3035. [metalCommandBuffer->handle addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
  3036. SDL_AtomicIncRef(&metalCommandBuffer->fence->complete);
  3037. }];
  3038. // Submit the command buffer
  3039. [metalCommandBuffer->handle commit];
  3040. metalCommandBuffer->handle = nil;
  3041. // Mark the command buffer as submitted
  3042. if (renderer->submittedCommandBufferCount >= renderer->submittedCommandBufferCapacity) {
  3043. renderer->submittedCommandBufferCapacity = renderer->submittedCommandBufferCount + 1;
  3044. renderer->submittedCommandBuffers = SDL_realloc(
  3045. renderer->submittedCommandBuffers,
  3046. sizeof(MetalCommandBuffer *) * renderer->submittedCommandBufferCapacity);
  3047. }
  3048. renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = metalCommandBuffer;
  3049. renderer->submittedCommandBufferCount += 1;
  3050. // Check if we can perform any cleanups
  3051. for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
  3052. if (SDL_AtomicGet(&renderer->submittedCommandBuffers[i]->fence->complete)) {
  3053. METAL_INTERNAL_CleanCommandBuffer(
  3054. renderer,
  3055. renderer->submittedCommandBuffers[i]);
  3056. }
  3057. }
  3058. METAL_INTERNAL_PerformPendingDestroys(renderer);
  3059. SDL_UnlockMutex(renderer->submitLock);
  3060. }
  3061. }
  3062. static SDL_GPUFence *METAL_SubmitAndAcquireFence(
  3063. SDL_GPUCommandBuffer *commandBuffer)
  3064. {
  3065. MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer;
  3066. MetalFence *fence = metalCommandBuffer->fence;
  3067. metalCommandBuffer->autoReleaseFence = 0;
  3068. METAL_Submit(commandBuffer);
  3069. return (SDL_GPUFence *)fence;
  3070. }
  3071. static void METAL_Wait(
  3072. SDL_GPURenderer *driverData)
  3073. {
  3074. @autoreleasepool {
  3075. MetalRenderer *renderer = (MetalRenderer *)driverData;
  3076. MetalCommandBuffer *commandBuffer;
  3077. /*
  3078. * Wait for all submitted command buffers to complete.
  3079. * Sort of equivalent to vkDeviceWaitIdle.
  3080. */
  3081. for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
  3082. while (!SDL_AtomicGet(&renderer->submittedCommandBuffers[i]->fence->complete)) {
  3083. // Spin!
  3084. }
  3085. }
  3086. SDL_LockMutex(renderer->submitLock);
  3087. for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
  3088. commandBuffer = renderer->submittedCommandBuffers[i];
  3089. METAL_INTERNAL_CleanCommandBuffer(renderer, commandBuffer);
  3090. }
  3091. METAL_INTERNAL_PerformPendingDestroys(renderer);
  3092. SDL_UnlockMutex(renderer->submitLock);
  3093. }
  3094. }
  3095. // Format Info
  3096. static bool METAL_SupportsTextureFormat(
  3097. SDL_GPURenderer *driverData,
  3098. SDL_GPUTextureFormat format,
  3099. SDL_GPUTextureType type,
  3100. SDL_GPUTextureUsageFlags usage)
  3101. {
  3102. @autoreleasepool {
  3103. MetalRenderer *renderer = (MetalRenderer *)driverData;
  3104. // Only depth textures can be used as... depth textures
  3105. if ((usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET_BIT)) {
  3106. if (!IsDepthFormat(format)) {
  3107. return false;
  3108. }
  3109. }
  3110. switch (format) {
  3111. // Apple GPU exclusive
  3112. case SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM:
  3113. case SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM:
  3114. case SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM:
  3115. return [renderer->device supportsFamily:MTLGPUFamilyApple1];
  3116. // Requires BC compression support
  3117. case SDL_GPU_TEXTUREFORMAT_BC1_UNORM:
  3118. case SDL_GPU_TEXTUREFORMAT_BC2_UNORM:
  3119. case SDL_GPU_TEXTUREFORMAT_BC3_UNORM:
  3120. case SDL_GPU_TEXTUREFORMAT_BC7_UNORM:
  3121. case SDL_GPU_TEXTUREFORMAT_BC3_UNORM_SRGB:
  3122. case SDL_GPU_TEXTUREFORMAT_BC7_UNORM_SRGB:
  3123. #ifdef SDL_PLATFORM_MACOS
  3124. if (@available(macOS 11.0, *)) {
  3125. return (
  3126. [renderer->device supportsBCTextureCompression] &&
  3127. !(usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT));
  3128. } else {
  3129. return false;
  3130. }
  3131. #else
  3132. // FIXME: iOS 16.4+ allows these formats!
  3133. return false;
  3134. #endif
  3135. // Requires D24S8 support
  3136. case SDL_GPU_TEXTUREFORMAT_D24_UNORM:
  3137. case SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT:
  3138. #ifdef SDL_PLATFORM_MACOS
  3139. return [renderer->device isDepth24Stencil8PixelFormatSupported];
  3140. #else
  3141. return false;
  3142. #endif
  3143. default:
  3144. return true;
  3145. }
  3146. }
  3147. }
  3148. // Device Creation
  3149. static bool METAL_PrepareDriver(SDL_VideoDevice *_this)
  3150. {
  3151. // FIXME: Add a macOS / iOS version check! Maybe support >= 10.14?
  3152. return (_this->Metal_CreateView != NULL);
  3153. }
  3154. static void METAL_INTERNAL_InitBlitResources(
  3155. MetalRenderer *renderer)
  3156. {
  3157. SDL_GPUShaderCreateInfo shaderModuleCreateInfo;
  3158. SDL_GPUSamplerCreateInfo samplerCreateInfo;
  3159. // Allocate the dynamic blit pipeline list
  3160. renderer->blitPipelineCapacity = 2;
  3161. renderer->blitPipelineCount = 0;
  3162. renderer->blitPipelines = SDL_malloc(
  3163. renderer->blitPipelineCapacity * sizeof(BlitPipelineCacheEntry));
  3164. // Fullscreen vertex shader
  3165. SDL_zero(shaderModuleCreateInfo);
  3166. shaderModuleCreateInfo.code = FullscreenVert_metallib;
  3167. shaderModuleCreateInfo.codeSize = FullscreenVert_metallib_len;
  3168. shaderModuleCreateInfo.stage = SDL_GPU_SHADERSTAGE_VERTEX;
  3169. shaderModuleCreateInfo.format = SDL_GPU_SHADERFORMAT_METALLIB;
  3170. shaderModuleCreateInfo.entryPointName = "FullscreenVert";
  3171. renderer->blitVertexShader = METAL_CreateShader(
  3172. (SDL_GPURenderer *)renderer,
  3173. &shaderModuleCreateInfo);
  3174. if (renderer->blitVertexShader == NULL) {
  3175. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile vertex shader for blit!");
  3176. }
  3177. // BlitFrom2D fragment shader
  3178. shaderModuleCreateInfo.code = BlitFrom2D_metallib;
  3179. shaderModuleCreateInfo.codeSize = BlitFrom2D_metallib_len;
  3180. shaderModuleCreateInfo.stage = SDL_GPU_SHADERSTAGE_FRAGMENT;
  3181. shaderModuleCreateInfo.entryPointName = "BlitFrom2D";
  3182. shaderModuleCreateInfo.samplerCount = 1;
  3183. shaderModuleCreateInfo.uniformBufferCount = 1;
  3184. renderer->blitFrom2DShader = METAL_CreateShader(
  3185. (SDL_GPURenderer *)renderer,
  3186. &shaderModuleCreateInfo);
  3187. if (renderer->blitFrom2DShader == NULL) {
  3188. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFrom2D fragment shader!");
  3189. }
  3190. // BlitFrom2DArray fragment shader
  3191. shaderModuleCreateInfo.code = BlitFrom2DArray_metallib;
  3192. shaderModuleCreateInfo.codeSize = BlitFrom2DArray_metallib_len;
  3193. shaderModuleCreateInfo.entryPointName = "BlitFrom2DArray";
  3194. renderer->blitFrom2DArrayShader = METAL_CreateShader(
  3195. (SDL_GPURenderer *)renderer,
  3196. &shaderModuleCreateInfo);
  3197. if (renderer->blitFrom2DArrayShader == NULL) {
  3198. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFrom2DArray fragment shader!");
  3199. }
  3200. // BlitFrom3D fragment shader
  3201. shaderModuleCreateInfo.code = BlitFrom3D_metallib;
  3202. shaderModuleCreateInfo.codeSize = BlitFrom3D_metallib_len;
  3203. shaderModuleCreateInfo.entryPointName = "BlitFrom3D";
  3204. renderer->blitFrom3DShader = METAL_CreateShader(
  3205. (SDL_GPURenderer *)renderer,
  3206. &shaderModuleCreateInfo);
  3207. if (renderer->blitFrom3DShader == NULL) {
  3208. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFrom3D fragment shader!");
  3209. }
  3210. // BlitFromCube fragment shader
  3211. shaderModuleCreateInfo.code = BlitFromCube_metallib;
  3212. shaderModuleCreateInfo.codeSize = BlitFromCube_metallib_len;
  3213. shaderModuleCreateInfo.entryPointName = "BlitFromCube";
  3214. renderer->blitFromCubeShader = METAL_CreateShader(
  3215. (SDL_GPURenderer *)renderer,
  3216. &shaderModuleCreateInfo);
  3217. if (renderer->blitFromCubeShader == NULL) {
  3218. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFromCube fragment shader!");
  3219. }
  3220. // Create samplers
  3221. samplerCreateInfo.addressModeU = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
  3222. samplerCreateInfo.addressModeV = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
  3223. samplerCreateInfo.addressModeW = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
  3224. samplerCreateInfo.anisotropyEnable = 0;
  3225. samplerCreateInfo.compareEnable = 0;
  3226. samplerCreateInfo.magFilter = SDL_GPU_FILTER_NEAREST;
  3227. samplerCreateInfo.minFilter = SDL_GPU_FILTER_NEAREST;
  3228. samplerCreateInfo.mipmapMode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
  3229. samplerCreateInfo.mipLodBias = 0.0f;
  3230. samplerCreateInfo.minLod = 0;
  3231. samplerCreateInfo.maxLod = 1000;
  3232. samplerCreateInfo.maxAnisotropy = 1.0f;
  3233. samplerCreateInfo.compareOp = SDL_GPU_COMPAREOP_ALWAYS;
  3234. renderer->blitNearestSampler = METAL_CreateSampler(
  3235. (SDL_GPURenderer *)renderer,
  3236. &samplerCreateInfo);
  3237. if (renderer->blitNearestSampler == NULL) {
  3238. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create blit nearest sampler!");
  3239. }
  3240. samplerCreateInfo.magFilter = SDL_GPU_FILTER_LINEAR;
  3241. samplerCreateInfo.minFilter = SDL_GPU_FILTER_LINEAR;
  3242. samplerCreateInfo.mipmapMode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR;
  3243. renderer->blitLinearSampler = METAL_CreateSampler(
  3244. (SDL_GPURenderer *)renderer,
  3245. &samplerCreateInfo);
  3246. if (renderer->blitLinearSampler == NULL) {
  3247. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create blit linear sampler!");
  3248. }
  3249. }
  3250. static void METAL_INTERNAL_DestroyBlitResources(
  3251. SDL_GPURenderer *driverData)
  3252. {
  3253. MetalRenderer *renderer = (MetalRenderer *)driverData;
  3254. METAL_ReleaseSampler(driverData, renderer->blitLinearSampler);
  3255. METAL_ReleaseSampler(driverData, renderer->blitNearestSampler);
  3256. METAL_ReleaseShader(driverData, renderer->blitVertexShader);
  3257. METAL_ReleaseShader(driverData, renderer->blitFrom2DShader);
  3258. METAL_ReleaseShader(driverData, renderer->blitFrom2DArrayShader);
  3259. METAL_ReleaseShader(driverData, renderer->blitFrom3DShader);
  3260. METAL_ReleaseShader(driverData, renderer->blitFromCubeShader);
  3261. for (Uint32 i = 0; i < renderer->blitPipelineCount; i += 1) {
  3262. METAL_ReleaseGraphicsPipeline(driverData, renderer->blitPipelines[i].pipeline);
  3263. }
  3264. SDL_free(renderer->blitPipelines);
  3265. }
  3266. static SDL_GPUDevice *METAL_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props)
  3267. {
  3268. @autoreleasepool {
  3269. MetalRenderer *renderer;
  3270. // Allocate and zero out the renderer
  3271. renderer = (MetalRenderer *)SDL_calloc(1, sizeof(MetalRenderer));
  3272. // Create the Metal device and command queue
  3273. #ifdef SDL_PLATFORM_MACOS
  3274. if (preferLowPower) {
  3275. NSArray<id<MTLDevice>> *devices = MTLCopyAllDevices();
  3276. for (id<MTLDevice> device in devices) {
  3277. if (device.isLowPower) {
  3278. renderer->device = device;
  3279. break;
  3280. }
  3281. }
  3282. }
  3283. #endif
  3284. if (renderer->device == NULL) {
  3285. renderer->device = MTLCreateSystemDefaultDevice();
  3286. }
  3287. renderer->queue = [renderer->device newCommandQueue];
  3288. // Print driver info
  3289. SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Metal");
  3290. SDL_LogInfo(
  3291. SDL_LOG_CATEGORY_GPU,
  3292. "Metal Device: %s",
  3293. [renderer->device.name UTF8String]);
  3294. // Remember debug mode
  3295. renderer->debugMode = debugMode;
  3296. // Set up colorspace array
  3297. SwapchainCompositionToColorSpace[0] = kCGColorSpaceSRGB;
  3298. SwapchainCompositionToColorSpace[1] = kCGColorSpaceSRGB;
  3299. SwapchainCompositionToColorSpace[2] = kCGColorSpaceExtendedLinearSRGB;
  3300. if (@available(macOS 11.0, *)) {
  3301. SwapchainCompositionToColorSpace[3] = kCGColorSpaceITUR_2100_PQ;
  3302. } else {
  3303. SwapchainCompositionToColorSpace[3] = NULL;
  3304. }
  3305. // Create mutexes
  3306. renderer->submitLock = SDL_CreateMutex();
  3307. renderer->acquireCommandBufferLock = SDL_CreateMutex();
  3308. renderer->acquireUniformBufferLock = SDL_CreateMutex();
  3309. renderer->disposeLock = SDL_CreateMutex();
  3310. renderer->fenceLock = SDL_CreateMutex();
  3311. renderer->windowLock = SDL_CreateMutex();
  3312. // Create command buffer pool
  3313. METAL_INTERNAL_AllocateCommandBuffers(renderer, 2);
  3314. // Create fence pool
  3315. renderer->availableFenceCapacity = 2;
  3316. renderer->availableFences = SDL_malloc(
  3317. sizeof(MetalFence *) * renderer->availableFenceCapacity);
  3318. // Create uniform buffer pool
  3319. renderer->uniformBufferPoolCapacity = 32;
  3320. renderer->uniformBufferPoolCount = 32;
  3321. renderer->uniformBufferPool = SDL_malloc(
  3322. renderer->uniformBufferPoolCapacity * sizeof(MetalUniformBuffer *));
  3323. for (Uint32 i = 0; i < renderer->uniformBufferPoolCount; i += 1) {
  3324. renderer->uniformBufferPool[i] = METAL_INTERNAL_CreateUniformBuffer(
  3325. renderer,
  3326. UNIFORM_BUFFER_SIZE);
  3327. }
  3328. // Create deferred destroy arrays
  3329. renderer->bufferContainersToDestroyCapacity = 2;
  3330. renderer->bufferContainersToDestroyCount = 0;
  3331. renderer->bufferContainersToDestroy = SDL_malloc(
  3332. renderer->bufferContainersToDestroyCapacity * sizeof(MetalBufferContainer *));
  3333. renderer->textureContainersToDestroyCapacity = 2;
  3334. renderer->textureContainersToDestroyCount = 0;
  3335. renderer->textureContainersToDestroy = SDL_malloc(
  3336. renderer->textureContainersToDestroyCapacity * sizeof(MetalTextureContainer *));
  3337. // Create claimed window list
  3338. renderer->claimedWindowCapacity = 1;
  3339. renderer->claimedWindows = SDL_malloc(
  3340. sizeof(MetalWindowData *) * renderer->claimedWindowCapacity);
  3341. // Initialize blit resources
  3342. METAL_INTERNAL_InitBlitResources(renderer);
  3343. SDL_GPUDevice *result = SDL_malloc(sizeof(SDL_GPUDevice));
  3344. ASSIGN_DRIVER(METAL)
  3345. result->driverData = (SDL_GPURenderer *)renderer;
  3346. renderer->sdlGPUDevice = result;
  3347. return result;
  3348. }
  3349. }
  3350. SDL_GPUBootstrap MetalDriver = {
  3351. "Metal",
  3352. SDL_GPU_DRIVER_METAL,
  3353. SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB,
  3354. METAL_PrepareDriver,
  3355. METAL_CreateDevice
  3356. };
  3357. #endif // SDL_GPU_METAL