code:
#pragma once

#define D3D11_NO_HELPERS

#include "d3d9_include.h"
#include "d3d9_caps.h"

#include "d3d9_format.h"

#include "../dxso/dxso_common.h"
#include "../dxvk/dxvk_device.h"

#include "../util/util_matrix.h"
#include "../util/util_misc.h"

#include <d3dcommon.h>

namespace dxvk {

  struct D3D9ShaderMasks {
    uint32_t samplerMask;
    uint32_t rtMask;
  };

  static constexpr D3D9ShaderMasks FixedFunctionMask =
    { 0b1111111, 0b1 };

  struct D3D9MipFilter {
    bool                MipsEnabled;
    VkSamplerMipmapMode MipFilter;
  };

  struct D3D9BlendState {
    D3DBLEND   Src;
    D3DBLEND   Dst;
    D3DBLENDOP Op;
  };

  inline void FixupBlendState(D3D9BlendState& State) {
    // Old DirectX 6 HW feature that still exists...
    // Yuck!
    if (unlikely(State.Src == D3DBLEND_BOTHSRCALPHA)) {
      State.Src = D3DBLEND_SRCALPHA;
      State.Dst = D3DBLEND_INVSRCALPHA;
    }
    else if (unlikely(State.Src == D3DBLEND_BOTHINVSRCALPHA)) {
      State.Src = D3DBLEND_INVSRCALPHA;
      State.Dst = D3DBLEND_SRCALPHA;
    }
  }

  inline bool InvalidSampler(DWORD Sampler) {
    if (Sampler >= caps::MaxTexturesPS && Sampler < D3DDMAPSAMPLER)
      return true;

    if (Sampler > D3DVERTEXTEXTURESAMPLER3)
      return true;

    return false;
  }

  inline DWORD RemapSamplerState(DWORD Sampler) {
    if (Sampler >= D3DDMAPSAMPLER)
      Sampler = caps::MaxTexturesPS + (Sampler - D3DDMAPSAMPLER);

    return Sampler;
  }

  inline std::pair<DxsoProgramType, DWORD> RemapStateSamplerShader(DWORD Sampler) {
    if (Sampler >= caps::MaxTexturesPS + 1)
      return std::make_pair(DxsoProgramTypes::VertexShader, Sampler - caps::MaxTexturesPS - 1);

    return std::make_pair(DxsoProgramTypes::PixelShader, Sampler);
  }

  inline std::pair<DxsoProgramType, DWORD> RemapSamplerShader(DWORD Sampler) {
    Sampler = RemapSamplerState(Sampler);

    return RemapStateSamplerShader(Sampler);
  }

  template <typename T, typename J>
  void CastRefPrivate(J* ptr, bool AddRef) {
    if (ptr == nullptr)
      return;

    T* castedPtr = reinterpret_cast<T*>(ptr);
    AddRef ? castedPtr->AddRefPrivate() : castedPtr->ReleasePrivate();
  }

  HRESULT DisassembleShader(
    const void*      pShader,
          BOOL       EnableColorCode,
          char*      pComments,
          ID3DBlob** ppDisassembly);

  HRESULT DecodeMultiSampleType(
    const Rc<DxvkDevice>&           pDevice,
          D3DMULTISAMPLE_TYPE       MultiSample,
          DWORD                     MultisampleQuality,
          VkSampleCountFlagBits*    pSampleCount);

  VkFormat GetPackedDepthStencilFormat(D3D9Format Format);

  VkFormatFeatureFlags GetImageFormatFeatures(DWORD Usage);

  VkImageUsageFlags GetImageUsageFlags(DWORD Usage);

  inline VkFormat PickSRGB(VkFormat format, VkFormat srgbFormat, bool srgb) {
    return srgb ? srgbFormat : format;
  }

  inline VkShaderStageFlagBits GetShaderStage(DxsoProgramType ProgramType) {
    switch (ProgramType) {
      case DxsoProgramTypes::VertexShader:  return VK_SHADER_STAGE_VERTEX_BIT;
      case DxsoProgramTypes::PixelShader:   return VK_SHADER_STAGE_FRAGMENT_BIT;
      default:                              return VkShaderStageFlagBits(0);
    }
  }

  inline uint32_t GetTransformIndex(D3DTRANSFORMSTATETYPE Type) {
    if (Type == D3DTS_VIEW)
      return 0;

    if (Type == D3DTS_PROJECTION)
      return 1;

    if (Type >= D3DTS_TEXTURE0 && Type <= D3DTS_TEXTURE7)
      return 2 + (Type - D3DTS_TEXTURE0);

    return 10 + (Type - D3DTS_WORLD);
  }

  inline Matrix4 ConvertMatrix(const D3DMATRIX* Matrix) {
    if (Matrix == nullptr) // Identity.
      return Matrix4();

    return Matrix4(Matrix->m);
  }

  uint32_t GetVertexCount(D3DPRIMITIVETYPE type, UINT count);

  DxvkInputAssemblyState DecodeInputAssemblyState(D3DPRIMITIVETYPE type);

  VkBlendFactor DecodeBlendFactor(D3DBLEND BlendFactor, bool IsAlpha);

  VkBlendOp DecodeBlendOp(D3DBLENDOP BlendOp);

  VkFilter DecodeFilter(D3DTEXTUREFILTERTYPE Filter);

  D3D9MipFilter DecodeMipFilter(D3DTEXTUREFILTERTYPE Filter);

  bool IsAnisotropic(D3DTEXTUREFILTERTYPE Filter);

  VkSamplerAddressMode DecodeAddressMode(D3DTEXTUREADDRESS Mode);

  VkCompareOp DecodeCompareOp(D3DCMPFUNC Func);

  VkStencilOp DecodeStencilOp(D3DSTENCILOP Op);

  VkCullModeFlags DecodeCullMode(D3DCULL Mode);

  VkPolygonMode DecodeFillMode(D3DFILLMODE Mode);

  VkIndexType DecodeIndexType(D3D9Format Format);

  VkFormat DecodeDecltype(D3DDECLTYPE Type);

  uint32_t GetDecltypeSize(D3DDECLTYPE Type);

  uint32_t GetDecltypeCount(D3DDECLTYPE Type);

  void ConvertBox(D3DBOX box, VkOffset3D& offset, VkExtent3D& extent);

  void ConvertRect(RECT rect, VkOffset3D& offset, VkExtent3D& extent);

  void ConvertRect(RECT rect, VkOffset2D& offset, VkExtent2D& extent);

  inline float GetDepthBufferRValue(VkFormat Format, int32_t vendorId) {
    switch (Format) {
      case VK_FORMAT_D16_UNORM_S8_UINT:
      case VK_FORMAT_D16_UNORM:
        return vendorId == 0x10de ? float(1 << 15) : float(1 << 16);

      case VK_FORMAT_D24_UNORM_S8_UINT:
        return vendorId == 0x10de ? float(1 << 23) : float(1 << 24);

      default:
      case VK_FORMAT_D32_SFLOAT_S8_UINT:
      case VK_FORMAT_D32_SFLOAT:
        return float(1 << 23);
    }
  }

  template<typename T>
  UINT CompactSparseList(T* pData, UINT Mask) {
    uint32_t count = 0;

    for (uint32_t id : bit::BitMask(Mask))
      pData[count++] = pData[id];

    return count;
  }

  bool IsDepthFormat(D3D9Format Format);

  inline bool operator == (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
    return a.X      == b.X      &&
           a.Y      == b.Y      &&
           a.Width  == b.Width  &&
           a.Height == b.Height &&
           a.MinZ   == b.MinZ   &&
           a.MaxZ   == b.MaxZ;
  }

  inline bool operator != (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
    return !(a == b);
  }

  inline bool operator == (const RECT& a, const RECT& b) {
    return a.left   == b.left  &&
           a.right  == b.right &&
           a.top    == b.top   &&
           a.bottom == b.bottom;
  }

  inline bool operator != (const RECT& a, const RECT& b) {
    return !(a == b);
  }

  inline bool operator == (const POINT& a, const POINT& b) {
    return a.x == b.x && a.y == b.y;
  }

  inline bool operator != (const POINT& a, const POINT& b) {
    return !(a == b);
  }

  inline bool IsPoolManaged(D3DPOOL Pool) {
    return Pool == D3DPOOL_MANAGED || Pool == D3DPOOL_MANAGED_EX;
  }

  inline D3DRENDERSTATETYPE ColorWriteIndex(uint32_t i) {
    return D3DRENDERSTATETYPE(i ? D3DRS_COLORWRITEENABLE1 + i - 1 : D3DRS_COLORWRITEENABLE);
  }

  inline bool AreFormatsSimilar(D3D9Format srcFormat, D3D9Format dstFormat) {
    return (srcFormat == dstFormat)
        || (srcFormat == D3D9Format::A8B8G8R8 && dstFormat == D3D9Format::X8B8G8R8)
        || (srcFormat == D3D9Format::A8R8G8B8 && dstFormat == D3D9Format::X8R8G8B8)
        || (srcFormat == D3D9Format::A1R5G5B5 && dstFormat == D3D9Format::X1R5G5B5)
        || (srcFormat == D3D9Format::A4R4G4B4 && dstFormat == D3D9Format::X4R4G4B4);
  }

  inline bool IsBlitRegionInvalid(VkOffset3D offsets[2], VkExtent3D extent) {
    // Only bother checking x, y as we don't have 3D blits.
    return offsets[1].x < offsets[0].x ||
           offsets[1].y < offsets[0].y ||
           offsets[0].x < 0 ||
           offsets[0].y < 0 ||
           uint32_t(offsets[1].x) > extent.width ||
           uint32_t(offsets[1].y) > extent.height;
  }

  enum D3D9TextureStageStateTypes : uint32_t
  {
      DXVK_TSS_COLOROP        =  0,
      DXVK_TSS_COLORARG1      =  1,
      DXVK_TSS_COLORARG2      =  2,
      DXVK_TSS_ALPHAOP        =  3,
      DXVK_TSS_ALPHAARG1      =  4,
      DXVK_TSS_ALPHAARG2      =  5,
      DXVK_TSS_BUMPENVMAT00   =  6,
      DXVK_TSS_BUMPENVMAT01   =  7,
      DXVK_TSS_BUMPENVMAT10   =  8,
      DXVK_TSS_BUMPENVMAT11   =  9,
      DXVK_TSS_TEXCOORDINDEX  = 10,
      DXVK_TSS_BUMPENVLSCALE  = 21,
      DXVK_TSS_BUMPENVLOFFSET = 22,
      DXVK_TSS_TEXTURETRANSFORMFLAGS = 23,
      DXVK_TSS_COLORARG0      = 25,
      DXVK_TSS_ALPHAARG0      = 26,
      DXVK_TSS_RESULTARG      = 27,
      DXVK_TSS_CONSTANT       = 31,
      DXVK_TSS_COUNT          = 32
  };

  constexpr uint32_t DXVK_TSS_TCI_PASSTHRU                      = 0x00000000;
  constexpr uint32_t DXVK_TSS_TCI_CAMERASPACENORMAL             = 0x00010000;
  constexpr uint32_t DXVK_TSS_TCI_CAMERASPACEPOSITION           = 0x00020000;
  constexpr uint32_t DXVK_TSS_TCI_CAMERASPACEREFLECTIONVECTOR   = 0x00030000;
  constexpr uint32_t DXVK_TSS_TCI_SPHEREMAP                     = 0x00040000;

  inline D3D9TextureStageStateTypes RemapTextureStageStateType(D3DTEXTURESTAGESTATETYPE Type) {
    return D3D9TextureStageStateTypes(Type - 1);
  }

}


code:
#include "d3d9_vertex_declaration.h"
#include "d3d9_util.h"

#include <algorithm>
#include <cstring>

namespace dxvk {

  D3D9VertexDecl::D3D9VertexDecl(
          D3D9DeviceEx*      pDevice,
          DWORD              FVF)
    : D3D9VertexDeclBase(pDevice) {
    this->SetFVF(FVF);
    this->Classify();
  }

  D3D9VertexDecl::D3D9VertexDecl(
          D3D9DeviceEx*      pDevice,
    const D3DVERTEXELEMENT9* pVertexElements,
          uint32_t           DeclCount)
    : D3D9VertexDeclBase( pDevice )
    , m_elements        ( DeclCount )
    , m_fvf             ( 0 ) {
    std::copy(pVertexElements, pVertexElements + DeclCount, m_elements.begin());
    this->Classify();
  }

  HRESULT STDMETHODCALLTYPE D3D9VertexDecl::QueryInterface(
          REFIID  riid,
          void** ppvObject) {
    if (ppvObject == nullptr)
      return E_POINTER;

    *ppvObject = nullptr;

    if (riid == __uuidof(IUnknown)
     || riid == __uuidof(IDirect3DVertexDeclaration9)) {
      *ppvObject = ref(this);
      return S_OK;
    }

    Logger::warn("D3D9VertexDecl::QueryInterface: Unknown interface query");
    Logger::warn(str::format(riid));
    return E_NOINTERFACE;
  }

  HRESULT STDMETHODCALLTYPE D3D9VertexDecl::GetDeclaration(
          D3DVERTEXELEMENT9* pElement,
          UINT*              pNumElements) {
    if (pNumElements == nullptr)
      return D3DERR_INVALIDCALL;

    *pNumElements = UINT(m_elements.size()) + 1u; // Account for D3DDECL_END

    if (pElement == nullptr)
      return D3D_OK;

    // The native runtime ignores pNumElements here...
    std::copy(m_elements.begin(), m_elements.end(), pElement);
    pElement[m_elements.size()] = D3DDECL_END();

    return D3D_OK;
  }

  void D3D9VertexDecl::SetFVF(DWORD FVF) {
    m_fvf = FVF;

    std::array<D3DVERTEXELEMENT9, 16> elements;
    uint32_t elemCount = 0;
    uint32_t texCount = 0;

    uint32_t betas = 0;
    uint8_t betaIdx = 0xFF;

    switch (FVF & D3DFVF_POSITION_MASK) {
      case D3DFVF_XYZ:
      case D3DFVF_XYZB1:
      case D3DFVF_XYZB2:
      case D3DFVF_XYZB3:
      case D3DFVF_XYZB4:
      case D3DFVF_XYZB5:
        elements[elemCount].Type = D3DDECLTYPE_FLOAT3;
        elements[elemCount].Usage = D3DDECLUSAGE_POSITION;
        elements[elemCount].UsageIndex = 0;
        elemCount++;

        if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ)
          break;

        betas = (((FVF & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1) + 1;
        if (FVF & D3DFVF_LASTBETA_D3DCOLOR)
          betaIdx = D3DDECLTYPE_D3DCOLOR;
        else if (FVF & D3DFVF_LASTBETA_UBYTE4)
          betaIdx = D3DDECLTYPE_UBYTE4;
        else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5)
          betaIdx = D3DDECLTYPE_FLOAT1;

        if (betaIdx != 0xFF)
          betas--;

        if (betas > 0) {
          switch (betas) {
            case 1: elements[elemCount].Type = D3DDECLTYPE_FLOAT1; break;
            case 2: elements[elemCount].Type = D3DDECLTYPE_FLOAT2; break;
            case 3: elements[elemCount].Type = D3DDECLTYPE_FLOAT3; break;
            case 4: elements[elemCount].Type = D3DDECLTYPE_FLOAT4; break;
            default: break;
          }
          elements[elemCount].Usage = D3DDECLUSAGE_BLENDWEIGHT;
          elements[elemCount].UsageIndex = 0;
          elemCount++;
        }

        if (betaIdx != 0xFF) {
          elements[elemCount].Type = betaIdx;
          elements[elemCount].Usage = D3DDECLUSAGE_BLENDINDICES;
          elements[elemCount].UsageIndex = 0;
          elemCount++;
        }
        break;

      case D3DFVF_XYZW:
      case D3DFVF_XYZRHW:
        elements[elemCount].Type = D3DDECLTYPE_FLOAT4;
        elements[elemCount].Usage =
          ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZW)
          ? D3DDECLUSAGE_POSITION
          : D3DDECLUSAGE_POSITIONT;
        elements[elemCount].UsageIndex = 0;
        elemCount++;
        break;

      default:
        break;
    }

    if (FVF & D3DFVF_NORMAL) {
      elements[elemCount].Type = D3DDECLTYPE_FLOAT3;
      elements[elemCount].Usage = D3DDECLUSAGE_NORMAL;
      elements[elemCount].UsageIndex = 0;
      elemCount++;
    }
    if (FVF & D3DFVF_PSIZE) {
      elements[elemCount].Type = D3DDECLTYPE_FLOAT1;
      elements[elemCount].Usage = D3DDECLUSAGE_PSIZE;
      elements[elemCount].UsageIndex = 0;
      elemCount++;
    }
    if (FVF & D3DFVF_DIFFUSE) {
      elements[elemCount].Type = D3DDECLTYPE_D3DCOLOR;
      elements[elemCount].Usage = D3DDECLUSAGE_COLOR;
      elements[elemCount].UsageIndex = 0;
      elemCount++;
    }
    if (FVF & D3DFVF_SPECULAR) {
      elements[elemCount].Type = D3DDECLTYPE_D3DCOLOR;
      elements[elemCount].Usage = D3DDECLUSAGE_COLOR;
      elements[elemCount].UsageIndex = 1;
      elemCount++;
    }

    texCount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
    texCount = std::min(texCount, 8u);

    for (uint32_t i = 0; i < texCount; i++) {
      switch ((FVF >> (16 + i * 2)) & 0x3) {
        case D3DFVF_TEXTUREFORMAT1:
          elements[elemCount].Type = D3DDECLTYPE_FLOAT1;
          break;

        case D3DFVF_TEXTUREFORMAT2:
          elements[elemCount].Type = D3DDECLTYPE_FLOAT2;
          break;

        case D3DFVF_TEXTUREFORMAT3:
          elements[elemCount].Type = D3DDECLTYPE_FLOAT3;
          break;

        case D3DFVF_TEXTUREFORMAT4:
          elements[elemCount].Type = D3DDECLTYPE_FLOAT4;
          break;

        default:
          break;
      }
      elements[elemCount].Usage = D3DDECLUSAGE_TEXCOORD;
      elements[elemCount].UsageIndex = i;
      elemCount++;
    }

    for (uint32_t i = 0; i < elemCount; i++) {
      elements[i].Stream = 0;
      elements[i].Offset = (i == 0)
        ? 0
        : (elements[i - 1].Offset + GetDecltypeSize(D3DDECLTYPE(elements[i - 1].Type)));

      elements[i].Method = D3DDECLMETHOD_DEFAULT;
    }

    m_elements.resize(elemCount);
    std::copy(elements.begin(), elements.begin() + elemCount, m_elements.data());
  }

  void D3D9VertexDecl::Classify() {
    for (const auto& element : m_elements) {
      if (element.Stream == 0 && element.Type != D3DDECLTYPE_UNUSED)
        m_size = std::max(m_size, element.Offset + GetDecltypeSize(D3DDECLTYPE(element.Type)));

      if (element.Usage == D3DDECLUSAGE_COLOR && element.UsageIndex == 0)
        m_flags.set(D3D9VertexDeclFlag::HasColor0);
      else if (element.Usage == D3DDECLUSAGE_COLOR && element.UsageIndex == 1)
        m_flags.set(D3D9VertexDeclFlag::HasColor1);
      else if (element.Usage == D3DDECLUSAGE_POSITIONT)
        m_flags.set(D3D9VertexDeclFlag::HasPositionT);
      else if (element.Usage == D3DDECLUSAGE_PSIZE)
        m_flags.set(D3D9VertexDeclFlag::HasPointSize);
      else if (element.Usage == D3DDECLUSAGE_FOG)
        m_flags.set(D3D9VertexDeclFlag::HasFog);
      else if (element.Usage == D3DDECLUSAGE_BLENDWEIGHT)
        m_flags.set(D3D9VertexDeclFlag::HasBlendWeight);
      else if (element.Usage == D3DDECLUSAGE_BLENDINDICES)
        m_flags.set(D3D9VertexDeclFlag::HasBlendIndices);

      if (element.Usage == D3DDECLUSAGE_TEXCOORD)
        m_texcoordMask |= GetDecltypeCount(D3DDECLTYPE(element.Type)) << (element.UsageIndex * 3);
    }
  }

}

repo_name: orochi/dxvk


code:
#pragma once

#include "d3d9_device_child.h"
#include "d3d9_util.h"

#include <vector>

namespace dxvk {

  enum class D3D9VertexDeclFlag {
    HasColor0,
    HasColor1,
    HasPositionT,
    HasPointSize,
    HasFog,
    HasBlendWeight,
    HasBlendIndices
  };
  using D3D9VertexDeclFlags = Flags<D3D9VertexDeclFlag>;

  using D3D9VertexDeclBase = D3D9DeviceChild<IDirect3DVertexDeclaration9>;
  class D3D9VertexDecl final : public D3D9VertexDeclBase {

  public:

    D3D9VertexDecl(
            D3D9DeviceEx*      pDevice,
            DWORD              FVF);

    D3D9VertexDecl(
            D3D9DeviceEx*      pDevice,
      const D3DVERTEXELEMENT9* pVertexElements,
            uint32_t           DeclCount);

    HRESULT STDMETHODCALLTYPE QueryInterface(
            REFIID  riid,
            void** ppvObject);

    HRESULT STDMETHODCALLTYPE GetDeclaration(
            D3DVERTEXELEMENT9* pElement,
            UINT*              pNumElements);

    inline DWORD GetFVF() {
      return m_fvf;
    }

    void SetFVF(DWORD FVF);

    const D3D9VertexElements& GetElements() const {
      return m_elements;
    }

    UINT GetSize() const {
      return m_size;
    }

    bool TestFlag(D3D9VertexDeclFlag flag) const {
      return m_flags.test(flag);
    }

    D3D9VertexDeclFlags GetFlags() const {
      return m_flags;
    }

    uint32_t GetTexcoordMask() const {
      return m_texcoordMask;
    }

  private:

    void Classify();

    D3D9VertexDeclFlags            m_flags;

    D3D9VertexElements             m_elements;

    DWORD                          m_fvf;

    uint32_t                       m_texcoordMask = 0;

    // The size of Stream 0. That's all we care about.
    uint32_t                       m_size = 0;

  };

}


code:
#include "d3d9_volume.h"

#include "d3d9_device.h"
#include "d3d9_texture.h"

namespace dxvk {

  D3D9Volume::D3D9Volume(
          D3D9DeviceEx*             pDevice,
    const D3D9_COMMON_TEXTURE_DESC* pDesc)
    : D3D9VolumeBase(
        pDevice,
        new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE, nullptr ),
        0, 0,
        nullptr,
        nullptr) { }

  D3D9Volume::D3D9Volume(
          D3D9DeviceEx*             pDevice,
          D3D9CommonTexture*        pTexture,
          UINT                      Face,
          UINT                      MipLevel,
          IDirect3DBaseTexture9*    pContainer)
    : D3D9VolumeBase(
        pDevice,
        pTexture,
        Face, MipLevel,
        pContainer,
        pContainer) { }

  void D3D9Volume::AddRefPrivate() {
    // Can't have a swapchain container for a volume.
    if (m_baseTexture != nullptr) {
      static_cast<D3D9Texture3D*>(m_baseTexture)->AddRefPrivate();
      return;
    }

    D3D9VolumeBase::AddRefPrivate();
  }

  void D3D9Volume::ReleasePrivate() {
    // Can't have a swapchain container for a volume.
    if (m_baseTexture != nullptr) {
      static_cast<D3D9Texture3D*>(m_baseTexture)->ReleasePrivate();
      return;
    }

    D3D9VolumeBase::ReleasePrivate();
  }

  HRESULT STDMETHODCALLTYPE D3D9Volume::QueryInterface(REFIID riid, void** ppvObject) {
    if (ppvObject == nullptr)
      return E_POINTER;

    *ppvObject = nullptr;

    if (riid == __uuidof(IUnknown)
     || riid == __uuidof(IDirect3DResource9)
     || riid == __uuidof(IDirect3DVolume9)) {
      *ppvObject = ref(this);
      return S_OK;
    }

    Logger::warn("D3D9Volume::QueryInterface: Unknown interface query");
    Logger::warn(str::format(riid));
    return E_NOINTERFACE;
  }

  HRESULT STDMETHODCALLTYPE D3D9Volume::GetDesc(D3DVOLUME_DESC *pDesc) {
    if (pDesc == nullptr)
      return D3DERR_INVALIDCALL;

    auto& desc = *(m_texture->Desc());

    pDesc->Format = static_cast<D3DFORMAT>(desc.Format);
    pDesc->Type   = D3DRTYPE_VOLUME;
    pDesc->Usage  = desc.Usage;
    pDesc->Pool   = desc.Pool;

    pDesc->Width  = std::max(1u, desc.Width  >> m_mipLevel);
    pDesc->Height = std::max(1u, desc.Height >> m_mipLevel);
    pDesc->Depth  = std::max(1u, desc.Depth  >> m_mipLevel);

    return D3D_OK;
  }

  HRESULT STDMETHODCALLTYPE D3D9Volume::LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) {
    if (unlikely(pLockedBox == nullptr))
      return D3DERR_INVALIDCALL;

    return m_parent->LockImage(
      m_texture,
      m_face, m_mipLevel,
      pLockedBox,
      pBox,
      Flags);
  }

  HRESULT STDMETHODCALLTYPE D3D9Volume::UnlockBox() {
    return m_parent->UnlockImage(
      m_texture,
      m_face, m_mipLevel);
  }

}


code:
#pragma once

#include "d3d9_subresource.h"

#include "d3d9_common_texture.h"

namespace dxvk {

  using D3D9VolumeBase = D3D9Subresource<IDirect3DVolume9>;
  class D3D9Volume final : public D3D9VolumeBase {

  public:

    D3D9Volume(
            D3D9DeviceEx*             pDevice,
      const D3D9_COMMON_TEXTURE_DESC* pDesc);

    D3D9Volume(
            D3D9DeviceEx*             pDevice,
            D3D9CommonTexture*        pTexture,
            UINT                      Face,
            UINT                      MipLevel,
            IDirect3DBaseTexture9*    pContainer);

    void AddRefPrivate();

    void ReleasePrivate();

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);

    HRESULT STDMETHODCALLTYPE GetDesc(D3DVOLUME_DESC *pDesc) final;

    HRESULT STDMETHODCALLTYPE LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) final;

    HRESULT STDMETHODCALLTYPE UnlockBox() final;

  };
}


code:
d3d9_res = wrc_generator.process('version.rc')

d3d9_shaders = files([
  'shaders/d3d9_convert_yuy2_uyvy.comp',
  'shaders/d3d9_convert_l6v5u5.comp',
  'shaders/d3d9_convert_x8l8v8u8.comp',
  'shaders/d3d9_convert_a2w10v10u10.comp',
  'shaders/d3d9_convert_nv12.comp',
  'shaders/d3d9_convert_yv12.comp'
])

d3d9_src = [
  'd3d9_main.cpp',
  'd3d9_interface.cpp',
  'd3d9_adapter.cpp',
  'd3d9_monitor.cpp',
  'd3d9_device.cpp',
  'd3d9_state.cpp',
  'd3d9_cursor.cpp',
  'd3d9_swapchain.cpp',
  'd3d9_format.cpp',
  'd3d9_common_texture.cpp',
  'd3d9_texture.cpp',
  'd3d9_surface.cpp',
  'd3d9_volume.cpp',
  'd3d9_common_buffer.cpp',
  'd3d9_buffer.cpp',
  'd3d9_shader.cpp',
  'd3d9_vertex_declaration.cpp',
  'd3d9_query.cpp',
  'd3d9_multithread.cpp',
  'd3d9_options.cpp',
  'd3d9_stateblock.cpp',
  'd3d9_sampler.cpp',
  'd3d9_util.cpp',
  'd3d9_initializer.cpp',
  'd3d9_fixed_function.cpp',
  'd3d9_names.cpp',
  'd3d9_swvp_emu.cpp',
  'd3d9_format_helpers.cpp',
  'd3d9_hud.cpp',
  'd3d9_annotation.cpp'
]

d3d9_dll = shared_library('d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res,
  name_prefix         : '',
  dependencies        : [ dxso_dep, dxvk_dep ],
  include_directories : dxvk_include_path,
  install             : true,
  vs_module_defs      : 'd3d9'+def_spec_ext,
)

d3d9_dep = declare_dependency(
  link_with           : [ d3d9_dll ],
  include_directories : [ dxvk_include_path ],
)


code:
#version 450
#extension GL_GOOGLE_include_directive : enable

#include "d3d9_convert_common.h"

layout(
  local_size_x = 8,
  local_size_y = 8,
  local_size_z = 1) in;

layout(binding = 0)
writeonly uniform image2D dst;

layout(binding = 1) uniform usamplerBuffer src;

layout(push_constant)
uniform u_info_t {
  uvec2 extent;
} u_info;

void main() {
  ivec3 thread_id = ivec3(gl_GlobalInvocationID);

  if (all(lessThan(thread_id.xy, u_info.extent))) {
    uint offset = thread_id.x
                + thread_id.y * u_info.extent.x;

    uint value = texelFetch(src, int(offset)).r;

    // Sign-extend magic!
    int  u10 = bitfieldExtract(int (value), 0,  10);
    int  v10 = bitfieldExtract(int (value), 10, 10);
    int  w10 = bitfieldExtract(int (value), 20, 10);
    uint a2  = bitfieldExtract(uint(value), 30, 2);

    vec4 color = vec4(
      snormalize(u10, 10),
      snormalize(v10, 10),
      snormalize(w10, 10),
      unormalize(a2,  2));

    imageStore(dst, thread_id.xy, color);
  }
}


code:
float unormalize(uint value, int bits) {
  const int range = (1 << bits) - 1;

  return float(value) / float(range);
}

float snormalize(int value, int bits) {
  const int range = (1 << (bits - 1)) - 1;

  // Min because, -32 and -31 map to -1.0f, and we
  // divide by 31.
  return max(float(value) / float(range), -1.0);
}

float unpackUnorm(uint p) {
  return float(p) / 255.0;
}

vec2 unpackUnorm2x8(uint p) {
  uvec2 value = uvec2(p & 0xFF, p >> 8);
  return vec2(unpackUnorm(value.x), unpackUnorm(value.y));
}

mat3x4 g_yuv_to_rgb = {
  { 298 / 256,  0,          409 / 256, 0.5 },
  { 298 / 256, -100 / 256, -208 / 256, 0.5 },
  { 298 / 256,  516 / 256,  0,         0.5 }
};

vec4 convertYUV(vec3 yuv) {
  vec3 value = vec4(yuv, 1 / 255.0) * g_yuv_to_rgb;

  return vec4(clamp(value, 0, 1), 1);
}

mat3x3 g_bt709_to_rgb = {
  { 1.164,  0,          1.793    },
  { 1.164, -0.213,     -0.533    },
  { 1.164,  2.112,      0        }
};

vec4 convertBT_709(vec3 cde) {
  return vec4(clamp(cde * g_bt709_to_rgb, 0, 1), 1);
}


code:
#version 450
#extension GL_GOOGLE_include_directive : enable

#include "d3d9_convert_common.h"

layout(
  local_size_x = 8,
  local_size_y = 8,
  local_size_z = 1) in;

layout(binding = 0)
writeonly uniform image2D dst;

layout(binding = 1) uniform usamplerBuffer src;

layout(push_constant)
uniform u_info_t {
  uvec2 extent;
} u_info;

void main() {
  ivec3 thread_id = ivec3(gl_GlobalInvocationID);

  if (all(lessThan(thread_id.xy, u_info.extent))) {
    uint offset = thread_id.x
                + thread_id.y * u_info.extent.x;

    uint value = texelFetch(src, int(offset)).r;

    // Sign-extend magic!
    int u5  = bitfieldExtract(int (value), 0,  5);
    int v5  = bitfieldExtract(int (value), 5,  5);
    uint l6 = bitfieldExtract(uint(value), 10, 6);

    vec4 color = vec4(
      snormalize(u5, 5),
      snormalize(v5, 5),
      unormalize(l6, 6),
      1.0f);

    imageStore(dst, thread_id.xy, color);
  }
}


code:
#version 450
#extension GL_GOOGLE_include_directive : enable

#include "d3d9_convert_common.h"

layout(
  local_size_x = 8,
  local_size_y = 8,
  local_size_z = 1) in;

layout(binding = 0)
writeonly uniform image2D dst;

layout(binding = 1) uniform usamplerBuffer src;

layout(push_constant)
uniform u_info_t {
  uvec2 extent;
} u_info;

vec2 fetchUnorm2x8(usamplerBuffer source, uint offset) {
  return unpackUnorm2x8(texelFetch(src, int(offset)).r);
}

// Format is:
// YYYYYYYYYYYYYYY...
// YYYYYYYYYYYYYYY...
// UVUVUVUVUVUVUVU...

void main() {
  ivec3 thread_id = ivec3(gl_GlobalInvocationID);

  if (all(lessThan(thread_id.xy, u_info.extent))) {
    uvec2 pitch = uvec2(u_info.extent.x, u_info.extent.y);

    uint offset = thread_id.x
                + thread_id.y * pitch.x;

    // Fetch 2 luminance samples.
    vec2 y = fetchUnorm2x8(src, offset) - (16 / 255.0);

    // Go into the second plane to get the chroma data.
    // UV data is subsampled as [2, 2]
    // So we need to divide thread_id.y by 2.
    // thread_id.x is already accounted for as we read uint16
    offset = thread_id.x
           + thread_id.y / 2 * pitch.x
           + pitch.x * pitch.y;

    vec2 uv = fetchUnorm2x8(src, offset) - (128 / 255.0);

    // The NV12 format seems to use the BT.709 color space.
    vec4 color0 = convertBT_709(vec3(y.x, uv.x, uv.y));
    vec4 color1 = convertBT_709(vec3(y.y, uv.x, uv.y));

    // We write as a macropixel of [2, 1]
    // So write out 2 pixels in this run.
    ivec2 writePos = thread_id.xy * ivec2(2, 1);

    imageStore(dst, ivec2(writePos.x,     writePos.y), color0);
    imageStore(dst, ivec2(writePos.x + 1, writePos.y), color1);
  }
}


code:
#version 450
#extension GL_GOOGLE_include_directive : enable

#include "d3d9_convert_common.h"

layout(
  local_size_x = 8,
  local_size_y = 8,
  local_size_z = 1) in;

layout(binding = 0)
writeonly uniform image2D dst;

layout(binding = 1) uniform usamplerBuffer src;

layout(push_constant)
uniform u_info_t {
  uvec2 extent;
} u_info;

void main() {
  ivec3 thread_id = ivec3(gl_GlobalInvocationID);

  if (all(lessThan(thread_id.xy, u_info.extent))) {
    uint offset = thread_id.x
                + thread_id.y * u_info.extent.x;

    uint value = texelFetch(src, int(offset)).r;

    // Sign-extend magic!
    int  u8 = bitfieldExtract(int (value), 0,  8);
    int  v8 = bitfieldExtract(int (value), 8,  8);
    uint l8 = bitfieldExtract(uint(value), 16, 8);

    vec4 color = vec4(
      snormalize(u8, 8),
      snormalize(v8, 8),
      unormalize(l8, 8),
      1.0f);

    imageStore(dst, thread_id.xy, color);
  }
}


code:
#version 450
#extension GL_GOOGLE_include_directive : enable

#include "d3d9_convert_common.h"

layout(constant_id = 1225) const bool s_is_uyvy = false;

layout(
  local_size_x = 8,
  local_size_y = 8,
  local_size_z = 1) in;

layout(binding = 0)
writeonly uniform image2D dst;

layout(binding = 1) uniform usamplerBuffer src;

layout(push_constant)
uniform u_info_t {
  uvec2 extent;
} u_info;

void main() {
  ivec3 thread_id = ivec3(gl_GlobalInvocationID);

  if (all(lessThan(thread_id.xy, u_info.extent))) {
    uint offset = thread_id.x
                + thread_id.y * u_info.extent.x;

    uint value = texelFetch(src, int(offset)).r;

    vec4 data = unpackUnorm4x8(value);

    // Flip around stuff for UYVY
    if (s_is_uyvy)
      data = data.yxwz;

    float y0 = data.x - (16   / 255.0);
    float u  = data.y - (128  / 255.0);
    float y1 = data.z - (16   / 255.0);
    float v  = data.w - (128  / 255.0);

    vec4 color0 = convertYUV(vec3(y0, u, v));
    vec4 color1 = convertYUV(vec3(y1, u, v));

    // YUY2 has a macropixel of [2, 1]
    // so we write 2 pixels in this run.
    ivec2 writePos = thread_id.xy * ivec2(2, 1);

    imageStore(dst, ivec2(writePos.x,     writePos.y), color0);
    imageStore(dst, ivec2(writePos.x + 1, writePos.y), color1);
  }
}


code:
#version 450
#extension GL_GOOGLE_include_directive : enable

#include "d3d9_convert_common.h"

layout(
  local_size_x = 8,
  local_size_y = 8,
  local_size_z = 1) in;

layout(binding = 0)
writeonly uniform image2D dst;

layout(binding = 1) uniform usamplerBuffer src;

layout(push_constant)
uniform u_info_t {
  uvec2 extent;
} u_info;

// Format is:
// YYYYYYYY...
// VVVV...
// UUUU...

float fetchUnorm(usamplerBuffer source, uint offset) {
  return unpackUnorm(texelFetch(src, int(offset)).r);
}

void main() {
  ivec3 thread_id = ivec3(gl_GlobalInvocationID);

  if (all(lessThan(thread_id.xy, u_info.extent))) {
    uvec2 pitch = uvec2(u_info.extent.x, u_info.extent.y);

    uint offset = thread_id.x
                + thread_id.y * pitch.x;

    // Fetch a Y, luminance sample.
    float y = fetchUnorm(src, offset) - (16 / 255.0);

    // Go into the second plane to get a V, chroma sample
    offset = (thread_id.x / 2)
           + (thread_id.y / 2) * (pitch.x / 2)
           + pitch.x * pitch.y;

    float v = fetchUnorm(src, offset) - (128 / 255.0);

    // Go into the third plane to get a U, chroma sample
    offset += (pitch.x / 2) * (pitch.y / 2);
    float u = fetchUnorm(src, offset) - (128 / 255.0);

    // TODO: Is this the right color space?
    vec4 color = convertBT_709(vec3(y, u, v));

    imageStore(dst, thread_id.xy, color);
  }
}


code:
#include <windows.h>

// DLL version information.
VS_VERSION_INFO    VERSIONINFO
FILEVERSION        10,0,17763,1
PRODUCTVERSION     10,0,17763,1
FILEFLAGSMASK      VS_FFI_FILEFLAGSMASK
FILEFLAGS          0
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "080904b0"
    BEGIN
      VALUE "CompanyName",      "DXVK"
      VALUE "FileDescription",  "Direct3D 9 Runtime"
      VALUE "FileVersion",      "10.0.17763.1 (WinBuild.160101.0800)"
      VALUE "InternalName",     "D3D9.dll"
      VALUE "LegalCopyright",   "zlib/libpng license"
      VALUE "OriginalFilename", "D3D9.dll"
      VALUE "ProductName",      "DXVK"
      VALUE "ProductVersion",   "10.0.17763.1"
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x0809, 1200
  END
END


code:
#include "dxbc_analysis.h"

namespace dxvk {

  DxbcAnalyzer::DxbcAnalyzer(
    const DxbcModuleInfo&     moduleInfo,
    const DxbcProgramInfo&    programInfo,
    const Rc<DxbcIsgn>&       isgn,
    const Rc<DxbcIsgn>&       osgn,
    const Rc<DxbcIsgn>&       psgn,
          DxbcAnalysisInfo&   analysis)
  : m_isgn    (isgn),
    m_osgn    (osgn),
    m_psgn    (psgn),
    m_analysis(&analysis) {
    // Get number of clipping and culling planes from the
    // input and output signatures. We will need this to
    // declare the shader input and output interfaces.
    m_analysis->clipCullIn  = getClipCullInfo(m_isgn);
    m_analysis->clipCullOut = getClipCullInfo(m_osgn);
  }

  DxbcAnalyzer::~DxbcAnalyzer() {

  }

  void DxbcAnalyzer::processInstruction(const DxbcShaderInstruction& ins) {
    switch (ins.opClass) {
      case DxbcInstClass::Atomic: {
        const uint32_t operandId = ins.dstCount - 1;

        if (ins.dst[operandId].type == DxbcOperandType::UnorderedAccessView) {
          const uint32_t registerId = ins.dst[operandId].idx[0].offset;
          m_analysis->uavInfos[registerId].accessAtomicOp = true;
          m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
        }
      } break;

      case DxbcInstClass::TextureSample:
      case DxbcInstClass::TextureGather:
      case DxbcInstClass::TextureQueryLod:
      case DxbcInstClass::VectorDeriv: {
        m_analysis->usesDerivatives = true;
      } break;

      case DxbcInstClass::ControlFlow: {
        if (ins.op == DxbcOpcode::Discard)
          m_analysis->usesKill = true;
      } break;

      case DxbcInstClass::BufferLoad: {
        uint32_t operandId = ins.op == DxbcOpcode::LdStructured ? 2 : 1;

        if (ins.src[operandId].type == DxbcOperandType::UnorderedAccessView) {
          const uint32_t registerId = ins.src[operandId].idx[0].offset;
          m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_READ_BIT;
        }
      } break;

      case DxbcInstClass::BufferStore: {
        if (ins.dst[0].type == DxbcOperandType::UnorderedAccessView) {
          const uint32_t registerId = ins.dst[0].idx[0].offset;
          m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_WRITE_BIT;
        }
      } break;

      case DxbcInstClass::TypedUavLoad: {
        const uint32_t registerId = ins.src[1].idx[0].offset;
        m_analysis->uavInfos[registerId].accessTypedLoad = true;
        m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_READ_BIT;
      } break;

      case DxbcInstClass::TypedUavStore: {
        const uint32_t registerId = ins.dst[0].idx[0].offset;
        m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_WRITE_BIT;
      } break;

      default:
        break;
    }

    for (uint32_t i = 0; i < ins.dstCount; i++) {
      if (ins.dst[0].type == DxbcOperandType::IndexableTemp) {
        uint32_t index = ins.dst[0].idx[0].offset;
        m_analysis->xRegMasks[index] |= ins.dst[0].mask;
      }
    }
  }

  DxbcClipCullInfo DxbcAnalyzer::getClipCullInfo(const Rc<DxbcIsgn>& sgn) const {
    DxbcClipCullInfo result;

    if (sgn != nullptr) {
      for (auto e = sgn->begin(); e != sgn->end(); e++) {
        const uint32_t componentCount = e->componentMask.popCount();

        if (e->systemValue == DxbcSystemValue::ClipDistance)
          result.numClipPlanes += componentCount;
        if (e->systemValue == DxbcSystemValue::CullDistance)
          result.numCullPlanes += componentCount;
      }
    }

    return result;
  }

}


code:
#pragma once

#include "dxbc_chunk_isgn.h"
#include "dxbc_decoder.h"
#include "dxbc_defs.h"
#include "dxbc_names.h"
#include "dxbc_modinfo.h"
#include "dxbc_util.h"

namespace dxvk {

  /**
   * \brief Info about unordered access views
   *
   * Stores whether an UAV is accessed with typed
   * read or atomic instructions. This information
   * will be used to generate image types.
   */
  struct DxbcUavInfo {
    bool accessTypedLoad = false;
    bool accessAtomicOp  = false;
    VkAccessFlags accessFlags = 0;
  };

  /**
   * \brief Counts cull and clip distances
   */
  struct DxbcClipCullInfo {
    uint32_t numClipPlanes = 0;
    uint32_t numCullPlanes = 0;
  };

  /**
   * \brief Shader analysis info
   */
  struct DxbcAnalysisInfo {
    std::array<DxbcUavInfo, 64> uavInfos;
    std::array<DxbcRegMask, 4096> xRegMasks;

    DxbcClipCullInfo clipCullIn;
    DxbcClipCullInfo clipCullOut;

    bool usesDerivatives  = false;
    bool usesKill         = false;
  };

  /**
   * \brief DXBC shader analysis pass
   *
   * Collects information about the shader itself
   * and the resources used by the shader, which
   * will later be used by the actual compiler.
   */
  class DxbcAnalyzer {

  public:

    DxbcAnalyzer(
      const DxbcModuleInfo&     moduleInfo,
      const DxbcProgramInfo&    programInfo,
      const Rc<DxbcIsgn>&       isgn,
      const Rc<DxbcIsgn>&       osgn,
      const Rc<DxbcIsgn>&       psgn,
            DxbcAnalysisInfo&   analysis);

    ~DxbcAnalyzer();

    /**
     * \brief Processes a single instruction
     * \param [in] ins The instruction
     */
    void processInstruction(
      const DxbcShaderInstruction&  ins);

  private:

    Rc<DxbcIsgn> m_isgn;
    Rc<DxbcIsgn> m_osgn;
    Rc<DxbcIsgn> m_psgn;

    DxbcAnalysisInfo* m_analysis = nullptr;

    DxbcClipCullInfo getClipCullInfo(
      const Rc<DxbcIsgn>& sgn) const;

  };

}


code:
#include "dxbc_chunk_isgn.h"

namespace dxvk {

  DxbcIsgn::DxbcIsgn(DxbcReader reader, DxbcTag tag) {
    uint32_t elementCount = reader.readu32();
    reader.skip(sizeof(uint32_t));

    std::array<DxbcScalarType, 4> componentTypes = {
      DxbcScalarType::Uint32, DxbcScalarType::Uint32,
      DxbcScalarType::Sint32, DxbcScalarType::Float32,
    };

    // https://github.com/DarkStarSword/3d-fixes/blob/master/dx11shaderanalyse.py#L101
    bool hasStream    = (tag == "ISG1") || (tag == "OSG1") || (tag == "PSG1") || (tag == "OSG5");
    bool hasPrecision = (tag == "ISG1") || (tag == "OSG1") || (tag == "PSG1");

    for (uint32_t i = 0; i < elementCount; i++) {
      DxbcSgnEntry entry;
      entry.streamId        = hasStream ? reader.readu32() : 0;
      entry.semanticName    = reader.clone(reader.readu32()).readString();
      entry.semanticIndex   = reader.readu32();
      entry.systemValue     = static_cast<DxbcSystemValue>(reader.readu32());
      entry.componentType   = componentTypes.at(reader.readu32());
      entry.registerId      = reader.readu32();
      entry.componentMask   = bit::extract(reader.readu32(), 0, 3);

      if (hasPrecision)
        reader.readu32();

      m_entries.push_back(entry);
    }
  }

  DxbcIsgn::~DxbcIsgn() {

  }

  const DxbcSgnEntry* DxbcIsgn::findByRegister(uint32_t registerId) const {
    for (auto e = this->begin(); e != this->end(); e++) {
      if (e->registerId == registerId)
        return &(*e);
    }

    return nullptr;
  }

  const DxbcSgnEntry* DxbcIsgn::find(
    const std::string& semanticName,
          uint32_t     semanticIndex,
          uint32_t     streamId) const {
    for (auto e = this->begin(); e != this->end(); e++) {
      if (e->semanticIndex == semanticIndex
       && e->streamId      == streamId
       && compareSemanticNames(semanticName, e->semanticName))
        return &(*e);
    }

    return nullptr;
  }

  DxbcRegMask DxbcIsgn::regMask(
          uint32_t     registerId) const {
    DxbcRegMask mask;

    for (auto e = this->begin(); e != this->end(); e++) {
      if (e->registerId == registerId)
        mask |= e->componentMask;
    }

    return mask;
  }

  uint32_t DxbcIsgn::maxRegisterCount() const {
    uint32_t result = 0;
    for (auto e = this->begin(); e != this->end(); e++)
      result = std::max(result, e->registerId + 1);
    return result;
  }

  void DxbcIsgn::printEntries() const {
    for (auto entry = this->begin(); entry != this->end(); entry++) {
          Logger::debug(str::format("SGN Entry:\n\t",
            "semanticName: ",  entry->semanticName, "\n\t",
            "semanticIndex: ", entry->semanticIndex, "\n\t",
            "registerId: ",    entry->registerId, "\n\t",
            "componentMask: ", entry->componentMask.maskString(), "\n\t",
            "componentType: ", entry->componentType, "\n\t",
            "systemValue: ",   entry->systemValue, "\n\t",
            "streamId: ",      entry->streamId, "\n",
            "\n"));
    }
  }

  bool DxbcIsgn::compareSemanticNames(
    const std::string& a, const std::string& b) {
    if (a.size() != b.size())
      return false;

    for (size_t i = 0; i < a.size(); i++) {
      char ac = a[i];
      char bc = b[i];

      if (ac != bc) {
        if (ac >= 'A' && ac <= 'Z') ac += 'a' - 'A';
        if (bc >= 'A' && bc <= 'Z') bc += 'a' - 'A';

        if (ac != bc)
          return false;
      }
    }

    return true;
  }

}


code:
#pragma once

#include <cctype>

#include "dxbc_common.h"
#include "dxbc_decoder.h"
#include "dxbc_enums.h"
#include "dxbc_reader.h"

namespace dxvk {

  /**
   * \brief Signature entry
   *
   * Stores the semantic name of an input or
   * output and the corresponding register.
   */
  struct DxbcSgnEntry {
    std::string       semanticName;
    uint32_t          semanticIndex;
    uint32_t          registerId;
    DxbcRegMask       componentMask;
    DxbcScalarType    componentType;
    DxbcSystemValue   systemValue;
    uint32_t          streamId;
  };

  /**
   * \brief Input/Output signature chunk
   *
   * Stores information about the input and
   * output registers used by the shader stage.
   */
  class DxbcIsgn : public RcObject {

  public:

    DxbcIsgn(DxbcReader reader, DxbcTag tag);
    ~DxbcIsgn();

    auto begin() const { return m_entries.cbegin(); }
    auto end  () const { return m_entries.cend();   }

    const DxbcSgnEntry* findByRegister(
            uint32_t     registerId) const;

    const DxbcSgnEntry* find(
      const std::string& semanticName,
            uint32_t     semanticIndex,
            uint32_t     streamIndex) const;

    DxbcRegMask regMask(
            uint32_t     registerId) const;

    uint32_t maxRegisterCount() const;

    void printEntries() const;

    static bool compareSemanticNames(
      const std::string& a,
      const std::string& b);

  private:

    std::vector<DxbcSgnEntry> m_entries;

  };

}


code:
#include "dxbc_chunk_shex.h"

namespace dxvk {

  DxbcShex::DxbcShex(DxbcReader reader) {
    // The shader version and type are stored in a 32-bit unit,
    // where the first byte contains the major and minor version
    // numbers, and the high word contains the program type.
    reader.skip(2);
    auto pType    = reader.readEnum<DxbcProgramType>();
    m_programInfo = DxbcProgramInfo(pType);

    // Read the actual shader code as an array of DWORDs.
    auto codeLength = reader.readu32() - 2;
    m_code.resize(codeLength);
    reader.read(m_code.data(), codeLength * sizeof(uint32_t));
  }

  DxbcShex::~DxbcShex() {

  }

}


code:
#pragma once

#include "dxbc_common.h"
#include "dxbc_decoder.h"
#include "dxbc_reader.h"

namespace dxvk {

  /**
   * \brief Shader code chunk
   *
   * Stores the DXBC shader code itself, as well
   * as some meta info about the shader, i.e. what
   * type of shader this is.
   */
  class DxbcShex : public RcObject {

  public:

    DxbcShex(DxbcReader reader);
    ~DxbcShex();

    DxbcProgramInfo programInfo() const {
      return m_programInfo;
    }

    DxbcCodeSlice slice() const {
      return DxbcCodeSlice(m_code.data(),
        m_code.data() + m_code.size());
    }

  private:

    DxbcProgramInfo       m_programInfo;
    std::vector<uint32_t> m_code;

  };

}


code:
#include "dxbc_common.h"

namespace dxvk {

  VkShaderStageFlagBits DxbcProgramInfo::shaderStage() const {
    switch (m_type) {
      case DxbcProgramType::PixelShader    : return VK_SHADER_STAGE_FRAGMENT_BIT;
      case DxbcProgramType::VertexShader   : return VK_SHADER_STAGE_VERTEX_BIT;
      case DxbcProgramType::GeometryShader : return VK_SHADER_STAGE_GEOMETRY_BIT;
      case DxbcProgramType::HullShader     : return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
      case DxbcProgramType::DomainShader   : return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
      case DxbcProgramType::ComputeShader  : return VK_SHADER_STAGE_COMPUTE_BIT;
    }

    throw DxvkError("DxbcProgramInfo::shaderStage: Unsupported program type");
  }

  spv::ExecutionModel DxbcProgramInfo::executionModel() const {
    switch (m_type) {
      case DxbcProgramType::PixelShader    : return spv::ExecutionModelFragment;
      case DxbcProgramType::VertexShader   : return spv::ExecutionModelVertex;
      case DxbcProgramType::GeometryShader : return spv::ExecutionModelGeometry;
      case DxbcProgramType::HullShader     : return spv::ExecutionModelTessellationControl;
      case DxbcProgramType::DomainShader   : return spv::ExecutionModelTessellationEvaluation;
      case DxbcProgramType::ComputeShader  : return spv::ExecutionModelGLCompute;
    }

    throw DxvkError("DxbcProgramInfo::executionModel: Unsupported program type");
  }

}


code:
#pragma once

#include "dxbc_include.h"

namespace dxvk {

  /**
   * \brief DXBC Program type
   *
   * Defines the shader stage that a DXBC
   * module has been compiled form.
   */
  enum class DxbcProgramType : uint16_t {
    PixelShader     = 0,
    VertexShader    = 1,
    GeometryShader  = 2,
    HullShader      = 3,
    DomainShader    = 4,
    ComputeShader   = 5,
  };

  /**
   * \brief DXBC shader info
   *
   * Stores the shader program type.
   */
  class DxbcProgramInfo {

  public:

    DxbcProgramInfo() { }
    DxbcProgramInfo(DxbcProgramType type)
    : m_type(type) { }

    /**
     * \brief Program type
     * \returns Program type
     */
    DxbcProgramType type() const {
      return m_type;
    }

    /**
     * \brief Vulkan shader stage
     *
     * The \c VkShaderStageFlagBits constant
     * that corresponds to the program type.
     * \returns Vulkan shaer stage
     */
    VkShaderStageFlagBits shaderStage() const;

    /**
     * \brief SPIR-V execution model
     *
     * The execution model that corresponds
     * to the Vulkan shader stage.
     * \returns SPIR-V execution model
     */
    spv::ExecutionModel executionModel() const;

  private:

    DxbcProgramType m_type  = DxbcProgramType::PixelShader;

  };

}