yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
43d0c2100
master
1#include "core/slang-basic.h" 2#include "examples/example-base/example-base.h" 3#include "platform/vector-math.h" 4#include "platform/window.h" 5#include "slang-com-ptr.h" 6#include "slang-rhi.h" 7#include "slang-rhi/shader-cursor.h" 8#include "slang.h" 9 10using namespace rhi ; 11using namespace Slang ; 12 13static const ExampleResources resourceBase ("autodiff-texture" ); 14 15struct Vertex 16{ 17float position [3 ]; 18}; 19 20static const int kVertexCount = 4 ; 21static const Vertex kVertexData [kVertexCount ]= { 22 {{0 ,0 ,0 }}, 23 {{0 ,1 ,0 }}, 24 {{1 ,0 ,0 }}, 25 {{1 ,1 ,0 }}, 26}; 27float clearValue []= {0.0f ,0.0f ,0.0f ,0.0f }; 28 29 30struct AutoDiffTexture :public WindowedAppBase 31{ 32 33List < uint32_t > mipMapOffset ; 34int textureWidth ; 35int textureHeight ; 36 37void diagnoseIfNeeded (slang::IBlob * diagnosticsBlob ) 38 { 39if (diagnosticsBlob != nullptr ) 40 { 41printf ("%s" , (const char * )diagnosticsBlob -> getBufferPointer ()); 42 } 43 } 44 45Result loadRenderProgram ( 46IDevice * device , 47const char * fileName , 48const char * fragmentShader , 49IShaderProgram ** outProgram ) 50 { 51ComPtr < slang::ISession > slangSession ; 52slangSession = device -> getSlangSession (); 53 54ComPtr < slang::IBlob > diagnosticsBlob ; 55Slang ::String path = resourceBase .resolveResource (fileName ); 56 slang::IModule * module = 57slangSession -> loadModule (path .getBuffer (),diagnosticsBlob .writeRef ()); 58diagnoseIfNeeded (diagnosticsBlob ); 59if (!module ) 60return SLANG_FAIL ; 61 62ComPtr < slang::IEntryPoint > vertexEntryPoint ; 63SLANG_RETURN_ON_FAIL ( 64module -> findEntryPointByName ("vertexMain" ,vertexEntryPoint .writeRef ())); 65ComPtr < slang::IEntryPoint > fragmentEntryPoint ; 66SLANG_RETURN_ON_FAIL ( 67module -> findEntryPointByName (fragmentShader ,fragmentEntryPoint .writeRef ())); 68 69Slang ::List < slang::IComponentType *> componentTypes ; 70componentTypes .add (module ); 71int entryPointCount = 0 ; 72int vertexEntryPointIndex = entryPointCount ++ ; 73componentTypes .add (vertexEntryPoint ); 74 75int fragmentEntryPointIndex = entryPointCount ++ ; 76componentTypes .add (fragmentEntryPoint ); 77 78ComPtr < slang::IComponentType > linkedProgram ; 79SlangResult result = slangSession -> createCompositeComponentType ( 80componentTypes .getBuffer (), 81componentTypes .getCount (), 82linkedProgram .writeRef (), 83diagnosticsBlob .writeRef ()); 84diagnoseIfNeeded (diagnosticsBlob ); 85SLANG_RETURN_ON_FAIL (result ); 86 87if (isTestMode ()) 88 { 89printEntrypointHashes (componentTypes .getCount ()- 1 ,1 ,linkedProgram ); 90 } 91 92ShaderProgramDesc programDesc = {}; 93programDesc .slangGlobalScope = linkedProgram ; 94SLANG_RETURN_ON_FAIL (device -> createShaderProgram (programDesc ,outProgram )); 95 96return SLANG_OK ; 97 } 98 99Result loadComputeProgram (IDevice * device ,const char * fileName ,IShaderProgram ** outProgram ) 100 { 101ComPtr < slang::ISession > slangSession ; 102slangSession = device -> getSlangSession (); 103 104ComPtr < slang::IBlob > diagnosticsBlob ; 105Slang ::String path = resourceBase .resolveResource (fileName ); 106 slang::IModule * module = 107slangSession -> loadModule (path .getBuffer (),diagnosticsBlob .writeRef ()); 108diagnoseIfNeeded (diagnosticsBlob ); 109if (!module ) 110return SLANG_FAIL ; 111 112Slang ::List < slang::IComponentType *> componentTypes ; 113componentTypes .add (module ); 114ComPtr < slang::IEntryPoint > computeEntryPoint ; 115SLANG_RETURN_ON_FAIL ( 116module -> findEntryPointByName ("computeMain" ,computeEntryPoint .writeRef ())); 117componentTypes .add (computeEntryPoint ); 118 119ComPtr < slang::IComponentType > linkedProgram ; 120SlangResult result = slangSession -> createCompositeComponentType ( 121componentTypes .getBuffer (), 122componentTypes .getCount (), 123linkedProgram .writeRef (), 124diagnosticsBlob .writeRef ()); 125diagnoseIfNeeded (diagnosticsBlob ); 126SLANG_RETURN_ON_FAIL (result ); 127 128if (isTestMode ()) 129 { 130printEntrypointHashes (componentTypes .getCount ()- 1 ,1 ,linkedProgram ); 131 } 132 133ShaderProgramDesc programDesc = {}; 134programDesc .slangGlobalScope = linkedProgram ; 135SLANG_RETURN_ON_FAIL (device -> createShaderProgram (programDesc ,outProgram )); 136 137return SLANG_OK ; 138 } 139 140ComPtr < IRenderPipeline > gRefPipeline ; 141ComPtr < IRenderPipeline > gIterPipeline ; 142ComPtr < IComputePipeline > gReconstructPipeline ; 143ComPtr < IComputePipeline > gConvertPipeline ; 144ComPtr < IComputePipeline > gBuildMipPipeline ; 145ComPtr < IComputePipeline > gLearnMipPipeline ; 146ComPtr < IRenderPipeline > gDrawQuadPipeline ; 147 148ComPtr < ITexture > gLearningTexture ; 149ComPtr < ITextureView > gLearningTextureSRV ; 150List < ComPtr < ITextureView >> gLearningTextureUAVs ; 151 152ComPtr < ITexture > gDiffTexture ; 153ComPtr < ITextureView > gDiffTextureSRV ; 154List < ComPtr < ITextureView >> gDiffTextureUAVs ; 155 156ComPtr < IBuffer > gVertexBuffer ; 157ComPtr < ITextureView > gTexView ; 158ComPtr < ISampler > gSampler ; 159 160ComPtr < ITexture > gDepthTexture ; 161ComPtr < ITextureView > gDepthTextureView ; 162 163ComPtr < ITexture > gIterImage ; 164ComPtr < ITextureView > gIterImageSRV ; 165 166ComPtr < ITexture > gRefImage ; 167ComPtr < ITextureView > gRefImageSRV ; 168 169ComPtr < IBuffer > gAccumulateBuffer ; 170ComPtr < ITextureView > gAccumulateBufferView ; 171 172ComPtr < IBuffer > gReconstructBuffer ; 173ComPtr < ITextureView > gReconstructBufferView ; 174 175 176bool resetLearntTexture = false; 177 178ComPtr < ITexture > createRenderTargetTexture (Format format ,int w ,int h ,int levels ) 179 { 180TextureDesc textureDesc = {}; 181textureDesc .format = format ; 182textureDesc .size .width = w ; 183textureDesc .size .height = h ; 184textureDesc .size .depth = 1 ; 185textureDesc .mipCount = levels ; 186textureDesc .usage = TextureUsage ::ShaderResource |TextureUsage ::UnorderedAccess | 187TextureUsage ::RenderTarget ; 188textureDesc .defaultState = ResourceState ::RenderTarget ; 189return gDevice -> createTexture (textureDesc ); 190 } 191ComPtr < ITexture > createDepthTexture () 192 { 193TextureDesc textureDesc = {}; 194textureDesc .format = Format ::D32Float ; 195textureDesc .size .width = windowWidth ; 196textureDesc .size .height = windowHeight ; 197textureDesc .size .depth = 1 ; 198textureDesc .mipCount = 1 ; 199textureDesc .usage = TextureUsage ::DepthStencil ; 200textureDesc .defaultState = ResourceState ::DepthWrite ; 201return gDevice -> createTexture (textureDesc ); 202 } 203ComPtr < ITextureView > createRTV (ITexture * tex ,Format f ) 204 { 205TextureViewDesc rtvDesc = {}; 206rtvDesc .format = f ; 207rtvDesc .subresourceRange .mipCount = 1 ; 208return gDevice -> createTextureView (tex ,rtvDesc ); 209 } 210ComPtr < ITextureView > createDSV (ITexture * tex ) 211 { 212TextureViewDesc dsvDesc = {}; 213dsvDesc .format = Format ::D32Float ; 214dsvDesc .subresourceRange .mipCount = 1 ; 215return gDevice -> createTextureView (tex ,dsvDesc ); 216 } 217ComPtr < ITextureView > createSRV (ITexture * tex ) 218 { 219TextureViewDesc srvDesc = {}; 220return gDevice -> createTextureView (tex ,srvDesc ); 221 } 222ComPtr < IRenderPipeline > createRenderPipeline (IInputLayout * inputLayout ,IShaderProgram * program ) 223 { 224ColorTargetDesc colorTarget ; 225colorTarget .format = Format ::RGBA8Unorm ; 226RenderPipelineDesc desc ; 227desc .inputLayout = inputLayout ; 228desc .program = program ; 229desc .targetCount = 1 ; 230desc .targets = & colorTarget ; 231desc .depthStencil .depthTestEnable = true; 232desc .depthStencil .depthWriteEnable = true; 233desc .depthStencil .format = Format ::D32Float ; 234desc .rasterizer .cullMode = CullMode ::None ; 235desc .primitiveTopology = PrimitiveTopology ::TriangleStrip ; 236return gDevice -> createRenderPipeline (desc ); 237 } 238ComPtr < IComputePipeline > createComputePipeline (IShaderProgram * program ) 239 { 240ComputePipelineDesc desc = {}; 241desc .program = program ; 242return gDevice -> createComputePipeline (desc ); 243 } 244ComPtr < ITextureView > createUAV (ITexture * texture ,int level ) 245 { 246TextureViewDesc desc = {}; 247SubresourceRange textureViewRange = {}; 248textureViewRange .mipCount = 1 ; 249textureViewRange .mip = level ;// Fixed: should be level, not 0 250textureViewRange .layerCount = 1 ;// Fixed: should be 1, not level 251textureViewRange .layer = 0 ; 252desc .subresourceRange = textureViewRange ; 253return gDevice -> createTextureView (texture ,desc ); 254 } 255Slang ::Result initialize () 256 { 257SLANG_RETURN_ON_FAIL (initializeBase ("autodiff-texture" ,1024 ,768 ,DeviceType ::Default )); 258srand (20421 ); 259 260if (!isTestMode ()) 261 { 262gWindow -> events .keyPress = [this ](platform::KeyEventArgs & e ) 263 { 264if (e .keyChar == 'R' || e .keyChar == 'r' ) 265resetLearntTexture = true; 266 }; 267 } 268 269 platform::Rect clientRect {}; 270if (isTestMode ()) 271 { 272clientRect .width = 1024 ; 273clientRect .height = 768 ; 274 } 275else 276 { 277clientRect = getWindow ()-> getClientRect (); 278 } 279 280windowWidth = clientRect .width ; 281windowHeight = clientRect .height ; 282 283InputElementDesc inputElements []= { 284 {"POSITION" ,0 ,Format ::RGB32Float , offsetof(Vertex ,position )}}; 285auto inputLayout = gDevice -> createInputLayout (sizeof (Vertex ),& inputElements [0 ],1 ); 286if (!inputLayout ) 287return SLANG_FAIL ; 288 289BufferDesc vertexBufferDesc ; 290vertexBufferDesc .size = kVertexCount * sizeof (Vertex ); 291vertexBufferDesc .elementSize = sizeof (Vertex ); 292vertexBufferDesc .usage = BufferUsage ::VertexBuffer ; 293gVertexBuffer = gDevice -> createBuffer (vertexBufferDesc ,& kVertexData [0 ]); 294if (!gVertexBuffer ) 295return SLANG_FAIL ; 296 297 { 298ComPtr < IShaderProgram > shaderProgram ; 299SLANG_RETURN_ON_FAIL (loadRenderProgram ( 300gDevice , 301"train.slang" , 302"fragmentMain" , 303shaderProgram .writeRef ())); 304gRefPipeline = createRenderPipeline (inputLayout ,shaderProgram ); 305 } 306 { 307ComPtr < IShaderProgram > shaderProgram ; 308SLANG_RETURN_ON_FAIL (loadRenderProgram ( 309gDevice , 310"train.slang" , 311"diffFragmentMain" , 312shaderProgram .writeRef ())); 313gIterPipeline = createRenderPipeline (inputLayout ,shaderProgram ); 314 } 315 { 316ComPtr < IShaderProgram > shaderProgram ; 317SLANG_RETURN_ON_FAIL (loadRenderProgram ( 318gDevice , 319"draw-quad.slang" , 320"fragmentMain" , 321shaderProgram .writeRef ())); 322gDrawQuadPipeline = createRenderPipeline (inputLayout ,shaderProgram ); 323 } 324 { 325ComPtr < IShaderProgram > shaderProgram ; 326SLANG_RETURN_ON_FAIL ( 327loadComputeProgram (gDevice ,"reconstruct.slang" ,shaderProgram .writeRef ())); 328gReconstructPipeline = createComputePipeline (shaderProgram ); 329 } 330 { 331ComPtr < IShaderProgram > shaderProgram ; 332SLANG_RETURN_ON_FAIL ( 333loadComputeProgram (gDevice ,"convert.slang" ,shaderProgram .writeRef ())); 334gConvertPipeline = createComputePipeline (shaderProgram ); 335 } 336 { 337ComPtr < IShaderProgram > shaderProgram ; 338SLANG_RETURN_ON_FAIL ( 339loadComputeProgram (gDevice ,"buildmip.slang" ,shaderProgram .writeRef ())); 340gBuildMipPipeline = createComputePipeline (shaderProgram ); 341 } 342 { 343ComPtr < IShaderProgram > shaderProgram ; 344SLANG_RETURN_ON_FAIL ( 345loadComputeProgram (gDevice ,"learnmip.slang" ,shaderProgram .writeRef ())); 346gLearnMipPipeline = createComputePipeline (shaderProgram ); 347 } 348 349// Load texture from file - this would need to be adapted to use slang-rhi texture loading 350Slang ::String imagePath = resourceBase .resolveResource ("checkerboard.jpg" ); 351gTexView = createTextureFromFile (imagePath .getBuffer (),textureWidth ,textureHeight ); 352textureWidth = 512 ;// Placeholder values 353textureHeight = 512 ; 354initMipOffsets (textureWidth ,textureHeight ); 355 356BufferDesc bufferDesc = {}; 357bufferDesc .size = mipMapOffset .getLast ()* sizeof (uint32_t ); 358bufferDesc .usage = BufferUsage ::ShaderResource |BufferUsage ::UnorderedAccess ; 359 360gAccumulateBuffer = gDevice -> createBuffer (bufferDesc ); 361if (!gAccumulateBuffer ) 362 { 363printf ("ERROR: Failed to create accumulate buffer!\n" ); 364return SLANG_FAIL ; 365 } 366 367gReconstructBuffer = gDevice -> createBuffer (bufferDesc ); 368if (!gReconstructBuffer ) 369 { 370printf ("ERROR: Failed to create reconstruct buffer!\n" ); 371return SLANG_FAIL ; 372 } 373 374int mipCount = 1 + Math ::Log2Ceil (Math ::Max (textureWidth ,textureHeight )); 375SubresourceData initialData = {}; 376initialData .data = gLearningTexture = 377createRenderTargetTexture (Format ::RGBA32Float ,textureWidth ,textureHeight ,mipCount ); 378gLearningTextureSRV = createSRV (gLearningTexture ); 379for (int i = 0 ;i < mipCount ;i ++ ) 380gLearningTextureUAVs .add (createUAV (gLearningTexture ,i )); 381 382gDiffTexture = 383createRenderTargetTexture (Format ::RGBA32Float ,textureWidth ,textureHeight ,mipCount ); 384gDiffTextureSRV = createSRV (gDiffTexture ); 385for (int i = 0 ;i < mipCount ;i ++ ) 386gDiffTextureUAVs .add (createUAV (gDiffTexture ,i )); 387 388SamplerDesc samplerDesc = {}; 389gSampler = gDevice -> createSampler (samplerDesc ); 390 391gDepthTexture = createDepthTexture (); 392gDepthTextureView = createDSV (gDepthTexture ); 393 394gRefImage = createRenderTargetTexture (Format ::RGBA8Unorm ,windowWidth ,windowHeight ,1 ); 395gRefImageSRV = createSRV (gRefImage ); 396 397gIterImage = createRenderTargetTexture (Format ::RGBA8Unorm ,windowWidth ,windowHeight ,1 ); 398gIterImageSRV = createSRV (gIterImage ); 399 400// Initialize textures 401 { 402auto commandEncoder = gQueue -> createCommandEncoder (); 403// Clear learning and diff textures 404commandEncoder -> clearTextureFloat (gLearningTexture ,kEntireTexture ,clearValue ); 405commandEncoder -> clearTextureFloat (gDiffTexture ,kEntireTexture ,clearValue ); 406 407gQueue -> submit (commandEncoder -> finish ()); 408 } 409 410return SLANG_OK ; 411 } 412 413void initMipOffsets (int w ,int h ) 414 { 415int layers = 1 + Math ::Log2Ceil (Math ::Max (w ,h )); 416uint32_t offset = 0 ; 417for (int i = 0 ;i < layers ;i ++ ) 418 { 419auto lw = Math ::Max (1 ,w >>i ); 420auto lh = Math ::Max (1 ,h >>i ); 421mipMapOffset .add (offset ); 422offset += lw * lh * 4 ; 423 } 424mipMapOffset .add (offset ); 425 } 426 427 glm::mat4x4 getTransformMatrix () 428 { 429float rotX = (rand () / (float )RAND_MAX )* 0.3f ; 430float rotY = (rand () / (float )RAND_MAX )* 0.2f ; 431 glm::mat4x4 matProj = glm::perspectiveRH_ZO ( 432 glm::radians (60.0f ), 433 (float )windowWidth / (float )windowHeight , 4340.1f , 4351000.0f ); 436auto identity = glm::mat4 (1.0f ); 437auto translate = glm::translate ( 438identity , 439 glm::vec3 ( 440-0.6f + 0.2f * (rand () / (float )RAND_MAX ), 441-0.6f + 0.2f * (rand () / (float )RAND_MAX ), 442-1.0f )); 443auto rot = glm::rotate (translate ,- glm::pi < float > ()* rotX , glm::vec3 (1.0f ,0.0f ,0.0f )); 444rot = glm::rotate (rot ,- glm::pi < float > ()* rotY , glm::vec3 (0.0f ,1.0f ,0.0f )); 445auto transformMatrix = matProj * rot ; 446transformMatrix = glm::transpose (transformMatrix ); 447return transformMatrix ; 448 } 449 450template < typename SetupPipelineFunc > 451void renderImage (ITexture * renderTarget ,const SetupPipelineFunc & setupPipeline ) 452 { 453auto commandEncoder = gQueue -> createCommandEncoder (); 454 455ComPtr < ITextureView > renderTargetView = createRTV (renderTarget ,Format ::RGBA8Unorm ); 456RenderPassColorAttachment colorAttachment = {}; 457colorAttachment .view = renderTargetView ; 458colorAttachment .loadOp = LoadOp ::Clear ; 459colorAttachment .clearValue [0 ]= 0.3f ; 460colorAttachment .clearValue [1 ]= 0.5f ; 461colorAttachment .clearValue [2 ]= 0.7f ; 462colorAttachment .clearValue [3 ]= 1.0f ; 463 464RenderPassDepthStencilAttachment depthAttachment = {}; 465depthAttachment .view = gDepthTextureView ; 466depthAttachment .depthLoadOp = LoadOp ::Clear ; 467depthAttachment .depthClearValue = 1.0f ; 468 469RenderPassDesc renderPass = {}; 470renderPass .colorAttachments = & colorAttachment ; 471renderPass .colorAttachmentCount = 1 ; 472renderPass .depthStencilAttachment = & depthAttachment ; 473 474auto renderEncoder = commandEncoder -> beginRenderPass (renderPass ); 475 476RenderState renderState = {}; 477renderState .viewports [0 ]= Viewport ::fromSize (windowWidth ,windowHeight ); 478renderState .viewportCount = 1 ; 479renderState .scissorRects [0 ]= ScissorRect ::fromSize (windowWidth ,windowHeight ); 480renderState .scissorRectCount = 1 ; 481renderState .vertexBuffers [0 ]= gVertexBuffer ; 482renderState .vertexBufferCount = 1 ; 483 484setupPipeline (renderEncoder ); 485 486 487renderEncoder -> setRenderState (renderState ); 488 489DrawArguments drawArgs = {}; 490drawArgs .vertexCount = 4 ; 491renderEncoder -> draw (drawArgs ); 492renderEncoder -> end (); 493gQueue -> submit (commandEncoder -> finish ()); 494 } 495 496void renderReferenceImage (glm::mat4x4 transformMatrix ) 497 { 498renderImage ( 499gRefImage , 500 [& ](IRenderPassEncoder * encoder ) 501 { 502auto rootObject = 503encoder -> bindPipeline (static_cast < IRenderPipeline *> (gRefPipeline .get ())); 504ShaderCursor rootCursor (rootObject ); 505rootCursor ["Uniforms" ]["modelViewProjection" ].setData ( 506& transformMatrix , 507sizeof (float )* 16 ); 508rootCursor ["Uniforms" ]["bwdTexture" ]["texture" ].setBinding (gTexView ); 509rootCursor ["Uniforms" ]["sampler" ].setBinding (gSampler ); 510rootCursor ["Uniforms" ]["mipOffset" ].setData ( 511mipMapOffset .getBuffer (), 512sizeof (uint32_t )* mipMapOffset .getCount ()); 513rootCursor ["Uniforms" ]["texRef" ].setBinding (gTexView ); 514rootCursor ["Uniforms" ]["bwdTexture" ]["accumulateBuffer" ].setBinding ( 515gAccumulateBuffer ); 516 }); 517 } 518 519virtual void renderFrame (ITexture * texture )override 520 { 521static uint32_t frameCount = 0 ; 522frameCount ++ ; 523auto transformMatrix = getTransformMatrix (); 524renderReferenceImage (transformMatrix ); 525 526// Clear buffers 527 { 528auto commandEncoder = gQueue -> createCommandEncoder (); 529commandEncoder -> clearBuffer (gAccumulateBuffer ,0 ,gAccumulateBuffer -> getDesc ().size ); 530commandEncoder -> clearBuffer (gReconstructBuffer ,0 ,gReconstructBuffer -> getDesc ().size ); 531 532if (resetLearntTexture ) 533 { 534commandEncoder -> clearTextureFloat (gLearningTexture ,kEntireTexture ,clearValue ); 535resetLearntTexture = false; 536 } 537gQueue -> submit (commandEncoder -> finish ()); 538 } 539 540// Render image using backward propagate shader to obtain texture-space gradients. 541renderImage ( 542gIterImage , 543 [& ](IRenderPassEncoder * encoder ) 544 { 545auto rootObject = encoder -> bindPipeline (gIterPipeline .get ()); 546ShaderCursor rootCursor (rootObject ); 547 548rootCursor ["Uniforms" ]["modelViewProjection" ].setData ( 549& transformMatrix , 550sizeof (float )* 16 ); 551rootCursor ["Uniforms" ]["bwdTexture" ]["texture" ].setBinding (gLearningTextureSRV ); 552rootCursor ["Uniforms" ]["sampler" ].setBinding (gSampler ); 553rootCursor ["Uniforms" ]["mipOffset" ].setData ( 554mipMapOffset .getBuffer (), 555sizeof (uint32_t )* mipMapOffset .getCount ()); 556rootCursor ["Uniforms" ]["texRef" ].setBinding (gRefImageSRV ); 557rootCursor ["Uniforms" ]["bwdTexture" ]["accumulateBuffer" ].setBinding ( 558gAccumulateBuffer ); 559rootCursor ["Uniforms" ]["bwdTexture" ]["minLOD" ].setData (5.0 ); 560 }); 561 562// Propagete gradients through mip map layers from top (lowest res) to bottom (highest res). 563 { 564auto commandEncoder = gQueue -> createCommandEncoder (); 565auto encoder = commandEncoder -> beginComputePass (); 566auto rootObject = encoder -> bindPipeline (gReconstructPipeline .get ()); 567for (int i = (int )mipMapOffset .getCount ()- 2 ;i >=0 ;i -- ) 568 { 569ShaderCursor rootCursor (rootObject ); 570rootCursor ["Uniforms" ]["mipOffset" ].setData ( 571mipMapOffset .getBuffer (), 572sizeof (uint32_t )* mipMapOffset .getCount ()); 573rootCursor ["Uniforms" ]["dstLayer" ].setData (i ); 574rootCursor ["Uniforms" ]["layerCount" ].setData (mipMapOffset .getCount ()- 1 ); 575rootCursor ["Uniforms" ]["width" ].setData (textureWidth ); 576rootCursor ["Uniforms" ]["height" ].setData (textureHeight ); 577rootCursor ["Uniforms" ]["accumulateBuffer" ].setBinding (gAccumulateBuffer ); 578rootCursor ["Uniforms" ]["dstBuffer" ].setBinding (gReconstructBuffer ); 579 580encoder -> dispatchCompute ( 581 ((textureWidth >>i )+ 15 ) /16 , 582 ((textureHeight >>i )+ 15 ) /16 , 5831 ); 584 } 585encoder -> end (); 586gQueue -> submit (commandEncoder -> finish ()); 587 588commandEncoder = gQueue -> createCommandEncoder (); 589// Convert bottom layer mip from buffer to texture 590 { 591auto encoder = commandEncoder -> beginComputePass (); 592auto rootObject = encoder -> bindPipeline (gConvertPipeline .get ()); 593ShaderCursor rootCursor (rootObject ); 594rootCursor ["Uniforms" ]["mipOffset" ].setData ( 595mipMapOffset .getBuffer (), 596sizeof (uint32_t )* mipMapOffset .getCount ()); 597rootCursor ["Uniforms" ]["dstLayer" ].setData (0 ); 598rootCursor ["Uniforms" ]["width" ].setData (textureWidth ); 599rootCursor ["Uniforms" ]["height" ].setData (textureHeight ); 600rootCursor ["Uniforms" ]["srcBuffer" ].setBinding (gReconstructBuffer ); 601rootCursor ["Uniforms" ]["dstTexture" ].setBinding (gDiffTextureUAVs [0 ]); 602encoder -> dispatchCompute ((textureWidth + 15 ) /16 , (textureHeight + 15 ) /16 ,1 ); 603encoder -> end (); 604 } 605 606// Build higher level mip map layers 607encoder = commandEncoder -> beginComputePass (); 608rootObject = encoder -> bindPipeline (gBuildMipPipeline .get ()); 609for (int i = 1 ;i < (int )mipMapOffset .getCount ()- 1 ;i ++ ) 610 { 611 612ShaderCursor rootCursor (rootObject ); 613rootCursor ["Uniforms" ]["dstWidth" ].setData (textureWidth >>i ); 614rootCursor ["Uniforms" ]["dstHeight" ].setData (textureHeight >>i ); 615rootCursor ["Uniforms" ]["srcTexture" ].setBinding (gDiffTextureUAVs [i - 1 ]); 616rootCursor ["Uniforms" ]["dstTexture" ].setBinding (gDiffTextureUAVs [i ]); 617encoder -> dispatchCompute ( 618 ((textureWidth >>i )+ 15 ) /16 , 619 ((textureHeight >>i )+ 15 ) /16 , 6201 ); 621 } 622encoder -> end (); 623 624// Accumulate gradients to learnt texture 625encoder = commandEncoder -> beginComputePass (); 626rootObject = encoder -> bindPipeline (gLearnMipPipeline .get ()); 627for (int i = 0 ;i < (int )mipMapOffset .getCount ()- 1 ;i ++ ) 628 { 629ShaderCursor rootCursor (rootObject ); 630rootCursor ["Uniforms" ]["dstWidth" ].setData (textureWidth >>i ); 631rootCursor ["Uniforms" ]["dstHeight" ].setData (textureHeight >>i ); 632rootCursor ["Uniforms" ]["learningRate" ].setData (0.1f ); 633rootCursor ["Uniforms" ]["srcTexture" ].setBinding (gDiffTextureUAVs [i ]); 634rootCursor ["Uniforms" ]["dstTexture" ].setBinding (gLearningTextureUAVs [i ]); 635encoder -> dispatchCompute ( 636 ((textureWidth >>i )+ 15 ) /16 , 637 ((textureHeight >>i )+ 15 ) /16 , 6381 ); 639 } 640encoder -> end (); 641 642gQueue -> submit (commandEncoder -> finish ()); 643 } 644 645// Draw currently learnt texture 646 { 647auto commandEncoder = gQueue -> createCommandEncoder (); 648 649ComPtr < ITextureView > textureView = gDevice -> createTextureView (texture , {}); 650RenderPassColorAttachment colorAttachment = {}; 651colorAttachment .view = textureView ; 652colorAttachment .loadOp = LoadOp ::Clear ; 653 654RenderPassDesc renderPass = {}; 655renderPass .colorAttachments = & colorAttachment ; 656renderPass .colorAttachmentCount = 1 ; 657 658auto renderEncoder = commandEncoder -> beginRenderPass (renderPass ); 659 660drawTexturedQuad (renderEncoder ,0 ,0 ,textureWidth ,textureHeight ,gLearningTextureSRV ); 661 662int refImageWidth = windowWidth - textureWidth - 10 ; 663int refImageHeight = refImageWidth * windowHeight /windowWidth ; 664drawTexturedQuad ( 665renderEncoder , 666textureWidth + 10 , 6670 , 668refImageWidth , 669refImageHeight , 670gRefImageSRV ); 671 672drawTexturedQuad ( 673renderEncoder , 674textureWidth + 10 , 675refImageHeight + 10 , 676refImageWidth , 677refImageHeight , 678gIterImageSRV ); 679renderEncoder -> end (); 680gQueue -> submit (commandEncoder -> finish ()); 681 } 682 683if (!isTestMode ()) 684 { 685gSurface -> present (); 686 } 687 } 688 689void drawTexturedQuad ( 690IRenderPassEncoder * renderEncoder , 691int x , 692int y , 693int w , 694int h , 695ITextureView * srv ) 696 { 697RenderState renderState = {}; 698renderState .viewports [0 ]= Viewport ::fromSize (windowWidth ,windowHeight ); 699renderState .viewportCount = 1 ; 700renderState .scissorRects [0 ]= ScissorRect ::fromSize (windowWidth ,windowHeight ); 701renderState .scissorRectCount = 1 ; 702renderState .vertexBuffers [0 ]= gVertexBuffer ; 703renderState .vertexBufferCount = 1 ; 704renderEncoder -> setRenderState (renderState ); 705 706auto root = 707renderEncoder -> bindPipeline (static_cast < IRenderPipeline *> (gDrawQuadPipeline .get ())); 708ShaderCursor rootCursor (root ); 709rootCursor ["Uniforms" ]["x" ].setData (x ); 710rootCursor ["Uniforms" ]["y" ].setData (y ); 711rootCursor ["Uniforms" ]["width" ].setData (w ); 712rootCursor ["Uniforms" ]["height" ].setData (h ); 713rootCursor ["Uniforms" ]["viewWidth" ].setData (windowWidth ); 714rootCursor ["Uniforms" ]["viewHeight" ].setData (windowHeight ); 715rootCursor ["Uniforms" ]["texture" ].setBinding (srv ); 716rootCursor ["Uniforms" ]["sampler" ].setBinding (gSampler ); 717 718DrawArguments drawArgs = {}; 719drawArgs .vertexCount = 4 ; 720renderEncoder -> draw (drawArgs ); 721 } 722}; 723 724EXAMPLE_MAIN (innerMain < AutoDiffTexture > );