src/ngfx/porting/d3d/D3DGraphicsPipeline.cpp

Source code

/*
 * Copyright 2020 GoPro Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
#include "ngfx/porting/d3d/D3DGraphicsPipeline.h"
#include "ngfx/porting/d3d/D3DCommandList.h"
#include "ngfx/porting/d3d/D3DDebugUtil.h"
#include "ngfx/porting/d3d/D3DGraphicsContext.h"
#include "ngfx/porting/d3d/D3DShaderModule.h"
#include <d3dx12.h>
using namespace ngfx;
using namespace std;

D3D12_PRIMITIVE_TOPOLOGY_TYPE
D3DGraphicsPipeline::getPrimitiveTopologyType(D3D_PRIMITIVE_TOPOLOGY topology) {
  switch (topology) {
  case D3D_PRIMITIVE_TOPOLOGY_LINELIST:
  case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP:
    return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
    break;
  case D3D_PRIMITIVE_TOPOLOGY_POINTLIST:
    return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
    break;
  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST:
  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP:
    return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
    break;
  default:
    NGFX_ERR("topology: %d unsupported", topology);
    return D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED;
    break;
  }
}

void D3DGraphicsPipeline::create(
    D3DGraphicsContext *ctx, const State &state,
    const std::vector<CD3DX12_ROOT_PARAMETER1> &rootParameters,
    const std::vector<D3D12_INPUT_ELEMENT_DESC> &inputElements,
    const Shaders &shaders, DXGI_FORMAT colorFormat, DXGI_FORMAT depthFormat) {
  D3DPipeline::create(ctx);
  HRESULT hResult;
  d3dPrimitiveTopology = state.primitiveTopology;
  auto d3dDevice = ctx->d3dDevice.v;
  createRootSignature(
      rootParameters,
      D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  D3D12_RASTERIZER_DESC rasterizerState = {
      state.fillMode,
      state.cullMode,
      state.frontFaceCounterClockwise,
      0,
      0.0f,
      0.0f,
      state.depthTestEnable,
      FALSE,
      FALSE,
      0,
      D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF};
  D3D12_RENDER_TARGET_BLEND_DESC renderTargetBlendDesc = {
      state.blendEnable,         FALSE,
      state.blendSrcColorFactor, state.blendDstColorFactor,
      state.blendColorOp,        state.blendSrcAlphaFactor,
      state.blendDstAlphaFactor, state.blendAlphaOp,
      D3D12_LOGIC_OP_NOOP,       state.colorWriteMask};

  D3D12_BLEND_DESC blendDesc = {};
  blendDesc.AlphaToCoverageEnable = FALSE;
  blendDesc.IndependentBlendEnable = FALSE;
  blendDesc.RenderTarget[0] = renderTargetBlendDesc;

  CD3DX12_DEPTH_STENCIL_DESC depthStencilDesc(D3D12_DEFAULT);
  depthStencilDesc.DepthEnable = state.depthTestEnable;

  D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {};
  desc.InputLayout = {inputElements.data(), UINT(inputElements.size())};
  desc.pRootSignature = d3dRootSignature.Get();
  desc.VS = shaders.VS;
  desc.PS = shaders.PS;
  desc.GS = shaders.GS;
  desc.RasterizerState = rasterizerState;
  desc.BlendState = blendDesc;
  desc.DepthStencilState = depthStencilDesc;
  desc.DSVFormat = depthFormat;
  desc.SampleMask = UINT_MAX;
  desc.PrimitiveTopologyType =
      getPrimitiveTopologyType(state.primitiveTopology);
  desc.NumRenderTargets = state.numColorAttachments;
  for (uint32_t j = 0; j < desc.NumRenderTargets; j++)
    desc.RTVFormats[j] = colorFormat;
  desc.SampleDesc.Count = state.numSamples;

  V(d3dDevice->CreateGraphicsPipelineState(&desc,
                                           IID_PPV_ARGS(&d3dPipelineState)));
}

GraphicsPipeline *
GraphicsPipeline::create(GraphicsContext *graphicsContext, const State &state,
                         VertexShaderModule *vs, FragmentShaderModule *fs,
                         PixelFormat colorFormat, PixelFormat depthFormat,
                         std::set<std::string> instanceAttributes) {
  D3DGraphicsPipeline *d3dGraphicsPipeline = new D3DGraphicsPipeline();

  auto getAlphaBlendFactor = [](BlendFactor blendFactor) -> BlendFactor {
    switch (blendFactor) {
    case BLEND_FACTOR_SRC_COLOR:
      return BLEND_FACTOR_SRC_ALPHA;
      break;
    case BLEND_FACTOR_DST_COLOR:
      return BLEND_FACTOR_DST_ALPHA;
      break;
    case BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
      return BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
      break;
    case BLEND_FACTOR_ONE_MINUS_DST_COLOR:
      return BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
      break;
    default:
      return blendFactor;
      break;
    };
  };
  struct State {
    D3D12_PRIMITIVE_TOPOLOGY primitiveTopology =
        D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
    D3D12_FILL_MODE fillMode = D3D12_FILL_MODE_SOLID;
    bool blendEnable = false;
    D3D12_BLEND blendSrcColorFactor = D3D12_BLEND_SRC_ALPHA;
    D3D12_BLEND blendDstColorFactor = D3D12_BLEND_INV_SRC_ALPHA;
    D3D12_BLEND_OP blendColorOp = D3D12_BLEND_OP_ADD;
    D3D12_BLEND blendSrcAlphaFactor = D3D12_BLEND_SRC_ALPHA;
    D3D12_BLEND blendDstAlphaFactor = D3D12_BLEND_INV_SRC_ALPHA;
    D3D12_BLEND_OP blendAlphaOp = D3D12_BLEND_OP_ADD;
    D3D12_COLOR_WRITE_ENABLE colorWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
    D3D12_CULL_MODE cullMode = D3D12_CULL_MODE_BACK;
    bool frontFaceCounterClockwise = false;
    float lineWidth = 1.0f;
    bool depthTestEnable = false, depthWriteEnable = false;
    D3DRenderPass *renderPass = nullptr;
    uint32_t numSamples = 1, numColorAttachments = 1;
  };
  D3DGraphicsPipeline::State d3dState = {
      D3D_PRIMITIVE_TOPOLOGY(state.primitiveTopology),
      D3D12_FILL_MODE(state.polygonMode),
      state.blendEnable,
      D3D12_BLEND(state.srcColorBlendFactor),
      D3D12_BLEND(state.dstColorBlendFactor),
      D3D12_BLEND_OP(state.colorBlendOp),
      D3D12_BLEND(getAlphaBlendFactor(state.srcAlphaBlendFactor)),
      D3D12_BLEND(getAlphaBlendFactor(state.dstAlphaBlendFactor)),
      D3D12_BLEND_OP(state.alphaBlendOp),
      state.colorWriteMask,
      D3D12_CULL_MODE(state.cullModeFlags),
      (state.frontFace == FRONT_FACE_COUNTER_CLOCKWISE),
      state.lineWidth,
      state.depthTestEnable,
      state.depthWriteEnable,
      d3d(state.renderPass),
      state.numSamples,
      state.numColorAttachments};
  auto &descriptorBindings = d3dGraphicsPipeline->descriptorBindings;

  std::vector<CD3DX12_ROOT_PARAMETER1> d3dRootParams;
  std::vector<std::unique_ptr<CD3DX12_DESCRIPTOR_RANGE1>> d3dDescriptorRanges;

  std::map<uint32_t, ShaderModule::DescriptorInfo> descriptors;
  for (auto &descriptor : vs->descriptors)
    descriptors[descriptor.set] = descriptor;
  for (auto &descriptor : fs->descriptors)
    descriptors[descriptor.set] = descriptor;
  uint32_t numDescriptors = uint32_t(descriptors.size());
  descriptorBindings.resize(numDescriptors);

  D3DPipelineUtil::parseDescriptors(descriptors, descriptorBindings,
                                    d3dRootParams, d3dDescriptorRanges,
                                    D3DPipelineUtil::PIPELINE_TYPE_GRAPHICS);

  std::vector<D3D12_INPUT_ELEMENT_DESC> d3dVertexInputAttributes(
      vs->attributes.size());
  auto &vertexAttributeBindings = d3dGraphicsPipeline->vertexAttributeBindings;
  vertexAttributeBindings.resize(vs->attributes.size());
  struct SemanticData {
    string name;
    uint32_t index;
  };
  std::vector<SemanticData> semanticData(vs->attributes.size());
  for (int j = 0; j < vs->attributes.size(); j++) {
    const auto &va = vs->attributes[j];
    uint32_t binding = va.location, offset = 0; // TODO: va.count
    D3D12_INPUT_CLASSIFICATION inputRate =
        D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
    if (instanceAttributes.find(va.name) != instanceAttributes.end())
      inputRate = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
    uint32_t semanticIndexOffset =
        uint32_t(va.semantic.find_first_of("0123456789"));
    string &semanticName = semanticData[j].name;
    uint32_t &semanticIndex = semanticData[j].index;
    if (semanticIndexOffset != string::npos) {
      semanticName = va.semantic.substr(0, semanticIndexOffset);
      string semanticIndexStr = va.semantic.substr(semanticIndexOffset);
      semanticIndex = atoi(semanticIndexStr.c_str());
    } else {
      semanticName = va.semantic;
      semanticIndex = 0;
    }
    d3dVertexInputAttributes[j] = {
        semanticName.c_str(),
        semanticIndex,
        DXGI_FORMAT(va.format),
        binding,
        offset,
        inputRate,
        (inputRate == D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA) ? UINT(0)
                                                                  : UINT(1)};
    vertexAttributeBindings[j] = j;
  }

  D3DGraphicsPipeline::Shaders shaders;
  shaders.VS = d3d(vs)->d3dShaderByteCode;
  shaders.PS = d3d(fs)->d3dShaderByteCode;
  d3dGraphicsPipeline->create(
      d3d(graphicsContext), d3dState, d3dRootParams, d3dVertexInputAttributes,
      shaders, DXGI_FORMAT(colorFormat), DXGI_FORMAT(depthFormat));

  return d3dGraphicsPipeline;
}

Updated on 3 April 2021 at 20:21:51 PDT