yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
43d0c2100
master
1#if 0 2// Duplicated: This is tested in slang-rhi\tests\test-cmd-draw.cpp 3 4#include "core/slang-basic.h" 5#include "gfx-test-util.h" 6#include "slang-gfx.h" 7#include "slang-rhi/shader-cursor.h" 8#include "unit-test/slang-unit-test.h" 9 10using namespace gfx ; 11 12namespace gfx_test 13{ 14struct Vertex 15{ 16float position [3 ]; 17}; 18 19struct Instance 20{ 21float position [3 ]; 22float color [3 ]; 23}; 24 25static const int kVertexCount = 6 ; 26static const Vertex kVertexData [kVertexCount ]= { 27// Triangle 1 28 {0 ,0 ,0.5 }, 29 {1 ,0 ,0.5 }, 30 {0 ,1 ,0.5 }, 31 32// Triangle 2 33 {-1 ,0 ,0.5 }, 34 {0 ,0 ,0.5 }, 35 {-1 ,1 ,0.5 }, 36}; 37 38static const int kInstanceCount = 2 ; 39static const Instance kInstanceData [kInstanceCount ]= { 40 {{0 ,0 ,0 }, {1 ,0 ,0 }}, 41 {{0 ,-1 ,0 }, {0 ,0 ,1 }}, 42}; 43 44static const int kIndexCount = 6 ; 45static const uint32_t kIndexData [kIndexCount ]= { 460 , 472 , 485 , 490 , 501 , 512 , 52}; 53 54const int kWidth = 256 ; 55const int kHeight = 256 ; 56const Format format = Format ::R32G32B32A32_FLOAT ; 57 58ComPtr < IBufferResource > createVertexBuffer (IDevice * device ) 59{ 60IBufferResource ::Desc vertexBufferDesc ; 61vertexBufferDesc .type = IResource ::Type ::Buffer ; 62vertexBufferDesc .sizeInBytes = kVertexCount * sizeof (Vertex ); 63vertexBufferDesc .defaultState = ResourceState ::VertexBuffer ; 64vertexBufferDesc .allowedStates = ResourceState ::VertexBuffer ; 65ComPtr < IBufferResource > vertexBuffer = 66device -> createBufferResource (vertexBufferDesc ,& kVertexData [0 ]); 67SLANG_CHECK_ABORT (vertexBuffer != nullptr ); 68return vertexBuffer ; 69} 70 71ComPtr < IBufferResource > createInstanceBuffer (IDevice * device ) 72{ 73IBufferResource ::Desc instanceBufferDesc ; 74instanceBufferDesc .type = IResource ::Type ::Buffer ; 75instanceBufferDesc .sizeInBytes = kInstanceCount * sizeof (Instance ); 76instanceBufferDesc .defaultState = ResourceState ::VertexBuffer ; 77instanceBufferDesc .allowedStates = ResourceState ::VertexBuffer ; 78ComPtr < IBufferResource > instanceBuffer = 79device -> createBufferResource (instanceBufferDesc ,& kInstanceData [0 ]); 80SLANG_CHECK_ABORT (instanceBuffer != nullptr ); 81return instanceBuffer ; 82} 83 84ComPtr < IBufferResource > createIndexBuffer (IDevice * device ) 85{ 86IBufferResource ::Desc indexBufferDesc ; 87indexBufferDesc .type = IResource ::Type ::Buffer ; 88indexBufferDesc .sizeInBytes = kIndexCount * sizeof (uint32_t ); 89indexBufferDesc .defaultState = ResourceState ::IndexBuffer ; 90indexBufferDesc .allowedStates = ResourceState ::IndexBuffer ; 91ComPtr < IBufferResource > indexBuffer = 92device -> createBufferResource (indexBufferDesc ,& kIndexData [0 ]); 93SLANG_CHECK_ABORT (indexBuffer != nullptr ); 94return indexBuffer ; 95} 96 97ComPtr < ITextureResource > createColorBuffer (IDevice * device ) 98{ 99 gfx::ITextureResource ::Desc colorBufferDesc ; 100colorBufferDesc .type = IResource ::Type ::Texture2D ; 101colorBufferDesc .size .width = kWidth ; 102colorBufferDesc .size .height = kHeight ; 103colorBufferDesc .size .depth = 1 ; 104colorBufferDesc .numMipLevels = 1 ; 105colorBufferDesc .format = format ; 106colorBufferDesc .defaultState = ResourceState ::RenderTarget ; 107colorBufferDesc .allowedStates = {ResourceState ::RenderTarget ,ResourceState ::CopySource }; 108ComPtr < ITextureResource > colorBuffer = device -> createTextureResource (colorBufferDesc ,nullptr ); 109SLANG_CHECK_ABORT (colorBuffer != nullptr ); 110return colorBuffer ; 111} 112 113class BaseDrawTest 114{ 115public : 116ComPtr < IDevice > device ; 117UnitTestContext * context ; 118 119ComPtr < ITransientResourceHeap > transientHeap ; 120ComPtr < IPipelineState > pipelineState ; 121ComPtr < IRenderPassLayout > renderPass ; 122ComPtr < IFramebuffer > framebuffer ; 123 124ComPtr < IBufferResource > vertexBuffer ; 125ComPtr < IBufferResource > instanceBuffer ; 126ComPtr < ITextureResource > colorBuffer ; 127 128void init (IDevice * device ,UnitTestContext * context ) 129 { 130this -> device = device ; 131this -> context = context ; 132 } 133 134void createRequiredResources () 135 { 136VertexStreamDesc vertexStreams []= { 137 {sizeof (Vertex ),InputSlotClass ::PerVertex ,0 }, 138 {sizeof (Instance ),InputSlotClass ::PerInstance ,1 }, 139 }; 140 141InputElementDesc inputElements []= { 142// Vertex buffer data 143 {"POSITIONA" ,0 ,Format ::R32G32B32_FLOAT , offsetof(Vertex ,position ),0 }, 144 145// Instance buffer data 146 {"POSITIONB" ,0 ,Format ::R32G32B32_FLOAT , offsetof(Instance ,position ),1 }, 147 {"COLOR" ,0 ,Format ::R32G32B32_FLOAT , offsetof(Instance ,color ),1 }, 148 }; 149IInputLayout ::Desc inputLayoutDesc = {}; 150inputLayoutDesc .inputElementCount = SLANG_COUNT_OF (inputElements ); 151inputLayoutDesc .inputElements = inputElements ; 152inputLayoutDesc .vertexStreamCount = SLANG_COUNT_OF (vertexStreams ); 153inputLayoutDesc .vertexStreams = vertexStreams ; 154auto inputLayout = device -> createInputLayout (inputLayoutDesc ); 155SLANG_CHECK_ABORT (inputLayout != nullptr ); 156 157vertexBuffer = createVertexBuffer (device ); 158instanceBuffer = createInstanceBuffer (device ); 159colorBuffer = createColorBuffer (device ); 160 161ITransientResourceHeap ::Desc transientHeapDesc = {}; 162transientHeapDesc .constantBufferSize = 4096 ; 163GFX_CHECK_CALL_ABORT ( 164device -> createTransientResourceHeap (transientHeapDesc ,transientHeap .writeRef ())); 165 166ComPtr < IShaderProgram > shaderProgram ; 167 slang::ProgramLayout * slangReflection ; 168GFX_CHECK_CALL_ABORT (loadGraphicsProgram ( 169device , 170shaderProgram , 171"graphics-smoke" , 172"vertexMain" , 173"fragmentMain" , 174slangReflection )); 175 176IFramebufferLayout ::TargetLayout targetLayout ; 177targetLayout .format = format ; 178targetLayout .sampleCount = 1 ; 179 180IFramebufferLayout ::Desc framebufferLayoutDesc ; 181framebufferLayoutDesc .renderTargetCount = 1 ; 182framebufferLayoutDesc .renderTargets = & targetLayout ; 183ComPtr < gfx::IFramebufferLayout > framebufferLayout = 184device -> createFramebufferLayout (framebufferLayoutDesc ); 185SLANG_CHECK_ABORT (framebufferLayout != nullptr ); 186 187GraphicsPipelineStateDesc pipelineDesc = {}; 188pipelineDesc .program = shaderProgram .get (); 189pipelineDesc .inputLayout = inputLayout ; 190pipelineDesc .framebufferLayout = framebufferLayout ; 191pipelineDesc .depthStencil .depthTestEnable = false; 192pipelineDesc .depthStencil .depthWriteEnable = false; 193GFX_CHECK_CALL_ABORT ( 194device -> createGraphicsPipelineState (pipelineDesc ,pipelineState .writeRef ())); 195 196IRenderPassLayout ::Desc renderPassDesc = {}; 197renderPassDesc .framebufferLayout = framebufferLayout ; 198renderPassDesc .renderTargetCount = 1 ; 199IRenderPassLayout ::TargetAccessDesc renderTargetAccess = {}; 200renderTargetAccess .loadOp = IRenderPassLayout ::TargetLoadOp ::Clear ; 201renderTargetAccess .storeOp = IRenderPassLayout ::TargetStoreOp ::Store ; 202renderTargetAccess .initialState = ResourceState ::RenderTarget ; 203renderTargetAccess .finalState = ResourceState ::CopySource ; 204renderPassDesc .renderTargetAccess = & renderTargetAccess ; 205GFX_CHECK_CALL_ABORT (device -> createRenderPassLayout (renderPassDesc ,renderPass .writeRef ())); 206 207 gfx::IResourceView ::Desc colorBufferViewDesc ; 208memset (& colorBufferViewDesc ,0 ,sizeof (colorBufferViewDesc )); 209colorBufferViewDesc .format = format ; 210colorBufferViewDesc .renderTarget .shape = gfx::IResource ::Type ::Texture2D ; 211colorBufferViewDesc .type = gfx::IResourceView ::Type ::RenderTarget ; 212auto rtv = device -> createTextureView (colorBuffer ,colorBufferViewDesc ); 213 214 gfx::IFramebuffer ::Desc framebufferDesc ; 215framebufferDesc .renderTargetCount = 1 ; 216framebufferDesc .depthStencilView = nullptr ; 217framebufferDesc .renderTargetViews = rtv .readRef (); 218framebufferDesc .layout = framebufferLayout ; 219GFX_CHECK_CALL_ABORT (device -> createFramebuffer (framebufferDesc ,framebuffer .writeRef ())); 220 } 221 222void checkTestResults ( 223int pixelCount , 224int channelCount , 225const int * testXCoords , 226const int * testYCoords , 227float * testResults ) 228 { 229// Read texture values back from four specific pixels located within the triangles 230// and compare against expected values (because testing every single pixel will be too long 231// and tedious and requires maintaining reference images). 232ComPtr < ISlangBlob > resultBlob ; 233size_t rowPitch = 0 ; 234size_t pixelSize = 0 ; 235GFX_CHECK_CALL_ABORT (device -> readTextureResource ( 236colorBuffer , 237ResourceState ::CopySource , 238resultBlob .writeRef (), 239& rowPitch , 240& pixelSize )); 241auto result = (float * )resultBlob -> getBufferPointer (); 242 243int cursor = 0 ; 244for (int i = 0 ;i < pixelCount ;++ i ) 245 { 246auto x = testXCoords [i ]; 247auto y = testYCoords [i ]; 248auto pixelPtr = result + x * channelCount + y * rowPitch /sizeof (float ); 249for (int j = 0 ;j < channelCount ;++ j ) 250 { 251testResults [cursor ]= pixelPtr [j ]; 252cursor ++ ; 253 } 254 } 255 256float expectedResult []= { 2571.0f , 2580.0f , 2590.0f , 2601.0f , 2611.0f , 2620.0f , 2630.0f , 2641.0f , 2650.0f , 2660.0f , 2671.0f , 2681.0f , 2690.0f , 2700.0f , 2711.0f , 2721.0f }; 273compareComputeResultFuzzy (testResults ,expectedResult ,sizeof (expectedResult )); 274 } 275}; 276 277struct DrawInstancedTest :BaseDrawTest 278{ 279void setUpAndDraw () 280 { 281createRequiredResources (); 282 283ICommandQueue ::Desc queueDesc = {ICommandQueue ::QueueType ::Graphics }; 284auto queue = device -> createCommandQueue (queueDesc ); 285auto commandBuffer = transientHeap -> createCommandBuffer (); 286 287auto encoder = commandBuffer -> encodeRenderCommands (renderPass ,framebuffer ); 288auto rootObject = encoder -> bindPipeline (pipelineState ); 289 290 gfx::Viewport viewport = {}; 291viewport .maxZ = 1.0f ; 292viewport .extentX = kWidth ; 293viewport .extentY = kHeight ; 294encoder -> setViewportAndScissor (viewport ); 295 296uint32_t startVertex = 0 ; 297uint32_t startInstanceLocation = 0 ; 298 299encoder -> setVertexBuffer (0 ,vertexBuffer ); 300encoder -> setVertexBuffer (1 ,instanceBuffer ); 301encoder -> setPrimitiveTopology (PrimitiveTopology ::TriangleList ); 302 303encoder -> drawInstanced (kVertexCount ,kInstanceCount ,startVertex ,startInstanceLocation ); 304encoder -> endEncoding (); 305commandBuffer -> close (); 306queue -> executeCommandBuffer (commandBuffer ); 307queue -> waitOnHost (); 308 } 309 310void run () 311 { 312setUpAndDraw (); 313 314const int kPixelCount = 4 ; 315const int kChannelCount = 4 ; 316int testXCoords [kPixelCount ]= {64 ,192 ,64 ,192 }; 317int testYCoords [kPixelCount ]= {100 ,100 ,250 ,250 }; 318float testResults [kPixelCount * kChannelCount ]; 319 320checkTestResults (kPixelCount ,kChannelCount ,testXCoords ,testYCoords ,testResults ); 321 } 322}; 323 324struct DrawIndexedInstancedTest :BaseDrawTest 325{ 326ComPtr < IBufferResource > indexBuffer ; 327 328void setUpAndDraw () 329 { 330createRequiredResources (); 331 332ICommandQueue ::Desc queueDesc = {ICommandQueue ::QueueType ::Graphics }; 333auto queue = device -> createCommandQueue (queueDesc ); 334auto commandBuffer = transientHeap -> createCommandBuffer (); 335 336auto encoder = commandBuffer -> encodeRenderCommands (renderPass ,framebuffer ); 337auto rootObject = encoder -> bindPipeline (pipelineState ); 338 339 gfx::Viewport viewport = {}; 340viewport .maxZ = 1.0f ; 341viewport .extentX = kWidth ; 342viewport .extentY = kHeight ; 343encoder -> setViewportAndScissor (viewport ); 344 345uint32_t startIndex = 0 ; 346int32_t startVertex = 0 ; 347uint32_t startInstanceLocation = 0 ; 348 349encoder -> setVertexBuffer (0 ,vertexBuffer ); 350encoder -> setVertexBuffer (1 ,instanceBuffer ); 351encoder -> setIndexBuffer (indexBuffer ,Format ::R32_UINT ); 352encoder -> setPrimitiveTopology (PrimitiveTopology ::TriangleList ); 353 354encoder -> drawIndexedInstanced ( 355kIndexCount , 356kInstanceCount , 357startIndex , 358startVertex , 359startInstanceLocation ); 360encoder -> endEncoding (); 361commandBuffer -> close (); 362queue -> executeCommandBuffer (commandBuffer ); 363queue -> waitOnHost (); 364 } 365 366void run () 367 { 368indexBuffer = createIndexBuffer (device ); 369 370setUpAndDraw (); 371 372const int kPixelCount = 4 ; 373const int kChannelCount = 4 ; 374int testXCoords [kPixelCount ]= {64 ,192 ,64 ,192 }; 375int testYCoords [kPixelCount ]= {32 ,100 ,150 ,250 }; 376float testResults [kPixelCount * kChannelCount ]; 377 378checkTestResults (kPixelCount ,kChannelCount ,testXCoords ,testYCoords ,testResults ); 379 } 380}; 381 382struct DrawIndirectTest :BaseDrawTest 383{ 384ComPtr < IBufferResource > indirectBuffer ; 385 386struct IndirectArgData 387 { 388float padding ;// Ensure args and count don't start at 0 offset for testing purposes 389IndirectDrawArguments args ; 390 }; 391 392ComPtr < IBufferResource > createIndirectBuffer (IDevice * device ) 393 { 394static const IndirectArgData kIndirectData = { 39542.0f ,// padding 396 {6 ,2 ,0 ,0 },// args 397 }; 398 399IBufferResource ::Desc indirectBufferDesc ; 400indirectBufferDesc .type = IResource ::Type ::Buffer ; 401indirectBufferDesc .sizeInBytes = sizeof (IndirectArgData ); 402indirectBufferDesc .defaultState = ResourceState ::IndirectArgument ; 403indirectBufferDesc .allowedStates = ResourceState ::IndirectArgument ; 404ComPtr < IBufferResource > indirectBuffer = 405device -> createBufferResource (indirectBufferDesc ,& kIndirectData ); 406SLANG_CHECK_ABORT (indirectBuffer != nullptr ); 407return indirectBuffer ; 408 } 409 410void setUpAndDraw () 411 { 412createRequiredResources (); 413 414ICommandQueue ::Desc queueDesc = {ICommandQueue ::QueueType ::Graphics }; 415auto queue = device -> createCommandQueue (queueDesc ); 416auto commandBuffer = transientHeap -> createCommandBuffer (); 417 418auto encoder = commandBuffer -> encodeRenderCommands (renderPass ,framebuffer ); 419auto rootObject = encoder -> bindPipeline (pipelineState ); 420 421 gfx::Viewport viewport = {}; 422viewport .maxZ = 1.0f ; 423viewport .extentX = kWidth ; 424viewport .extentY = kHeight ; 425encoder -> setViewportAndScissor (viewport ); 426 427encoder -> setVertexBuffer (0 ,vertexBuffer ); 428encoder -> setVertexBuffer (1 ,instanceBuffer ); 429encoder -> setPrimitiveTopology (PrimitiveTopology ::TriangleList ); 430 431uint32_t maxDrawCount = 1 ; 432Offset argOffset = offsetof(IndirectArgData ,args ); 433 434encoder -> drawIndirect (maxDrawCount ,indirectBuffer ,argOffset ); 435encoder -> endEncoding (); 436commandBuffer -> close (); 437queue -> executeCommandBuffer (commandBuffer ); 438queue -> waitOnHost (); 439 } 440 441void run () 442 { 443indirectBuffer = createIndirectBuffer (device ); 444 445setUpAndDraw (); 446 447const int kPixelCount = 4 ; 448const int kChannelCount = 4 ; 449int testXCoords [kPixelCount ]= {64 ,192 ,64 ,192 }; 450int testYCoords [kPixelCount ]= {100 ,100 ,250 ,250 }; 451float testResults [kPixelCount * kChannelCount ]; 452 453checkTestResults (kPixelCount ,kChannelCount ,testXCoords ,testYCoords ,testResults ); 454 } 455}; 456 457struct DrawIndexedIndirectTest :BaseDrawTest 458{ 459ComPtr < IBufferResource > indexBuffer ; 460ComPtr < IBufferResource > indirectBuffer ; 461 462struct IndexedIndirectArgData 463 { 464float padding ;// Ensure args and count don't start at 0 offset for testing purposes 465IndirectDrawIndexedArguments args ; 466 }; 467 468ComPtr < IBufferResource > createIndirectBuffer (IDevice * device ) 469 { 470static const IndexedIndirectArgData kIndexedIndirectData = { 47142.0f ,// padding 472 {6 ,2 ,0 ,0 ,0 },// args 473 }; 474 475IBufferResource ::Desc indirectBufferDesc ; 476indirectBufferDesc .type = IResource ::Type ::Buffer ; 477indirectBufferDesc .sizeInBytes = sizeof (IndexedIndirectArgData ); 478indirectBufferDesc .defaultState = ResourceState ::IndirectArgument ; 479indirectBufferDesc .allowedStates = ResourceState ::IndirectArgument ; 480ComPtr < IBufferResource > indexBuffer = 481device -> createBufferResource (indirectBufferDesc ,& kIndexedIndirectData ); 482SLANG_CHECK_ABORT (indexBuffer != nullptr ); 483return indexBuffer ; 484 } 485 486void setUpAndDraw () 487 { 488createRequiredResources (); 489 490ICommandQueue ::Desc queueDesc = {ICommandQueue ::QueueType ::Graphics }; 491auto queue = device -> createCommandQueue (queueDesc ); 492auto commandBuffer = transientHeap -> createCommandBuffer (); 493 494auto encoder = commandBuffer -> encodeRenderCommands (renderPass ,framebuffer ); 495auto rootObject = encoder -> bindPipeline (pipelineState ); 496 497 gfx::Viewport viewport = {}; 498viewport .maxZ = 1.0f ; 499viewport .extentX = kWidth ; 500viewport .extentY = kHeight ; 501encoder -> setViewportAndScissor (viewport ); 502 503encoder -> setVertexBuffer (0 ,vertexBuffer ); 504encoder -> setVertexBuffer (1 ,instanceBuffer ); 505encoder -> setIndexBuffer (indexBuffer ,Format ::R32_UINT ); 506encoder -> setPrimitiveTopology (PrimitiveTopology ::TriangleList ); 507 508uint32_t maxDrawCount = 1 ; 509Offset argOffset = offsetof(IndexedIndirectArgData ,args ); 510 511encoder -> drawIndexedIndirect (maxDrawCount ,indirectBuffer ,argOffset ); 512encoder -> endEncoding (); 513commandBuffer -> close (); 514queue -> executeCommandBuffer (commandBuffer ); 515queue -> waitOnHost (); 516 } 517 518void run () 519 { 520indexBuffer = createIndexBuffer (device ); 521indirectBuffer = createIndirectBuffer (device ); 522 523setUpAndDraw (); 524 525const int kPixelCount = 4 ; 526const int kChannelCount = 4 ; 527int testXCoords [kPixelCount ]= {64 ,192 ,64 ,192 }; 528int testYCoords [kPixelCount ]= {32 ,100 ,150 ,250 }; 529float testResults [kPixelCount * kChannelCount ]; 530 531checkTestResults (kPixelCount ,kChannelCount ,testXCoords ,testYCoords ,testResults ); 532 } 533}; 534 535template < typename T > 536void drawTestImpl (IDevice * device ,UnitTestContext * context ) 537{ 538T test ; 539test .init (device ,context ); 540test .run (); 541} 542 543SLANG_UNIT_TEST (drawInstancedD3D11 ) 544{ 545runTestImpl (drawTestImpl < DrawInstancedTest > ,unitTestContext ,Slang ::RenderApiFlag ::D3D11 ); 546} 547 548SLANG_UNIT_TEST (drawIndexedInstancedD3D11 ) 549{ 550runTestImpl ( 551drawTestImpl < DrawIndexedInstancedTest > , 552unitTestContext , 553Slang ::RenderApiFlag ::D3D11 ); 554} 555 556SLANG_UNIT_TEST (drawInstancedD3D12 ) 557{ 558runTestImpl (drawTestImpl < DrawInstancedTest > ,unitTestContext ,Slang ::RenderApiFlag ::D3D12 ); 559} 560 561SLANG_UNIT_TEST (drawIndexedInstancedD3D12 ) 562{ 563runTestImpl ( 564drawTestImpl < DrawIndexedInstancedTest > , 565unitTestContext , 566Slang ::RenderApiFlag ::D3D12 ); 567} 568 569SLANG_UNIT_TEST (drawIndirectD3D12 ) 570{ 571runTestImpl (drawTestImpl < DrawIndirectTest > ,unitTestContext ,Slang ::RenderApiFlag ::D3D12 ); 572} 573 574SLANG_UNIT_TEST (drawIndexedIndirectD3D12 ) 575{ 576runTestImpl ( 577drawTestImpl < DrawIndexedIndirectTest > , 578unitTestContext , 579Slang ::RenderApiFlag ::D3D12 ); 580} 581 582SLANG_UNIT_TEST (drawInstancedVulkan ) 583{ 584runTestImpl (drawTestImpl < DrawInstancedTest > ,unitTestContext ,Slang ::RenderApiFlag ::Vulkan ); 585} 586 587SLANG_UNIT_TEST (drawIndexedInstancedVulkan ) 588{ 589runTestImpl ( 590drawTestImpl < DrawIndexedInstancedTest > , 591unitTestContext , 592Slang ::RenderApiFlag ::Vulkan ); 593} 594 595SLANG_UNIT_TEST (drawIndirectVulkan ) 596{ 597runTestImpl (drawTestImpl < DrawIndirectTest > ,unitTestContext ,Slang ::RenderApiFlag ::Vulkan ); 598} 599 600SLANG_UNIT_TEST (drawIndexedIndirectVulkan ) 601{ 602runTestImpl ( 603drawTestImpl < DrawIndexedIndirectTest > , 604unitTestContext , 605Slang ::RenderApiFlag ::Vulkan ); 606} 607}// namespace gfx_test 608 609#endif