Example #1
0
  void PreDraw(uint32_t eid, ID3D12GraphicsCommandList *cmd)
  {
    if(std::find(m_Events.begin(), m_Events.end(), eid) == m_Events.end())
      return;

    // we customise the pipeline to disable framebuffer writes, but perform normal testing
    // and substitute our quad calculation fragment shader that writes to a storage image
    // that is bound in a new root signature element.

    D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState;
    m_PrevState = rs;

    // check cache first
    CachedPipeline cache = m_PipelineCache[rs.pipe];

    // if we don't get a hit, create a modified pipeline
    if(cache.pipe == NULL)
    {
      HRESULT hr = S_OK;

      WrappedID3D12RootSignature *sig =
          m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(
              rs.graphics.rootsig);

      // need to be able to add a descriptor table with our UAV without hitting the 64 DWORD limit
      RDCASSERT(sig->sig.dwordLength < 64);

      D3D12RootSignature modsig = sig->sig;

      // make sure no other UAV tables overlap. We can't remove elements entirely because then the
      // root signature indices wouldn't match up as expected.
      // Instead move them into an unused space.
      for(size_t i = 0; i < modsig.params.size(); i++)
      {
        if(modsig.params[i].ShaderVisibility == D3D12_SHADER_VISIBILITY_PIXEL)
        {
          if(modsig.params[i].ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV)
          {
            modsig.params[i].Descriptor.RegisterSpace = modsig.numSpaces;
          }
          else if(modsig.params[i].ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
          {
            for(size_t r = 0; r < modsig.params[i].ranges.size(); r++)
            {
              modsig.params[i].ranges[r].RegisterSpace = modsig.numSpaces;
            }
          }
        }
      }

      D3D12_DESCRIPTOR_RANGE1 range;
      range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
      range.NumDescriptors = 1;
      range.BaseShaderRegister = 0;
      range.RegisterSpace = 0;
      range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE;
      range.OffsetInDescriptorsFromTableStart = 0;

      modsig.params.push_back(D3D12RootSignatureParameter());
      D3D12RootSignatureParameter &param = modsig.params.back();
      param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
      param.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
      param.DescriptorTable.NumDescriptorRanges = 1;
      param.DescriptorTable.pDescriptorRanges = &range;

      cache.sigElem = uint32_t(modsig.params.size() - 1);

      std::vector<D3D12_ROOT_PARAMETER1> params;
      params.resize(modsig.params.size());
      for(size_t i = 0; i < params.size(); i++)
        params[i] = modsig.params[i];

      ID3DBlob *root = m_pDevice->GetShaderCache()->MakeRootSig(modsig);

      hr = m_pDevice->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(),
                                          __uuidof(ID3D12RootSignature), (void **)&cache.sig);
      RDCASSERTEQUAL(hr, S_OK);

      SAFE_RELEASE(root);

      WrappedID3D12PipelineState *origPSO =
          m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12PipelineState>(rs.pipe);

      RDCASSERT(origPSO->IsGraphics());

      D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc = origPSO->GetGraphicsDesc();

      for(size_t i = 0; i < ARRAY_COUNT(pipeDesc.BlendState.RenderTarget); i++)
        pipeDesc.BlendState.RenderTarget[i].RenderTargetWriteMask = 0;

      // disable depth/stencil writes
      pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
      pipeDesc.DepthStencilState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
      pipeDesc.DepthStencilState.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
      pipeDesc.DepthStencilState.StencilWriteMask = 0;

      pipeDesc.PS = m_QuadWritePS;

      pipeDesc.pRootSignature = cache.sig;

      hr = m_pDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState),
                                                  (void **)&cache.pipe);
      RDCASSERTEQUAL(hr, S_OK);

      m_PipelineCache[rs.pipe] = cache;
    }

    // modify state for first draw call
    rs.pipe = GetResID(cache.pipe);
    rs.graphics.rootsig = GetResID(cache.sig);

    if(rs.graphics.sigelems.size() <= cache.sigElem)
      rs.graphics.sigelems.resize(cache.sigElem + 1);

    PortableHandle uav = m_UAV;

    // if a CBV_SRV_UAV heap is already set, we need to copy our descriptor in
    // if we haven't already. Otherwise we can set our own heap.
    for(size_t i = 0; i < rs.heaps.size(); i++)
    {
      WrappedID3D12DescriptorHeap *h =
          m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12DescriptorHeap>(rs.heaps[i]);
      if(h->GetDesc().Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
      {
        // use the last descriptor
        D3D12_CPU_DESCRIPTOR_HANDLE dst = h->GetCPUDescriptorHandleForHeapStart();
        dst.ptr += (h->GetDesc().NumDescriptors - 1) * sizeof(D3D12Descriptor);

        if(m_CopiedHeaps.find(rs.heaps[i]) == m_CopiedHeaps.end())
        {
          WrappedID3D12DescriptorHeap *h2 =
              m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12DescriptorHeap>(m_UAV.heap);
          D3D12_CPU_DESCRIPTOR_HANDLE src = h2->GetCPUDescriptorHandleForHeapStart();
          src.ptr += m_UAV.index * sizeof(D3D12Descriptor);

          // can't do a copy because the src heap is CPU write-only (shader visible). So instead,
          // create directly
          D3D12Descriptor *srcDesc = (D3D12Descriptor *)src.ptr;
          srcDesc->Create(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pDevice, dst);

          m_CopiedHeaps.insert(rs.heaps[i]);
        }

        uav = ToPortableHandle(dst);

        break;
      }
    }

    if(uav.heap == m_UAV.heap)
      rs.heaps.push_back(m_UAV.heap);

    rs.graphics.sigelems[cache.sigElem] =
        D3D12RenderState::SignatureElement(eRootTable, uav.heap, uav.index);

    // as we're changing the root signature, we need to reapply all elements,
    // so just apply all state
    if(cmd)
      rs.ApplyState(cmd);
  }