home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 13 The Compute Shader / Blur / BlurFilter.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  7.3 KB  |  223 lines

  1. //***************************************************************************************
  2. // BlurFilter.cpp by Frank Luna (C) 2011 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "BlurFilter.h"
  6.  
  7. BlurFilter::BlurFilter(ID3D12Device* device, 
  8.                        UINT width, UINT height,
  9.                        DXGI_FORMAT format)
  10. {
  11.     md3dDevice = device;
  12.  
  13.     mWidth = width;
  14.     mHeight = height;
  15.     mFormat = format;
  16.  
  17.     BuildResources();
  18. }
  19.  
  20. ID3D12Resource* BlurFilter::Output()
  21. {
  22.     return mBlurMap0.Get();
  23. }
  24.  
  25. void BlurFilter::BuildDescriptors(CD3DX12_CPU_DESCRIPTOR_HANDLE hCpuDescriptor,
  26.                                   CD3DX12_GPU_DESCRIPTOR_HANDLE hGpuDescriptor,
  27.                                   UINT descriptorSize)
  28. {
  29.     // Save references to the descriptors. 
  30.     mBlur0CpuSrv = hCpuDescriptor;
  31.     mBlur0CpuUav = hCpuDescriptor.Offset(1, descriptorSize);
  32.     mBlur1CpuSrv = hCpuDescriptor.Offset(1, descriptorSize);
  33.     mBlur1CpuUav = hCpuDescriptor.Offset(1, descriptorSize);
  34.  
  35.     mBlur0GpuSrv = hGpuDescriptor;
  36.     mBlur0GpuUav = hGpuDescriptor.Offset(1, descriptorSize);
  37.     mBlur1GpuSrv = hGpuDescriptor.Offset(1, descriptorSize);
  38.     mBlur1GpuUav = hGpuDescriptor.Offset(1, descriptorSize);
  39.  
  40.     BuildDescriptors();
  41. }
  42.  
  43. void BlurFilter::OnResize(UINT newWidth, UINT newHeight)
  44. {
  45.     if((mWidth != newWidth) || (mHeight != newHeight))
  46.     {
  47.         mWidth = newWidth;
  48.         mHeight = newHeight;
  49.  
  50.         BuildResources();
  51.  
  52.         // New resource, so we need new descriptors to that resource.
  53.         BuildDescriptors();
  54.     }
  55. }
  56.  
  57. void BlurFilter::Execute(ID3D12GraphicsCommandList* cmdList, 
  58.                          ID3D12RootSignature* rootSig,
  59.                          ID3D12PipelineState* horzBlurPSO,
  60.                          ID3D12PipelineState* vertBlurPSO,
  61.                          ID3D12Resource* input, 
  62.                          int blurCount)
  63. {
  64.     auto weights = CalcGaussWeights(2.5f);
  65.     int blurRadius = (int)weights.size() / 2;
  66.  
  67.     cmdList->SetComputeRootSignature(rootSig);
  68.  
  69.     cmdList->SetComputeRoot32BitConstants(0, 1, &blurRadius, 0);
  70.     cmdList->SetComputeRoot32BitConstants(0, (UINT)weights.size(), weights.data(), 1);
  71.  
  72.     cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(input,
  73.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE));
  74.  
  75.     cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mBlurMap0.Get(),
  76.         D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST));
  77.  
  78.     // Copy the input (back-buffer in this example) to BlurMap0.
  79.     cmdList->CopyResource(mBlurMap0.Get(), input);
  80.     
  81.     cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mBlurMap0.Get(),
  82.         D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
  83.  
  84.     cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mBlurMap1.Get(),
  85.         D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
  86.  
  87.     for(int i = 0; i < blurCount; ++i)
  88.     {
  89.         //
  90.         // Horizontal Blur pass.
  91.         //
  92.  
  93.         cmdList->SetPipelineState(horzBlurPSO);
  94.  
  95.         cmdList->SetComputeRootDescriptorTable(1, mBlur0GpuSrv);
  96.         cmdList->SetComputeRootDescriptorTable(2, mBlur1GpuUav);
  97.  
  98.         // How many groups do we need to dispatch to cover a row of pixels, where each
  99.         // group covers 256 pixels (the 256 is defined in the ComputeShader).
  100.         UINT numGroupsX = (UINT)ceilf(mWidth / 256.0f);
  101.         cmdList->Dispatch(numGroupsX, mHeight, 1);
  102.  
  103.         cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mBlurMap0.Get(),
  104.             D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
  105.  
  106.         cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mBlurMap1.Get(),
  107.             D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_GENERIC_READ));
  108.  
  109.         //
  110.         // Vertical Blur pass.
  111.         //
  112.  
  113.         cmdList->SetPipelineState(vertBlurPSO);
  114.  
  115.         cmdList->SetComputeRootDescriptorTable(1, mBlur1GpuSrv);
  116.         cmdList->SetComputeRootDescriptorTable(2, mBlur0GpuUav);
  117.  
  118.         // How many groups do we need to dispatch to cover a column of pixels, where each
  119.         // group covers 256 pixels  (the 256 is defined in the ComputeShader).
  120.         UINT numGroupsY = (UINT)ceilf(mHeight / 256.0f);
  121.         cmdList->Dispatch(mWidth, numGroupsY, 1);
  122.  
  123.         cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mBlurMap0.Get(),
  124.             D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_GENERIC_READ));
  125.  
  126.         cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mBlurMap1.Get(),
  127.             D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
  128.     }
  129. }
  130.  
  131. std::vector<float> BlurFilter::CalcGaussWeights(float sigma)
  132. {
  133.     float twoSigma2 = 2.0f*sigma*sigma;
  134.  
  135.     // Estimate the blur radius based on sigma since sigma controls the "width" of the bell curve.
  136.     // For example, for sigma = 3, the width of the bell curve is 
  137.     int blurRadius = (int)ceil(2.0f * sigma);
  138.  
  139.     assert(blurRadius <= MaxBlurRadius);
  140.  
  141.     std::vector<float> weights;
  142.     weights.resize(2 * blurRadius + 1);
  143.     
  144.     float weightSum = 0.0f;
  145.  
  146.     for(int i = -blurRadius; i <= blurRadius; ++i)
  147.     {
  148.         float x = (float)i;
  149.  
  150.         weights[i+blurRadius] = expf(-x*x / twoSigma2);
  151.  
  152.         weightSum += weights[i+blurRadius];
  153.     }
  154.  
  155.     // Divide by the sum so all the weights add up to 1.0.
  156.     for(int i = 0; i < weights.size(); ++i)
  157.     {
  158.         weights[i] /= weightSum;
  159.     }
  160.  
  161.     return weights;
  162. }
  163.  
  164. void BlurFilter::BuildDescriptors()
  165. {
  166.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  167.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  168.     srvDesc.Format = mFormat;
  169.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  170.     srvDesc.Texture2D.MostDetailedMip = 0;
  171.     srvDesc.Texture2D.MipLevels = 1;
  172.  
  173.     D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
  174.  
  175.     uavDesc.Format = mFormat;
  176.     uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
  177.     uavDesc.Texture2D.MipSlice = 0;
  178.  
  179.     md3dDevice->CreateShaderResourceView(mBlurMap0.Get(), &srvDesc, mBlur0CpuSrv);
  180.     md3dDevice->CreateUnorderedAccessView(mBlurMap0.Get(), nullptr, &uavDesc, mBlur0CpuUav);
  181.  
  182.     md3dDevice->CreateShaderResourceView(mBlurMap1.Get(), &srvDesc, mBlur1CpuSrv);
  183.     md3dDevice->CreateUnorderedAccessView(mBlurMap1.Get(), nullptr, &uavDesc, mBlur1CpuUav);
  184. }
  185.  
  186. void BlurFilter::BuildResources()
  187. {
  188.     // Note, compressed formats cannot be used for UAV.  We get error like:
  189.     // ERROR: ID3D11Device::CreateTexture2D: The format (0x4d, BC3_UNORM) 
  190.     // cannot be bound as an UnorderedAccessView, or cast to a format that
  191.     // could be bound as an UnorderedAccessView.  Therefore this format 
  192.     // does not support D3D11_BIND_UNORDERED_ACCESS.
  193.  
  194.     D3D12_RESOURCE_DESC texDesc;
  195.     ZeroMemory(&texDesc, sizeof(D3D12_RESOURCE_DESC));
  196.     texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
  197.     texDesc.Alignment = 0;
  198.     texDesc.Width = mWidth;
  199.     texDesc.Height = mHeight;
  200.     texDesc.DepthOrArraySize = 1;
  201.     texDesc.MipLevels = 1;
  202.     texDesc.Format = mFormat;
  203.     texDesc.SampleDesc.Count = 1;
  204.     texDesc.SampleDesc.Quality = 0;
  205.     texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
  206.     texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
  207.  
  208.     ThrowIfFailed(md3dDevice->CreateCommittedResource(
  209.         &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
  210.         D3D12_HEAP_FLAG_NONE,
  211.         &texDesc,
  212.         D3D12_RESOURCE_STATE_COMMON,
  213.         nullptr,
  214.         IID_PPV_ARGS(&mBlurMap0)));
  215.  
  216.     ThrowIfFailed(md3dDevice->CreateCommittedResource(
  217.         &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
  218.         D3D12_HEAP_FLAG_NONE,
  219.         &texDesc,
  220.         D3D12_RESOURCE_STATE_COMMON,
  221.         nullptr,
  222.         IID_PPV_ARGS(&mBlurMap1)));
  223. }