SDL_gpu.c 120 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2026 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. #include "SDL_sysgpu.h"
  20. /* Normally this macro would use something like SDL_IsObjectValid, but in GPU's
  21. * case we can prioritize performance and be more trusting of application
  22. * behavior than, say, SDL_Render, so trust that applications will be careful
  23. * about disposing the device and its resources.
  24. * -flibit
  25. */
  26. #define CHECK_DEVICE_MAGIC(device, retval) \
  27. CHECK_PARAM(device == NULL) { \
  28. SDL_SetError("Invalid GPU device"); \
  29. return retval; \
  30. }
  31. #define CHECK_COMMAND_BUFFER \
  32. if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \
  33. SDL_assert_release(!"Command buffer already submitted!"); \
  34. return; \
  35. }
  36. #define CHECK_COMMAND_BUFFER_RETURN_FALSE \
  37. if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \
  38. SDL_assert_release(!"Command buffer already submitted!"); \
  39. return false; \
  40. }
  41. #define CHECK_COMMAND_BUFFER_RETURN_NULL \
  42. if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \
  43. SDL_assert_release(!"Command buffer already submitted!"); \
  44. return NULL; \
  45. }
  46. #define CHECK_ANY_PASS_IN_PROGRESS(msg, retval) \
  47. if ( \
  48. ((CommandBufferCommonHeader *)command_buffer)->render_pass.in_progress || \
  49. ((CommandBufferCommonHeader *)command_buffer)->compute_pass.in_progress || \
  50. ((CommandBufferCommonHeader *)command_buffer)->copy_pass.in_progress) { \
  51. SDL_assert_release(!msg); \
  52. return retval; \
  53. }
  54. #define CHECK_RENDERPASS \
  55. if (!((RenderPass *)render_pass)->in_progress) { \
  56. SDL_assert_release(!"Render pass not in progress!"); \
  57. return; \
  58. }
  59. #if 0
  60. // The below validation is too aggressive, since there are advanced situations
  61. // where this is legal. This is being temporarily disabled for further review.
  62. // See: https://github.com/libsdl-org/SDL/issues/13871
  63. #define CHECK_SAMPLER_TEXTURES \
  64. RenderPass *rp = (RenderPass *)render_pass; \
  65. for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \
  66. for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
  67. if (rp->color_targets[color_target_index] == texture_sampler_bindings[texture_sampler_index].texture) { \
  68. SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a sampler!"); \
  69. } \
  70. } \
  71. } \
  72. \
  73. for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
  74. if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == texture_sampler_bindings[texture_sampler_index].texture) { \
  75. SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a sampler!"); \
  76. } \
  77. }
  78. #define CHECK_STORAGE_TEXTURES \
  79. RenderPass *rp = (RenderPass *)render_pass; \
  80. for (Uint32 color_target_index = 0; color_target_index < rp->num_color_targets; color_target_index += 1) { \
  81. for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
  82. if (rp->color_targets[color_target_index] == storage_textures[texture_sampler_index]) { \
  83. SDL_assert_release(!"Texture cannot be simultaneously bound as a color target and a storage texture!"); \
  84. } \
  85. } \
  86. } \
  87. \
  88. for (Uint32 texture_sampler_index = 0; texture_sampler_index < num_bindings; texture_sampler_index += 1) { \
  89. if (rp->depth_stencil_target != NULL && rp->depth_stencil_target == storage_textures[texture_sampler_index]) { \
  90. SDL_assert_release(!"Texture cannot be simultaneously bound as a depth stencil target and a storage texture!"); \
  91. } \
  92. }
  93. #else
  94. #define CHECK_SAMPLER_TEXTURES
  95. #define CHECK_STORAGE_TEXTURES
  96. #endif
  97. #define CHECK_GRAPHICS_PIPELINE_BOUND \
  98. if (!((RenderPass *)render_pass)->graphics_pipeline) { \
  99. SDL_assert_release(!"Graphics pipeline not bound!"); \
  100. return; \
  101. }
  102. #define CHECK_COMPUTEPASS \
  103. if (!((Pass *)compute_pass)->in_progress) { \
  104. SDL_assert_release(!"Compute pass not in progress!"); \
  105. return; \
  106. }
  107. #define CHECK_COMPUTE_PIPELINE_BOUND \
  108. if (!((ComputePass *)compute_pass)->compute_pipeline) { \
  109. SDL_assert_release(!"Compute pipeline not bound!"); \
  110. return; \
  111. }
  112. #define CHECK_COPYPASS \
  113. if (!((Pass *)copy_pass)->in_progress) { \
  114. SDL_assert_release(!"Copy pass not in progress!"); \
  115. return; \
  116. }
  117. #define CHECK_TEXTUREFORMAT_ENUM_INVALID(enumval, retval) \
  118. if (enumval <= SDL_GPU_TEXTUREFORMAT_INVALID || enumval >= SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE) { \
  119. SDL_assert_release(!"Invalid texture format enum!"); \
  120. return retval; \
  121. }
  122. #define CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(enumval, retval) \
  123. if (enumval <= SDL_GPU_VERTEXELEMENTFORMAT_INVALID || enumval >= SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE) { \
  124. SDL_assert_release(!"Invalid vertex format enum!"); \
  125. return retval; \
  126. }
  127. #define CHECK_COMPAREOP_ENUM_INVALID(enumval, retval) \
  128. if (enumval <= SDL_GPU_COMPAREOP_INVALID || enumval >= SDL_GPU_COMPAREOP_MAX_ENUM_VALUE) { \
  129. SDL_assert_release(!"Invalid compare op enum!"); \
  130. return retval; \
  131. }
  132. #define CHECK_STENCILOP_ENUM_INVALID(enumval, retval) \
  133. if (enumval <= SDL_GPU_STENCILOP_INVALID || enumval >= SDL_GPU_STENCILOP_MAX_ENUM_VALUE) { \
  134. SDL_assert_release(!"Invalid stencil op enum!"); \
  135. return retval; \
  136. }
  137. #define CHECK_BLENDOP_ENUM_INVALID(enumval, retval) \
  138. if (enumval <= SDL_GPU_BLENDOP_INVALID || enumval >= SDL_GPU_BLENDOP_MAX_ENUM_VALUE) { \
  139. SDL_assert_release(!"Invalid blend op enum!"); \
  140. return retval; \
  141. }
  142. #define CHECK_BLENDFACTOR_ENUM_INVALID(enumval, retval) \
  143. if (enumval <= SDL_GPU_BLENDFACTOR_INVALID || enumval >= SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE) { \
  144. SDL_assert_release(!"Invalid blend factor enum!"); \
  145. return retval; \
  146. }
  147. #define CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(enumval, retval) \
  148. if (enumval < 0 || enumval >= SDL_GPU_SWAPCHAINCOMPOSITION_MAX_ENUM_VALUE) { \
  149. SDL_assert_release(!"Invalid swapchain composition enum!"); \
  150. return retval; \
  151. }
  152. #define CHECK_PRESENTMODE_ENUM_INVALID(enumval, retval) \
  153. if (enumval < 0 || enumval >= SDL_GPU_PRESENTMODE_MAX_ENUM_VALUE) { \
  154. SDL_assert_release(!"Invalid present mode enum!"); \
  155. return retval; \
  156. }
  157. #define COMMAND_BUFFER_DEVICE \
  158. ((CommandBufferCommonHeader *)command_buffer)->device
  159. #define RENDERPASS_COMMAND_BUFFER \
  160. ((RenderPass *)render_pass)->command_buffer
  161. #define RENDERPASS_DEVICE \
  162. ((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->device
  163. #define RENDERPASS_BOUND_PIPELINE \
  164. ((RenderPass *)render_pass)->graphics_pipeline
  165. #define COMPUTEPASS_COMMAND_BUFFER \
  166. ((Pass *)compute_pass)->command_buffer
  167. #define COMPUTEPASS_DEVICE \
  168. ((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->device
  169. #define COMPUTEPASS_BOUND_PIPELINE \
  170. ((ComputePass *)compute_pass)->compute_pipeline
  171. #define COPYPASS_COMMAND_BUFFER \
  172. ((Pass *)copy_pass)->command_buffer
  173. #define COPYPASS_DEVICE \
  174. ((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->device
  175. static bool TextureFormatIsComputeWritable[] = {
  176. false, // INVALID
  177. false, // A8_UNORM
  178. true, // R8_UNORM
  179. true, // R8G8_UNORM
  180. true, // R8G8B8A8_UNORM
  181. true, // R16_UNORM
  182. true, // R16G16_UNORM
  183. true, // R16G16B16A16_UNORM
  184. true, // R10G10B10A2_UNORM
  185. false, // B5G6R5_UNORM
  186. false, // B5G5R5A1_UNORM
  187. false, // B4G4R4A4_UNORM
  188. false, // B8G8R8A8_UNORM
  189. false, // BC1_UNORM
  190. false, // BC2_UNORM
  191. false, // BC3_UNORM
  192. false, // BC4_UNORM
  193. false, // BC5_UNORM
  194. false, // BC7_UNORM
  195. false, // BC6H_FLOAT
  196. false, // BC6H_UFLOAT
  197. true, // R8_SNORM
  198. true, // R8G8_SNORM
  199. true, // R8G8B8A8_SNORM
  200. true, // R16_SNORM
  201. true, // R16G16_SNORM
  202. true, // R16G16B16A16_SNORM
  203. true, // R16_FLOAT
  204. true, // R16G16_FLOAT
  205. true, // R16G16B16A16_FLOAT
  206. true, // R32_FLOAT
  207. true, // R32G32_FLOAT
  208. true, // R32G32B32A32_FLOAT
  209. true, // R11G11B10_UFLOAT
  210. true, // R8_UINT
  211. true, // R8G8_UINT
  212. true, // R8G8B8A8_UINT
  213. true, // R16_UINT
  214. true, // R16G16_UINT
  215. true, // R16G16B16A16_UINT
  216. true, // R32_UINT
  217. true, // R32G32_UINT
  218. true, // R32G32B32A32_UINT
  219. true, // R8_INT
  220. true, // R8G8_INT
  221. true, // R8G8B8A8_INT
  222. true, // R16_INT
  223. true, // R16G16_INT
  224. true, // R16G16B16A16_INT
  225. true, // R32_INT
  226. true, // R32G32_INT
  227. true, // R32G32B32A32_INT
  228. false, // R8G8B8A8_UNORM_SRGB
  229. false, // B8G8R8A8_UNORM_SRGB
  230. false, // BC1_UNORM_SRGB
  231. false, // BC3_UNORM_SRGB
  232. false, // BC3_UNORM_SRGB
  233. false, // BC7_UNORM_SRGB
  234. false, // D16_UNORM
  235. false, // D24_UNORM
  236. false, // D32_FLOAT
  237. false, // D24_UNORM_S8_UINT
  238. false, // D32_FLOAT_S8_UINT
  239. false, // ASTC_4x4_UNORM
  240. false, // ASTC_5x4_UNORM
  241. false, // ASTC_5x5_UNORM
  242. false, // ASTC_6x5_UNORM
  243. false, // ASTC_6x6_UNORM
  244. false, // ASTC_8x5_UNORM
  245. false, // ASTC_8x6_UNORM
  246. false, // ASTC_8x8_UNORM
  247. false, // ASTC_10x5_UNORM
  248. false, // ASTC_10x6_UNORM
  249. false, // ASTC_10x8_UNORM
  250. false, // ASTC_10x10_UNORM
  251. false, // ASTC_12x10_UNORM
  252. false, // ASTC_12x12_UNORM
  253. false, // ASTC_4x4_UNORM_SRGB
  254. false, // ASTC_5x4_UNORM_SRGB
  255. false, // ASTC_5x5_UNORM_SRGB
  256. false, // ASTC_6x5_UNORM_SRGB
  257. false, // ASTC_6x6_UNORM_SRGB
  258. false, // ASTC_8x5_UNORM_SRGB
  259. false, // ASTC_8x6_UNORM_SRGB
  260. false, // ASTC_8x8_UNORM_SRGB
  261. false, // ASTC_10x5_UNORM_SRGB
  262. false, // ASTC_10x6_UNORM_SRGB
  263. false, // ASTC_10x8_UNORM_SRGB
  264. false, // ASTC_10x10_UNORM_SRGB
  265. false, // ASTC_12x10_UNORM_SRGB
  266. false, // ASTC_12x12_UNORM_SRGB
  267. false, // ASTC_4x4_FLOAT
  268. false, // ASTC_5x4_FLOAT
  269. false, // ASTC_5x5_FLOAT
  270. false, // ASTC_6x5_FLOAT
  271. false, // ASTC_6x6_FLOAT
  272. false, // ASTC_8x5_FLOAT
  273. false, // ASTC_8x6_FLOAT
  274. false, // ASTC_8x8_FLOAT
  275. false, // ASTC_10x5_FLOAT
  276. false, // ASTC_10x6_FLOAT
  277. false, // ASTC_10x8_FLOAT
  278. false, // ASTC_10x10_FLOAT
  279. false, // ASTC_12x10_FLOAT
  280. false // ASTC_12x12_FLOAT
  281. };
  282. // Drivers
  283. #ifndef SDL_GPU_DISABLED
  284. static const SDL_GPUBootstrap *backends[] = {
  285. #ifdef SDL_GPU_PRIVATE
  286. &PrivateGPUDriver,
  287. #endif
  288. #ifdef SDL_GPU_METAL
  289. &MetalDriver,
  290. #endif
  291. #ifdef SDL_GPU_D3D12
  292. &D3D12Driver,
  293. #endif
  294. #ifdef SDL_GPU_VULKAN
  295. &VulkanDriver,
  296. #endif
  297. NULL
  298. };
  299. #endif // !SDL_GPU_DISABLED
  300. // Internal Utility Functions
  301. SDL_GPUGraphicsPipeline *SDL_GPU_FetchBlitPipeline(
  302. SDL_GPUDevice *device,
  303. SDL_GPUTextureType source_texture_type,
  304. SDL_GPUTextureFormat destination_format,
  305. SDL_GPUShader *blit_vertex_shader,
  306. SDL_GPUShader *blit_from_2d_shader,
  307. SDL_GPUShader *blit_from_2d_array_shader,
  308. SDL_GPUShader *blit_from_3d_shader,
  309. SDL_GPUShader *blit_from_cube_shader,
  310. SDL_GPUShader *blit_from_cube_array_shader,
  311. BlitPipelineCacheEntry **blit_pipelines,
  312. Uint32 *blit_pipeline_count,
  313. Uint32 *blit_pipeline_capacity)
  314. {
  315. SDL_GPUGraphicsPipelineCreateInfo blit_pipeline_create_info;
  316. SDL_GPUColorTargetDescription color_target_desc;
  317. SDL_GPUGraphicsPipeline *pipeline;
  318. if (blit_pipeline_count == NULL) {
  319. // use pre-created, format-agnostic pipelines
  320. return (*blit_pipelines)[source_texture_type].pipeline;
  321. }
  322. for (Uint32 i = 0; i < *blit_pipeline_count; i += 1) {
  323. if ((*blit_pipelines)[i].type == source_texture_type && (*blit_pipelines)[i].format == destination_format) {
  324. return (*blit_pipelines)[i].pipeline;
  325. }
  326. }
  327. // No pipeline found, we'll need to make one!
  328. SDL_zero(blit_pipeline_create_info);
  329. SDL_zero(color_target_desc);
  330. color_target_desc.blend_state.color_write_mask = 0xF;
  331. color_target_desc.format = destination_format;
  332. blit_pipeline_create_info.target_info.color_target_descriptions = &color_target_desc;
  333. blit_pipeline_create_info.target_info.num_color_targets = 1;
  334. blit_pipeline_create_info.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM; // arbitrary
  335. blit_pipeline_create_info.target_info.has_depth_stencil_target = false;
  336. blit_pipeline_create_info.vertex_shader = blit_vertex_shader;
  337. if (source_texture_type == SDL_GPU_TEXTURETYPE_CUBE) {
  338. blit_pipeline_create_info.fragment_shader = blit_from_cube_shader;
  339. } else if (source_texture_type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
  340. blit_pipeline_create_info.fragment_shader = blit_from_cube_array_shader;
  341. } else if (source_texture_type == SDL_GPU_TEXTURETYPE_2D_ARRAY) {
  342. blit_pipeline_create_info.fragment_shader = blit_from_2d_array_shader;
  343. } else if (source_texture_type == SDL_GPU_TEXTURETYPE_3D) {
  344. blit_pipeline_create_info.fragment_shader = blit_from_3d_shader;
  345. } else {
  346. blit_pipeline_create_info.fragment_shader = blit_from_2d_shader;
  347. }
  348. blit_pipeline_create_info.rasterizer_state.enable_depth_clip = device->default_enable_depth_clip;
  349. blit_pipeline_create_info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1;
  350. blit_pipeline_create_info.multisample_state.enable_mask = false;
  351. blit_pipeline_create_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
  352. pipeline = SDL_CreateGPUGraphicsPipeline(
  353. device,
  354. &blit_pipeline_create_info);
  355. if (pipeline == NULL) {
  356. SDL_SetError("Failed to create GPU pipeline for blit");
  357. return NULL;
  358. }
  359. // Cache the new pipeline
  360. EXPAND_ARRAY_IF_NEEDED(
  361. (*blit_pipelines),
  362. BlitPipelineCacheEntry,
  363. *blit_pipeline_count + 1,
  364. *blit_pipeline_capacity,
  365. *blit_pipeline_capacity * 2);
  366. (*blit_pipelines)[*blit_pipeline_count].pipeline = pipeline;
  367. (*blit_pipelines)[*blit_pipeline_count].type = source_texture_type;
  368. (*blit_pipelines)[*blit_pipeline_count].format = destination_format;
  369. *blit_pipeline_count += 1;
  370. return pipeline;
  371. }
  372. void SDL_GPU_BlitCommon(
  373. SDL_GPUCommandBuffer *command_buffer,
  374. const SDL_GPUBlitInfo *info,
  375. SDL_GPUSampler *blit_linear_sampler,
  376. SDL_GPUSampler *blit_nearest_sampler,
  377. SDL_GPUShader *blit_vertex_shader,
  378. SDL_GPUShader *blit_from_2d_shader,
  379. SDL_GPUShader *blit_from_2d_array_shader,
  380. SDL_GPUShader *blit_from_3d_shader,
  381. SDL_GPUShader *blit_from_cube_shader,
  382. SDL_GPUShader *blit_from_cube_array_shader,
  383. BlitPipelineCacheEntry **blit_pipelines,
  384. Uint32 *blit_pipeline_count,
  385. Uint32 *blit_pipeline_capacity)
  386. {
  387. CommandBufferCommonHeader *cmdbufHeader = (CommandBufferCommonHeader *)command_buffer;
  388. SDL_GPURenderPass *render_pass;
  389. TextureCommonHeader *src_header = (TextureCommonHeader *)info->source.texture;
  390. TextureCommonHeader *dst_header = (TextureCommonHeader *)info->destination.texture;
  391. SDL_GPUGraphicsPipeline *blit_pipeline;
  392. SDL_GPUColorTargetInfo color_target_info;
  393. SDL_GPUViewport viewport;
  394. SDL_GPUTextureSamplerBinding texture_sampler_binding;
  395. BlitFragmentUniforms blit_fragment_uniforms;
  396. Uint32 layer_divisor;
  397. blit_pipeline = SDL_GPU_FetchBlitPipeline(
  398. cmdbufHeader->device,
  399. src_header->info.type,
  400. dst_header->info.format,
  401. blit_vertex_shader,
  402. blit_from_2d_shader,
  403. blit_from_2d_array_shader,
  404. blit_from_3d_shader,
  405. blit_from_cube_shader,
  406. blit_from_cube_array_shader,
  407. blit_pipelines,
  408. blit_pipeline_count,
  409. blit_pipeline_capacity);
  410. SDL_assert(blit_pipeline != NULL);
  411. color_target_info.load_op = info->load_op;
  412. color_target_info.clear_color = info->clear_color;
  413. color_target_info.store_op = SDL_GPU_STOREOP_STORE;
  414. color_target_info.texture = info->destination.texture;
  415. color_target_info.mip_level = info->destination.mip_level;
  416. color_target_info.layer_or_depth_plane = info->destination.layer_or_depth_plane;
  417. color_target_info.cycle = info->cycle;
  418. render_pass = SDL_BeginGPURenderPass(
  419. command_buffer,
  420. &color_target_info,
  421. 1,
  422. NULL);
  423. viewport.x = (float)info->destination.x;
  424. viewport.y = (float)info->destination.y;
  425. viewport.w = (float)info->destination.w;
  426. viewport.h = (float)info->destination.h;
  427. viewport.min_depth = 0;
  428. viewport.max_depth = 1;
  429. SDL_SetGPUViewport(
  430. render_pass,
  431. &viewport);
  432. SDL_BindGPUGraphicsPipeline(
  433. render_pass,
  434. blit_pipeline);
  435. texture_sampler_binding.texture = info->source.texture;
  436. texture_sampler_binding.sampler =
  437. info->filter == SDL_GPU_FILTER_NEAREST ? blit_nearest_sampler : blit_linear_sampler;
  438. SDL_BindGPUFragmentSamplers(
  439. render_pass,
  440. 0,
  441. &texture_sampler_binding,
  442. 1);
  443. blit_fragment_uniforms.left = (float)info->source.x / (src_header->info.width >> info->source.mip_level);
  444. blit_fragment_uniforms.top = (float)info->source.y / (src_header->info.height >> info->source.mip_level);
  445. blit_fragment_uniforms.width = (float)info->source.w / (src_header->info.width >> info->source.mip_level);
  446. blit_fragment_uniforms.height = (float)info->source.h / (src_header->info.height >> info->source.mip_level);
  447. blit_fragment_uniforms.mip_level = info->source.mip_level;
  448. layer_divisor = (src_header->info.type == SDL_GPU_TEXTURETYPE_3D) ? src_header->info.layer_count_or_depth : 1;
  449. blit_fragment_uniforms.layer_or_depth = (float)info->source.layer_or_depth_plane / layer_divisor;
  450. if (info->flip_mode & SDL_FLIP_HORIZONTAL) {
  451. blit_fragment_uniforms.left += blit_fragment_uniforms.width;
  452. blit_fragment_uniforms.width *= -1;
  453. }
  454. if (info->flip_mode & SDL_FLIP_VERTICAL) {
  455. blit_fragment_uniforms.top += blit_fragment_uniforms.height;
  456. blit_fragment_uniforms.height *= -1;
  457. }
  458. SDL_PushGPUFragmentUniformData(
  459. command_buffer,
  460. 0,
  461. &blit_fragment_uniforms,
  462. sizeof(blit_fragment_uniforms));
  463. SDL_DrawGPUPrimitives(render_pass, 3, 1, 0, 0);
  464. SDL_EndGPURenderPass(render_pass);
  465. }
  466. static void SDL_GPU_CheckGraphicsBindings(SDL_GPURenderPass *render_pass)
  467. {
  468. RenderPass *rp = (RenderPass *)render_pass;
  469. GraphicsPipelineCommonHeader *pipeline = (GraphicsPipelineCommonHeader *)RENDERPASS_BOUND_PIPELINE;
  470. for (Uint32 i = 0; i < pipeline->num_vertex_samplers; i += 1) {
  471. if (!rp->vertex_sampler_bound[i]) {
  472. SDL_assert_release(!"Missing vertex sampler binding!");
  473. }
  474. }
  475. for (Uint32 i = 0; i < pipeline->num_vertex_storage_textures; i += 1) {
  476. if (!rp->vertex_storage_texture_bound[i]) {
  477. SDL_assert_release(!"Missing vertex storage texture binding!");
  478. }
  479. }
  480. for (Uint32 i = 0; i < pipeline->num_vertex_storage_buffers; i += 1) {
  481. if (!rp->vertex_storage_buffer_bound[i]) {
  482. SDL_assert_release(!"Missing vertex storage buffer binding!");
  483. }
  484. }
  485. for (Uint32 i = 0; i < pipeline->num_fragment_samplers; i += 1) {
  486. if (!rp->fragment_sampler_bound[i]) {
  487. SDL_assert_release(!"Missing fragment sampler binding!");
  488. }
  489. }
  490. for (Uint32 i = 0; i < pipeline->num_fragment_storage_textures; i += 1) {
  491. if (!rp->fragment_storage_texture_bound[i]) {
  492. SDL_assert_release(!"Missing fragment storage texture binding!");
  493. }
  494. }
  495. for (Uint32 i = 0; i < pipeline->num_fragment_storage_buffers; i += 1) {
  496. if (!rp->fragment_storage_buffer_bound[i]) {
  497. SDL_assert_release(!"Missing fragment storage buffer binding!");
  498. }
  499. }
  500. }
  501. static void SDL_GPU_CheckComputeBindings(SDL_GPUComputePass *compute_pass)
  502. {
  503. ComputePass *cp = (ComputePass *)compute_pass;
  504. ComputePipelineCommonHeader *pipeline = (ComputePipelineCommonHeader *)COMPUTEPASS_BOUND_PIPELINE;
  505. for (Uint32 i = 0; i < pipeline->numSamplers; i += 1) {
  506. if (!cp->sampler_bound[i]) {
  507. SDL_assert_release(!"Missing compute sampler binding!");
  508. }
  509. }
  510. for (Uint32 i = 0; i < pipeline->numReadonlyStorageTextures; i += 1) {
  511. if (!cp->read_only_storage_texture_bound[i]) {
  512. SDL_assert_release(!"Missing compute readonly storage texture binding!");
  513. }
  514. }
  515. for (Uint32 i = 0; i < pipeline->numReadonlyStorageBuffers; i += 1) {
  516. if (!cp->read_only_storage_buffer_bound[i]) {
  517. SDL_assert_release(!"Missing compute readonly storage buffer binding!");
  518. }
  519. }
  520. for (Uint32 i = 0; i < pipeline->numReadWriteStorageTextures; i += 1) {
  521. if (!cp->read_write_storage_texture_bound[i]) {
  522. SDL_assert_release(!"Missing compute read-write storage texture binding!");
  523. }
  524. }
  525. for (Uint32 i = 0; i < pipeline->numReadWriteStorageBuffers; i += 1) {
  526. if (!cp->read_write_storage_buffer_bound[i]) {
  527. SDL_assert_release(!"Missing compute read-write storage buffer bbinding!");
  528. }
  529. }
  530. }
  531. // Driver Functions
  532. #ifndef SDL_GPU_DISABLED
  533. static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
  534. {
  535. Uint32 i;
  536. const char *gpudriver;
  537. SDL_VideoDevice *_this = SDL_GetVideoDevice();
  538. if (_this == NULL) {
  539. SDL_SetError("Video subsystem not initialized");
  540. return NULL;
  541. }
  542. #ifndef HAVE_GPU_OPENXR
  543. if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false)) {
  544. SDL_SetError("OpenXR is not enabled in this build of SDL");
  545. return NULL;
  546. }
  547. #endif
  548. gpudriver = SDL_GetHint(SDL_HINT_GPU_DRIVER);
  549. if (gpudriver == NULL) {
  550. gpudriver = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, NULL);
  551. }
  552. // Environment/Properties override...
  553. if (gpudriver != NULL) {
  554. for (i = 0; backends[i]; i += 1) {
  555. if (SDL_strcasecmp(gpudriver, backends[i]->name) == 0) {
  556. if (backends[i]->PrepareDriver(_this, props)) {
  557. return backends[i];
  558. }
  559. }
  560. }
  561. SDL_SetError("SDL_HINT_GPU_DRIVER %s unsupported!", gpudriver);
  562. return NULL;
  563. }
  564. for (i = 0; backends[i]; i += 1) {
  565. if (backends[i]->PrepareDriver(_this, props)) {
  566. return backends[i];
  567. }
  568. }
  569. SDL_SetError("No supported SDL_GPU backend found!");
  570. return NULL;
  571. }
  572. static void SDL_GPU_FillProperties(
  573. SDL_PropertiesID props,
  574. SDL_GPUShaderFormat format_flags,
  575. bool debug_mode,
  576. const char *name)
  577. {
  578. if (format_flags & SDL_GPU_SHADERFORMAT_PRIVATE) {
  579. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN, true);
  580. }
  581. if (format_flags & SDL_GPU_SHADERFORMAT_SPIRV) {
  582. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, true);
  583. }
  584. if (format_flags & SDL_GPU_SHADERFORMAT_DXBC) {
  585. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN, true);
  586. }
  587. if (format_flags & SDL_GPU_SHADERFORMAT_DXIL) {
  588. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN, true);
  589. }
  590. if (format_flags & SDL_GPU_SHADERFORMAT_MSL) {
  591. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN, true);
  592. }
  593. if (format_flags & SDL_GPU_SHADERFORMAT_METALLIB) {
  594. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN, true);
  595. }
  596. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, debug_mode);
  597. SDL_SetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, name);
  598. }
  599. #endif // SDL_GPU_DISABLED
  600. bool SDL_GPUSupportsShaderFormats(
  601. SDL_GPUShaderFormat format_flags,
  602. const char *name)
  603. {
  604. #ifndef SDL_GPU_DISABLED
  605. bool result;
  606. SDL_PropertiesID props = SDL_CreateProperties();
  607. SDL_GPU_FillProperties(props, format_flags, false, name);
  608. result = SDL_GPUSupportsProperties(props);
  609. SDL_DestroyProperties(props);
  610. return result;
  611. #else
  612. SDL_SetError("SDL not built with GPU support");
  613. return false;
  614. #endif
  615. }
  616. bool SDL_GPUSupportsProperties(SDL_PropertiesID props)
  617. {
  618. #ifndef SDL_GPU_DISABLED
  619. return (SDL_GPUSelectBackend(props) != NULL);
  620. #else
  621. SDL_SetError("SDL not built with GPU support");
  622. return false;
  623. #endif
  624. }
  625. SDL_GPUDevice *SDL_CreateGPUDevice(
  626. SDL_GPUShaderFormat format_flags,
  627. bool debug_mode,
  628. const char *name)
  629. {
  630. #ifndef SDL_GPU_DISABLED
  631. SDL_GPUDevice *result;
  632. SDL_PropertiesID props = SDL_CreateProperties();
  633. SDL_GPU_FillProperties(props, format_flags, debug_mode, name);
  634. result = SDL_CreateGPUDeviceWithProperties(props);
  635. SDL_DestroyProperties(props);
  636. return result;
  637. #else
  638. SDL_SetError("SDL not built with GPU support");
  639. return NULL;
  640. #endif // SDL_GPU_DISABLED
  641. }
  642. SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props)
  643. {
  644. #ifndef SDL_GPU_DISABLED
  645. bool debug_mode;
  646. bool preferLowPower;
  647. SDL_GPUDevice *result = NULL;
  648. const SDL_GPUBootstrap *selectedBackend;
  649. selectedBackend = SDL_GPUSelectBackend(props);
  650. if (selectedBackend != NULL) {
  651. SDL_DebugLogBackend("gpu", selectedBackend->name);
  652. debug_mode = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, true);
  653. preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, false);
  654. result = selectedBackend->CreateDevice(debug_mode, preferLowPower, props);
  655. if (result != NULL) {
  656. result->backend = selectedBackend->name;
  657. result->debug_mode = debug_mode;
  658. if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, true)) {
  659. result->default_enable_depth_clip = false;
  660. } else {
  661. result->default_enable_depth_clip = true;
  662. result->validate_feature_depth_clamp_disabled = true;
  663. }
  664. if (!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, true)) {
  665. result->validate_feature_anisotropy_disabled = true;
  666. }
  667. }
  668. }
  669. return result;
  670. #else
  671. SDL_SetError("SDL not built with GPU support");
  672. return NULL;
  673. #endif // SDL_GPU_DISABLED
  674. }
  675. void SDL_DestroyGPUDevice(SDL_GPUDevice *device)
  676. {
  677. CHECK_DEVICE_MAGIC(device, );
  678. device->DestroyDevice(device);
  679. }
  680. XrResult SDL_DestroyGPUXRSwapchain(SDL_GPUDevice *device, XrSwapchain swapchain, SDL_GPUTexture **swapchainImages)
  681. {
  682. CHECK_DEVICE_MAGIC(device, XR_ERROR_HANDLE_INVALID);
  683. return device->DestroyXRSwapchain(device->driverData, swapchain, swapchainImages);
  684. }
  685. int SDL_GetNumGPUDrivers(void)
  686. {
  687. #ifndef SDL_GPU_DISABLED
  688. return SDL_arraysize(backends) - 1;
  689. #else
  690. return 0;
  691. #endif
  692. }
  693. const char * SDL_GetGPUDriver(int index)
  694. {
  695. CHECK_PARAM(index < 0 || index >= SDL_GetNumGPUDrivers()) {
  696. SDL_InvalidParamError("index");
  697. return NULL;
  698. }
  699. #ifndef SDL_GPU_DISABLED
  700. return backends[index]->name;
  701. #else
  702. return NULL;
  703. #endif
  704. }
  705. const char * SDL_GetGPUDeviceDriver(SDL_GPUDevice *device)
  706. {
  707. CHECK_DEVICE_MAGIC(device, NULL);
  708. return device->backend;
  709. }
  710. SDL_GPUShaderFormat SDL_GetGPUShaderFormats(SDL_GPUDevice *device)
  711. {
  712. CHECK_DEVICE_MAGIC(device, SDL_GPU_SHADERFORMAT_INVALID);
  713. return device->shader_formats;
  714. }
  715. SDL_PropertiesID SDL_GetGPUDeviceProperties(SDL_GPUDevice *device)
  716. {
  717. CHECK_DEVICE_MAGIC(device, 0);
  718. return device->GetDeviceProperties(device);
  719. }
  720. Uint32 SDL_GPUTextureFormatTexelBlockSize(
  721. SDL_GPUTextureFormat format)
  722. {
  723. switch (format) {
  724. case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM:
  725. case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB:
  726. case SDL_GPU_TEXTUREFORMAT_BC4_R_UNORM:
  727. return 8;
  728. case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM:
  729. case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM:
  730. case SDL_GPU_TEXTUREFORMAT_BC5_RG_UNORM:
  731. case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM:
  732. case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT:
  733. case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT:
  734. case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB:
  735. case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB:
  736. case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB:
  737. return 16;
  738. case SDL_GPU_TEXTUREFORMAT_R8_UNORM:
  739. case SDL_GPU_TEXTUREFORMAT_R8_SNORM:
  740. case SDL_GPU_TEXTUREFORMAT_A8_UNORM:
  741. case SDL_GPU_TEXTUREFORMAT_R8_UINT:
  742. case SDL_GPU_TEXTUREFORMAT_R8_INT:
  743. return 1;
  744. case SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM:
  745. case SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM:
  746. case SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM:
  747. case SDL_GPU_TEXTUREFORMAT_R16_FLOAT:
  748. case SDL_GPU_TEXTUREFORMAT_R8G8_SNORM:
  749. case SDL_GPU_TEXTUREFORMAT_R8G8_UNORM:
  750. case SDL_GPU_TEXTUREFORMAT_R8G8_UINT:
  751. case SDL_GPU_TEXTUREFORMAT_R8G8_INT:
  752. case SDL_GPU_TEXTUREFORMAT_R16_UNORM:
  753. case SDL_GPU_TEXTUREFORMAT_R16_SNORM:
  754. case SDL_GPU_TEXTUREFORMAT_R16_UINT:
  755. case SDL_GPU_TEXTUREFORMAT_R16_INT:
  756. case SDL_GPU_TEXTUREFORMAT_D16_UNORM:
  757. return 2;
  758. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM:
  759. case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM:
  760. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB:
  761. case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB:
  762. case SDL_GPU_TEXTUREFORMAT_R32_FLOAT:
  763. case SDL_GPU_TEXTUREFORMAT_R16G16_FLOAT:
  764. case SDL_GPU_TEXTUREFORMAT_R11G11B10_UFLOAT:
  765. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM:
  766. case SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM:
  767. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT:
  768. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT:
  769. case SDL_GPU_TEXTUREFORMAT_R16G16_UINT:
  770. case SDL_GPU_TEXTUREFORMAT_R16G16_INT:
  771. case SDL_GPU_TEXTUREFORMAT_R16G16_UNORM:
  772. case SDL_GPU_TEXTUREFORMAT_R16G16_SNORM:
  773. case SDL_GPU_TEXTUREFORMAT_D24_UNORM:
  774. case SDL_GPU_TEXTUREFORMAT_D32_FLOAT:
  775. case SDL_GPU_TEXTUREFORMAT_R32_UINT:
  776. case SDL_GPU_TEXTUREFORMAT_R32_INT:
  777. case SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT:
  778. return 4;
  779. case SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT:
  780. return 5;
  781. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT:
  782. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM:
  783. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_SNORM:
  784. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT:
  785. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT:
  786. case SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT:
  787. case SDL_GPU_TEXTUREFORMAT_R32G32_UINT:
  788. case SDL_GPU_TEXTUREFORMAT_R32G32_INT:
  789. return 8;
  790. case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT:
  791. case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT:
  792. case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT:
  793. return 16;
  794. case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM:
  795. case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM:
  796. case SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM:
  797. case SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM:
  798. case SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM:
  799. case SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM:
  800. case SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM:
  801. case SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM:
  802. case SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM:
  803. case SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM:
  804. case SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM:
  805. case SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM:
  806. case SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM:
  807. case SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM:
  808. case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM_SRGB:
  809. case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM_SRGB:
  810. case SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM_SRGB:
  811. case SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM_SRGB:
  812. case SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM_SRGB:
  813. case SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM_SRGB:
  814. case SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM_SRGB:
  815. case SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM_SRGB:
  816. case SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM_SRGB:
  817. case SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM_SRGB:
  818. case SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM_SRGB:
  819. case SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM_SRGB:
  820. case SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM_SRGB:
  821. case SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM_SRGB:
  822. case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_FLOAT:
  823. case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_FLOAT:
  824. case SDL_GPU_TEXTUREFORMAT_ASTC_5x5_FLOAT:
  825. case SDL_GPU_TEXTUREFORMAT_ASTC_6x5_FLOAT:
  826. case SDL_GPU_TEXTUREFORMAT_ASTC_6x6_FLOAT:
  827. case SDL_GPU_TEXTUREFORMAT_ASTC_8x5_FLOAT:
  828. case SDL_GPU_TEXTUREFORMAT_ASTC_8x6_FLOAT:
  829. case SDL_GPU_TEXTUREFORMAT_ASTC_8x8_FLOAT:
  830. case SDL_GPU_TEXTUREFORMAT_ASTC_10x5_FLOAT:
  831. case SDL_GPU_TEXTUREFORMAT_ASTC_10x6_FLOAT:
  832. case SDL_GPU_TEXTUREFORMAT_ASTC_10x8_FLOAT:
  833. case SDL_GPU_TEXTUREFORMAT_ASTC_10x10_FLOAT:
  834. case SDL_GPU_TEXTUREFORMAT_ASTC_12x10_FLOAT:
  835. case SDL_GPU_TEXTUREFORMAT_ASTC_12x12_FLOAT:
  836. return 16;
  837. default:
  838. SDL_assert_release(!"Unrecognized TextureFormat!");
  839. return 0;
  840. }
  841. }
  842. bool SDL_GPUTextureSupportsFormat(
  843. SDL_GPUDevice *device,
  844. SDL_GPUTextureFormat format,
  845. SDL_GPUTextureType type,
  846. SDL_GPUTextureUsageFlags usage)
  847. {
  848. CHECK_DEVICE_MAGIC(device, false);
  849. if (device->debug_mode) {
  850. CHECK_TEXTUREFORMAT_ENUM_INVALID(format, false);
  851. }
  852. if ((usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) ||
  853. (usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) {
  854. if (!TextureFormatIsComputeWritable[format]) {
  855. return false;
  856. }
  857. }
  858. return device->SupportsTextureFormat(
  859. device->driverData,
  860. format,
  861. type,
  862. usage);
  863. }
  864. bool SDL_GPUTextureSupportsSampleCount(
  865. SDL_GPUDevice *device,
  866. SDL_GPUTextureFormat format,
  867. SDL_GPUSampleCount sample_count)
  868. {
  869. CHECK_DEVICE_MAGIC(device, 0);
  870. if (device->debug_mode) {
  871. CHECK_TEXTUREFORMAT_ENUM_INVALID(format, 0);
  872. }
  873. return device->SupportsSampleCount(
  874. device->driverData,
  875. format,
  876. sample_count);
  877. }
  878. // State Creation
  879. SDL_GPUComputePipeline *SDL_CreateGPUComputePipeline(
  880. SDL_GPUDevice *device,
  881. const SDL_GPUComputePipelineCreateInfo *createinfo)
  882. {
  883. CHECK_DEVICE_MAGIC(device, NULL);
  884. if (createinfo == NULL) {
  885. SDL_InvalidParamError("createinfo");
  886. return NULL;
  887. }
  888. if (device->debug_mode) {
  889. if (createinfo->format == SDL_GPU_SHADERFORMAT_INVALID) {
  890. SDL_assert_release(!"Shader format cannot be INVALID!");
  891. return NULL;
  892. }
  893. if (!(createinfo->format & device->shader_formats)) {
  894. SDL_assert_release(!"Incompatible shader format for GPU backend");
  895. return NULL;
  896. }
  897. if (createinfo->num_readwrite_storage_textures > MAX_COMPUTE_WRITE_TEXTURES) {
  898. SDL_COMPILE_TIME_ASSERT(compute_write_textures, MAX_COMPUTE_WRITE_TEXTURES == 8);
  899. SDL_assert_release(!"Compute pipeline write-only texture count cannot be higher than 8!");
  900. return NULL;
  901. }
  902. if (createinfo->num_readwrite_storage_buffers > MAX_COMPUTE_WRITE_BUFFERS) {
  903. SDL_COMPILE_TIME_ASSERT(compute_write_buffers, MAX_COMPUTE_WRITE_BUFFERS == 8);
  904. SDL_assert_release(!"Compute pipeline write-only buffer count cannot be higher than 8!");
  905. return NULL;
  906. }
  907. if (createinfo->num_samplers > MAX_TEXTURE_SAMPLERS_PER_STAGE) {
  908. SDL_COMPILE_TIME_ASSERT(compute_texture_samplers, MAX_TEXTURE_SAMPLERS_PER_STAGE == 16);
  909. SDL_assert_release(!"Compute pipeline sampler count cannot be higher than 16!");
  910. return NULL;
  911. }
  912. if (createinfo->num_readonly_storage_textures > MAX_STORAGE_TEXTURES_PER_STAGE) {
  913. SDL_COMPILE_TIME_ASSERT(compute_storage_textures, MAX_STORAGE_TEXTURES_PER_STAGE == 8);
  914. SDL_assert_release(!"Compute pipeline readonly storage texture count cannot be higher than 8!");
  915. return NULL;
  916. }
  917. if (createinfo->num_readonly_storage_buffers > MAX_STORAGE_BUFFERS_PER_STAGE) {
  918. SDL_COMPILE_TIME_ASSERT(compute_storage_buffers, MAX_STORAGE_BUFFERS_PER_STAGE == 8);
  919. SDL_assert_release(!"Compute pipeline readonly storage buffer count cannot be higher than 8!");
  920. return NULL;
  921. }
  922. if (createinfo->num_uniform_buffers > MAX_UNIFORM_BUFFERS_PER_STAGE) {
  923. SDL_COMPILE_TIME_ASSERT(compute_uniform_buffers, MAX_UNIFORM_BUFFERS_PER_STAGE == 4);
  924. SDL_assert_release(!"Compute pipeline uniform buffer count cannot be higher than 4!");
  925. return NULL;
  926. }
  927. if (createinfo->threadcount_x == 0 ||
  928. createinfo->threadcount_y == 0 ||
  929. createinfo->threadcount_z == 0) {
  930. SDL_assert_release(!"Compute pipeline threadCount dimensions must be at least 1!");
  931. return NULL;
  932. }
  933. }
  934. return device->CreateComputePipeline(
  935. device->driverData,
  936. createinfo);
  937. }
  938. SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline(
  939. SDL_GPUDevice *device,
  940. const SDL_GPUGraphicsPipelineCreateInfo *graphicsPipelineCreateInfo)
  941. {
  942. CHECK_DEVICE_MAGIC(device, NULL);
  943. CHECK_PARAM(graphicsPipelineCreateInfo == NULL) {
  944. SDL_InvalidParamError("graphicsPipelineCreateInfo");
  945. return NULL;
  946. }
  947. if (device->debug_mode) {
  948. if (graphicsPipelineCreateInfo->vertex_shader == NULL) {
  949. SDL_assert_release(!"Vertex shader cannot be NULL!");
  950. return NULL;
  951. }
  952. if (graphicsPipelineCreateInfo->fragment_shader == NULL) {
  953. SDL_assert_release(!"Fragment shader cannot be NULL!");
  954. return NULL;
  955. }
  956. if (graphicsPipelineCreateInfo->target_info.num_color_targets > 0 && graphicsPipelineCreateInfo->target_info.color_target_descriptions == NULL) {
  957. SDL_assert_release(!"Color target descriptions array pointer cannot be NULL if num_color_targets is greater than zero!");
  958. return NULL;
  959. }
  960. for (Uint32 i = 0; i < graphicsPipelineCreateInfo->target_info.num_color_targets; i += 1) {
  961. CHECK_TEXTUREFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format, NULL);
  962. if (IsDepthFormat(graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format)) {
  963. SDL_assert_release(!"Color target formats cannot be a depth format!");
  964. return NULL;
  965. }
  966. if (!SDL_GPUTextureSupportsFormat(device, graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format, SDL_GPU_TEXTURETYPE_2D, SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
  967. SDL_assert_release(!"Format is not supported for color targets on this device!");
  968. return NULL;
  969. }
  970. if (graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].blend_state.enable_blend) {
  971. const SDL_GPUColorTargetBlendState *blend_state = &graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].blend_state;
  972. CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->src_color_blendfactor, NULL);
  973. CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->dst_color_blendfactor, NULL);
  974. CHECK_BLENDOP_ENUM_INVALID(blend_state->color_blend_op, NULL);
  975. CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->src_alpha_blendfactor, NULL);
  976. CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->dst_alpha_blendfactor, NULL);
  977. CHECK_BLENDOP_ENUM_INVALID(blend_state->alpha_blend_op, NULL);
  978. // TODO: validate that format support blending?
  979. }
  980. }
  981. if (graphicsPipelineCreateInfo->target_info.has_depth_stencil_target) {
  982. CHECK_TEXTUREFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->target_info.depth_stencil_format, NULL);
  983. if (!IsDepthFormat(graphicsPipelineCreateInfo->target_info.depth_stencil_format)) {
  984. SDL_assert_release(!"Depth-stencil target format must be a depth format!");
  985. return NULL;
  986. }
  987. if (!SDL_GPUTextureSupportsFormat(device, graphicsPipelineCreateInfo->target_info.depth_stencil_format, SDL_GPU_TEXTURETYPE_2D, SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
  988. SDL_assert_release(!"Format is not supported for depth targets on this device!");
  989. return NULL;
  990. }
  991. }
  992. if (graphicsPipelineCreateInfo->multisample_state.enable_alpha_to_coverage) {
  993. if (graphicsPipelineCreateInfo->target_info.num_color_targets < 1) {
  994. SDL_assert_release(!"Alpha-to-coverage enabled but no color targets present!");
  995. return NULL;
  996. }
  997. if (!FormatHasAlpha(graphicsPipelineCreateInfo->target_info.color_target_descriptions[0].format)) {
  998. SDL_assert_release(!"Format is not compatible with alpha-to-coverage!");
  999. return NULL;
  1000. }
  1001. // TODO: validate that format supports belnding? This is only required on Metal.
  1002. }
  1003. if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers > 0 && graphicsPipelineCreateInfo->vertex_input_state.vertex_buffer_descriptions == NULL) {
  1004. SDL_assert_release(!"Vertex buffer descriptions array pointer cannot be NULL!");
  1005. return NULL;
  1006. }
  1007. if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers > MAX_VERTEX_BUFFERS) {
  1008. SDL_COMPILE_TIME_ASSERT(vertex_buffers, MAX_VERTEX_BUFFERS == 16);
  1009. SDL_assert_release(!"The number of vertex buffer descriptions in a vertex input state must not exceed 16!");
  1010. return NULL;
  1011. }
  1012. if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes > 0 && graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes == NULL) {
  1013. SDL_assert_release(!"Vertex attributes array pointer cannot be NULL!");
  1014. return NULL;
  1015. }
  1016. if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes > MAX_VERTEX_ATTRIBUTES) {
  1017. SDL_COMPILE_TIME_ASSERT(vertex_attributes, MAX_VERTEX_ATTRIBUTES == 16);
  1018. SDL_assert_release(!"The number of vertex attributes in a vertex input state must not exceed 16!");
  1019. return NULL;
  1020. }
  1021. for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers; i += 1) {
  1022. if (graphicsPipelineCreateInfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate != 0) {
  1023. SDL_assert_release(!"For all vertex buffer descriptions, instance_step_rate must be 0!");
  1024. return NULL;
  1025. }
  1026. }
  1027. Uint32 locations[MAX_VERTEX_ATTRIBUTES];
  1028. for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes; i += 1) {
  1029. CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].format, NULL);
  1030. locations[i] = graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].location;
  1031. for (Uint32 j = 0; j < i; j += 1) {
  1032. if (locations[j] == locations[i]) {
  1033. SDL_assert_release(!"Each vertex attribute location in a vertex input state must be unique!");
  1034. return NULL;
  1035. }
  1036. }
  1037. }
  1038. if (graphicsPipelineCreateInfo->multisample_state.enable_mask) {
  1039. SDL_assert_release(!"For multisample states, enable_mask must be false!");
  1040. return NULL;
  1041. }
  1042. if (graphicsPipelineCreateInfo->multisample_state.sample_mask != 0) {
  1043. SDL_assert_release(!"For multisample states, sample_mask must be 0!");
  1044. return NULL;
  1045. }
  1046. if (graphicsPipelineCreateInfo->depth_stencil_state.enable_depth_test) {
  1047. CHECK_COMPAREOP_ENUM_INVALID(graphicsPipelineCreateInfo->depth_stencil_state.compare_op, NULL);
  1048. }
  1049. if (graphicsPipelineCreateInfo->depth_stencil_state.enable_stencil_test) {
  1050. const SDL_GPUStencilOpState *stencil_state = &graphicsPipelineCreateInfo->depth_stencil_state.back_stencil_state;
  1051. CHECK_COMPAREOP_ENUM_INVALID(stencil_state->compare_op, NULL);
  1052. CHECK_STENCILOP_ENUM_INVALID(stencil_state->fail_op, NULL);
  1053. CHECK_STENCILOP_ENUM_INVALID(stencil_state->pass_op, NULL);
  1054. CHECK_STENCILOP_ENUM_INVALID(stencil_state->depth_fail_op, NULL);
  1055. }
  1056. if (device->validate_feature_depth_clamp_disabled &&
  1057. !graphicsPipelineCreateInfo->rasterizer_state.enable_depth_clip) {
  1058. SDL_assert_release(!"Rasterizer state enable_depth_clip must be set to true (FEATURE_DEPTH_CLAMPING disabled)");
  1059. return NULL;
  1060. }
  1061. }
  1062. return device->CreateGraphicsPipeline(
  1063. device->driverData,
  1064. graphicsPipelineCreateInfo);
  1065. }
  1066. SDL_GPUSampler *SDL_CreateGPUSampler(
  1067. SDL_GPUDevice *device,
  1068. const SDL_GPUSamplerCreateInfo *createinfo)
  1069. {
  1070. CHECK_DEVICE_MAGIC(device, NULL);
  1071. CHECK_PARAM(createinfo == NULL) {
  1072. SDL_InvalidParamError("createinfo");
  1073. return NULL;
  1074. }
  1075. if (device->debug_mode) {
  1076. if (device->validate_feature_anisotropy_disabled &&
  1077. createinfo->enable_anisotropy) {
  1078. SDL_assert_release(!"enable_anisotropy must be set to false (FEATURE_ANISOTROPY disabled)");
  1079. return NULL;
  1080. }
  1081. }
  1082. return device->CreateSampler(
  1083. device->driverData,
  1084. createinfo);
  1085. }
  1086. SDL_GPUShader *SDL_CreateGPUShader(
  1087. SDL_GPUDevice *device,
  1088. const SDL_GPUShaderCreateInfo *createinfo)
  1089. {
  1090. CHECK_DEVICE_MAGIC(device, NULL);
  1091. CHECK_PARAM(createinfo == NULL) {
  1092. SDL_InvalidParamError("createinfo");
  1093. return NULL;
  1094. }
  1095. if (device->debug_mode) {
  1096. if (createinfo->format == SDL_GPU_SHADERFORMAT_INVALID) {
  1097. SDL_assert_release(!"Shader format cannot be INVALID!");
  1098. return NULL;
  1099. }
  1100. if (!(createinfo->format & device->shader_formats)) {
  1101. SDL_assert_release(!"Incompatible shader format for GPU backend");
  1102. return NULL;
  1103. }
  1104. if (createinfo->num_samplers > MAX_TEXTURE_SAMPLERS_PER_STAGE) {
  1105. SDL_COMPILE_TIME_ASSERT(shader_texture_samplers, MAX_TEXTURE_SAMPLERS_PER_STAGE == 16);
  1106. SDL_assert_release(!"Shader sampler count cannot be higher than 16!");
  1107. return NULL;
  1108. }
  1109. if (createinfo->num_storage_textures > MAX_STORAGE_TEXTURES_PER_STAGE) {
  1110. SDL_COMPILE_TIME_ASSERT(shader_storage_textures, MAX_STORAGE_TEXTURES_PER_STAGE == 8);
  1111. SDL_assert_release(!"Shader storage texture count cannot be higher than 8!");
  1112. return NULL;
  1113. }
  1114. if (createinfo->num_storage_buffers > MAX_STORAGE_BUFFERS_PER_STAGE) {
  1115. SDL_COMPILE_TIME_ASSERT(shader_storage_buffers, MAX_STORAGE_BUFFERS_PER_STAGE == 8);
  1116. SDL_assert_release(!"Shader storage buffer count cannot be higher than 8!");
  1117. return NULL;
  1118. }
  1119. if (createinfo->num_uniform_buffers > MAX_UNIFORM_BUFFERS_PER_STAGE) {
  1120. SDL_COMPILE_TIME_ASSERT(shader_uniform_buffers, MAX_UNIFORM_BUFFERS_PER_STAGE == 4);
  1121. SDL_assert_release(!"Shader uniform buffer count cannot be higher than 4!");
  1122. return NULL;
  1123. }
  1124. }
  1125. return device->CreateShader(
  1126. device->driverData,
  1127. createinfo);
  1128. }
  1129. SDL_GPUTexture *SDL_CreateGPUTexture(
  1130. SDL_GPUDevice *device,
  1131. const SDL_GPUTextureCreateInfo *createinfo)
  1132. {
  1133. CHECK_DEVICE_MAGIC(device, NULL);
  1134. CHECK_PARAM(createinfo == NULL) {
  1135. SDL_InvalidParamError("createinfo");
  1136. return NULL;
  1137. }
  1138. if (device->debug_mode) {
  1139. bool failed = false;
  1140. const Uint32 MAX_2D_DIMENSION = 16384;
  1141. const Uint32 MAX_3D_DIMENSION = 2048;
  1142. // Common checks for all texture types
  1143. CHECK_TEXTUREFORMAT_ENUM_INVALID(createinfo->format, NULL);
  1144. if (createinfo->width <= 0 || createinfo->height <= 0 || createinfo->layer_count_or_depth <= 0) {
  1145. SDL_assert_release(!"For any texture: width, height, and layer_count_or_depth must be >= 1");
  1146. failed = true;
  1147. }
  1148. if (createinfo->num_levels <= 0) {
  1149. SDL_assert_release(!"For any texture: num_levels must be >= 1");
  1150. failed = true;
  1151. }
  1152. if ((createinfo->usage & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) && (createinfo->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER)) {
  1153. SDL_assert_release(!"For any texture: usage cannot contain both GRAPHICS_STORAGE_READ and SAMPLER");
  1154. failed = true;
  1155. }
  1156. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1 &&
  1157. (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER |
  1158. SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ |
  1159. SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ |
  1160. SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE))) {
  1161. SDL_assert_release(!"For multisample textures: usage cannot contain SAMPLER or STORAGE flags");
  1162. failed = true;
  1163. }
  1164. if (IsDepthFormat(createinfo->format) && (createinfo->usage & ~(SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER))) {
  1165. SDL_assert_release(!"For depth textures: usage cannot contain any flags except for DEPTH_STENCIL_TARGET and SAMPLER");
  1166. failed = true;
  1167. }
  1168. if (IsIntegerFormat(createinfo->format) && (createinfo->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER)) {
  1169. SDL_assert_release(!"For any texture: usage cannot contain SAMPLER for textures with an integer format");
  1170. failed = true;
  1171. }
  1172. if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE) {
  1173. // Cubemap validation
  1174. if (createinfo->width != createinfo->height) {
  1175. SDL_assert_release(!"For cube textures: width and height must be identical");
  1176. failed = true;
  1177. }
  1178. if (createinfo->width > MAX_2D_DIMENSION || createinfo->height > MAX_2D_DIMENSION) {
  1179. SDL_assert_release(!"For cube textures: width and height must be <= 16384");
  1180. failed = true;
  1181. }
  1182. if (createinfo->layer_count_or_depth != 6) {
  1183. SDL_assert_release(!"For cube textures: layer_count_or_depth must be 6");
  1184. failed = true;
  1185. }
  1186. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) {
  1187. SDL_assert_release(!"For cube textures: sample_count must be SDL_GPU_SAMPLECOUNT_1");
  1188. failed = true;
  1189. }
  1190. if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_CUBE, createinfo->usage)) {
  1191. SDL_assert_release(!"For cube textures: the format is unsupported for the given usage");
  1192. failed = true;
  1193. }
  1194. } else if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
  1195. // Cubemap array validation
  1196. if (createinfo->width != createinfo->height) {
  1197. SDL_assert_release(!"For cube array textures: width and height must be identical");
  1198. failed = true;
  1199. }
  1200. if (createinfo->width > MAX_2D_DIMENSION || createinfo->height > MAX_2D_DIMENSION) {
  1201. SDL_assert_release(!"For cube array textures: width and height must be <= 16384");
  1202. failed = true;
  1203. }
  1204. if (createinfo->layer_count_or_depth % 6 != 0) {
  1205. SDL_assert_release(!"For cube array textures: layer_count_or_depth must be a multiple of 6");
  1206. failed = true;
  1207. }
  1208. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) {
  1209. SDL_assert_release(!"For cube array textures: sample_count must be SDL_GPU_SAMPLECOUNT_1");
  1210. failed = true;
  1211. }
  1212. if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_CUBE_ARRAY, createinfo->usage)) {
  1213. SDL_assert_release(!"For cube array textures: the format is unsupported for the given usage");
  1214. failed = true;
  1215. }
  1216. } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) {
  1217. // 3D Texture Validation
  1218. if (createinfo->width > MAX_3D_DIMENSION || createinfo->height > MAX_3D_DIMENSION || createinfo->layer_count_or_depth > MAX_3D_DIMENSION) {
  1219. SDL_assert_release(!"For 3D textures: width, height, and layer_count_or_depth must be <= 2048");
  1220. failed = true;
  1221. }
  1222. if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
  1223. SDL_assert_release(!"For 3D textures: usage must not contain DEPTH_STENCIL_TARGET");
  1224. failed = true;
  1225. }
  1226. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) {
  1227. SDL_assert_release(!"For 3D textures: sample_count must be SDL_GPU_SAMPLECOUNT_1");
  1228. failed = true;
  1229. }
  1230. if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_3D, createinfo->usage)) {
  1231. SDL_assert_release(!"For 3D textures: the format is unsupported for the given usage");
  1232. failed = true;
  1233. }
  1234. } else {
  1235. if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) {
  1236. // Array Texture Validation
  1237. if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
  1238. SDL_assert_release(!"For array textures: usage must not contain DEPTH_STENCIL_TARGET");
  1239. failed = true;
  1240. }
  1241. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) {
  1242. SDL_assert_release(!"For array textures: sample_count must be SDL_GPU_SAMPLECOUNT_1");
  1243. failed = true;
  1244. }
  1245. }
  1246. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1 && createinfo->num_levels > 1) {
  1247. SDL_assert_release(!"For 2D multisample textures: num_levels must be 1");
  1248. failed = true;
  1249. }
  1250. if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_2D, createinfo->usage)) {
  1251. SDL_assert_release(!"For 2D textures: the format is unsupported for the given usage");
  1252. failed = true;
  1253. }
  1254. }
  1255. if (failed) {
  1256. return NULL;
  1257. }
  1258. }
  1259. return device->CreateTexture(
  1260. device->driverData,
  1261. createinfo);
  1262. }
  1263. SDL_GPUBuffer *SDL_CreateGPUBuffer(
  1264. SDL_GPUDevice *device,
  1265. const SDL_GPUBufferCreateInfo *createinfo)
  1266. {
  1267. CHECK_DEVICE_MAGIC(device, NULL);
  1268. CHECK_PARAM(createinfo == NULL) {
  1269. SDL_InvalidParamError("createinfo");
  1270. return NULL;
  1271. }
  1272. if (device->debug_mode) {
  1273. if (createinfo->size < 4) {
  1274. SDL_assert_release(!"Cannot create a buffer with size less than 4 bytes!");
  1275. }
  1276. }
  1277. const char *debugName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, NULL);
  1278. return device->CreateBuffer(
  1279. device->driverData,
  1280. createinfo->usage,
  1281. createinfo->size,
  1282. debugName);
  1283. }
  1284. SDL_GPUTransferBuffer *SDL_CreateGPUTransferBuffer(
  1285. SDL_GPUDevice *device,
  1286. const SDL_GPUTransferBufferCreateInfo *createinfo)
  1287. {
  1288. CHECK_DEVICE_MAGIC(device, NULL);
  1289. CHECK_PARAM(createinfo == NULL) {
  1290. SDL_InvalidParamError("createinfo");
  1291. return NULL;
  1292. }
  1293. const char *debugName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TRANSFERBUFFER_CREATE_NAME_STRING, NULL);
  1294. return device->CreateTransferBuffer(
  1295. device->driverData,
  1296. createinfo->usage,
  1297. createinfo->size,
  1298. debugName);
  1299. }
  1300. // Debug Naming
  1301. void SDL_SetGPUBufferName(
  1302. SDL_GPUDevice *device,
  1303. SDL_GPUBuffer *buffer,
  1304. const char *text)
  1305. {
  1306. CHECK_DEVICE_MAGIC(device, );
  1307. CHECK_PARAM(buffer == NULL) {
  1308. SDL_InvalidParamError("buffer");
  1309. return;
  1310. }
  1311. CHECK_PARAM(text == NULL) {
  1312. SDL_InvalidParamError("text");
  1313. }
  1314. device->SetBufferName(
  1315. device->driverData,
  1316. buffer,
  1317. text);
  1318. }
  1319. void SDL_SetGPUTextureName(
  1320. SDL_GPUDevice *device,
  1321. SDL_GPUTexture *texture,
  1322. const char *text)
  1323. {
  1324. CHECK_DEVICE_MAGIC(device, );
  1325. CHECK_PARAM(texture == NULL) {
  1326. SDL_InvalidParamError("texture");
  1327. return;
  1328. }
  1329. CHECK_PARAM(text == NULL) {
  1330. SDL_InvalidParamError("text");
  1331. }
  1332. device->SetTextureName(
  1333. device->driverData,
  1334. texture,
  1335. text);
  1336. }
  1337. void SDL_InsertGPUDebugLabel(
  1338. SDL_GPUCommandBuffer *command_buffer,
  1339. const char *text)
  1340. {
  1341. CHECK_PARAM(command_buffer == NULL) {
  1342. SDL_InvalidParamError("command_buffer");
  1343. return;
  1344. }
  1345. CHECK_PARAM(text == NULL) {
  1346. SDL_InvalidParamError("text");
  1347. return;
  1348. }
  1349. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1350. CHECK_COMMAND_BUFFER
  1351. }
  1352. COMMAND_BUFFER_DEVICE->InsertDebugLabel(
  1353. command_buffer,
  1354. text);
  1355. }
  1356. void SDL_PushGPUDebugGroup(
  1357. SDL_GPUCommandBuffer *command_buffer,
  1358. const char *name)
  1359. {
  1360. CHECK_PARAM(command_buffer == NULL) {
  1361. SDL_InvalidParamError("command_buffer");
  1362. return;
  1363. }
  1364. CHECK_PARAM(name == NULL) {
  1365. SDL_InvalidParamError("name");
  1366. return;
  1367. }
  1368. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1369. CHECK_COMMAND_BUFFER
  1370. }
  1371. COMMAND_BUFFER_DEVICE->PushDebugGroup(
  1372. command_buffer,
  1373. name);
  1374. }
  1375. void SDL_PopGPUDebugGroup(
  1376. SDL_GPUCommandBuffer *command_buffer)
  1377. {
  1378. CHECK_PARAM(command_buffer == NULL) {
  1379. SDL_InvalidParamError("command_buffer");
  1380. return;
  1381. }
  1382. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1383. CHECK_COMMAND_BUFFER
  1384. }
  1385. COMMAND_BUFFER_DEVICE->PopDebugGroup(
  1386. command_buffer);
  1387. }
  1388. // Disposal
  1389. void SDL_ReleaseGPUTexture(
  1390. SDL_GPUDevice *device,
  1391. SDL_GPUTexture *texture)
  1392. {
  1393. CHECK_DEVICE_MAGIC(device, );
  1394. CHECK_PARAM(texture == NULL) {
  1395. return;
  1396. }
  1397. device->ReleaseTexture(
  1398. device->driverData,
  1399. texture);
  1400. }
  1401. void SDL_ReleaseGPUSampler(
  1402. SDL_GPUDevice *device,
  1403. SDL_GPUSampler *sampler)
  1404. {
  1405. CHECK_DEVICE_MAGIC(device, );
  1406. CHECK_PARAM(sampler == NULL) {
  1407. return;
  1408. }
  1409. device->ReleaseSampler(
  1410. device->driverData,
  1411. sampler);
  1412. }
  1413. void SDL_ReleaseGPUBuffer(
  1414. SDL_GPUDevice *device,
  1415. SDL_GPUBuffer *buffer)
  1416. {
  1417. CHECK_DEVICE_MAGIC(device, );
  1418. CHECK_PARAM(buffer == NULL) {
  1419. return;
  1420. }
  1421. device->ReleaseBuffer(
  1422. device->driverData,
  1423. buffer);
  1424. }
  1425. void SDL_ReleaseGPUTransferBuffer(
  1426. SDL_GPUDevice *device,
  1427. SDL_GPUTransferBuffer *transfer_buffer)
  1428. {
  1429. CHECK_DEVICE_MAGIC(device, );
  1430. CHECK_PARAM(transfer_buffer == NULL) {
  1431. return;
  1432. }
  1433. device->ReleaseTransferBuffer(
  1434. device->driverData,
  1435. transfer_buffer);
  1436. }
  1437. void SDL_ReleaseGPUShader(
  1438. SDL_GPUDevice *device,
  1439. SDL_GPUShader *shader)
  1440. {
  1441. CHECK_DEVICE_MAGIC(device, );
  1442. CHECK_PARAM(shader == NULL) {
  1443. return;
  1444. }
  1445. device->ReleaseShader(
  1446. device->driverData,
  1447. shader);
  1448. }
  1449. void SDL_ReleaseGPUComputePipeline(
  1450. SDL_GPUDevice *device,
  1451. SDL_GPUComputePipeline *compute_pipeline)
  1452. {
  1453. CHECK_DEVICE_MAGIC(device, );
  1454. CHECK_PARAM(compute_pipeline == NULL) {
  1455. return;
  1456. }
  1457. device->ReleaseComputePipeline(
  1458. device->driverData,
  1459. compute_pipeline);
  1460. }
  1461. void SDL_ReleaseGPUGraphicsPipeline(
  1462. SDL_GPUDevice *device,
  1463. SDL_GPUGraphicsPipeline *graphics_pipeline)
  1464. {
  1465. CHECK_DEVICE_MAGIC(device, );
  1466. CHECK_PARAM(graphics_pipeline == NULL) {
  1467. return;
  1468. }
  1469. device->ReleaseGraphicsPipeline(
  1470. device->driverData,
  1471. graphics_pipeline);
  1472. }
  1473. // Command Buffer
  1474. SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer(
  1475. SDL_GPUDevice *device)
  1476. {
  1477. SDL_GPUCommandBuffer *command_buffer;
  1478. CommandBufferCommonHeader *commandBufferHeader;
  1479. CHECK_DEVICE_MAGIC(device, NULL);
  1480. command_buffer = device->AcquireCommandBuffer(
  1481. device->driverData);
  1482. if (command_buffer == NULL) {
  1483. return NULL;
  1484. }
  1485. commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  1486. commandBufferHeader->device = device;
  1487. commandBufferHeader->render_pass.command_buffer = command_buffer;
  1488. commandBufferHeader->compute_pass.command_buffer = command_buffer;
  1489. commandBufferHeader->copy_pass.command_buffer = command_buffer;
  1490. if (device->debug_mode) {
  1491. commandBufferHeader->render_pass.in_progress = false;
  1492. commandBufferHeader->render_pass.graphics_pipeline = NULL;
  1493. commandBufferHeader->compute_pass.in_progress = false;
  1494. commandBufferHeader->compute_pass.compute_pipeline = NULL;
  1495. commandBufferHeader->copy_pass.in_progress = false;
  1496. commandBufferHeader->swapchain_texture_acquired = false;
  1497. commandBufferHeader->submitted = false;
  1498. commandBufferHeader->ignore_render_pass_texture_validation = false;
  1499. SDL_zeroa(commandBufferHeader->render_pass.vertex_sampler_bound);
  1500. SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_texture_bound);
  1501. SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_buffer_bound);
  1502. SDL_zeroa(commandBufferHeader->render_pass.fragment_sampler_bound);
  1503. SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_texture_bound);
  1504. SDL_zeroa(commandBufferHeader->render_pass.fragment_storage_buffer_bound);
  1505. SDL_zeroa(commandBufferHeader->compute_pass.sampler_bound);
  1506. SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_texture_bound);
  1507. SDL_zeroa(commandBufferHeader->compute_pass.read_only_storage_buffer_bound);
  1508. SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_texture_bound);
  1509. SDL_zeroa(commandBufferHeader->compute_pass.read_write_storage_buffer_bound);
  1510. }
  1511. return command_buffer;
  1512. }
  1513. // Uniforms
  1514. void SDL_PushGPUVertexUniformData(
  1515. SDL_GPUCommandBuffer *command_buffer,
  1516. Uint32 slot_index,
  1517. const void *data,
  1518. Uint32 length)
  1519. {
  1520. CHECK_PARAM(command_buffer == NULL) {
  1521. SDL_InvalidParamError("command_buffer");
  1522. return;
  1523. }
  1524. CHECK_PARAM(data == NULL) {
  1525. SDL_InvalidParamError("data");
  1526. return;
  1527. }
  1528. CHECK_PARAM(slot_index >= MAX_UNIFORM_BUFFERS_PER_STAGE) {
  1529. SDL_SetError("slot_index exceeds MAX_UNIFORM_BUFFERS_PER_STAGE");
  1530. return;
  1531. }
  1532. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1533. CHECK_COMMAND_BUFFER
  1534. }
  1535. COMMAND_BUFFER_DEVICE->PushVertexUniformData(
  1536. command_buffer,
  1537. slot_index,
  1538. data,
  1539. length);
  1540. }
  1541. void SDL_PushGPUFragmentUniformData(
  1542. SDL_GPUCommandBuffer *command_buffer,
  1543. Uint32 slot_index,
  1544. const void *data,
  1545. Uint32 length)
  1546. {
  1547. CHECK_PARAM(command_buffer == NULL) {
  1548. SDL_InvalidParamError("command_buffer");
  1549. return;
  1550. }
  1551. CHECK_PARAM(data == NULL) {
  1552. SDL_InvalidParamError("data");
  1553. return;
  1554. }
  1555. CHECK_PARAM(slot_index >= MAX_UNIFORM_BUFFERS_PER_STAGE) {
  1556. SDL_SetError("slot_index exceeds MAX_UNIFORM_BUFFERS_PER_STAGE");
  1557. return;
  1558. }
  1559. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1560. CHECK_COMMAND_BUFFER
  1561. }
  1562. COMMAND_BUFFER_DEVICE->PushFragmentUniformData(
  1563. command_buffer,
  1564. slot_index,
  1565. data,
  1566. length);
  1567. }
  1568. void SDL_PushGPUComputeUniformData(
  1569. SDL_GPUCommandBuffer *command_buffer,
  1570. Uint32 slot_index,
  1571. const void *data,
  1572. Uint32 length)
  1573. {
  1574. CHECK_PARAM(command_buffer == NULL) {
  1575. SDL_InvalidParamError("command_buffer");
  1576. return;
  1577. }
  1578. CHECK_PARAM(data == NULL) {
  1579. SDL_InvalidParamError("data");
  1580. return;
  1581. }
  1582. CHECK_PARAM(slot_index >= MAX_UNIFORM_BUFFERS_PER_STAGE) {
  1583. SDL_SetError("slot_index exceeds MAX_UNIFORM_BUFFERS_PER_STAGE");
  1584. return;
  1585. }
  1586. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1587. CHECK_COMMAND_BUFFER
  1588. }
  1589. COMMAND_BUFFER_DEVICE->PushComputeUniformData(
  1590. command_buffer,
  1591. slot_index,
  1592. data,
  1593. length);
  1594. }
  1595. // Render Pass
  1596. SDL_GPURenderPass *SDL_BeginGPURenderPass(
  1597. SDL_GPUCommandBuffer *command_buffer,
  1598. const SDL_GPUColorTargetInfo *color_target_infos,
  1599. Uint32 num_color_targets,
  1600. const SDL_GPUDepthStencilTargetInfo *depth_stencil_target_info)
  1601. {
  1602. CommandBufferCommonHeader *commandBufferHeader;
  1603. CHECK_PARAM(command_buffer == NULL) {
  1604. SDL_InvalidParamError("command_buffer");
  1605. return NULL;
  1606. }
  1607. CHECK_PARAM(color_target_infos == NULL && num_color_targets > 0) {
  1608. SDL_InvalidParamError("color_target_infos");
  1609. return NULL;
  1610. }
  1611. CHECK_PARAM(num_color_targets > MAX_COLOR_TARGET_BINDINGS) {
  1612. SDL_SetError("num_color_targets exceeds MAX_COLOR_TARGET_BINDINGS");
  1613. return NULL;
  1614. }
  1615. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1616. CHECK_COMMAND_BUFFER_RETURN_NULL
  1617. CHECK_ANY_PASS_IN_PROGRESS("Cannot begin render pass during another pass!", NULL);
  1618. for (Uint32 i = 0; i < num_color_targets; i += 1) {
  1619. TextureCommonHeader *textureHeader = (TextureCommonHeader *)color_target_infos[i].texture;
  1620. if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) {
  1621. SDL_assert_release(!"Cannot cycle color target when load op is LOAD!");
  1622. return NULL;
  1623. }
  1624. if (color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE || color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
  1625. if (color_target_infos[i].resolve_texture == NULL) {
  1626. SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but resolve_texture is NULL!");
  1627. return NULL;
  1628. } else {
  1629. TextureCommonHeader *resolveTextureHeader = (TextureCommonHeader *)color_target_infos[i].resolve_texture;
  1630. if (textureHeader->info.sample_count == SDL_GPU_SAMPLECOUNT_1) {
  1631. SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but texture is not multisample!");
  1632. return NULL;
  1633. }
  1634. if (resolveTextureHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) {
  1635. SDL_assert_release(!"Resolve texture must have a sample count of 1!");
  1636. return NULL;
  1637. }
  1638. if (resolveTextureHeader->info.format != textureHeader->info.format) {
  1639. SDL_assert_release(!"Resolve texture must have the same format as its corresponding color target!");
  1640. return NULL;
  1641. }
  1642. if (resolveTextureHeader->info.type == SDL_GPU_TEXTURETYPE_3D) {
  1643. SDL_assert_release(!"Resolve texture must not be of TEXTURETYPE_3D!");
  1644. return NULL;
  1645. }
  1646. if (!(resolveTextureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
  1647. SDL_assert_release(!"Resolve texture usage must include COLOR_TARGET!");
  1648. return NULL;
  1649. }
  1650. }
  1651. }
  1652. if (color_target_infos[i].layer_or_depth_plane >= textureHeader->info.layer_count_or_depth) {
  1653. SDL_assert_release(!"Color target layer index must be less than the texture's layer count!");
  1654. return NULL;
  1655. }
  1656. if (color_target_infos[i].mip_level >= textureHeader->info.num_levels) {
  1657. SDL_assert_release(!"Color target mip level must be less than the texture's level count!");
  1658. return NULL;
  1659. }
  1660. }
  1661. if (depth_stencil_target_info != NULL) {
  1662. TextureCommonHeader *textureHeader = (TextureCommonHeader *)depth_stencil_target_info->texture;
  1663. if (!(textureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
  1664. SDL_assert_release(!"Depth target must have been created with the DEPTH_STENCIL_TARGET usage flag!");
  1665. return NULL;
  1666. }
  1667. if (textureHeader->info.layer_count_or_depth > 255) {
  1668. SDL_assert_release(!"Cannot bind a depth texture with more than 255 layers!");
  1669. return NULL;
  1670. }
  1671. if (depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->stencil_load_op == SDL_GPU_LOADOP_LOAD)) {
  1672. SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!");
  1673. return NULL;
  1674. }
  1675. if (depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE ||
  1676. depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE ||
  1677. depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE ||
  1678. depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
  1679. SDL_assert_release(!"RESOLVE store ops are not supported for depth-stencil targets!");
  1680. return NULL;
  1681. }
  1682. }
  1683. }
  1684. COMMAND_BUFFER_DEVICE->BeginRenderPass(
  1685. command_buffer,
  1686. color_target_infos,
  1687. num_color_targets,
  1688. depth_stencil_target_info);
  1689. commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  1690. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1691. commandBufferHeader->render_pass.in_progress = true;
  1692. for (Uint32 i = 0; i < num_color_targets; i += 1) {
  1693. commandBufferHeader->render_pass.color_targets[i] = color_target_infos[i].texture;
  1694. }
  1695. commandBufferHeader->render_pass.num_color_targets = num_color_targets;
  1696. if (depth_stencil_target_info != NULL) {
  1697. commandBufferHeader->render_pass.depth_stencil_target = depth_stencil_target_info->texture;
  1698. } else {
  1699. commandBufferHeader->render_pass.depth_stencil_target = NULL;
  1700. }
  1701. }
  1702. return (SDL_GPURenderPass *)&(commandBufferHeader->render_pass);
  1703. }
  1704. void SDL_BindGPUGraphicsPipeline(
  1705. SDL_GPURenderPass *render_pass,
  1706. SDL_GPUGraphicsPipeline *graphics_pipeline)
  1707. {
  1708. CHECK_PARAM(render_pass == NULL) {
  1709. SDL_InvalidParamError("render_pass");
  1710. return;
  1711. }
  1712. CHECK_PARAM(graphics_pipeline == NULL) {
  1713. SDL_InvalidParamError("graphics_pipeline");
  1714. return;
  1715. }
  1716. RENDERPASS_DEVICE->BindGraphicsPipeline(
  1717. RENDERPASS_COMMAND_BUFFER,
  1718. graphics_pipeline);
  1719. if (RENDERPASS_DEVICE->debug_mode) {
  1720. RENDERPASS_BOUND_PIPELINE = graphics_pipeline;
  1721. }
  1722. }
  1723. void SDL_SetGPUViewport(
  1724. SDL_GPURenderPass *render_pass,
  1725. const SDL_GPUViewport *viewport)
  1726. {
  1727. CHECK_PARAM(render_pass == NULL) {
  1728. SDL_InvalidParamError("render_pass");
  1729. return;
  1730. }
  1731. CHECK_PARAM(viewport == NULL) {
  1732. SDL_InvalidParamError("viewport");
  1733. return;
  1734. }
  1735. if (RENDERPASS_DEVICE->debug_mode) {
  1736. CHECK_RENDERPASS
  1737. }
  1738. RENDERPASS_DEVICE->SetViewport(
  1739. RENDERPASS_COMMAND_BUFFER,
  1740. viewport);
  1741. }
  1742. void SDL_SetGPUScissor(
  1743. SDL_GPURenderPass *render_pass,
  1744. const SDL_Rect *scissor)
  1745. {
  1746. CHECK_PARAM(render_pass == NULL) {
  1747. SDL_InvalidParamError("render_pass");
  1748. return;
  1749. }
  1750. CHECK_PARAM(scissor == NULL) {
  1751. SDL_InvalidParamError("scissor");
  1752. return;
  1753. }
  1754. if (RENDERPASS_DEVICE->debug_mode) {
  1755. CHECK_RENDERPASS
  1756. }
  1757. RENDERPASS_DEVICE->SetScissor(
  1758. RENDERPASS_COMMAND_BUFFER,
  1759. scissor);
  1760. }
  1761. void SDL_SetGPUBlendConstants(
  1762. SDL_GPURenderPass *render_pass,
  1763. SDL_FColor blend_constants)
  1764. {
  1765. CHECK_PARAM(render_pass == NULL) {
  1766. SDL_InvalidParamError("render_pass");
  1767. return;
  1768. }
  1769. if (RENDERPASS_DEVICE->debug_mode) {
  1770. CHECK_RENDERPASS
  1771. }
  1772. RENDERPASS_DEVICE->SetBlendConstants(
  1773. RENDERPASS_COMMAND_BUFFER,
  1774. blend_constants);
  1775. }
  1776. void SDL_SetGPUStencilReference(
  1777. SDL_GPURenderPass *render_pass,
  1778. Uint8 reference)
  1779. {
  1780. CHECK_PARAM(render_pass == NULL) {
  1781. SDL_InvalidParamError("render_pass");
  1782. return;
  1783. }
  1784. if (RENDERPASS_DEVICE->debug_mode) {
  1785. CHECK_RENDERPASS
  1786. }
  1787. RENDERPASS_DEVICE->SetStencilReference(
  1788. RENDERPASS_COMMAND_BUFFER,
  1789. reference);
  1790. }
  1791. void SDL_BindGPUVertexBuffers(
  1792. SDL_GPURenderPass *render_pass,
  1793. Uint32 first_binding,
  1794. const SDL_GPUBufferBinding *bindings,
  1795. Uint32 num_bindings)
  1796. {
  1797. CHECK_PARAM(render_pass == NULL) {
  1798. SDL_InvalidParamError("render_pass");
  1799. return;
  1800. }
  1801. if (bindings == NULL && num_bindings > 0) {
  1802. SDL_InvalidParamError("bindings");
  1803. return;
  1804. }
  1805. if (RENDERPASS_DEVICE->debug_mode) {
  1806. CHECK_RENDERPASS
  1807. }
  1808. RENDERPASS_DEVICE->BindVertexBuffers(
  1809. RENDERPASS_COMMAND_BUFFER,
  1810. first_binding,
  1811. bindings,
  1812. num_bindings);
  1813. }
  1814. void SDL_BindGPUIndexBuffer(
  1815. SDL_GPURenderPass *render_pass,
  1816. const SDL_GPUBufferBinding *binding,
  1817. SDL_GPUIndexElementSize index_element_size)
  1818. {
  1819. CHECK_PARAM(render_pass == NULL) {
  1820. SDL_InvalidParamError("render_pass");
  1821. return;
  1822. }
  1823. if (binding == NULL) {
  1824. SDL_InvalidParamError("binding");
  1825. return;
  1826. }
  1827. if (RENDERPASS_DEVICE->debug_mode) {
  1828. CHECK_RENDERPASS
  1829. }
  1830. RENDERPASS_DEVICE->BindIndexBuffer(
  1831. RENDERPASS_COMMAND_BUFFER,
  1832. binding,
  1833. index_element_size);
  1834. }
  1835. void SDL_BindGPUVertexSamplers(
  1836. SDL_GPURenderPass *render_pass,
  1837. Uint32 first_slot,
  1838. const SDL_GPUTextureSamplerBinding *texture_sampler_bindings,
  1839. Uint32 num_bindings)
  1840. {
  1841. CHECK_PARAM(render_pass == NULL) {
  1842. SDL_InvalidParamError("render_pass");
  1843. return;
  1844. }
  1845. CHECK_PARAM(texture_sampler_bindings == NULL && num_bindings > 0) {
  1846. SDL_InvalidParamError("texture_sampler_bindings");
  1847. return;
  1848. }
  1849. CHECK_PARAM(first_slot + num_bindings > MAX_TEXTURE_SAMPLERS_PER_STAGE) {
  1850. SDL_SetError("first_slot + num_bindings exceeds MAX_TEXTURE_SAMPLERS_PER_STAGE");
  1851. return;
  1852. }
  1853. if (RENDERPASS_DEVICE->debug_mode) {
  1854. CHECK_RENDERPASS
  1855. if (!((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation)
  1856. {
  1857. CHECK_SAMPLER_TEXTURES
  1858. }
  1859. for (Uint32 i = 0; i < num_bindings; i += 1) {
  1860. ((RenderPass *)render_pass)->vertex_sampler_bound[first_slot + i] = true;
  1861. }
  1862. }
  1863. RENDERPASS_DEVICE->BindVertexSamplers(
  1864. RENDERPASS_COMMAND_BUFFER,
  1865. first_slot,
  1866. texture_sampler_bindings,
  1867. num_bindings);
  1868. }
  1869. void SDL_BindGPUVertexStorageTextures(
  1870. SDL_GPURenderPass *render_pass,
  1871. Uint32 first_slot,
  1872. SDL_GPUTexture *const *storage_textures,
  1873. Uint32 num_bindings)
  1874. {
  1875. CHECK_PARAM(render_pass == NULL) {
  1876. SDL_InvalidParamError("render_pass");
  1877. return;
  1878. }
  1879. CHECK_PARAM(storage_textures == NULL && num_bindings > 0) {
  1880. SDL_InvalidParamError("storage_textures");
  1881. return;
  1882. }
  1883. CHECK_PARAM(first_slot + num_bindings > MAX_STORAGE_TEXTURES_PER_STAGE) {
  1884. SDL_SetError("first_slot + num_bindings exceeds MAX_STORAGE_TEXTURES_PER_STAGE");
  1885. return;
  1886. }
  1887. if (RENDERPASS_DEVICE->debug_mode) {
  1888. CHECK_RENDERPASS
  1889. CHECK_STORAGE_TEXTURES
  1890. for (Uint32 i = 0; i < num_bindings; i += 1) {
  1891. ((RenderPass *)render_pass)->vertex_storage_texture_bound[first_slot + i] = true;
  1892. }
  1893. }
  1894. RENDERPASS_DEVICE->BindVertexStorageTextures(
  1895. RENDERPASS_COMMAND_BUFFER,
  1896. first_slot,
  1897. storage_textures,
  1898. num_bindings);
  1899. }
  1900. void SDL_BindGPUVertexStorageBuffers(
  1901. SDL_GPURenderPass *render_pass,
  1902. Uint32 first_slot,
  1903. SDL_GPUBuffer *const *storage_buffers,
  1904. Uint32 num_bindings)
  1905. {
  1906. CHECK_PARAM(render_pass == NULL) {
  1907. SDL_InvalidParamError("render_pass");
  1908. return;
  1909. }
  1910. CHECK_PARAM(storage_buffers == NULL && num_bindings > 0) {
  1911. SDL_InvalidParamError("storage_buffers");
  1912. return;
  1913. }
  1914. CHECK_PARAM(first_slot + num_bindings > MAX_STORAGE_BUFFERS_PER_STAGE) {
  1915. SDL_SetError("first_slot + num_bindings exceeds MAX_STORAGE_BUFFERS_PER_STAGE");
  1916. return;
  1917. }
  1918. if (RENDERPASS_DEVICE->debug_mode) {
  1919. CHECK_RENDERPASS
  1920. for (Uint32 i = 0; i < num_bindings; i += 1) {
  1921. ((RenderPass *)render_pass)->vertex_storage_buffer_bound[first_slot + i] = true;
  1922. }
  1923. }
  1924. RENDERPASS_DEVICE->BindVertexStorageBuffers(
  1925. RENDERPASS_COMMAND_BUFFER,
  1926. first_slot,
  1927. storage_buffers,
  1928. num_bindings);
  1929. }
  1930. void SDL_BindGPUFragmentSamplers(
  1931. SDL_GPURenderPass *render_pass,
  1932. Uint32 first_slot,
  1933. const SDL_GPUTextureSamplerBinding *texture_sampler_bindings,
  1934. Uint32 num_bindings)
  1935. {
  1936. CHECK_PARAM(render_pass == NULL) {
  1937. SDL_InvalidParamError("render_pass");
  1938. return;
  1939. }
  1940. CHECK_PARAM(texture_sampler_bindings == NULL && num_bindings > 0) {
  1941. SDL_InvalidParamError("texture_sampler_bindings");
  1942. return;
  1943. }
  1944. CHECK_PARAM(first_slot + num_bindings > MAX_TEXTURE_SAMPLERS_PER_STAGE) {
  1945. SDL_SetError("first_slot + num_bindings exceeds MAX_TEXTURE_SAMPLERS_PER_STAGE");
  1946. return;
  1947. }
  1948. if (RENDERPASS_DEVICE->debug_mode) {
  1949. CHECK_RENDERPASS
  1950. if (!((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation) {
  1951. CHECK_SAMPLER_TEXTURES
  1952. }
  1953. for (Uint32 i = 0; i < num_bindings; i += 1) {
  1954. ((RenderPass *)render_pass)->fragment_sampler_bound[first_slot + i] = true;
  1955. }
  1956. }
  1957. RENDERPASS_DEVICE->BindFragmentSamplers(
  1958. RENDERPASS_COMMAND_BUFFER,
  1959. first_slot,
  1960. texture_sampler_bindings,
  1961. num_bindings);
  1962. }
  1963. void SDL_BindGPUFragmentStorageTextures(
  1964. SDL_GPURenderPass *render_pass,
  1965. Uint32 first_slot,
  1966. SDL_GPUTexture *const *storage_textures,
  1967. Uint32 num_bindings)
  1968. {
  1969. CHECK_PARAM(render_pass == NULL) {
  1970. SDL_InvalidParamError("render_pass");
  1971. return;
  1972. }
  1973. CHECK_PARAM(storage_textures == NULL && num_bindings > 0) {
  1974. SDL_InvalidParamError("storage_textures");
  1975. return;
  1976. }
  1977. CHECK_PARAM(first_slot + num_bindings > MAX_STORAGE_TEXTURES_PER_STAGE) {
  1978. SDL_SetError("first_slot + num_bindings exceeds MAX_STORAGE_TEXTURES_PER_STAGE");
  1979. return;
  1980. }
  1981. if (RENDERPASS_DEVICE->debug_mode) {
  1982. CHECK_RENDERPASS
  1983. CHECK_STORAGE_TEXTURES
  1984. for (Uint32 i = 0; i < num_bindings; i += 1) {
  1985. ((RenderPass *)render_pass)->fragment_storage_texture_bound[first_slot + i] = true;
  1986. }
  1987. }
  1988. RENDERPASS_DEVICE->BindFragmentStorageTextures(
  1989. RENDERPASS_COMMAND_BUFFER,
  1990. first_slot,
  1991. storage_textures,
  1992. num_bindings);
  1993. }
  1994. void SDL_BindGPUFragmentStorageBuffers(
  1995. SDL_GPURenderPass *render_pass,
  1996. Uint32 first_slot,
  1997. SDL_GPUBuffer *const *storage_buffers,
  1998. Uint32 num_bindings)
  1999. {
  2000. CHECK_PARAM(render_pass == NULL) {
  2001. SDL_InvalidParamError("render_pass");
  2002. return;
  2003. }
  2004. CHECK_PARAM(storage_buffers == NULL && num_bindings > 0) {
  2005. SDL_InvalidParamError("storage_buffers");
  2006. return;
  2007. }
  2008. CHECK_PARAM(first_slot + num_bindings > MAX_STORAGE_BUFFERS_PER_STAGE) {
  2009. SDL_SetError("first_slot + num_bindings exceeds MAX_STORAGE_BUFFERS_PER_STAGE");
  2010. return;
  2011. }
  2012. if (RENDERPASS_DEVICE->debug_mode) {
  2013. CHECK_RENDERPASS
  2014. for (Uint32 i = 0; i < num_bindings; i += 1) {
  2015. ((RenderPass *)render_pass)->fragment_storage_buffer_bound[first_slot + i] = true;
  2016. }
  2017. }
  2018. RENDERPASS_DEVICE->BindFragmentStorageBuffers(
  2019. RENDERPASS_COMMAND_BUFFER,
  2020. first_slot,
  2021. storage_buffers,
  2022. num_bindings);
  2023. }
  2024. void SDL_DrawGPUIndexedPrimitives(
  2025. SDL_GPURenderPass *render_pass,
  2026. Uint32 num_indices,
  2027. Uint32 num_instances,
  2028. Uint32 first_index,
  2029. Sint32 vertex_offset,
  2030. Uint32 first_instance)
  2031. {
  2032. CHECK_PARAM(render_pass == NULL) {
  2033. SDL_InvalidParamError("render_pass");
  2034. return;
  2035. }
  2036. if (RENDERPASS_DEVICE->debug_mode) {
  2037. CHECK_RENDERPASS
  2038. CHECK_GRAPHICS_PIPELINE_BOUND
  2039. SDL_GPU_CheckGraphicsBindings(render_pass);
  2040. }
  2041. RENDERPASS_DEVICE->DrawIndexedPrimitives(
  2042. RENDERPASS_COMMAND_BUFFER,
  2043. num_indices,
  2044. num_instances,
  2045. first_index,
  2046. vertex_offset,
  2047. first_instance);
  2048. }
  2049. void SDL_DrawGPUPrimitives(
  2050. SDL_GPURenderPass *render_pass,
  2051. Uint32 num_vertices,
  2052. Uint32 num_instances,
  2053. Uint32 first_vertex,
  2054. Uint32 first_instance)
  2055. {
  2056. CHECK_PARAM(render_pass == NULL) {
  2057. SDL_InvalidParamError("render_pass");
  2058. return;
  2059. }
  2060. if (RENDERPASS_DEVICE->debug_mode) {
  2061. CHECK_RENDERPASS
  2062. CHECK_GRAPHICS_PIPELINE_BOUND
  2063. SDL_GPU_CheckGraphicsBindings(render_pass);
  2064. }
  2065. RENDERPASS_DEVICE->DrawPrimitives(
  2066. RENDERPASS_COMMAND_BUFFER,
  2067. num_vertices,
  2068. num_instances,
  2069. first_vertex,
  2070. first_instance);
  2071. }
  2072. void SDL_DrawGPUPrimitivesIndirect(
  2073. SDL_GPURenderPass *render_pass,
  2074. SDL_GPUBuffer *buffer,
  2075. Uint32 offset,
  2076. Uint32 draw_count)
  2077. {
  2078. CHECK_PARAM(render_pass == NULL) {
  2079. SDL_InvalidParamError("render_pass");
  2080. return;
  2081. }
  2082. CHECK_PARAM(buffer == NULL) {
  2083. SDL_InvalidParamError("buffer");
  2084. return;
  2085. }
  2086. if (RENDERPASS_DEVICE->debug_mode) {
  2087. CHECK_RENDERPASS
  2088. CHECK_GRAPHICS_PIPELINE_BOUND
  2089. SDL_GPU_CheckGraphicsBindings(render_pass);
  2090. }
  2091. RENDERPASS_DEVICE->DrawPrimitivesIndirect(
  2092. RENDERPASS_COMMAND_BUFFER,
  2093. buffer,
  2094. offset,
  2095. draw_count);
  2096. }
  2097. void SDL_DrawGPUIndexedPrimitivesIndirect(
  2098. SDL_GPURenderPass *render_pass,
  2099. SDL_GPUBuffer *buffer,
  2100. Uint32 offset,
  2101. Uint32 draw_count)
  2102. {
  2103. CHECK_PARAM(render_pass == NULL) {
  2104. SDL_InvalidParamError("render_pass");
  2105. return;
  2106. }
  2107. CHECK_PARAM(buffer == NULL) {
  2108. SDL_InvalidParamError("buffer");
  2109. return;
  2110. }
  2111. if (RENDERPASS_DEVICE->debug_mode) {
  2112. CHECK_RENDERPASS
  2113. CHECK_GRAPHICS_PIPELINE_BOUND
  2114. SDL_GPU_CheckGraphicsBindings(render_pass);
  2115. }
  2116. RENDERPASS_DEVICE->DrawIndexedPrimitivesIndirect(
  2117. RENDERPASS_COMMAND_BUFFER,
  2118. buffer,
  2119. offset,
  2120. draw_count);
  2121. }
  2122. void SDL_EndGPURenderPass(
  2123. SDL_GPURenderPass *render_pass)
  2124. {
  2125. CHECK_PARAM(render_pass == NULL) {
  2126. SDL_InvalidParamError("render_pass");
  2127. return;
  2128. }
  2129. CommandBufferCommonHeader *commandBufferCommonHeader;
  2130. commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
  2131. if (RENDERPASS_DEVICE->debug_mode) {
  2132. CHECK_RENDERPASS
  2133. }
  2134. RENDERPASS_DEVICE->EndRenderPass(
  2135. RENDERPASS_COMMAND_BUFFER);
  2136. if (RENDERPASS_DEVICE->debug_mode) {
  2137. commandBufferCommonHeader->render_pass.in_progress = false;
  2138. for (Uint32 i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1)
  2139. {
  2140. commandBufferCommonHeader->render_pass.color_targets[i] = NULL;
  2141. }
  2142. commandBufferCommonHeader->render_pass.num_color_targets = 0;
  2143. commandBufferCommonHeader->render_pass.depth_stencil_target = NULL;
  2144. commandBufferCommonHeader->render_pass.graphics_pipeline = NULL;
  2145. SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_sampler_bound);
  2146. SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_storage_texture_bound);
  2147. SDL_zeroa(commandBufferCommonHeader->render_pass.vertex_storage_buffer_bound);
  2148. SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_sampler_bound);
  2149. SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_storage_texture_bound);
  2150. SDL_zeroa(commandBufferCommonHeader->render_pass.fragment_storage_buffer_bound);
  2151. }
  2152. }
  2153. // Compute Pass
  2154. SDL_GPUComputePass *SDL_BeginGPUComputePass(
  2155. SDL_GPUCommandBuffer *command_buffer,
  2156. const SDL_GPUStorageTextureReadWriteBinding *storage_texture_bindings,
  2157. Uint32 num_storage_texture_bindings,
  2158. const SDL_GPUStorageBufferReadWriteBinding *storage_buffer_bindings,
  2159. Uint32 num_storage_buffer_bindings)
  2160. {
  2161. CommandBufferCommonHeader *commandBufferHeader;
  2162. CHECK_PARAM(command_buffer == NULL) {
  2163. SDL_InvalidParamError("command_buffer");
  2164. return NULL;
  2165. }
  2166. CHECK_PARAM(storage_texture_bindings == NULL && num_storage_texture_bindings > 0) {
  2167. SDL_InvalidParamError("storage_texture_bindings");
  2168. return NULL;
  2169. }
  2170. CHECK_PARAM(storage_buffer_bindings == NULL && num_storage_buffer_bindings > 0) {
  2171. SDL_InvalidParamError("storage_buffer_bindings");
  2172. return NULL;
  2173. }
  2174. CHECK_PARAM(num_storage_texture_bindings > MAX_COMPUTE_WRITE_TEXTURES) {
  2175. SDL_InvalidParamError("num_storage_texture_bindings");
  2176. return NULL;
  2177. }
  2178. CHECK_PARAM(num_storage_buffer_bindings > MAX_COMPUTE_WRITE_BUFFERS) {
  2179. SDL_InvalidParamError("num_storage_buffer_bindings");
  2180. return NULL;
  2181. }
  2182. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2183. CHECK_COMMAND_BUFFER_RETURN_NULL
  2184. CHECK_ANY_PASS_IN_PROGRESS("Cannot begin compute pass during another pass!", NULL);
  2185. for (Uint32 i = 0; i < num_storage_texture_bindings; i += 1) {
  2186. TextureCommonHeader *header = (TextureCommonHeader *)storage_texture_bindings[i].texture;
  2187. if (!(header->info.usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) && !(header->info.usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) {
  2188. SDL_assert_release(!"Texture must be created with COMPUTE_STORAGE_WRITE or COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE flag");
  2189. return NULL;
  2190. }
  2191. if (storage_texture_bindings[i].layer >= header->info.layer_count_or_depth) {
  2192. SDL_assert_release(!"Storage texture layer index must be less than the texture's layer count!");
  2193. return NULL;
  2194. }
  2195. if (storage_texture_bindings[i].mip_level >= header->info.num_levels) {
  2196. SDL_assert_release(!"Storage texture mip level must be less than the texture's level count!");
  2197. return NULL;
  2198. }
  2199. }
  2200. // TODO: validate buffer usage?
  2201. }
  2202. COMMAND_BUFFER_DEVICE->BeginComputePass(
  2203. command_buffer,
  2204. storage_texture_bindings,
  2205. num_storage_texture_bindings,
  2206. storage_buffer_bindings,
  2207. num_storage_buffer_bindings);
  2208. commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2209. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2210. commandBufferHeader->compute_pass.in_progress = true;
  2211. for (Uint32 i = 0; i < num_storage_texture_bindings; i += 1) {
  2212. commandBufferHeader->compute_pass.read_write_storage_texture_bound[i] = true;
  2213. }
  2214. for (Uint32 i = 0; i < num_storage_buffer_bindings; i += 1) {
  2215. commandBufferHeader->compute_pass.read_write_storage_buffer_bound[i] = true;
  2216. }
  2217. }
  2218. return (SDL_GPUComputePass *)&(commandBufferHeader->compute_pass);
  2219. }
  2220. void SDL_BindGPUComputePipeline(
  2221. SDL_GPUComputePass *compute_pass,
  2222. SDL_GPUComputePipeline *compute_pipeline)
  2223. {
  2224. CHECK_PARAM(compute_pass == NULL) {
  2225. SDL_InvalidParamError("compute_pass");
  2226. return;
  2227. }
  2228. CHECK_PARAM(compute_pipeline == NULL) {
  2229. SDL_InvalidParamError("compute_pipeline");
  2230. return;
  2231. }
  2232. if (COMPUTEPASS_DEVICE->debug_mode) {
  2233. CHECK_COMPUTEPASS
  2234. }
  2235. COMPUTEPASS_DEVICE->BindComputePipeline(
  2236. COMPUTEPASS_COMMAND_BUFFER,
  2237. compute_pipeline);
  2238. if (COMPUTEPASS_DEVICE->debug_mode) {
  2239. COMPUTEPASS_BOUND_PIPELINE = compute_pipeline;
  2240. }
  2241. }
  2242. void SDL_BindGPUComputeSamplers(
  2243. SDL_GPUComputePass *compute_pass,
  2244. Uint32 first_slot,
  2245. const SDL_GPUTextureSamplerBinding *texture_sampler_bindings,
  2246. Uint32 num_bindings)
  2247. {
  2248. CHECK_PARAM(compute_pass == NULL) {
  2249. SDL_InvalidParamError("compute_pass");
  2250. return;
  2251. }
  2252. CHECK_PARAM(texture_sampler_bindings == NULL && num_bindings > 0) {
  2253. SDL_InvalidParamError("texture_sampler_bindings");
  2254. return;
  2255. }
  2256. CHECK_PARAM(first_slot + num_bindings > MAX_TEXTURE_SAMPLERS_PER_STAGE) {
  2257. SDL_SetError("first_slot + num_bindings exceeds MAX_TEXTURE_SAMPLERS_PER_STAGE");
  2258. return;
  2259. }
  2260. if (COMPUTEPASS_DEVICE->debug_mode) {
  2261. CHECK_COMPUTEPASS
  2262. for (Uint32 i = 0; i < num_bindings; i += 1) {
  2263. ((ComputePass *)compute_pass)->sampler_bound[first_slot + i] = true;
  2264. }
  2265. }
  2266. COMPUTEPASS_DEVICE->BindComputeSamplers(
  2267. COMPUTEPASS_COMMAND_BUFFER,
  2268. first_slot,
  2269. texture_sampler_bindings,
  2270. num_bindings);
  2271. }
  2272. void SDL_BindGPUComputeStorageTextures(
  2273. SDL_GPUComputePass *compute_pass,
  2274. Uint32 first_slot,
  2275. SDL_GPUTexture *const *storage_textures,
  2276. Uint32 num_bindings)
  2277. {
  2278. CHECK_PARAM(compute_pass == NULL) {
  2279. SDL_InvalidParamError("compute_pass");
  2280. return;
  2281. }
  2282. CHECK_PARAM(storage_textures == NULL && num_bindings > 0) {
  2283. SDL_InvalidParamError("storage_textures");
  2284. return;
  2285. }
  2286. CHECK_PARAM(first_slot + num_bindings > MAX_STORAGE_TEXTURES_PER_STAGE) {
  2287. SDL_SetError("first_slot + num_bindings exceeds MAX_STORAGE_TEXTURES_PER_STAGE");
  2288. return;
  2289. }
  2290. if (COMPUTEPASS_DEVICE->debug_mode) {
  2291. CHECK_COMPUTEPASS
  2292. for (Uint32 i = 0; i < num_bindings; i += 1) {
  2293. ((ComputePass *)compute_pass)->read_only_storage_texture_bound[first_slot + i] = true;
  2294. }
  2295. }
  2296. COMPUTEPASS_DEVICE->BindComputeStorageTextures(
  2297. COMPUTEPASS_COMMAND_BUFFER,
  2298. first_slot,
  2299. storage_textures,
  2300. num_bindings);
  2301. }
  2302. void SDL_BindGPUComputeStorageBuffers(
  2303. SDL_GPUComputePass *compute_pass,
  2304. Uint32 first_slot,
  2305. SDL_GPUBuffer *const *storage_buffers,
  2306. Uint32 num_bindings)
  2307. {
  2308. CHECK_PARAM(compute_pass == NULL) {
  2309. SDL_InvalidParamError("compute_pass");
  2310. return;
  2311. }
  2312. CHECK_PARAM(storage_buffers == NULL && num_bindings > 0) {
  2313. SDL_InvalidParamError("storage_buffers");
  2314. return;
  2315. }
  2316. CHECK_PARAM(first_slot + num_bindings > MAX_STORAGE_BUFFERS_PER_STAGE) {
  2317. SDL_SetError("first_slot + num_bindings exceeds MAX_STORAGE_BUFFERS_PER_STAGE");
  2318. return;
  2319. }
  2320. if (COMPUTEPASS_DEVICE->debug_mode) {
  2321. CHECK_COMPUTEPASS
  2322. for (Uint32 i = 0; i < num_bindings; i += 1) {
  2323. ((ComputePass *)compute_pass)->read_only_storage_buffer_bound[first_slot + i] = true;
  2324. }
  2325. }
  2326. COMPUTEPASS_DEVICE->BindComputeStorageBuffers(
  2327. COMPUTEPASS_COMMAND_BUFFER,
  2328. first_slot,
  2329. storage_buffers,
  2330. num_bindings);
  2331. }
  2332. void SDL_DispatchGPUCompute(
  2333. SDL_GPUComputePass *compute_pass,
  2334. Uint32 groupcount_x,
  2335. Uint32 groupcount_y,
  2336. Uint32 groupcount_z)
  2337. {
  2338. CHECK_PARAM(compute_pass == NULL) {
  2339. SDL_InvalidParamError("compute_pass");
  2340. return;
  2341. }
  2342. if (COMPUTEPASS_DEVICE->debug_mode) {
  2343. CHECK_COMPUTEPASS
  2344. CHECK_COMPUTE_PIPELINE_BOUND
  2345. SDL_GPU_CheckComputeBindings(compute_pass);
  2346. }
  2347. COMPUTEPASS_DEVICE->DispatchCompute(
  2348. COMPUTEPASS_COMMAND_BUFFER,
  2349. groupcount_x,
  2350. groupcount_y,
  2351. groupcount_z);
  2352. }
  2353. void SDL_DispatchGPUComputeIndirect(
  2354. SDL_GPUComputePass *compute_pass,
  2355. SDL_GPUBuffer *buffer,
  2356. Uint32 offset)
  2357. {
  2358. CHECK_PARAM(compute_pass == NULL) {
  2359. SDL_InvalidParamError("compute_pass");
  2360. return;
  2361. }
  2362. if (COMPUTEPASS_DEVICE->debug_mode) {
  2363. CHECK_COMPUTEPASS
  2364. CHECK_COMPUTE_PIPELINE_BOUND
  2365. SDL_GPU_CheckComputeBindings(compute_pass);
  2366. }
  2367. COMPUTEPASS_DEVICE->DispatchComputeIndirect(
  2368. COMPUTEPASS_COMMAND_BUFFER,
  2369. buffer,
  2370. offset);
  2371. }
  2372. void SDL_EndGPUComputePass(
  2373. SDL_GPUComputePass *compute_pass)
  2374. {
  2375. CommandBufferCommonHeader *commandBufferCommonHeader;
  2376. CHECK_PARAM(compute_pass == NULL) {
  2377. SDL_InvalidParamError("compute_pass");
  2378. return;
  2379. }
  2380. if (COMPUTEPASS_DEVICE->debug_mode) {
  2381. CHECK_COMPUTEPASS
  2382. }
  2383. COMPUTEPASS_DEVICE->EndComputePass(
  2384. COMPUTEPASS_COMMAND_BUFFER);
  2385. if (COMPUTEPASS_DEVICE->debug_mode) {
  2386. commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
  2387. commandBufferCommonHeader->compute_pass.in_progress = false;
  2388. commandBufferCommonHeader->compute_pass.compute_pipeline = NULL;
  2389. SDL_zeroa(commandBufferCommonHeader->compute_pass.sampler_bound);
  2390. SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_texture_bound);
  2391. SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_buffer_bound);
  2392. SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_texture_bound);
  2393. SDL_zeroa(commandBufferCommonHeader->compute_pass.read_write_storage_buffer_bound);
  2394. }
  2395. }
  2396. // TransferBuffer Data
  2397. void *SDL_MapGPUTransferBuffer(
  2398. SDL_GPUDevice *device,
  2399. SDL_GPUTransferBuffer *transfer_buffer,
  2400. bool cycle)
  2401. {
  2402. CHECK_DEVICE_MAGIC(device, NULL);
  2403. CHECK_PARAM(transfer_buffer == NULL) {
  2404. SDL_InvalidParamError("transfer_buffer");
  2405. return NULL;
  2406. }
  2407. return device->MapTransferBuffer(
  2408. device->driverData,
  2409. transfer_buffer,
  2410. cycle);
  2411. }
  2412. void SDL_UnmapGPUTransferBuffer(
  2413. SDL_GPUDevice *device,
  2414. SDL_GPUTransferBuffer *transfer_buffer)
  2415. {
  2416. CHECK_DEVICE_MAGIC(device, );
  2417. CHECK_PARAM(transfer_buffer == NULL) {
  2418. SDL_InvalidParamError("transfer_buffer");
  2419. return;
  2420. }
  2421. device->UnmapTransferBuffer(
  2422. device->driverData,
  2423. transfer_buffer);
  2424. }
  2425. // Copy Pass
  2426. SDL_GPUCopyPass *SDL_BeginGPUCopyPass(
  2427. SDL_GPUCommandBuffer *command_buffer)
  2428. {
  2429. CommandBufferCommonHeader *commandBufferHeader;
  2430. CHECK_PARAM(command_buffer == NULL) {
  2431. SDL_InvalidParamError("command_buffer");
  2432. return NULL;
  2433. }
  2434. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2435. CHECK_COMMAND_BUFFER_RETURN_NULL
  2436. CHECK_ANY_PASS_IN_PROGRESS("Cannot begin copy pass during another pass!", NULL);
  2437. }
  2438. COMMAND_BUFFER_DEVICE->BeginCopyPass(
  2439. command_buffer);
  2440. commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2441. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2442. commandBufferHeader->copy_pass.in_progress = true;
  2443. }
  2444. return (SDL_GPUCopyPass *)&(commandBufferHeader->copy_pass);
  2445. }
  2446. void SDL_UploadToGPUTexture(
  2447. SDL_GPUCopyPass *copy_pass,
  2448. const SDL_GPUTextureTransferInfo *source,
  2449. const SDL_GPUTextureRegion *destination,
  2450. bool cycle)
  2451. {
  2452. CHECK_PARAM(copy_pass == NULL) {
  2453. SDL_InvalidParamError("copy_pass");
  2454. return;
  2455. }
  2456. CHECK_PARAM(source == NULL) {
  2457. SDL_InvalidParamError("source");
  2458. return;
  2459. }
  2460. if (destination == NULL) {
  2461. SDL_InvalidParamError("destination");
  2462. return;
  2463. }
  2464. if (COPYPASS_DEVICE->debug_mode) {
  2465. CHECK_COPYPASS
  2466. if (source->transfer_buffer == NULL) {
  2467. SDL_assert_release(!"Source transfer buffer cannot be NULL!");
  2468. return;
  2469. }
  2470. if (destination->texture == NULL) {
  2471. SDL_assert_release(!"Destination texture cannot be NULL!");
  2472. return;
  2473. }
  2474. }
  2475. COPYPASS_DEVICE->UploadToTexture(
  2476. COPYPASS_COMMAND_BUFFER,
  2477. source,
  2478. destination,
  2479. cycle);
  2480. }
  2481. void SDL_UploadToGPUBuffer(
  2482. SDL_GPUCopyPass *copy_pass,
  2483. const SDL_GPUTransferBufferLocation *source,
  2484. const SDL_GPUBufferRegion *destination,
  2485. bool cycle)
  2486. {
  2487. CHECK_PARAM(copy_pass == NULL) {
  2488. SDL_InvalidParamError("copy_pass");
  2489. return;
  2490. }
  2491. CHECK_PARAM(source == NULL) {
  2492. SDL_InvalidParamError("source");
  2493. return;
  2494. }
  2495. CHECK_PARAM(destination == NULL) {
  2496. SDL_InvalidParamError("destination");
  2497. return;
  2498. }
  2499. if (COPYPASS_DEVICE->debug_mode) {
  2500. CHECK_COPYPASS
  2501. if (source->transfer_buffer == NULL) {
  2502. SDL_assert_release(!"Source transfer buffer cannot be NULL!");
  2503. return;
  2504. }
  2505. if (destination->buffer == NULL) {
  2506. SDL_assert_release(!"Destination buffer cannot be NULL!");
  2507. return;
  2508. }
  2509. }
  2510. COPYPASS_DEVICE->UploadToBuffer(
  2511. COPYPASS_COMMAND_BUFFER,
  2512. source,
  2513. destination,
  2514. cycle);
  2515. }
  2516. void SDL_CopyGPUTextureToTexture(
  2517. SDL_GPUCopyPass *copy_pass,
  2518. const SDL_GPUTextureLocation *source,
  2519. const SDL_GPUTextureLocation *destination,
  2520. Uint32 w,
  2521. Uint32 h,
  2522. Uint32 d,
  2523. bool cycle)
  2524. {
  2525. CHECK_PARAM(copy_pass == NULL) {
  2526. SDL_InvalidParamError("copy_pass");
  2527. return;
  2528. }
  2529. CHECK_PARAM(source == NULL) {
  2530. SDL_InvalidParamError("source");
  2531. return;
  2532. }
  2533. CHECK_PARAM(destination == NULL) {
  2534. SDL_InvalidParamError("destination");
  2535. return;
  2536. }
  2537. if (COPYPASS_DEVICE->debug_mode) {
  2538. CHECK_COPYPASS
  2539. if (source->texture == NULL) {
  2540. SDL_assert_release(!"Source texture cannot be NULL!");
  2541. return;
  2542. }
  2543. if (destination->texture == NULL) {
  2544. SDL_assert_release(!"Destination texture cannot be NULL!");
  2545. return;
  2546. }
  2547. TextureCommonHeader *srcHeader = (TextureCommonHeader *)source->texture;
  2548. TextureCommonHeader *dstHeader = (TextureCommonHeader *)destination->texture;
  2549. if (srcHeader->info.format != dstHeader->info.format) {
  2550. SDL_assert_release(!"Source and destination textures must have the same format!");
  2551. return;
  2552. }
  2553. }
  2554. COPYPASS_DEVICE->CopyTextureToTexture(
  2555. COPYPASS_COMMAND_BUFFER,
  2556. source,
  2557. destination,
  2558. w,
  2559. h,
  2560. d,
  2561. cycle);
  2562. }
  2563. void SDL_CopyGPUBufferToBuffer(
  2564. SDL_GPUCopyPass *copy_pass,
  2565. const SDL_GPUBufferLocation *source,
  2566. const SDL_GPUBufferLocation *destination,
  2567. Uint32 size,
  2568. bool cycle)
  2569. {
  2570. CHECK_PARAM(copy_pass == NULL) {
  2571. SDL_InvalidParamError("copy_pass");
  2572. return;
  2573. }
  2574. CHECK_PARAM(source == NULL) {
  2575. SDL_InvalidParamError("source");
  2576. return;
  2577. }
  2578. CHECK_PARAM(destination == NULL) {
  2579. SDL_InvalidParamError("destination");
  2580. return;
  2581. }
  2582. if (COPYPASS_DEVICE->debug_mode) {
  2583. CHECK_COPYPASS
  2584. if (source->buffer == NULL) {
  2585. SDL_assert_release(!"Source buffer cannot be NULL!");
  2586. return;
  2587. }
  2588. if (destination->buffer == NULL) {
  2589. SDL_assert_release(!"Destination buffer cannot be NULL!");
  2590. return;
  2591. }
  2592. }
  2593. COPYPASS_DEVICE->CopyBufferToBuffer(
  2594. COPYPASS_COMMAND_BUFFER,
  2595. source,
  2596. destination,
  2597. size,
  2598. cycle);
  2599. }
  2600. void SDL_DownloadFromGPUTexture(
  2601. SDL_GPUCopyPass *copy_pass,
  2602. const SDL_GPUTextureRegion *source,
  2603. const SDL_GPUTextureTransferInfo *destination)
  2604. {
  2605. CHECK_PARAM(copy_pass == NULL) {
  2606. SDL_InvalidParamError("copy_pass");
  2607. return;
  2608. }
  2609. CHECK_PARAM(source == NULL) {
  2610. SDL_InvalidParamError("source");
  2611. return;
  2612. }
  2613. CHECK_PARAM(destination == NULL) {
  2614. SDL_InvalidParamError("destination");
  2615. return;
  2616. }
  2617. if (COPYPASS_DEVICE->debug_mode) {
  2618. CHECK_COPYPASS
  2619. if (source->texture == NULL) {
  2620. SDL_assert_release(!"Source texture cannot be NULL!");
  2621. return;
  2622. }
  2623. if (destination->transfer_buffer == NULL) {
  2624. SDL_assert_release(!"Destination transfer buffer cannot be NULL!");
  2625. return;
  2626. }
  2627. }
  2628. COPYPASS_DEVICE->DownloadFromTexture(
  2629. COPYPASS_COMMAND_BUFFER,
  2630. source,
  2631. destination);
  2632. }
  2633. void SDL_DownloadFromGPUBuffer(
  2634. SDL_GPUCopyPass *copy_pass,
  2635. const SDL_GPUBufferRegion *source,
  2636. const SDL_GPUTransferBufferLocation *destination)
  2637. {
  2638. CHECK_PARAM(copy_pass == NULL) {
  2639. SDL_InvalidParamError("copy_pass");
  2640. return;
  2641. }
  2642. CHECK_PARAM(source == NULL) {
  2643. SDL_InvalidParamError("source");
  2644. return;
  2645. }
  2646. CHECK_PARAM(destination == NULL) {
  2647. SDL_InvalidParamError("destination");
  2648. return;
  2649. }
  2650. if (COPYPASS_DEVICE->debug_mode) {
  2651. CHECK_COPYPASS
  2652. if (source->buffer == NULL) {
  2653. SDL_assert_release(!"Source buffer cannot be NULL!");
  2654. return;
  2655. }
  2656. if (destination->transfer_buffer == NULL) {
  2657. SDL_assert_release(!"Destination transfer buffer cannot be NULL!");
  2658. return;
  2659. }
  2660. }
  2661. COPYPASS_DEVICE->DownloadFromBuffer(
  2662. COPYPASS_COMMAND_BUFFER,
  2663. source,
  2664. destination);
  2665. }
  2666. void SDL_EndGPUCopyPass(
  2667. SDL_GPUCopyPass *copy_pass)
  2668. {
  2669. CHECK_PARAM(copy_pass == NULL) {
  2670. SDL_InvalidParamError("copy_pass");
  2671. return;
  2672. }
  2673. if (COPYPASS_DEVICE->debug_mode) {
  2674. CHECK_COPYPASS
  2675. }
  2676. COPYPASS_DEVICE->EndCopyPass(
  2677. COPYPASS_COMMAND_BUFFER);
  2678. if (COPYPASS_DEVICE->debug_mode) {
  2679. ((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
  2680. }
  2681. }
  2682. void SDL_GenerateMipmapsForGPUTexture(
  2683. SDL_GPUCommandBuffer *command_buffer,
  2684. SDL_GPUTexture *texture)
  2685. {
  2686. CHECK_PARAM(command_buffer == NULL) {
  2687. SDL_InvalidParamError("command_buffer");
  2688. return;
  2689. }
  2690. CHECK_PARAM(texture == NULL) {
  2691. SDL_InvalidParamError("texture");
  2692. return;
  2693. }
  2694. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2695. CHECK_COMMAND_BUFFER
  2696. CHECK_ANY_PASS_IN_PROGRESS("Cannot generate mipmaps during a pass!", );
  2697. TextureCommonHeader *header = (TextureCommonHeader *)texture;
  2698. if (header->info.num_levels <= 1) {
  2699. SDL_assert_release(!"Cannot generate mipmaps for texture with num_levels <= 1!");
  2700. return;
  2701. }
  2702. if (!(header->info.usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) || !(header->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
  2703. SDL_assert_release(!"GenerateMipmaps texture must be created with SAMPLER and COLOR_TARGET usage flags!");
  2704. return;
  2705. }
  2706. CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2707. commandBufferHeader->ignore_render_pass_texture_validation = true;
  2708. }
  2709. COMMAND_BUFFER_DEVICE->GenerateMipmaps(
  2710. command_buffer,
  2711. texture);
  2712. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2713. CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2714. commandBufferHeader->ignore_render_pass_texture_validation = false;
  2715. }
  2716. }
  2717. void SDL_BlitGPUTexture(
  2718. SDL_GPUCommandBuffer *command_buffer,
  2719. const SDL_GPUBlitInfo *info)
  2720. {
  2721. CHECK_PARAM(command_buffer == NULL) {
  2722. SDL_InvalidParamError("command_buffer");
  2723. return;
  2724. }
  2725. CHECK_PARAM(info == NULL) {
  2726. SDL_InvalidParamError("info");
  2727. return;
  2728. }
  2729. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2730. CHECK_COMMAND_BUFFER
  2731. CHECK_ANY_PASS_IN_PROGRESS("Cannot blit during a pass!", );
  2732. // Validation
  2733. bool failed = false;
  2734. TextureCommonHeader *srcHeader = (TextureCommonHeader *)info->source.texture;
  2735. TextureCommonHeader *dstHeader = (TextureCommonHeader *)info->destination.texture;
  2736. if (srcHeader == NULL) {
  2737. SDL_assert_release(!"Blit source texture must be non-NULL");
  2738. return; // attempting to proceed will crash
  2739. }
  2740. if (dstHeader == NULL) {
  2741. SDL_assert_release(!"Blit destination texture must be non-NULL");
  2742. return; // attempting to proceed will crash
  2743. }
  2744. if (srcHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) {
  2745. SDL_assert_release(!"Blit source texture must have a sample count of 1");
  2746. failed = true;
  2747. }
  2748. if ((srcHeader->info.usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) == 0) {
  2749. SDL_assert_release(!"Blit source texture must be created with the SAMPLER usage flag");
  2750. failed = true;
  2751. }
  2752. if ((dstHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) == 0) {
  2753. SDL_assert_release(!"Blit destination texture must be created with the COLOR_TARGET usage flag");
  2754. failed = true;
  2755. }
  2756. if (IsDepthFormat(srcHeader->info.format)) {
  2757. SDL_assert_release(!"Blit source texture cannot have a depth format");
  2758. failed = true;
  2759. }
  2760. if (info->source.w == 0 || info->source.h == 0 || info->destination.w == 0 || info->destination.h == 0) {
  2761. SDL_assert_release(!"Blit source/destination regions must have non-zero width, height, and depth");
  2762. failed = true;
  2763. }
  2764. if (failed) {
  2765. return;
  2766. }
  2767. }
  2768. COMMAND_BUFFER_DEVICE->Blit(
  2769. command_buffer,
  2770. info);
  2771. }
  2772. // Submission/Presentation
  2773. bool SDL_WindowSupportsGPUSwapchainComposition(
  2774. SDL_GPUDevice *device,
  2775. SDL_Window *window,
  2776. SDL_GPUSwapchainComposition swapchain_composition)
  2777. {
  2778. CHECK_DEVICE_MAGIC(device, false);
  2779. CHECK_PARAM(window == NULL) {
  2780. SDL_InvalidParamError("window");
  2781. return false;
  2782. }
  2783. if (device->debug_mode) {
  2784. CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(swapchain_composition, false);
  2785. }
  2786. return device->SupportsSwapchainComposition(
  2787. device->driverData,
  2788. window,
  2789. swapchain_composition);
  2790. }
  2791. bool SDL_WindowSupportsGPUPresentMode(
  2792. SDL_GPUDevice *device,
  2793. SDL_Window *window,
  2794. SDL_GPUPresentMode present_mode)
  2795. {
  2796. CHECK_DEVICE_MAGIC(device, false);
  2797. CHECK_PARAM(window == NULL) {
  2798. SDL_InvalidParamError("window");
  2799. return false;
  2800. }
  2801. if (device->debug_mode) {
  2802. CHECK_PRESENTMODE_ENUM_INVALID(present_mode, false);
  2803. }
  2804. return device->SupportsPresentMode(
  2805. device->driverData,
  2806. window,
  2807. present_mode);
  2808. }
  2809. bool SDL_ClaimWindowForGPUDevice(
  2810. SDL_GPUDevice *device,
  2811. SDL_Window *window)
  2812. {
  2813. CHECK_DEVICE_MAGIC(device, false);
  2814. CHECK_PARAM(window == NULL) {
  2815. return SDL_InvalidParamError("window");
  2816. }
  2817. if ((window->flags & SDL_WINDOW_TRANSPARENT) != 0) {
  2818. return SDL_SetError("The GPU API doesn't support transparent windows");
  2819. }
  2820. return device->ClaimWindow(
  2821. device->driverData,
  2822. window);
  2823. }
  2824. void SDL_ReleaseWindowFromGPUDevice(
  2825. SDL_GPUDevice *device,
  2826. SDL_Window *window)
  2827. {
  2828. CHECK_DEVICE_MAGIC(device, );
  2829. CHECK_PARAM(window == NULL) {
  2830. SDL_InvalidParamError("window");
  2831. return;
  2832. }
  2833. device->ReleaseWindow(
  2834. device->driverData,
  2835. window);
  2836. }
  2837. bool SDL_SetGPUSwapchainParameters(
  2838. SDL_GPUDevice *device,
  2839. SDL_Window *window,
  2840. SDL_GPUSwapchainComposition swapchain_composition,
  2841. SDL_GPUPresentMode present_mode)
  2842. {
  2843. CHECK_DEVICE_MAGIC(device, false);
  2844. CHECK_PARAM(window == NULL) {
  2845. SDL_InvalidParamError("window");
  2846. return false;
  2847. }
  2848. if (device->debug_mode) {
  2849. CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(swapchain_composition, false);
  2850. CHECK_PRESENTMODE_ENUM_INVALID(present_mode, false);
  2851. }
  2852. return device->SetSwapchainParameters(
  2853. device->driverData,
  2854. window,
  2855. swapchain_composition,
  2856. present_mode);
  2857. }
  2858. bool SDL_SetGPUAllowedFramesInFlight(
  2859. SDL_GPUDevice *device,
  2860. Uint32 allowed_frames_in_flight)
  2861. {
  2862. CHECK_DEVICE_MAGIC(device, false);
  2863. if (device->debug_mode) {
  2864. if (allowed_frames_in_flight < 1 || allowed_frames_in_flight > 3)
  2865. {
  2866. SDL_COMPILE_TIME_ASSERT(max_frames_in_flight, MAX_FRAMES_IN_FLIGHT == 3);
  2867. SDL_assert_release(!"allowed_frames_in_flight value must be between 1 and 3!");
  2868. }
  2869. }
  2870. allowed_frames_in_flight = SDL_clamp(allowed_frames_in_flight, 1, 3);
  2871. return device->SetAllowedFramesInFlight(
  2872. device->driverData,
  2873. allowed_frames_in_flight);
  2874. }
  2875. SDL_GPUTextureFormat SDL_GetGPUSwapchainTextureFormat(
  2876. SDL_GPUDevice *device,
  2877. SDL_Window *window)
  2878. {
  2879. CHECK_DEVICE_MAGIC(device, SDL_GPU_TEXTUREFORMAT_INVALID);
  2880. CHECK_PARAM(window == NULL) {
  2881. SDL_InvalidParamError("window");
  2882. return SDL_GPU_TEXTUREFORMAT_INVALID;
  2883. }
  2884. return device->GetSwapchainTextureFormat(
  2885. device->driverData,
  2886. window);
  2887. }
  2888. bool SDL_AcquireGPUSwapchainTexture(
  2889. SDL_GPUCommandBuffer *command_buffer,
  2890. SDL_Window *window,
  2891. SDL_GPUTexture **swapchain_texture,
  2892. Uint32 *swapchain_texture_width,
  2893. Uint32 *swapchain_texture_height)
  2894. {
  2895. CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2896. CHECK_PARAM(command_buffer == NULL) {
  2897. return SDL_InvalidParamError("command_buffer");
  2898. }
  2899. CHECK_PARAM(window == NULL) {
  2900. return SDL_InvalidParamError("window");
  2901. }
  2902. CHECK_PARAM(swapchain_texture == NULL) {
  2903. return SDL_InvalidParamError("swapchain_texture");
  2904. }
  2905. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2906. CHECK_COMMAND_BUFFER_RETURN_FALSE
  2907. CHECK_ANY_PASS_IN_PROGRESS("Cannot acquire a swapchain texture during a pass!", false);
  2908. }
  2909. bool result = COMMAND_BUFFER_DEVICE->AcquireSwapchainTexture(
  2910. command_buffer,
  2911. window,
  2912. swapchain_texture,
  2913. swapchain_texture_width,
  2914. swapchain_texture_height);
  2915. if (*swapchain_texture != NULL){
  2916. commandBufferHeader->swapchain_texture_acquired = true;
  2917. }
  2918. return result;
  2919. }
  2920. bool SDL_WaitForGPUSwapchain(
  2921. SDL_GPUDevice *device,
  2922. SDL_Window *window)
  2923. {
  2924. CHECK_DEVICE_MAGIC(device, false);
  2925. CHECK_PARAM(window == NULL) {
  2926. return SDL_InvalidParamError("window");
  2927. }
  2928. return device->WaitForSwapchain(
  2929. device->driverData,
  2930. window);
  2931. }
  2932. bool SDL_WaitAndAcquireGPUSwapchainTexture(
  2933. SDL_GPUCommandBuffer *command_buffer,
  2934. SDL_Window *window,
  2935. SDL_GPUTexture **swapchain_texture,
  2936. Uint32 *swapchain_texture_width,
  2937. Uint32 *swapchain_texture_height)
  2938. {
  2939. CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2940. CHECK_PARAM(command_buffer == NULL) {
  2941. return SDL_InvalidParamError("command_buffer");
  2942. }
  2943. CHECK_PARAM(window == NULL) {
  2944. return SDL_InvalidParamError("window");
  2945. }
  2946. CHECK_PARAM(swapchain_texture == NULL) {
  2947. return SDL_InvalidParamError("swapchain_texture");
  2948. }
  2949. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2950. CHECK_COMMAND_BUFFER_RETURN_FALSE
  2951. CHECK_ANY_PASS_IN_PROGRESS("Cannot acquire a swapchain texture during a pass!", false);
  2952. }
  2953. bool result = COMMAND_BUFFER_DEVICE->WaitAndAcquireSwapchainTexture(
  2954. command_buffer,
  2955. window,
  2956. swapchain_texture,
  2957. swapchain_texture_width,
  2958. swapchain_texture_height);
  2959. if (*swapchain_texture != NULL){
  2960. commandBufferHeader->swapchain_texture_acquired = true;
  2961. }
  2962. return result;
  2963. }
  2964. bool SDL_SubmitGPUCommandBuffer(
  2965. SDL_GPUCommandBuffer *command_buffer)
  2966. {
  2967. CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2968. CHECK_PARAM(command_buffer == NULL) {
  2969. SDL_InvalidParamError("command_buffer");
  2970. return false;
  2971. }
  2972. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2973. CHECK_COMMAND_BUFFER_RETURN_FALSE
  2974. if (
  2975. commandBufferHeader->render_pass.in_progress ||
  2976. commandBufferHeader->compute_pass.in_progress ||
  2977. commandBufferHeader->copy_pass.in_progress) {
  2978. SDL_assert_release(!"Cannot submit command buffer while a pass is in progress!");
  2979. return false;
  2980. }
  2981. }
  2982. commandBufferHeader->submitted = true;
  2983. return COMMAND_BUFFER_DEVICE->Submit(
  2984. command_buffer);
  2985. }
  2986. SDL_GPUFence *SDL_SubmitGPUCommandBufferAndAcquireFence(
  2987. SDL_GPUCommandBuffer *command_buffer)
  2988. {
  2989. CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2990. CHECK_PARAM(command_buffer == NULL) {
  2991. SDL_InvalidParamError("command_buffer");
  2992. return NULL;
  2993. }
  2994. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2995. CHECK_COMMAND_BUFFER_RETURN_NULL
  2996. if (
  2997. commandBufferHeader->render_pass.in_progress ||
  2998. commandBufferHeader->compute_pass.in_progress ||
  2999. commandBufferHeader->copy_pass.in_progress) {
  3000. SDL_assert_release(!"Cannot submit command buffer while a pass is in progress!");
  3001. return NULL;
  3002. }
  3003. }
  3004. commandBufferHeader->submitted = true;
  3005. return COMMAND_BUFFER_DEVICE->SubmitAndAcquireFence(
  3006. command_buffer);
  3007. }
  3008. bool SDL_CancelGPUCommandBuffer(
  3009. SDL_GPUCommandBuffer *command_buffer)
  3010. {
  3011. CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  3012. CHECK_PARAM(command_buffer == NULL) {
  3013. SDL_InvalidParamError("command_buffer");
  3014. return false;
  3015. }
  3016. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  3017. if (commandBufferHeader->swapchain_texture_acquired) {
  3018. SDL_assert_release(!"Cannot cancel command buffer after a swapchain texture has been acquired!");
  3019. return false;
  3020. }
  3021. }
  3022. return COMMAND_BUFFER_DEVICE->Cancel(
  3023. command_buffer);
  3024. }
  3025. bool SDL_WaitForGPUIdle(
  3026. SDL_GPUDevice *device)
  3027. {
  3028. CHECK_DEVICE_MAGIC(device, false);
  3029. return device->Wait(
  3030. device->driverData);
  3031. }
  3032. bool SDL_WaitForGPUFences(
  3033. SDL_GPUDevice *device,
  3034. bool wait_all,
  3035. SDL_GPUFence *const *fences,
  3036. Uint32 num_fences)
  3037. {
  3038. CHECK_DEVICE_MAGIC(device, false);
  3039. CHECK_PARAM(fences == NULL && num_fences > 0) {
  3040. SDL_InvalidParamError("fences");
  3041. return false;
  3042. }
  3043. return device->WaitForFences(
  3044. device->driverData,
  3045. wait_all,
  3046. fences,
  3047. num_fences);
  3048. }
  3049. bool SDL_QueryGPUFence(
  3050. SDL_GPUDevice *device,
  3051. SDL_GPUFence *fence)
  3052. {
  3053. CHECK_DEVICE_MAGIC(device, false);
  3054. CHECK_PARAM(fence == NULL) {
  3055. SDL_InvalidParamError("fence");
  3056. return false;
  3057. }
  3058. return device->QueryFence(
  3059. device->driverData,
  3060. fence);
  3061. }
  3062. void SDL_ReleaseGPUFence(
  3063. SDL_GPUDevice *device,
  3064. SDL_GPUFence *fence)
  3065. {
  3066. CHECK_DEVICE_MAGIC(device, );
  3067. CHECK_PARAM(fence == NULL) {
  3068. return;
  3069. }
  3070. device->ReleaseFence(
  3071. device->driverData,
  3072. fence);
  3073. }
  3074. Uint32 SDL_CalculateGPUTextureFormatSize(
  3075. SDL_GPUTextureFormat format,
  3076. Uint32 width,
  3077. Uint32 height,
  3078. Uint32 depth_or_layer_count)
  3079. {
  3080. Uint32 blockWidth = SDL_max(Texture_GetBlockWidth(format), 1);
  3081. Uint32 blockHeight = SDL_max(Texture_GetBlockHeight(format), 1);
  3082. Uint32 blocksPerRow = (width + blockWidth - 1) / blockWidth;
  3083. Uint32 blocksPerColumn = (height + blockHeight - 1) / blockHeight;
  3084. return depth_or_layer_count * blocksPerRow * blocksPerColumn * SDL_GPUTextureFormatTexelBlockSize(format);
  3085. }
  3086. SDL_PixelFormat SDL_GetPixelFormatFromGPUTextureFormat(SDL_GPUTextureFormat format)
  3087. {
  3088. switch (format) {
  3089. case SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM:
  3090. return SDL_PIXELFORMAT_ARGB4444;
  3091. case SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM:
  3092. return SDL_PIXELFORMAT_RGB565;
  3093. case SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM:
  3094. return SDL_PIXELFORMAT_ARGB1555;
  3095. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT:
  3096. return SDL_PIXELFORMAT_RGBA32;
  3097. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM:
  3098. return SDL_PIXELFORMAT_RGBA32;
  3099. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM:
  3100. return SDL_PIXELFORMAT_RGBA32;
  3101. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB:
  3102. return SDL_PIXELFORMAT_RGBA32;
  3103. case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM:
  3104. return SDL_PIXELFORMAT_BGRA32;
  3105. case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB:
  3106. return SDL_PIXELFORMAT_BGRA32;
  3107. case SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM:
  3108. return SDL_PIXELFORMAT_ABGR2101010;
  3109. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT:
  3110. return SDL_PIXELFORMAT_RGBA64;
  3111. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM:
  3112. return SDL_PIXELFORMAT_RGBA64;
  3113. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT:
  3114. return SDL_PIXELFORMAT_RGBA64_FLOAT;
  3115. case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT:
  3116. return SDL_PIXELFORMAT_RGBA128_FLOAT;
  3117. default:
  3118. return SDL_PIXELFORMAT_UNKNOWN;
  3119. }
  3120. }
  3121. SDL_GPUTextureFormat SDL_GetGPUTextureFormatFromPixelFormat(SDL_PixelFormat format)
  3122. {
  3123. switch (format) {
  3124. case SDL_PIXELFORMAT_ARGB4444:
  3125. return SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM;
  3126. case SDL_PIXELFORMAT_RGB565:
  3127. return SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM;
  3128. case SDL_PIXELFORMAT_ARGB1555:
  3129. return SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM;
  3130. case SDL_PIXELFORMAT_BGRA32:
  3131. case SDL_PIXELFORMAT_BGRX32:
  3132. return SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
  3133. case SDL_PIXELFORMAT_RGBA32:
  3134. case SDL_PIXELFORMAT_RGBX32:
  3135. return SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
  3136. case SDL_PIXELFORMAT_ABGR2101010:
  3137. return SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM;
  3138. case SDL_PIXELFORMAT_RGBA64:
  3139. return SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM;
  3140. case SDL_PIXELFORMAT_RGBA64_FLOAT:
  3141. return SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT;
  3142. case SDL_PIXELFORMAT_RGBA128_FLOAT:
  3143. return SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT;
  3144. default:
  3145. return SDL_GPU_TEXTUREFORMAT_INVALID;
  3146. }
  3147. }
  3148. XrResult SDL_CreateGPUXRSession(
  3149. SDL_GPUDevice *device,
  3150. const XrSessionCreateInfo *createinfo,
  3151. XrSession *session)
  3152. {
  3153. CHECK_DEVICE_MAGIC(device, XR_ERROR_HANDLE_INVALID);
  3154. return device->CreateXRSession(device->driverData, createinfo, session);
  3155. }
  3156. SDL_GPUTextureFormat* SDL_GetGPUXRSwapchainFormats(
  3157. SDL_GPUDevice *device,
  3158. XrSession session,
  3159. int *num_formats)
  3160. {
  3161. CHECK_DEVICE_MAGIC(device, NULL);
  3162. return device->GetXRSwapchainFormats(device->driverData, session, num_formats);
  3163. }
  3164. XrResult SDL_CreateGPUXRSwapchain(
  3165. SDL_GPUDevice *device,
  3166. XrSession session,
  3167. const XrSwapchainCreateInfo *createinfo,
  3168. SDL_GPUTextureFormat format,
  3169. XrSwapchain *swapchain,
  3170. SDL_GPUTexture ***textures)
  3171. {
  3172. CHECK_DEVICE_MAGIC(device, XR_ERROR_HANDLE_INVALID);
  3173. return device->CreateXRSwapchain(device->driverData, session, createinfo, format, swapchain, textures);
  3174. }