code:
#pragma once

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

#include "../d3d10/d3d10_view_rtv.h"

#include "d3d11_device_child.h"
#include "d3d11_view.h"

namespace dxvk {

  class D3D11Device;

  /**
   * \brief Render target view
   */
  class D3D11RenderTargetView : public D3D11DeviceChild<ID3D11RenderTargetView1> {

  public:

    D3D11RenderTargetView(
            D3D11Device*                      pDevice,
            ID3D11Resource*                   pResource,
      const D3D11_RENDER_TARGET_VIEW_DESC1*   pDesc);

    ~D3D11RenderTargetView();

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

    void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final;

    void STDMETHODCALLTYPE GetDesc(D3D11_RENDER_TARGET_VIEW_DESC* pDesc) final;

    void STDMETHODCALLTYPE GetDesc1(D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) final;

    const D3D11_VK_VIEW_INFO& GetViewInfo() const {
      return m_info;
    }

    BOOL HasBindFlag(UINT Flags) const {
      return m_info.BindFlags & Flags;
    }

    D3D11_RESOURCE_DIMENSION GetResourceType() const {
      D3D11_RESOURCE_DIMENSION type;
      m_resource->GetType(&type);
      return type;
    }

    Rc<DxvkImageView> GetImageView() const {
      return m_view;
    }

    VkImageLayout GetRenderLayout() const {
      return m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL
        ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
        : VK_IMAGE_LAYOUT_GENERAL;
    }

    D3D10RenderTargetView* GetD3D10Iface() {
      return &m_d3d10;
    }

    static HRESULT GetDescFromResource(
            ID3D11Resource*                   pResource,
            D3D11_RENDER_TARGET_VIEW_DESC1*   pDesc);

    static D3D11_RENDER_TARGET_VIEW_DESC1 PromoteDesc(
      const D3D11_RENDER_TARGET_VIEW_DESC*    pDesc,
            UINT                              Plane);

    static HRESULT NormalizeDesc(
            ID3D11Resource*                   pResource,
            D3D11_RENDER_TARGET_VIEW_DESC1*   pDesc);

    static UINT GetPlaneSlice(
      const D3D11_RENDER_TARGET_VIEW_DESC1*   pDesc);

  private:

    ID3D11Resource*                   m_resource;
    D3D11_RENDER_TARGET_VIEW_DESC1    m_desc;
    D3D11_VK_VIEW_INFO                m_info;
    Rc<DxvkImageView>                 m_view;
    D3D10RenderTargetView             m_d3d10;

  };

}


code:
#include "d3d11_device.h"
#include "d3d11_buffer.h"
#include "d3d11_resource.h"
#include "d3d11_texture.h"
#include "d3d11_view_srv.h"

namespace dxvk {

  D3D11ShaderResourceView::D3D11ShaderResourceView(
          D3D11Device*                      pDevice,
          ID3D11Resource*                   pResource,
    const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc)
  : D3D11DeviceChild<ID3D11ShaderResourceView1>(pDevice),
    m_resource(pResource), m_desc(*pDesc), m_d3d10(this) {
    ResourceAddRefPrivate(m_resource);

    D3D11_COMMON_RESOURCE_DESC resourceDesc;
    GetCommonResourceDesc(pResource, &resourceDesc);

    // Basic view resource info
    m_info.pResource = pResource;
    m_info.Dimension = resourceDesc.Dim;
    m_info.BindFlags = resourceDesc.BindFlags;

    if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
      auto buffer = static_cast<D3D11Buffer*>(pResource);

      // Move buffer description to a common struct to
      // avoid having to handle the two cases separately
      D3D11_BUFFEREX_SRV bufInfo;

      if (pDesc->ViewDimension == D3D11_SRV_DIMENSION_BUFFEREX) {
        bufInfo.FirstElement = pDesc->BufferEx.FirstElement;
        bufInfo.NumElements  = pDesc->BufferEx.NumElements;
        bufInfo.Flags        = pDesc->BufferEx.Flags;
      } else if (pDesc->ViewDimension == D3D11_SRV_DIMENSION_BUFFER) {
        bufInfo.FirstElement = pDesc->Buffer.FirstElement;
        bufInfo.NumElements  = pDesc->Buffer.NumElements;
        bufInfo.Flags        = 0;
      } else {
        throw DxvkError("D3D11: Invalid view dimension for buffer SRV");
      }

      // Fill in buffer view info
      DxvkBufferViewCreateInfo viewInfo;

      if (bufInfo.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) {
        // Raw buffer view. We'll represent this as a
        // uniform texel buffer with UINT32 elements.
        viewInfo.format = VK_FORMAT_R32_UINT;
        viewInfo.rangeOffset = sizeof(uint32_t) * bufInfo.FirstElement;
        viewInfo.rangeLength = sizeof(uint32_t) * bufInfo.NumElements;
      } else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) {
        // Structured buffer view
        viewInfo.format = VK_FORMAT_R32_UINT;
        viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * bufInfo.FirstElement;
        viewInfo.rangeLength = buffer->Desc()->StructureByteStride * bufInfo.NumElements;
      } else {
        viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format;

        const DxvkFormatInfo* formatInfo = imageFormatInfo(viewInfo.format);
        viewInfo.rangeOffset = formatInfo->elementSize * bufInfo.FirstElement;
        viewInfo.rangeLength = formatInfo->elementSize * bufInfo.NumElements;
      }

      // Populate view info struct
      m_info.Buffer.Offset = viewInfo.rangeOffset;
      m_info.Buffer.Length = viewInfo.rangeLength;

      // Create underlying buffer view object
      m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
        buffer->GetBuffer(), viewInfo);
    } else {
      auto texture = GetCommonTexture(pResource);
      auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());

      DxvkImageViewCreateInfo viewInfo;
      viewInfo.format  = formatInfo.Format;
      viewInfo.aspect  = formatInfo.Aspect;
      viewInfo.swizzle = formatInfo.Swizzle;
      viewInfo.usage   = VK_IMAGE_USAGE_SAMPLED_BIT;

      // Shaders expect the stencil value in the G component
      if (viewInfo.aspect == VK_IMAGE_ASPECT_STENCIL_BIT) {
        viewInfo.swizzle = VkComponentMapping {
          VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R,
          VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO };
      }

      switch (pDesc->ViewDimension) {
        case D3D11_SRV_DIMENSION_TEXTURE1D:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_1D;
          viewInfo.minLevel  = pDesc->Texture1D.MostDetailedMip;
          viewInfo.numLevels = pDesc->Texture1D.MipLevels;
          viewInfo.minLayer  = 0;
          viewInfo.numLayers = 1;
          break;

        case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
          viewInfo.minLevel  = pDesc->Texture1DArray.MostDetailedMip;
          viewInfo.numLevels = pDesc->Texture1DArray.MipLevels;
          viewInfo.minLayer  = pDesc->Texture1DArray.FirstArraySlice;
          viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
          break;

        case D3D11_SRV_DIMENSION_TEXTURE2D:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_2D;
          viewInfo.minLevel  = pDesc->Texture2D.MostDetailedMip;
          viewInfo.numLevels = pDesc->Texture2D.MipLevels;
          viewInfo.minLayer  = 0;
          viewInfo.numLayers = 1;
          break;

        case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
          viewInfo.minLevel  = pDesc->Texture2DArray.MostDetailedMip;
          viewInfo.numLevels = pDesc->Texture2DArray.MipLevels;
          viewInfo.minLayer  = pDesc->Texture2DArray.FirstArraySlice;
          viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
          break;

        case D3D11_SRV_DIMENSION_TEXTURE2DMS:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_2D;
          viewInfo.minLevel  = 0;
          viewInfo.numLevels = 1;
          viewInfo.minLayer  = 0;
          viewInfo.numLayers = 1;
          break;

        case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
          viewInfo.minLevel  = 0;
          viewInfo.numLevels = 1;
          viewInfo.minLayer  = pDesc->Texture2DMSArray.FirstArraySlice;
          viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
          break;

        case D3D11_SRV_DIMENSION_TEXTURE3D:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_3D;
          viewInfo.minLevel  = pDesc->Texture3D.MostDetailedMip;
          viewInfo.numLevels = pDesc->Texture3D.MipLevels;
          viewInfo.minLayer  = 0;
          viewInfo.numLayers = 1;
          break;

        case D3D11_SRV_DIMENSION_TEXTURECUBE: {
          const bool cubeArraysEnabled = pDevice->GetDXVKDevice()->features().core.features.imageCubeArray;
          viewInfo.type      = cubeArraysEnabled ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
          viewInfo.minLevel  = pDesc->TextureCube.MostDetailedMip;
          viewInfo.numLevels = pDesc->TextureCube.MipLevels;
          viewInfo.minLayer  = 0;
          viewInfo.numLayers = 6;
        } break;

        case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
          viewInfo.minLevel  = pDesc->TextureCubeArray.MostDetailedMip;
          viewInfo.numLevels = pDesc->TextureCubeArray.MipLevels;
          viewInfo.minLayer  = pDesc->TextureCubeArray.First2DArrayFace;
          viewInfo.numLayers = pDesc->TextureCubeArray.NumCubes * 6;
          break;

        default:
          throw DxvkError("D3D11: Invalid view dimension for image SRV");
      }

      if (texture->GetPlaneCount() > 1)
        viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));

      // Populate view info struct
      m_info.Image.Aspects   = viewInfo.aspect;
      m_info.Image.MinLevel  = viewInfo.minLevel;
      m_info.Image.MinLayer  = viewInfo.minLayer;
      m_info.Image.NumLevels = viewInfo.numLevels;
      m_info.Image.NumLayers = viewInfo.numLayers;

      // Create the underlying image view object
      m_imageView = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo);
    }
  }

  D3D11ShaderResourceView::~D3D11ShaderResourceView() {
    ResourceReleasePrivate(m_resource);
  }

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

    *ppvObject = nullptr;

    if (riid == __uuidof(IUnknown)
     || riid == __uuidof(ID3D11DeviceChild)
     || riid == __uuidof(ID3D11View)
     || riid == __uuidof(ID3D11ShaderResourceView)
     || riid == __uuidof(ID3D11ShaderResourceView1)) {
      *ppvObject = ref(this);
      return S_OK;
    }

    if (riid == __uuidof(ID3D10DeviceChild)
     || riid == __uuidof(ID3D10View)
     || riid == __uuidof(ID3D10ShaderResourceView)
     || riid == __uuidof(ID3D10ShaderResourceView1)) {
      *ppvObject = ref(this);
      return S_OK;
    }

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

  void STDMETHODCALLTYPE D3D11ShaderResourceView::GetResource(ID3D11Resource** ppResource) {
    *ppResource = ref(m_resource);
  }

  void STDMETHODCALLTYPE D3D11ShaderResourceView::GetDesc(D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc) {
    pDesc->Format            = m_desc.Format;
    pDesc->ViewDimension     = m_desc.ViewDimension;

    switch (m_desc.ViewDimension) {
      case D3D11_SRV_DIMENSION_UNKNOWN:
        break;

      case D3D11_SRV_DIMENSION_BUFFER:
        pDesc->Buffer = m_desc.Buffer;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE1D:
        pDesc->Texture1D = m_desc.Texture1D;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
        pDesc->Texture1DArray = m_desc.Texture1DArray;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2D:
        pDesc->Texture2D.MostDetailedMip = m_desc.Texture2D.MostDetailedMip;
        pDesc->Texture2D.MipLevels       = m_desc.Texture2D.MipLevels;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
        pDesc->Texture2DArray.MostDetailedMip = m_desc.Texture2DArray.MostDetailedMip;
        pDesc->Texture2DArray.MipLevels       = m_desc.Texture2DArray.MipLevels;
        pDesc->Texture2DArray.FirstArraySlice = m_desc.Texture2DArray.FirstArraySlice;
        pDesc->Texture2DArray.ArraySize       = m_desc.Texture2DArray.ArraySize;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2DMS:
        pDesc->Texture2DMS = m_desc.Texture2DMS;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
        pDesc->Texture2DMSArray = m_desc.Texture2DMSArray;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE3D:
        pDesc->Texture3D = m_desc.Texture3D;
        break;

      case D3D11_SRV_DIMENSION_TEXTURECUBE:
        pDesc->TextureCube = m_desc.TextureCube;
        break;

      case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
        pDesc->TextureCubeArray = m_desc.TextureCubeArray;
        break;

      case D3D11_SRV_DIMENSION_BUFFEREX:
        pDesc->BufferEx = m_desc.BufferEx;
        break;
    }
  }

  void STDMETHODCALLTYPE D3D11ShaderResourceView::GetDesc1(D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) {
    *pDesc = m_desc;
  }

  HRESULT D3D11ShaderResourceView::GetDescFromResource(
          ID3D11Resource*                   pResource,
          D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) {
    D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
    pResource->GetType(&resourceDim);

    switch (resourceDim) {
      case D3D11_RESOURCE_DIMENSION_BUFFER: {
        D3D11_BUFFER_DESC bufferDesc;
        static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);

        if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
          pDesc->Format              = DXGI_FORMAT_UNKNOWN;
          pDesc->ViewDimension       = D3D11_SRV_DIMENSION_BUFFER;
          pDesc->Buffer.FirstElement = 0;
          pDesc->Buffer.NumElements  = bufferDesc.ByteWidth / bufferDesc.StructureByteStride;
          return S_OK;
        }
      } return E_INVALIDARG;

      case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
        D3D11_TEXTURE1D_DESC resourceDesc;
        static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);

        pDesc->Format = resourceDesc.Format;

        if (resourceDesc.ArraySize == 1) {
          pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
          pDesc->Texture1D.MostDetailedMip = 0;
          pDesc->Texture1D.MipLevels       = resourceDesc.MipLevels;
        } else {
          pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
          pDesc->Texture1DArray.MostDetailedMip = 0;
          pDesc->Texture1DArray.MipLevels       = resourceDesc.MipLevels;
          pDesc->Texture1DArray.FirstArraySlice = 0;
          pDesc->Texture1DArray.ArraySize       = resourceDesc.ArraySize;
        }
      } return S_OK;

      case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
        D3D11_TEXTURE2D_DESC resourceDesc;
        static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);

        pDesc->Format = resourceDesc.Format;

        if (resourceDesc.SampleDesc.Count == 1) {
          if (resourceDesc.ArraySize == 1) {
            pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
            pDesc->Texture2D.MostDetailedMip = 0;
            pDesc->Texture2D.MipLevels       = resourceDesc.MipLevels;
            pDesc->Texture2D.PlaneSlice      = 0;
          } else {
            pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
            pDesc->Texture2DArray.MostDetailedMip = 0;
            pDesc->Texture2DArray.MipLevels       = resourceDesc.MipLevels;
            pDesc->Texture2DArray.FirstArraySlice = 0;
            pDesc->Texture2DArray.ArraySize       = resourceDesc.ArraySize;
            pDesc->Texture2DArray.PlaneSlice      = 0;
          }
        } else {
          if (resourceDesc.ArraySize == 1) {
            pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
          } else {
            pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
            pDesc->Texture2DMSArray.FirstArraySlice = 0;
            pDesc->Texture2DMSArray.ArraySize       = resourceDesc.ArraySize;
          }
        }
      } return S_OK;

      case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
        D3D11_TEXTURE3D_DESC resourceDesc;
        static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);

        pDesc->Format = resourceDesc.Format;
        pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
        pDesc->Texture3D.MostDetailedMip = 0;
        pDesc->Texture3D.MipLevels       = resourceDesc.MipLevels;
      } return S_OK;

      default:
        Logger::err(str::format(
          "D3D11: Unsupported dimension for shader resource view: ",
          resourceDim));
        return E_INVALIDARG;
    }
  }

  D3D11_SHADER_RESOURCE_VIEW_DESC1 D3D11ShaderResourceView::PromoteDesc(
    const D3D11_SHADER_RESOURCE_VIEW_DESC*  pDesc,
          UINT                              Plane) {
    D3D11_SHADER_RESOURCE_VIEW_DESC1 dstDesc;
    dstDesc.Format            = pDesc->Format;
    dstDesc.ViewDimension     = pDesc->ViewDimension;

    switch (pDesc->ViewDimension) {
      case D3D11_SRV_DIMENSION_UNKNOWN:
        break;

      case D3D11_SRV_DIMENSION_BUFFER:
        dstDesc.Buffer = pDesc->Buffer;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE1D:
        dstDesc.Texture1D = pDesc->Texture1D;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
        dstDesc.Texture1DArray = pDesc->Texture1DArray;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2D:
        dstDesc.Texture2D.MostDetailedMip = pDesc->Texture2D.MostDetailedMip;
        dstDesc.Texture2D.MipLevels       = pDesc->Texture2D.MipLevels;
        dstDesc.Texture2D.PlaneSlice      = Plane;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
        dstDesc.Texture2DArray.MostDetailedMip = pDesc->Texture2DArray.MostDetailedMip;
        dstDesc.Texture2DArray.MipLevels       = pDesc->Texture2DArray.MipLevels;
        dstDesc.Texture2DArray.FirstArraySlice = pDesc->Texture2DArray.FirstArraySlice;
        dstDesc.Texture2DArray.ArraySize       = pDesc->Texture2DArray.ArraySize;
        dstDesc.Texture2DArray.PlaneSlice      = Plane;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2DMS:
        dstDesc.Texture2DMS = pDesc->Texture2DMS;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
        dstDesc.Texture2DMSArray = pDesc->Texture2DMSArray;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE3D:
        dstDesc.Texture3D = pDesc->Texture3D;
        break;

      case D3D11_SRV_DIMENSION_TEXTURECUBE:
        dstDesc.TextureCube = pDesc->TextureCube;
        break;

      case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
        dstDesc.TextureCubeArray = pDesc->TextureCubeArray;
        break;

      case D3D11_SRV_DIMENSION_BUFFEREX:
        dstDesc.BufferEx = pDesc->BufferEx;
        break;
    }

    return dstDesc;
  }

  HRESULT D3D11ShaderResourceView::NormalizeDesc(
          ID3D11Resource*                   pResource,
          D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) {
    D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
    pResource->GetType(&resourceDim);

    DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
    uint32_t mipLevels = 0;
    uint32_t numLayers = 0;

    switch (resourceDim) {
      case D3D11_RESOURCE_DIMENSION_BUFFER: {
        if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_BUFFER
         && pDesc->ViewDimension != D3D11_SRV_DIMENSION_BUFFEREX) {
          Logger::err("D3D11: Incompatible view dimension for Buffer");
          return E_INVALIDARG;
        }
      } break;

      case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
        D3D11_TEXTURE1D_DESC resourceDesc;
        static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);

        if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE1D
         && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE1DARRAY) {
          Logger::err("D3D11: Incompatible view dimension for Texture1D");
          return E_INVALIDARG;
        }

        format    = resourceDesc.Format;
        mipLevels = resourceDesc.MipLevels;
        numLayers = resourceDesc.ArraySize;
      } break;

      case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
        D3D11_TEXTURE2D_DESC resourceDesc;
        static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);

        if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2D
         && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2DARRAY
         && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2DMS
         && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY
         && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURECUBE
         && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) {
          Logger::err("D3D11: Incompatible view dimension for Texture2D");
          return E_INVALIDARG;
        }

        format    = resourceDesc.Format;
        mipLevels = resourceDesc.MipLevels;
        numLayers = resourceDesc.ArraySize;
      } break;

      case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
        D3D11_TEXTURE3D_DESC resourceDesc;
        static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);

        if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE3D) {
          Logger::err("D3D11: Incompatible view dimension for Texture3D");
          return E_INVALIDARG;
        }

        format    = resourceDesc.Format;
        mipLevels = resourceDesc.MipLevels;
        numLayers = 1;
      } break;

      default:
        return E_INVALIDARG;
    }

    if (pDesc->Format == DXGI_FORMAT_UNKNOWN)
      pDesc->Format = format;

    switch (pDesc->ViewDimension) {
      case D3D11_SRV_DIMENSION_BUFFER:
        if (pDesc->Buffer.NumElements == 0)
          return E_INVALIDARG;
        break;

      case D3D11_SRV_DIMENSION_BUFFEREX:
        if (pDesc->BufferEx.NumElements == 0)
          return E_INVALIDARG;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE1D:
        if (pDesc->Texture1D.MipLevels > mipLevels - pDesc->Texture1D.MostDetailedMip)
          pDesc->Texture1D.MipLevels = mipLevels - pDesc->Texture1D.MostDetailedMip;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
        if (pDesc->Texture1DArray.MipLevels > mipLevels - pDesc->Texture1DArray.MostDetailedMip)
          pDesc->Texture1DArray.MipLevels = mipLevels - pDesc->Texture1DArray.MostDetailedMip;
        if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice)
          pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2D:
        if (pDesc->Texture2D.MipLevels > mipLevels - pDesc->Texture2D.MostDetailedMip)
          pDesc->Texture2D.MipLevels = mipLevels - pDesc->Texture2D.MostDetailedMip;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
        if (pDesc->Texture2DArray.MipLevels > mipLevels - pDesc->Texture2DArray.MostDetailedMip)
          pDesc->Texture2DArray.MipLevels = mipLevels - pDesc->Texture2DArray.MostDetailedMip;
        if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice)
          pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
        if (pDesc->Texture2DMSArray.ArraySize > numLayers - pDesc->Texture2DMSArray.FirstArraySlice)
          pDesc->Texture2DMSArray.ArraySize = numLayers - pDesc->Texture2DMSArray.FirstArraySlice;
        break;

      case D3D11_SRV_DIMENSION_TEXTURECUBE:
        if (pDesc->TextureCube.MipLevels > mipLevels - pDesc->TextureCube.MostDetailedMip)
          pDesc->TextureCube.MipLevels = mipLevels - pDesc->TextureCube.MostDetailedMip;
        break;

      case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
        if (pDesc->TextureCubeArray.MipLevels > mipLevels - pDesc->TextureCubeArray.MostDetailedMip)
          pDesc->TextureCubeArray.MipLevels = mipLevels - pDesc->TextureCubeArray.MostDetailedMip;
        if (pDesc->TextureCubeArray.NumCubes > (numLayers - pDesc->TextureCubeArray.First2DArrayFace) / 6)
          pDesc->TextureCubeArray.NumCubes = (numLayers - pDesc->TextureCubeArray.First2DArrayFace) / 6;
        break;

      case D3D11_SRV_DIMENSION_TEXTURE3D:
        if (pDesc->Texture3D.MipLevels > mipLevels - pDesc->Texture3D.MostDetailedMip)
          pDesc->Texture3D.MipLevels = mipLevels - pDesc->Texture3D.MostDetailedMip;
        break;

      default:
        break;
    }

    return S_OK;
  }

  UINT D3D11ShaderResourceView::GetPlaneSlice(const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) {
    switch (pDesc->ViewDimension) {
      case D3D11_SRV_DIMENSION_TEXTURE2D:
        return pDesc->Texture2D.PlaneSlice;
      case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
        return pDesc->Texture2DArray.PlaneSlice;
      default:
        return 0;
    }
  }

}

repo_name: orochi/dxvk


code:
#pragma once

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

#include "../d3d10/d3d10_view_srv.h"

#include "d3d11_device_child.h"
#include "d3d11_view.h"

namespace dxvk {

  class D3D11Device;

  /**
   * \brief Shader resource view
   */
  class D3D11ShaderResourceView : public D3D11DeviceChild<ID3D11ShaderResourceView1> {

  public:

    D3D11ShaderResourceView(
            D3D11Device*                      pDevice,
            ID3D11Resource*                   pResource,
      const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc);

    ~D3D11ShaderResourceView();

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

    void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final;

    void STDMETHODCALLTYPE GetDesc(D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc) final;

    void STDMETHODCALLTYPE GetDesc1(D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) final;

    const D3D11_VK_VIEW_INFO& GetViewInfo() const {
      return m_info;
    }

    BOOL TestHazards() const {
      return m_info.BindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_UNORDERED_ACCESS);
    }

    D3D11_RESOURCE_DIMENSION GetResourceType() const {
      D3D11_RESOURCE_DIMENSION type;
      m_resource->GetType(&type);
      return type;
    }

    D3D11_COMMON_RESOURCE_DESC GetResourceDesc() const {
      D3D11_COMMON_RESOURCE_DESC desc;
      GetCommonResourceDesc(m_resource, &desc);
      return desc;
    }

    Rc<DxvkBufferView> GetBufferView() const {
      return m_bufferView;
    }

    Rc<DxvkImageView> GetImageView() const {
      return m_imageView;
    }

    D3D10ShaderResourceView* GetD3D10Iface() {
      return &m_d3d10;
    }

    static HRESULT GetDescFromResource(
            ID3D11Resource*                   pResource,
            D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc);

    static D3D11_SHADER_RESOURCE_VIEW_DESC1 PromoteDesc(
      const D3D11_SHADER_RESOURCE_VIEW_DESC*  pDesc,
            UINT                              Plane);

    static HRESULT NormalizeDesc(
            ID3D11Resource*                   pResource,
            D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc);

    static UINT GetPlaneSlice(
      const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc);

  private:

    ID3D11Resource*                   m_resource;
    D3D11_SHADER_RESOURCE_VIEW_DESC1  m_desc;
    D3D11_VK_VIEW_INFO                m_info;
    Rc<DxvkBufferView>                m_bufferView;
    Rc<DxvkImageView>                 m_imageView;
    D3D10ShaderResourceView           m_d3d10;

  };

}


code:
#include "d3d11_device.h"
#include "d3d11_buffer.h"
#include "d3d11_resource.h"
#include "d3d11_texture.h"
#include "d3d11_view_uav.h"

namespace dxvk {

  D3D11UnorderedAccessView::D3D11UnorderedAccessView(
          D3D11Device*                       pDevice,
          ID3D11Resource*                    pResource,
    const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc)
  : D3D11DeviceChild<ID3D11UnorderedAccessView1>(pDevice),
    m_resource(pResource), m_desc(*pDesc) {
    ResourceAddRefPrivate(m_resource);

    D3D11_COMMON_RESOURCE_DESC resourceDesc;
    GetCommonResourceDesc(pResource, &resourceDesc);

    // Basic view resource info
    m_info.pResource = pResource;
    m_info.Dimension = resourceDesc.Dim;
    m_info.BindFlags = resourceDesc.BindFlags;

    if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
      auto buffer = static_cast<D3D11Buffer*>(pResource);

      DxvkBufferViewCreateInfo viewInfo;

      if (pDesc->Buffer.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) {
        viewInfo.format      = VK_FORMAT_R32_UINT;
        viewInfo.rangeOffset = sizeof(uint32_t) * pDesc->Buffer.FirstElement;
        viewInfo.rangeLength = sizeof(uint32_t) * pDesc->Buffer.NumElements;
      } else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) {
        viewInfo.format      = VK_FORMAT_R32_UINT;
        viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * pDesc->Buffer.FirstElement;
        viewInfo.rangeLength = buffer->Desc()->StructureByteStride * pDesc->Buffer.NumElements;
      } else {
        viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format;

        const DxvkFormatInfo* formatInfo = imageFormatInfo(viewInfo.format);
        viewInfo.rangeOffset = formatInfo->elementSize * pDesc->Buffer.FirstElement;
        viewInfo.rangeLength = formatInfo->elementSize * pDesc->Buffer.NumElements;
      }

      if (pDesc->Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND | D3D11_BUFFER_UAV_FLAG_COUNTER))
        m_counterBuffer = CreateCounterBuffer();

      // Populate view info struct
      m_info.Buffer.Offset = viewInfo.rangeOffset;
      m_info.Buffer.Length = viewInfo.rangeLength;

      m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
        buffer->GetBuffer(), viewInfo);
    } else {
      auto texture = GetCommonTexture(pResource);
      auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());

      DxvkImageViewCreateInfo viewInfo;
      viewInfo.format  = formatInfo.Format;
      viewInfo.aspect  = formatInfo.Aspect;
      viewInfo.swizzle = formatInfo.Swizzle;
      viewInfo.usage   = VK_IMAGE_USAGE_STORAGE_BIT;

      switch (pDesc->ViewDimension) {
        case D3D11_UAV_DIMENSION_TEXTURE1D:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_1D;
          viewInfo.minLevel  = pDesc->Texture1D.MipSlice;
          viewInfo.numLevels = 1;
          viewInfo.minLayer  = 0;
          viewInfo.numLayers = 1;
          break;

        case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
          viewInfo.minLevel  = pDesc->Texture1DArray.MipSlice;
          viewInfo.numLevels = 1;
          viewInfo.minLayer  = pDesc->Texture1DArray.FirstArraySlice;
          viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
          break;

        case D3D11_UAV_DIMENSION_TEXTURE2D:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_2D;
          viewInfo.minLevel  = pDesc->Texture2D.MipSlice;
          viewInfo.numLevels = 1;
          viewInfo.minLayer  = 0;
          viewInfo.numLayers = 1;
          break;

        case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
          viewInfo.minLevel  = pDesc->Texture2DArray.MipSlice;
          viewInfo.numLevels = 1;
          viewInfo.minLayer  = pDesc->Texture2DArray.FirstArraySlice;
          viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
          break;

        case D3D11_UAV_DIMENSION_TEXTURE3D:
          // FIXME we actually have to map this to a
          // 2D array view in order to support W slices
          viewInfo.type      = VK_IMAGE_VIEW_TYPE_3D;
          viewInfo.minLevel  = pDesc->Texture3D.MipSlice;
          viewInfo.numLevels = 1;
          viewInfo.minLayer  = 0;
          viewInfo.numLayers = 1;
          break;

        default:
          throw DxvkError("D3D11: Invalid view dimension for image UAV");
      }

      if (texture->GetPlaneCount() > 1)
        viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));

      // Populate view info struct
      m_info.Image.Aspects   = viewInfo.aspect;
      m_info.Image.MinLevel  = viewInfo.minLevel;
      m_info.Image.MinLayer  = viewInfo.minLayer;
      m_info.Image.NumLevels = viewInfo.numLevels;
      m_info.Image.NumLayers = viewInfo.numLayers;

      m_imageView = pDevice->GetDXVKDevice()->createImageView(
        GetCommonTexture(pResource)->GetImage(), viewInfo);
    }
  }

  D3D11UnorderedAccessView::~D3D11UnorderedAccessView() {
    ResourceReleasePrivate(m_resource);
  }

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

    *ppvObject = nullptr;

    if (riid == __uuidof(IUnknown)
     || riid == __uuidof(ID3D11DeviceChild)
     || riid == __uuidof(ID3D11View)
     || riid == __uuidof(ID3D11UnorderedAccessView)
     || riid == __uuidof(ID3D11UnorderedAccessView1)) {
      *ppvObject = ref(this);
      return S_OK;
    }

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

  void STDMETHODCALLTYPE D3D11UnorderedAccessView::GetResource(ID3D11Resource** ppResource) {
    *ppResource = ref(m_resource);
  }

  void STDMETHODCALLTYPE D3D11UnorderedAccessView::GetDesc(D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc) {
    pDesc->Format            = m_desc.Format;
    pDesc->ViewDimension     = m_desc.ViewDimension;

    switch (m_desc.ViewDimension) {
      case D3D11_UAV_DIMENSION_UNKNOWN:
        break;

      case D3D11_UAV_DIMENSION_BUFFER:
        pDesc->Buffer = m_desc.Buffer;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE1D:
        pDesc->Texture1D = m_desc.Texture1D;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
        pDesc->Texture1DArray = m_desc.Texture1DArray;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE2D:
        pDesc->Texture2D.MipSlice = m_desc.Texture2D.MipSlice;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
        pDesc->Texture2DArray.MipSlice        = m_desc.Texture2DArray.MipSlice;
        pDesc->Texture2DArray.FirstArraySlice = m_desc.Texture2DArray.FirstArraySlice;
        pDesc->Texture2DArray.ArraySize       = m_desc.Texture2DArray.ArraySize;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE3D:
        pDesc->Texture3D = m_desc.Texture3D;
        break;
    }
  }

  void STDMETHODCALLTYPE D3D11UnorderedAccessView::GetDesc1(D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) {
    *pDesc = m_desc;
  }

  HRESULT D3D11UnorderedAccessView::GetDescFromResource(
          ID3D11Resource*                    pResource,
          D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) {
    D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
    pResource->GetType(&resourceDim);

    switch (resourceDim) {
      case D3D11_RESOURCE_DIMENSION_BUFFER: {
        D3D11_BUFFER_DESC bufferDesc;
        static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);

        if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
          pDesc->Format              = DXGI_FORMAT_UNKNOWN;
          pDesc->ViewDimension       = D3D11_UAV_DIMENSION_BUFFER;
          pDesc->Buffer.FirstElement = 0;
          pDesc->Buffer.NumElements  = bufferDesc.ByteWidth / bufferDesc.StructureByteStride;
          pDesc->Buffer.Flags = 0;
          return S_OK;
        }
      } return E_INVALIDARG;

      case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
        D3D11_TEXTURE1D_DESC resourceDesc;
        static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);

        pDesc->Format = resourceDesc.Format;

        if (resourceDesc.ArraySize == 1) {
          pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1D;
          pDesc->Texture1D.MipSlice = 0;
        } else {
          pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1DARRAY;
          pDesc->Texture1DArray.MipSlice        = 0;
          pDesc->Texture1DArray.FirstArraySlice = 0;
          pDesc->Texture1DArray.ArraySize       = resourceDesc.ArraySize;
        }
      } return S_OK;

      case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
        D3D11_TEXTURE2D_DESC resourceDesc;
        static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);

        pDesc->Format = resourceDesc.Format;

        if (resourceDesc.ArraySize == 1) {
          pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
          pDesc->Texture2D.MipSlice   = 0;
          pDesc->Texture2D.PlaneSlice = 0;
        } else {
          pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
          pDesc->Texture2DArray.MipSlice        = 0;
          pDesc->Texture2DArray.FirstArraySlice = 0;
          pDesc->Texture2DArray.ArraySize       = resourceDesc.ArraySize;
          pDesc->Texture2DArray.PlaneSlice      = 0;
        }
      } return S_OK;

      case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
        D3D11_TEXTURE3D_DESC resourceDesc;
        static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);

        pDesc->Format        = resourceDesc.Format;
        pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
        pDesc->Texture3D.MipSlice = 0;
        pDesc->Texture3D.WSize    = resourceDesc.Depth;
      } return S_OK;

      default:
        Logger::err(str::format(
          "D3D11: Unsupported dimension for unordered access view: ",
          resourceDim));
        return E_INVALIDARG;
    }
  }

  D3D11_UNORDERED_ACCESS_VIEW_DESC1 D3D11UnorderedAccessView::PromoteDesc(
    const D3D11_UNORDERED_ACCESS_VIEW_DESC*  pDesc,
          UINT                               Plane) {
    D3D11_UNORDERED_ACCESS_VIEW_DESC1 dstDesc;
    dstDesc.Format            = pDesc->Format;
    dstDesc.ViewDimension     = pDesc->ViewDimension;

    switch (pDesc->ViewDimension) {
      case D3D11_UAV_DIMENSION_UNKNOWN:
        break;

      case D3D11_UAV_DIMENSION_BUFFER:
        dstDesc.Buffer = pDesc->Buffer;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE1D:
        dstDesc.Texture1D = pDesc->Texture1D;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
        dstDesc.Texture1DArray = pDesc->Texture1DArray;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE2D:
        dstDesc.Texture2D.MipSlice   = pDesc->Texture2D.MipSlice;
        dstDesc.Texture2D.PlaneSlice = Plane;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
        dstDesc.Texture2DArray.MipSlice        = pDesc->Texture2DArray.MipSlice;
        dstDesc.Texture2DArray.FirstArraySlice = pDesc->Texture2DArray.FirstArraySlice;
        dstDesc.Texture2DArray.ArraySize       = pDesc->Texture2DArray.ArraySize;
        dstDesc.Texture2DArray.PlaneSlice      = Plane;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE3D:
        dstDesc.Texture3D = pDesc->Texture3D;
        break;
    }

    return dstDesc;
  }

  HRESULT D3D11UnorderedAccessView::NormalizeDesc(
          ID3D11Resource*                    pResource,
          D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) {
    D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
    pResource->GetType(&resourceDim);

    DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
    uint32_t numLayers = 0;

    switch (resourceDim) {
      case D3D11_RESOURCE_DIMENSION_BUFFER: {
        if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_BUFFER) {
          Logger::err("D3D11: Incompatible view dimension for Buffer");
          return E_INVALIDARG;
        }
      } break;

      case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
        D3D11_TEXTURE1D_DESC resourceDesc;
        static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);

        if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE1D
         && pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE1DARRAY) {
          Logger::err("D3D11: Incompatible view dimension for Texture1D");
          return E_INVALIDARG;
        }

        format    = resourceDesc.Format;
        numLayers = resourceDesc.ArraySize;
      } break;

      case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
        D3D11_TEXTURE2D_DESC resourceDesc;
        static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);

        if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE2D
         && pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE2DARRAY) {
          Logger::err("D3D11: Incompatible view dimension for Texture2D");
          return E_INVALIDARG;
        }

        format    = resourceDesc.Format;
        numLayers = resourceDesc.ArraySize;
      } break;

      case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
        D3D11_TEXTURE3D_DESC resourceDesc;
        static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);

        if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE3D) {
          Logger::err("D3D11: Incompatible view dimension for Texture3D");
          return E_INVALIDARG;
        }

        format    = resourceDesc.Format;
        numLayers = std::max(resourceDesc.Depth >> pDesc->Texture3D.MipSlice, 1u);
      } break;

      default:
        return E_INVALIDARG;
    }

    if (pDesc->Format == DXGI_FORMAT_UNKNOWN)
      pDesc->Format = format;

    switch (pDesc->ViewDimension) {
      case D3D11_UAV_DIMENSION_BUFFER:
        if (pDesc->Buffer.NumElements == 0)
          return E_INVALIDARG;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
        if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice)
          pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE2D:
        break;

      case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
        if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice)
          pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice;
        break;

      case D3D11_UAV_DIMENSION_TEXTURE3D:
        if (pDesc->Texture3D.WSize > numLayers - pDesc->Texture3D.FirstWSlice)
          pDesc->Texture3D.WSize = numLayers - pDesc->Texture3D.FirstWSlice;
        break;

      default:
        break;
    }

    return S_OK;
  }

  UINT D3D11UnorderedAccessView::GetPlaneSlice(const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) {
    switch (pDesc->ViewDimension) {
      case D3D11_UAV_DIMENSION_TEXTURE2D:
        return pDesc->Texture2D.PlaneSlice;
      case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
        return pDesc->Texture2DArray.PlaneSlice;
      default:
        return 0;
    }
  }

  Rc<DxvkBuffer> D3D11UnorderedAccessView::CreateCounterBuffer() {
    Rc<DxvkDevice> device = m_parent->GetDXVKDevice();

    DxvkBufferCreateInfo info;
    info.size   = sizeof(uint32_t);
    info.usage  = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
                | VK_BUFFER_USAGE_TRANSFER_DST_BIT
                | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
    info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
                | device->getShaderPipelineStages();
    info.access = VK_ACCESS_TRANSFER_WRITE_BIT
                | VK_ACCESS_TRANSFER_READ_BIT
                | VK_ACCESS_SHADER_WRITE_BIT
                | VK_ACCESS_SHADER_READ_BIT;
    return device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  }

}


code:
#pragma once

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

#include "d3d11_device_child.h"
#include "d3d11_view.h"

namespace dxvk {

  class D3D11Device;

  /**
   * \brief Unordered access view
   *
   * Unordered access views are special in that they can
   * have counters, which can be used inside shaders to
   * atomically append or consume structures.
   */
  class D3D11UnorderedAccessView : public D3D11DeviceChild<ID3D11UnorderedAccessView1> {

  public:

    D3D11UnorderedAccessView(
            D3D11Device*                       pDevice,
            ID3D11Resource*                    pResource,
      const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc);

    ~D3D11UnorderedAccessView();

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

    void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final;

    void STDMETHODCALLTYPE GetDesc(D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc) final;

    void STDMETHODCALLTYPE GetDesc1(D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) final;

    const D3D11_VK_VIEW_INFO& GetViewInfo() const {
      return m_info;
    }

    BOOL HasBindFlag(UINT Flags) const {
      return m_info.BindFlags & Flags;
    }

    D3D11_RESOURCE_DIMENSION GetResourceType() const {
      D3D11_RESOURCE_DIMENSION type;
      m_resource->GetType(&type);
      return type;
    }

    Rc<DxvkBufferView> GetBufferView() const {
      return m_bufferView;
    }

    Rc<DxvkImageView> GetImageView() const {
      return m_imageView;
    }

    DxvkBufferSlice GetCounterSlice() const {
      return m_counterBuffer != nullptr
        ? DxvkBufferSlice(m_counterBuffer)
        : DxvkBufferSlice();
    }

    static HRESULT GetDescFromResource(
            ID3D11Resource*                    pResource,
            D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc);

    static D3D11_UNORDERED_ACCESS_VIEW_DESC1 PromoteDesc(
      const D3D11_UNORDERED_ACCESS_VIEW_DESC*  pDesc,
            UINT                               Plane);

    static HRESULT NormalizeDesc(
            ID3D11Resource*                    pResource,
            D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc);

    static UINT GetPlaneSlice(
      const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc);

  private:

    ID3D11Resource*                   m_resource;
    D3D11_UNORDERED_ACCESS_VIEW_DESC1 m_desc;
    D3D11_VK_VIEW_INFO                m_info;
    Rc<DxvkBufferView>                m_bufferView;
    Rc<DxvkImageView>                 m_imageView;
    Rc<DxvkBuffer>                    m_counterBuffer;

    Rc<DxvkBuffer> CreateCounterBuffer();

  };

}


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

dxgi_common_src = [
  '../dxgi/dxgi_format.cpp',
  '../dxgi/dxgi_monitor.cpp',
  '../dxgi/dxgi_swapchain.cpp',
]

d3d10_src = [
  '../d3d10/d3d10_blend.cpp',
  '../d3d10/d3d10_buffer.cpp',
  '../d3d10/d3d10_depth_stencil.cpp',
  '../d3d10/d3d10_device.cpp',
  '../d3d10/d3d10_input_layout.cpp',
  '../d3d10/d3d10_multithread.cpp',
  '../d3d10/d3d10_query.cpp',
  '../d3d10/d3d10_rasterizer.cpp',
  '../d3d10/d3d10_sampler.cpp',
  '../d3d10/d3d10_texture.cpp',
  '../d3d10/d3d10_util.cpp',
  '../d3d10/d3d10_view_dsv.cpp',
  '../d3d10/d3d10_view_rtv.cpp',
  '../d3d10/d3d10_view_srv.cpp',
]

d3d11_src = [
  'd3d11_annotation.cpp',
  'd3d11_blend.cpp',
  'd3d11_buffer.cpp',
  'd3d11_class_linkage.cpp',
  'd3d11_cmdlist.cpp',
  'd3d11_context.cpp',
  'd3d11_context_def.cpp',
  'd3d11_context_ext.cpp',
  'd3d11_context_imm.cpp',
  'd3d11_cuda.cpp',
  'd3d11_depth_stencil.cpp',
  'd3d11_device.cpp',
  'd3d11_enums.cpp',
  'd3d11_fence.cpp',
  'd3d11_gdi.cpp',
  'd3d11_initializer.cpp',
  'd3d11_input_layout.cpp',
  'd3d11_interop.cpp',
  'd3d11_main.cpp',
  'd3d11_options.cpp',
  'd3d11_query.cpp',
  'd3d11_rasterizer.cpp',
  'd3d11_resource.cpp',
  'd3d11_sampler.cpp',
  'd3d11_shader.cpp',
  'd3d11_state.cpp',
  'd3d11_state_object.cpp',
  'd3d11_swapchain.cpp',
  'd3d11_texture.cpp',
  'd3d11_util.cpp',
  'd3d11_video.cpp',
  'd3d11_view_dsv.cpp',
  'd3d11_view_rtv.cpp',
  'd3d11_view_srv.cpp',
  'd3d11_view_uav.cpp',
]

d3d11_shaders = files([
  'shaders/d3d11_video_blit_frag.frag',
  'shaders/d3d11_video_blit_vert.vert',
])

d3d11_dll = shared_library('d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src,
    glsl_generator.process(d3d11_shaders), d3d11_res,
  name_prefix         : '',
  dependencies        : [ lib_dxgi, dxbc_dep, dxvk_dep ],
  include_directories : dxvk_include_path,
  install             : true,
  vs_module_defs      : 'd3d11'+def_spec_ext,
)

d3d11_dep = declare_dependency(
  link_with           : [ d3d11_dll ],
  include_directories : [ dxvk_include_path ],
)


code:
#version 450

layout(constant_id = 3) const bool c_planar = true;

// Can't use matrix types here since even a two-row
// matrix will be padded to 16 bytes per column for
// absolutely no reason
layout(std140, set = 0, binding = 0)
uniform ubo_t {
  vec4 color_matrix_r1;
  vec4 color_matrix_r2;
  vec4 color_matrix_r3;
  vec2 coord_matrix_c1;
  vec2 coord_matrix_c2;
  vec2 coord_matrix_c3;
  float y_min;
  float y_max;
};

layout(location = 0) in vec2 i_texcoord;
layout(location = 0) out vec4 o_color;

layout(set = 0, binding = 1) uniform sampler s_sampler;
layout(set = 0, binding = 2) uniform texture2D s_inputY;
layout(set = 0, binding = 3) uniform texture2D s_inputCbCr;

void main() {
  // Transform input texture coordinates to
  // account for rotation and source rectangle
  mat3x2 coord_matrix = mat3x2(
    coord_matrix_c1,
    coord_matrix_c2,
    coord_matrix_c3);

  vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f);

  // Fetch source image color
  vec4 color = vec4(0.0f, 0.0f, 0.0f, 1.0f);

  if (c_planar) {
    color.g  = texture(sampler2D(s_inputY,    s_sampler), coord).r;
    color.rb = texture(sampler2D(s_inputCbCr, s_sampler), coord).gr;
    color.g  = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f);
  } else {
    color = texture(sampler2D(s_inputY, s_sampler), coord);
  }

  // Color space transformation
  mat3x4 color_matrix = mat3x4(
    color_matrix_r1,
    color_matrix_r2,
    color_matrix_r3);

  o_color.rgb = vec4(color.rgb, 1.0f) * color_matrix;
  o_color.a = color.a;
}


code:
#version 450

layout(location = 0) out vec2 o_texcoord;

void main() {
  vec2 coord = vec2(
    float(gl_VertexIndex & 1) * 2.0f,
    float(gl_VertexIndex & 2));

  o_texcoord  = coord;
  gl_Position = vec4(-1.0f + 2.0f * coord, 0.0f, 1.0f);
}


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 11 Runtime"
      VALUE "FileVersion",      "10.0.17763.1 (WinBuild.160101.0800)"
      VALUE "InternalName",     "D3D11.dll"
      VALUE "LegalCopyright",   "zlib/libpng license"
      VALUE "OriginalFilename", "D3D11.dll"
      VALUE "ProductName",      "DXVK"
      VALUE "ProductVersion",   "10.0.17763.1"
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x0809, 1200
  END
END


code:
LIBRARY D3D9.DLL
EXPORTS
  Direct3DShaderValidatorCreate9 @24

  PSGPError @25
  PSGPSampleTexture @26

  D3DPERF_BeginEvent @27
  D3DPERF_EndEvent @28
  D3DPERF_GetStatus @29
  D3DPERF_QueryRepeatFrame @30
  D3DPERF_SetMarker @31
  D3DPERF_SetOptions @32
  D3DPERF_SetRegion @33

  DebugSetLevel @34
  DebugSetMute @35

  Direct3D9EnableMaximizedWindowedModeShim @36

  Direct3DCreate9 @ 37
  Direct3DCreate9Ex @ 38

  DXVK_RegisterAnnotation @ 28257 NONAME
  DXVK_UnRegisterAnnotation @ 28258 NONAME

  Direct3D9ForceHybridEnumeration @16 NONAME PRIVATE


code:
#include "d3d9_adapter.h"

#include "d3d9_interface.h"
#include "d3d9_monitor.h"
#include "d3d9_caps.h"
#include "d3d9_util.h"

#include "../util/util_bit.h"
#include "../util/util_luid.h"
#include "../util/util_ratio.h"

#include <cfloat>

namespace dxvk {

  const char* GetDriverDLL(DxvkGpuVendor vendor) {
    switch (vendor) {
      default:
      case DxvkGpuVendor::Nvidia: return "nvd3dum.dll";

#if defined(__x86_64__) || defined(_M_X64)
      case DxvkGpuVendor::Amd:    return "aticfx64.dll";
      case DxvkGpuVendor::Intel:  return "igdumd64.dll";
#else
      case DxvkGpuVendor::Amd:    return "aticfx32.dll";
      case DxvkGpuVendor::Intel:  return "igdumd32.dll";
#endif
    }
  }

  D3D9Adapter::D3D9Adapter(
          D3D9InterfaceEx* pParent,
          Rc<DxvkAdapter>  Adapter,
          UINT             Ordinal,
          UINT             DisplayIndex)
  : m_parent          (pParent),
    m_adapter         (Adapter),
    m_ordinal         (Ordinal),
    m_displayIndex    (DisplayIndex),
    m_modeCacheFormat (D3D9Format::Unknown),
    m_d3d9Formats     (Adapter, m_parent->GetOptions()) {
    m_adapter->logAdapterInfo();
  }

  template <size_t N>
  static void copyToStringArray(char (&dst)[N], const char* src) {
    dxvk::str::strlcpy(dst, src, N);
  }

  HRESULT D3D9Adapter::GetAdapterIdentifier(
          DWORD                   Flags,
          D3DADAPTER_IDENTIFIER9* pIdentifier) {
    if (unlikely(pIdentifier == nullptr))
      return D3DERR_INVALIDCALL;

    auto& options = m_parent->GetOptions();

    const auto& props = m_adapter->deviceProperties();

    DISPLAY_DEVICEA device = { };
    device.cb = sizeof(device);

    if (!::EnumDisplayDevicesA(nullptr, m_displayIndex, &device, 0)) {
      Logger::err("D3D9Adapter::GetAdapterIdentifier: Failed to query display info");
      return D3DERR_INVALIDCALL;
    }

    GUID guid          = bit::cast<GUID>(m_adapter->devicePropertiesExt().coreDeviceId.deviceUUID);

    uint32_t vendorId  = options.customVendorId == -1     ? props.vendorID   : uint32_t(options.customVendorId);
    uint32_t deviceId  = options.customDeviceId == -1     ? props.deviceID   : uint32_t(options.customDeviceId);
    const char*  desc  = options.customDeviceDesc.empty() ? props.deviceName : options.customDeviceDesc.c_str();
    const char* driver = GetDriverDLL(DxvkGpuVendor(vendorId));

    copyToStringArray(pIdentifier->Description, desc);
    copyToStringArray(pIdentifier->DeviceName,  device.DeviceName); // The GDI device name. Not the actual device name.
    copyToStringArray(pIdentifier->Driver,      driver);            // This is the driver's dll.

    pIdentifier->DeviceIdentifier       = guid;
    pIdentifier->DeviceId               = deviceId;
    pIdentifier->VendorId               = vendorId;
    pIdentifier->Revision               = 0;
    pIdentifier->SubSysId               = 0;
    pIdentifier->WHQLLevel              = m_parent->IsExtended() ? 1 : 0; // This doesn't check with the driver on Direct3D9Ex and is always 1.
    pIdentifier->DriverVersion.QuadPart = INT64_MAX;

    return D3D_OK;
  }

  HRESULT D3D9Adapter::CheckDeviceType(
          D3DDEVTYPE DevType,
          D3D9Format AdapterFormat,
          D3D9Format BackBufferFormat,
          BOOL       bWindowed) {
    if (!IsSupportedAdapterFormat(AdapterFormat))
      return D3DERR_NOTAVAILABLE;

    if (!IsSupportedBackBufferFormat(AdapterFormat, BackBufferFormat, bWindowed))
      return D3DERR_NOTAVAILABLE;

    return D3D_OK;
  }

  HRESULT D3D9Adapter::CheckDeviceFormat(
          D3DDEVTYPE      DeviceType,
          D3D9Format      AdapterFormat,
          DWORD           Usage,
          D3DRESOURCETYPE RType,
          D3D9Format      CheckFormat) {
    if (!IsSupportedAdapterFormat(AdapterFormat))
      return D3DERR_NOTAVAILABLE;

    const bool dmap = Usage & D3DUSAGE_DMAP;
    const bool rt   = Usage & D3DUSAGE_RENDERTARGET;
    const bool ds   = Usage & D3DUSAGE_DEPTHSTENCIL;

    const bool surface = RType == D3DRTYPE_SURFACE;
    const bool texture = RType == D3DRTYPE_TEXTURE;

    const bool twoDimensional = surface || texture;

    const bool srgb = (Usage & (D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE)) != 0;

    if (CheckFormat == D3D9Format::INST)
      return D3D_OK;

    if (rt && CheckFormat == D3D9Format::A8 && m_parent->GetOptions().disableA8RT)
      return D3DERR_NOTAVAILABLE;

    if (ds && !IsDepthFormat(CheckFormat))
      return D3DERR_NOTAVAILABLE;

    if (rt && CheckFormat == D3D9Format::NULL_FORMAT && twoDimensional)
      return D3D_OK;

    if (rt && CheckFormat == D3D9Format::RESZ && surface)
      return D3D_OK;

    if (CheckFormat == D3D9Format::ATOC && surface)
      return D3D_OK;

    if (CheckFormat == D3D9Format::NVDB && surface)
      return m_adapter->features().core.features.depthBounds
        ? D3D_OK
        : D3DERR_NOTAVAILABLE;

    // I really don't want to support this...
    if (dmap)
      return D3DERR_NOTAVAILABLE;

    auto mapping = m_d3d9Formats.GetFormatMapping(CheckFormat);
    if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
      return D3DERR_NOTAVAILABLE;

    if (mapping.FormatSrgb  == VK_FORMAT_UNDEFINED && srgb)
      return D3DERR_NOTAVAILABLE;

    if (RType == D3DRTYPE_VERTEXBUFFER || RType == D3DRTYPE_INDEXBUFFER)
      return D3D_OK;

    // Let's actually ask Vulkan now that we got some quirks out the way!
    return CheckDeviceVkFormat(mapping.FormatColor, Usage, RType);
  }

  HRESULT D3D9Adapter::CheckDeviceMultiSampleType(
        D3DDEVTYPE          DeviceType,
        D3D9Format          SurfaceFormat,
        BOOL                Windowed,
        D3DMULTISAMPLE_TYPE MultiSampleType,
        DWORD*              pQualityLevels) {
    if (pQualityLevels != nullptr)
      *pQualityLevels = 1;

    auto dst = ConvertFormatUnfixed(SurfaceFormat);
    if (dst.FormatColor == VK_FORMAT_UNDEFINED)
      return D3DERR_NOTAVAILABLE;

    if (MultiSampleType != D3DMULTISAMPLE_NONE
     && (SurfaceFormat == D3D9Format::D32_LOCKABLE
      || SurfaceFormat == D3D9Format::D32F_LOCKABLE
      || SurfaceFormat == D3D9Format::D16_LOCKABLE
      || SurfaceFormat == D3D9Format::INTZ))
      return D3DERR_NOTAVAILABLE;

    uint32_t sampleCount = std::max<uint32_t>(MultiSampleType, 1u);

    // Check if this is a power of two...
    if (sampleCount & (sampleCount - 1))
      return D3DERR_NOTAVAILABLE;

    // Therefore...
    VkSampleCountFlags sampleFlags = VkSampleCountFlags(sampleCount);

    auto availableFlags = !IsDepthFormat(SurfaceFormat)
      ? m_adapter->deviceProperties().limits.framebufferColorSampleCounts
      : m_adapter->deviceProperties().limits.framebufferDepthSampleCounts;

    if (!(availableFlags & sampleFlags))
      return D3DERR_NOTAVAILABLE;

    if (pQualityLevels != nullptr) {
      if (MultiSampleType == D3DMULTISAMPLE_NONMASKABLE)
        *pQualityLevels = 32 - bit::lzcnt(availableFlags);
      else
        *pQualityLevels = 1;
    }

    return D3D_OK;
  }

  HRESULT D3D9Adapter::CheckDepthStencilMatch(
          D3DDEVTYPE DeviceType,
          D3D9Format AdapterFormat,
          D3D9Format RenderTargetFormat,
          D3D9Format DepthStencilFormat) {
    if (!IsDepthFormat(DepthStencilFormat))
      return D3DERR_NOTAVAILABLE;

    if (RenderTargetFormat == dxvk::D3D9Format::NULL_FORMAT)
      return D3D_OK;

    auto mapping = ConvertFormatUnfixed(RenderTargetFormat);
    if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
      return D3DERR_NOTAVAILABLE;

    return D3D_OK;
  }

  HRESULT D3D9Adapter::CheckDeviceFormatConversion(
          D3DDEVTYPE DeviceType,
          D3D9Format SourceFormat,
          D3D9Format TargetFormat) {
    bool sourceSupported = SourceFormat != D3D9Format::Unknown
                        && IsSupportedBackBufferFormat(SourceFormat);
    bool targetSupported = TargetFormat == D3D9Format::X1R5G5B5
                        || TargetFormat == D3D9Format::A1R5G5B5
                        || TargetFormat == D3D9Format::R5G6B5
                     // || TargetFormat == D3D9Format::R8G8B8 <-- We don't support R8G8B8
                        || TargetFormat == D3D9Format::X8R8G8B8
                        || TargetFormat == D3D9Format::A8R8G8B8
                        || TargetFormat == D3D9Format::A2R10G10B10
                        || TargetFormat == D3D9Format::A16B16G16R16
                        || TargetFormat == D3D9Format::A2B10G10R10
                        || TargetFormat == D3D9Format::A8B8G8R8
                        || TargetFormat == D3D9Format::X8B8G8R8
                        || TargetFormat == D3D9Format::A16B16G16R16F
                        || TargetFormat == D3D9Format::A32B32G32R32F;

    return (sourceSupported && targetSupported)
      ? D3D_OK
      : D3DERR_NOTAVAILABLE;
  }

  HRESULT D3D9Adapter::GetDeviceCaps(
          D3DDEVTYPE DeviceType,
          D3DCAPS9*  pCaps) {
    using namespace dxvk::caps;

    if (pCaps == nullptr)
      return D3DERR_INVALIDCALL;

    auto& options = m_parent->GetOptions();

    // TODO: Actually care about what the adapter supports here.
    // ^ For Intel and older cards most likely here.

    // Device Type
    pCaps->DeviceType               = DeviceType;
    // Adapter Id
    pCaps->AdapterOrdinal           = m_ordinal;
    // Caps 1
    pCaps->Caps                     = D3DCAPS_READ_SCANLINE;
    // Caps 2
    pCaps->Caps2                    = D3DCAPS2_FULLSCREENGAMMA
                                 /* | D3DCAPS2_CANCALIBRATEGAMMA */
                                 /* | D3DCAPS2_RESERVED */
                                 /* | D3DCAPS2_CANMANAGERESOURCE */
                                    | D3DCAPS2_DYNAMICTEXTURES
                                    | D3DCAPS2_CANAUTOGENMIPMAP
                                 /* | D3DCAPS2_CANSHARERESOURCE */;
    // Caps 3
    pCaps->Caps3                    = D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD
                                    | D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION
                                    | D3DCAPS3_COPY_TO_VIDMEM
                                    | D3DCAPS3_COPY_TO_SYSTEMMEM
                                 /* | D3DCAPS3_DXVAHD */
                                 /* | D3DCAPS3_DXVAHD_LIMITED */;
    // Presentation Intervals
    pCaps->PresentationIntervals    = D3DPRESENT_INTERVAL_DEFAULT
                                    | D3DPRESENT_INTERVAL_ONE
                                    | D3DPRESENT_INTERVAL_TWO
                                    | D3DPRESENT_INTERVAL_THREE
                                    | D3DPRESENT_INTERVAL_FOUR
                                    | D3DPRESENT_INTERVAL_IMMEDIATE;
    // Cursor
    pCaps->CursorCaps               = D3DCURSORCAPS_COLOR; // I do not support Cursor yet, but I don't want to say I don't support it for compatibility reasons.
    // Dev Caps
    pCaps->DevCaps                  = D3DDEVCAPS_EXECUTESYSTEMMEMORY
                                    | D3DDEVCAPS_EXECUTEVIDEOMEMORY
                                    | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY
                                    | D3DDEVCAPS_TLVERTEXVIDEOMEMORY
                                 /* | D3DDEVCAPS_TEXTURESYSTEMMEMORY */
                                    | D3DDEVCAPS_TEXTUREVIDEOMEMORY
                                    | D3DDEVCAPS_DRAWPRIMTLVERTEX
                                    | D3DDEVCAPS_CANRENDERAFTERFLIP
                                    | D3DDEVCAPS_TEXTURENONLOCALVIDMEM
                                    | D3DDEVCAPS_DRAWPRIMITIVES2
                                 /* | D3DDEVCAPS_SEPARATETEXTUREMEMORIES */
                                    | D3DDEVCAPS_DRAWPRIMITIVES2EX
                                    | D3DDEVCAPS_HWTRANSFORMANDLIGHT
                                    | D3DDEVCAPS_CANBLTSYSTONONLOCAL
                                    | D3DDEVCAPS_HWRASTERIZATION
                                    | D3DDEVCAPS_PUREDEVICE
                                 /* | D3DDEVCAPS_QUINTICRTPATCHES */
                                 /* | D3DDEVCAPS_RTPATCHES */
                                 /* | D3DDEVCAPS_RTPATCHHANDLEZERO */
                                 /* | D3DDEVCAPS_NPATCHES */;
    // Primitive Misc. Caps
    pCaps->PrimitiveMiscCaps        = D3DPMISCCAPS_MASKZ
                                    | D3DPMISCCAPS_CULLNONE
                                    | D3DPMISCCAPS_CULLCW
                                    | D3DPMISCCAPS_CULLCCW
                                    | D3DPMISCCAPS_COLORWRITEENABLE
                                    | D3DPMISCCAPS_CLIPPLANESCALEDPOINTS
                                    | D3DPMISCCAPS_CLIPTLVERTS
                                    | D3DPMISCCAPS_TSSARGTEMP
                                    | D3DPMISCCAPS_BLENDOP
                                 /* | D3DPMISCCAPS_NULLREFERENCE */
                                    | D3DPMISCCAPS_INDEPENDENTWRITEMASKS
                                    | D3DPMISCCAPS_PERSTAGECONSTANT
                                    | D3DPMISCCAPS_FOGANDSPECULARALPHA
                                    | D3DPMISCCAPS_SEPARATEALPHABLEND
                                    | D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS
                                    | D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING
                                    | D3DPMISCCAPS_FOGVERTEXCLAMPED
                                    | D3DPMISCCAPS_POSTBLENDSRGBCONVERT;
    // Raster Caps
    pCaps->RasterCaps               = D3DPRASTERCAPS_DITHER
                                    | D3DPRASTERCAPS_ZTEST
                                    | D3DPRASTERCAPS_FOGVERTEX
                                    | D3DPRASTERCAPS_FOGTABLE
                                    | D3DPRASTERCAPS_MIPMAPLODBIAS
                                 /* | D3DPRASTERCAPS_ZBUFFERLESSHSR */
                                    | D3DPRASTERCAPS_FOGRANGE
                                    | D3DPRASTERCAPS_ANISOTROPY
                                 /* | D3DPRASTERCAPS_WBUFFER */
                                    | D3DPRASTERCAPS_WFOG
                                    | D3DPRASTERCAPS_ZFOG
                                    | D3DPRASTERCAPS_COLORPERSPECTIVE
                                    | D3DPRASTERCAPS_SCISSORTEST
                                    | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS
                                    | D3DPRASTERCAPS_DEPTHBIAS
                                    | D3DPRASTERCAPS_MULTISAMPLE_TOGGLE; // <-- TODO! (but difficult in Vk)
    // Z Comparison Caps
    pCaps->ZCmpCaps                 = D3DPCMPCAPS_NEVER
                                    | D3DPCMPCAPS_LESS
                                    | D3DPCMPCAPS_EQUAL
                                    | D3DPCMPCAPS_LESSEQUAL
                                    | D3DPCMPCAPS_GREATER
                                    | D3DPCMPCAPS_NOTEQUAL
                                    | D3DPCMPCAPS_GREATEREQUAL
                                    | D3DPCMPCAPS_ALWAYS;
    // Source Blend Caps
    pCaps->SrcBlendCaps             = D3DPBLENDCAPS_ZERO
                                    | D3DPBLENDCAPS_ONE
                                    | D3DPBLENDCAPS_SRCCOLOR
                                    | D3DPBLENDCAPS_INVSRCCOLOR
                                    | D3DPBLENDCAPS_SRCALPHA
                                    | D3DPBLENDCAPS_INVSRCALPHA
                                    | D3DPBLENDCAPS_DESTALPHA
                                    | D3DPBLENDCAPS_INVDESTALPHA
                                    | D3DPBLENDCAPS_DESTCOLOR
                                    | D3DPBLENDCAPS_INVDESTCOLOR
                                    | D3DPBLENDCAPS_SRCALPHASAT
                                    | D3DPBLENDCAPS_BOTHSRCALPHA
                                    | D3DPBLENDCAPS_BOTHINVSRCALPHA
                                    | D3DPBLENDCAPS_BLENDFACTOR
                                    | D3DPBLENDCAPS_INVSRCCOLOR2
                                    | D3DPBLENDCAPS_SRCCOLOR2;
    // Destination Blend Caps
    pCaps->DestBlendCaps            = pCaps->SrcBlendCaps;
    // Alpha Comparison Caps
    pCaps->AlphaCmpCaps             = pCaps->ZCmpCaps;
    // Shade Caps
    pCaps->ShadeCaps                = D3DPSHADECAPS_COLORGOURAUDRGB
                                    | D3DPSHADECAPS_SPECULARGOURAUDRGB
                                    | D3DPSHADECAPS_ALPHAGOURAUDBLEND
                                    | D3DPSHADECAPS_FOGGOURAUD;
    // Texture Caps
    pCaps->TextureCaps              = D3DPTEXTURECAPS_PERSPECTIVE
                                 /* | D3DPTEXTURECAPS_POW2 */
                                    | D3DPTEXTURECAPS_ALPHA
                                 /* | D3DPTEXTURECAPS_SQUAREONLY */
                                    | D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE
                                    | D3DPTEXTURECAPS_ALPHAPALETTE
                                 /* | D3DPTEXTURECAPS_NONPOW2CONDITIONAL */
                                    | D3DPTEXTURECAPS_PROJECTED
                                    | D3DPTEXTURECAPS_CUBEMAP
                                    | D3DPTEXTURECAPS_VOLUMEMAP
                                    | D3DPTEXTURECAPS_MIPMAP
                                    | D3DPTEXTURECAPS_MIPVOLUMEMAP
                                    | D3DPTEXTURECAPS_MIPCUBEMAP
                                 /* | D3DPTEXTURECAPS_CUBEMAP_POW2 */
                                 /* | D3DPTEXTURECAPS_VOLUMEMAP_POW2 */
                                 /* | D3DPTEXTURECAPS_NOPROJECTEDBUMPENV */;
    // Texture Filter Caps
    pCaps->TextureFilterCaps        = D3DPTFILTERCAPS_MINFPOINT
                                    | D3DPTFILTERCAPS_MINFLINEAR
                                    | D3DPTFILTERCAPS_MINFANISOTROPIC
                                 /* | D3DPTFILTERCAPS_MINFPYRAMIDALQUAD */
                                 /* | D3DPTFILTERCAPS_MINFGAUSSIANQUAD */
                                    | D3DPTFILTERCAPS_MIPFPOINT
                                    | D3DPTFILTERCAPS_MIPFLINEAR
                                 /* | D3DPTFILTERCAPS_CONVOLUTIONMONO */
                                    | D3DPTFILTERCAPS_MAGFPOINT
                                    | D3DPTFILTERCAPS_MAGFLINEAR
                                    | D3DPTFILTERCAPS_MAGFANISOTROPIC
                                 /* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
                                 /* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */;
    // Cube Texture Filter Caps
    pCaps->CubeTextureFilterCaps    = pCaps->TextureFilterCaps;
    // Volume Texture Filter Caps
    pCaps->VolumeTextureFilterCaps  = pCaps->TextureFilterCaps;
    // Texture Address Caps
    pCaps->TextureAddressCaps       = D3DPTADDRESSCAPS_WRAP
                                    | D3DPTADDRESSCAPS_MIRROR
                                    | D3DPTADDRESSCAPS_CLAMP
                                    | D3DPTADDRESSCAPS_BORDER
                                    | D3DPTADDRESSCAPS_INDEPENDENTUV
                                    | D3DPTADDRESSCAPS_MIRRORONCE;
    // Volume Texture Address Caps
    pCaps->VolumeTextureAddressCaps = pCaps->TextureAddressCaps;
    // Line Caps
    pCaps->LineCaps                 = D3DLINECAPS_TEXTURE
                                    | D3DLINECAPS_ZTEST
                                    | D3DLINECAPS_BLEND
                                    | D3DLINECAPS_ALPHACMP
                                    | D3DLINECAPS_FOG
                                    | D3DLINECAPS_ANTIALIAS; //<-- Lying about doing AA lines here, we don't *fully* support that.
    // Max Texture Width
    pCaps->MaxTextureWidth          = MaxTextureDimension;
    // Max Texture Height
    pCaps->MaxTextureHeight         = MaxTextureDimension;
    // Max Volume Extent
    pCaps->MaxVolumeExtent          = 8192;
    // Max Texture Repeat
    pCaps->MaxTextureRepeat         = 8192;
    // Max Texture Aspect Ratio
    pCaps->MaxTextureAspectRatio    = 8192;
    // Max Anisotropy
    pCaps->MaxAnisotropy            = 16;
    // Max Vertex W
    pCaps->MaxVertexW               = 1e10f;
    // Guard Bands
    pCaps->GuardBandLeft            = -32768.0f;
    pCaps->GuardBandTop             = -32768.0f;
    pCaps->GuardBandRight           =  32768.0f;
    pCaps->GuardBandBottom          =  32768.0f;
    // Extents Adjust
    pCaps->ExtentsAdjust            = 0.0f;
    // Stencil Caps
    pCaps->StencilCaps              = D3DSTENCILCAPS_KEEP
                                    | D3DSTENCILCAPS_ZERO
                                    | D3DSTENCILCAPS_REPLACE
                                    | D3DSTENCILCAPS_INCRSAT
                                    | D3DSTENCILCAPS_DECRSAT
                                    | D3DSTENCILCAPS_INVERT
                                    | D3DSTENCILCAPS_INCR
                                    | D3DSTENCILCAPS_DECR
                                    | D3DSTENCILCAPS_TWOSIDED;
    // FVF Caps
    pCaps->FVFCaps                  = (MaxSimultaneousTextures & D3DFVFCAPS_TEXCOORDCOUNTMASK)
                                 /* | D3DFVFCAPS_DONOTSTRIPELEMENTS */
                                    | D3DFVFCAPS_PSIZE;
    // Texture Op Caps
    pCaps->TextureOpCaps            = D3DTEXOPCAPS_DISABLE
                                    | D3DTEXOPCAPS_SELECTARG1
                                    | D3DTEXOPCAPS_SELECTARG2
                                    | D3DTEXOPCAPS_MODULATE
                                    | D3DTEXOPCAPS_MODULATE2X
                                    | D3DTEXOPCAPS_MODULATE4X
                                    | D3DTEXOPCAPS_ADD
                                    | D3DTEXOPCAPS_ADDSIGNED
                                    | D3DTEXOPCAPS_ADDSIGNED2X
                                    | D3DTEXOPCAPS_SUBTRACT
                                    | D3DTEXOPCAPS_ADDSMOOTH
                                    | D3DTEXOPCAPS_BLENDDIFFUSEALPHA
                                    | D3DTEXOPCAPS_BLENDTEXTUREALPHA
                                    | D3DTEXOPCAPS_BLENDFACTORALPHA
                                    | D3DTEXOPCAPS_BLENDTEXTUREALPHAPM
                                    | D3DTEXOPCAPS_BLENDCURRENTALPHA
                                    | D3DTEXOPCAPS_PREMODULATE
                                    | D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR
                                    | D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA
                                    | D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR
                                    | D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA
                                    | D3DTEXOPCAPS_BUMPENVMAP
                                    | D3DTEXOPCAPS_BUMPENVMAPLUMINANCE
                                    | D3DTEXOPCAPS_DOTPRODUCT3
                                    | D3DTEXOPCAPS_MULTIPLYADD
                                    | D3DTEXOPCAPS_LERP;
    // Max Texture Blend Stages
    pCaps->MaxTextureBlendStages    = MaxTextureBlendStages;
    // Max Simultaneous Textures
    pCaps->MaxSimultaneousTextures  = MaxSimultaneousTextures;
    // Vertex Processing Caps
    pCaps->VertexProcessingCaps      = D3DVTXPCAPS_TEXGEN
                                     | D3DVTXPCAPS_MATERIALSOURCE7
                                     | D3DVTXPCAPS_DIRECTIONALLIGHTS
                                     | D3DVTXPCAPS_POSITIONALLIGHTS
                                     | D3DVTXPCAPS_LOCALVIEWER
                                     | D3DVTXPCAPS_TWEENING
                                     | D3DVTXPCAPS_TEXGEN_SPHEREMAP
                                  /* | D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER*/;
    // Max Active Lights
    pCaps->MaxActiveLights           = caps::MaxEnabledLights;
    // Max User Clip Planes
    pCaps->MaxUserClipPlanes         = MaxClipPlanes;
    // Max Vertex Blend Matrices
    pCaps->MaxVertexBlendMatrices    = 4;
    // Max Vertex Blend Matrix Index
    pCaps->MaxVertexBlendMatrixIndex = 8;
    // Max Point Size
    pCaps->MaxPointSize              = 256.0f;
    // Max Primitive Count
    pCaps->MaxPrimitiveCount         = 0x00555555;
    // Max Vertex Index
    pCaps->MaxVertexIndex            = 0x00ffffff;
    // Max Streams
    pCaps->MaxStreams                = MaxStreams;
    // Max Stream Stride
    pCaps->MaxStreamStride           = 508; // bytes

    const uint32_t majorVersion = options.shaderModel;
    const uint32_t minorVersion = options.shaderModel != 1 ? 0 : 4;

    // Shader Versions
    pCaps->VertexShaderVersion = D3DVS_VERSION(majorVersion, minorVersion);
    pCaps->PixelShaderVersion  = D3DPS_VERSION(majorVersion, minorVersion);

    // Max Vertex Shader Const
    pCaps->MaxVertexShaderConst       = MaxFloatConstantsVS;
    // Max PS1 Value
    pCaps->PixelShader1xMaxValue      = FLT_MAX;
    // Dev Caps 2
    pCaps->DevCaps2                   = D3DDEVCAPS2_STREAMOFFSET
                                   /* | D3DDEVCAPS2_DMAPNPATCH */
                                   /* | D3DDEVCAPS2_ADAPTIVETESSRTPATCH */
                                   /* | D3DDEVCAPS2_ADAPTIVETESSNPATCH */
                                      | D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES
                                   /* | D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH */
                                      | D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET;
    // Max N Patch Tesselation Level
    pCaps->MaxNpatchTessellationLevel = 0.0f;
    // Reserved for... something
    pCaps->Reserved5                  = 0;
    // Master adapter for us is adapter 0, atm...
    pCaps->MasterAdapterOrdinal       = 0;
    // The group of adapters this one is in
    pCaps->AdapterOrdinalInGroup      = 0;
    // Number of adapters in current group
    pCaps->NumberOfAdaptersInGroup    = 1;
    // Decl Type Caps
    pCaps->DeclTypes                  = D3DDTCAPS_UBYTE4
                                      | D3DDTCAPS_UBYTE4N
                                      | D3DDTCAPS_SHORT2N
                                      | D3DDTCAPS_SHORT4N
                                      | D3DDTCAPS_USHORT2N
                                      | D3DDTCAPS_USHORT4N
                                      | D3DDTCAPS_UDEC3
                                      | D3DDTCAPS_DEC3N
                                      | D3DDTCAPS_FLOAT16_2
                                      | D3DDTCAPS_FLOAT16_4;
    // Number of simultaneous RTs
    pCaps->NumSimultaneousRTs         = MaxSimultaneousRenderTargets;
    // Possible StretchRect filters
    pCaps->StretchRectFilterCaps      = D3DPTFILTERCAPS_MINFPOINT
                                      | D3DPTFILTERCAPS_MINFLINEAR
                                   /* | D3DPTFILTERCAPS_MINFANISOTROPIC */
                                   /* | D3DPTFILTERCAPS_MINFPYRAMIDALQUAD */
                                   /* | D3DPTFILTERCAPS_MINFGAUSSIANQUAD */
                                   /* | D3DPTFILTERCAPS_MIPFPOINT */
                                   /* | D3DPTFILTERCAPS_MIPFLINEAR */
                                   /* | D3DPTFILTERCAPS_CONVOLUTIONMONO */
                                      | D3DPTFILTERCAPS_MAGFPOINT
                                      | D3DPTFILTERCAPS_MAGFLINEAR
                                   /* | D3DPTFILTERCAPS_MAGFANISOTROPIC */
                                   /* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
                                   /* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */;

    // Not too bothered about doing these longhand
    // We should match whatever my AMD hardware reports here
    // methinks for the best chance of stuff working.
    pCaps->VS20Caps.Caps                     = 1;
    pCaps->VS20Caps.DynamicFlowControlDepth  = 24;
    pCaps->VS20Caps.NumTemps                 = 32;
    pCaps->VS20Caps.StaticFlowControlDepth   = 4;

    pCaps->PS20Caps.Caps                     = 31;
    pCaps->PS20Caps.DynamicFlowControlDepth  = 24;
    pCaps->PS20Caps.NumTemps                 = 32;
    pCaps->PS20Caps.StaticFlowControlDepth   = 4;

    pCaps->PS20Caps.NumInstructionSlots      = options.shaderModel >= 2 ? 512 : 256;

    pCaps->VertexTextureFilterCaps           = 50332416;
    pCaps->MaxVShaderInstructionsExecuted    = 4294967295;
    pCaps->MaxPShaderInstructionsExecuted    = 4294967295;

    pCaps->MaxVertexShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
    pCaps->MaxPixelShader30InstructionSlots  = options.shaderModel == 3 ? 32768 : 0;

    return D3D_OK;
  }

  HMONITOR D3D9Adapter::GetMonitor() {
    return GetDefaultMonitor();
  }

  UINT D3D9Adapter::GetAdapterModeCountEx(const D3DDISPLAYMODEFILTER* pFilter) {
    if (pFilter == nullptr)
      return 0;

    // We don't offer any interlaced formats here so early out and avoid destroying mode cache.
    if (pFilter->ScanLineOrdering == D3DSCANLINEORDERING_INTERLACED)
      return 0;

    CacheModes(EnumerateFormat(pFilter->Format));
    return m_modes.size();
  }

  HRESULT D3D9Adapter::EnumAdapterModesEx(
    const D3DDISPLAYMODEFILTER* pFilter,
          UINT                  Mode,
          D3DDISPLAYMODEEX*     pMode) {
    if (pMode == nullptr || pFilter == nullptr)
      return D3DERR_INVALIDCALL;

    const D3D9Format format =
      EnumerateFormat(pFilter->Format);

    if (FAILED(CheckDeviceFormat(
      D3DDEVTYPE_HAL, EnumerateFormat(pFilter->Format),
      D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE,
      EnumerateFormat(pFilter->Format))))
      return D3DERR_INVALIDCALL;

    CacheModes(format);

    // We don't return any scanline orderings that aren't progressive,
    // The format filtering is already handled for us by cache modes
    // So we can early out here and then just index.
    if (pFilter->ScanLineOrdering == D3DSCANLINEORDERING_INTERLACED)
      return D3DERR_INVALIDCALL;

    if (Mode >= m_modes.size())
      return D3DERR_INVALIDCALL;

    *pMode = m_modes[Mode];

    return D3D_OK;
  }

  HRESULT D3D9Adapter::GetAdapterDisplayModeEx(
          D3DDISPLAYMODEEX*   pMode,
          D3DDISPLAYROTATION* pRotation) {
    if (pMode == nullptr)
      return D3DERR_INVALIDCALL;

    if (pRotation != nullptr)
      *pRotation = D3DDISPLAYROTATION_IDENTITY;

    DEVMODEW devMode = DEVMODEW();
    devMode.dmSize = sizeof(devMode);

    if (!GetMonitorDisplayMode(GetDefaultMonitor(), ENUM_CURRENT_SETTINGS, &devMode)) {
      Logger::err("D3D9Adapter::GetAdapterDisplayModeEx: Failed to enum display settings");
      return D3DERR_INVALIDCALL;
    }

    pMode->Size             = sizeof(D3DDISPLAYMODEEX);
    pMode->Width            = devMode.dmPelsWidth;
    pMode->Height           = devMode.dmPelsHeight;
    pMode->RefreshRate      = devMode.dmDisplayFrequency;
    pMode->Format           = D3DFMT_X8R8G8B8;
    pMode->ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
    return D3D_OK;
  }

  HRESULT D3D9Adapter::GetAdapterLUID(LUID* pLUID) {
    if (pLUID == nullptr)
      return D3DERR_INVALIDCALL;

    auto& deviceId = m_adapter->devicePropertiesExt().coreDeviceId;

    if (deviceId.deviceLUIDValid)
      *pLUID = bit::cast<LUID>(deviceId.deviceLUID);
    else
      *pLUID = dxvk::GetAdapterLUID(m_ordinal);

    return D3D_OK;
  }

  HRESULT D3D9Adapter::CheckDeviceVkFormat(
          VkFormat        Format,
          DWORD           Usage,
          D3DRESOURCETYPE RType) {
    VkFormatFeatureFlags checkFlags = 0;

    if (RType != D3DRTYPE_SURFACE)
      checkFlags |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;

    if (Usage & D3DUSAGE_RENDERTARGET) {
      checkFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;

      if (Usage & D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING)
        checkFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
    }

    if (Usage & D3DUSAGE_DEPTHSTENCIL)
      checkFlags |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
    else
      checkFlags |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;

    VkFormatFeatureFlags checkFlagsMipGen = checkFlags;

    if (Usage & D3DUSAGE_AUTOGENMIPMAP) {
      checkFlagsMipGen |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
      checkFlagsMipGen |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
    }

    VkFormatProperties   fmtSupport  = m_adapter->formatProperties(Format);
    VkFormatFeatureFlags imgFeatures = fmtSupport.optimalTilingFeatures | fmtSupport.linearTilingFeatures;

    if ((imgFeatures & checkFlags) != checkFlags)
      return D3DERR_NOTAVAILABLE;

    return ((imgFeatures & checkFlagsMipGen) != checkFlagsMipGen)
      ? D3DOK_NOAUTOGEN
      : D3D_OK;
  }

  void D3D9Adapter::CacheModes(D3D9Format Format) {
    if (!m_modes.empty() && m_modeCacheFormat == Format)
      return; // We already cached the modes for this format. No need to do it again.

    m_modes.clear();
    m_modeCacheFormat = Format;

    // Skip unsupported formats
    if (!IsSupportedAdapterFormat(Format))
      return;

    auto& options = m_parent->GetOptions();

    // Walk over all modes that the display supports and
    // return those that match the requested format etc.
    DEVMODEW devMode = { };
    devMode.dmSize = sizeof(DEVMODEW);

    uint32_t modeIndex = 0;

    const auto forcedRatio = Ratio<DWORD>(options.forceAspectRatio);

    while (GetMonitorDisplayMode(GetDefaultMonitor(), modeIndex++, &devMode)) {
      // Skip interlaced modes altogether
      if (devMode.dmDisplayFlags & DM_INTERLACED)
        continue;

      // Skip modes with incompatible formats
      if (devMode.dmBitsPerPel != GetMonitorFormatBpp(Format))
        continue;

      if (!forcedRatio.undefined() && Ratio<DWORD>(devMode.dmPelsWidth, devMode.dmPelsHeight) != forcedRatio)
        continue;

      D3DDISPLAYMODEEX mode;
      mode.Size             = sizeof(D3DDISPLAYMODEEX);
      mode.Width            = devMode.dmPelsWidth;
      mode.Height           = devMode.dmPelsHeight;
      mode.RefreshRate      = devMode.dmDisplayFrequency;
      mode.Format           = static_cast<D3DFORMAT>(Format);
      mode.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;

      m_modes.push_back(mode);
    }

    // Sort display modes by width, height and refresh rate,
    // in that order. Some games rely on correct ordering.
    std::sort(m_modes.begin(), m_modes.end(),
      [](const D3DDISPLAYMODEEX& a, const D3DDISPLAYMODEEX& b) {
        if (a.Width < b.Width)   return true;
        if (a.Width > b.Width)   return false;

        if (a.Height < b.Height) return true;
        if (a.Height > b.Height) return false;

        return a.RefreshRate < b.RefreshRate;
    });
  }

}


code:
#pragma once

#include "d3d9_include.h"

#include "d3d9_options.h"
#include "d3d9_format.h"

#include "../dxvk/dxvk_adapter.h"

namespace dxvk {

  class D3D9InterfaceEx;

  class D3D9Adapter {

  public:

    D3D9Adapter(
            D3D9InterfaceEx* pParent,
            Rc<DxvkAdapter>  Adapter,
            UINT             Ordinal,
            UINT             DisplayIndex);

    HRESULT GetAdapterIdentifier(
            DWORD                   Flags,
            D3DADAPTER_IDENTIFIER9* pIdentifier);

    HRESULT CheckDeviceType(
            D3DDEVTYPE DevType,
            D3D9Format AdapterFormat,
            D3D9Format BackBufferFormat,
            BOOL       bWindowed);

    HRESULT CheckDeviceFormat(
            D3DDEVTYPE      DeviceType,
            D3D9Format      AdapterFormat,
            DWORD           Usage,
            D3DRESOURCETYPE RType,
            D3D9Format      CheckFormat);

    HRESULT CheckDeviceMultiSampleType(
            D3DDEVTYPE          DeviceType,
            D3D9Format          SurfaceFormat,
            BOOL                Windowed,
            D3DMULTISAMPLE_TYPE MultiSampleType,
            DWORD*              pQualityLevels);

    HRESULT CheckDepthStencilMatch(
            D3DDEVTYPE DeviceType,
            D3D9Format AdapterFormat,
            D3D9Format RenderTargetFormat,
            D3D9Format DepthStencilFormat);

    HRESULT CheckDeviceFormatConversion(
            D3DDEVTYPE DeviceType,
            D3D9Format SourceFormat,
            D3D9Format TargetFormat);

    HRESULT GetDeviceCaps(
            D3DDEVTYPE DeviceType,
            D3DCAPS9*  pCaps);

    HMONITOR GetMonitor();

    UINT GetAdapterModeCountEx(const D3DDISPLAYMODEFILTER* pFilter);

    HRESULT EnumAdapterModesEx(
      const D3DDISPLAYMODEFILTER* pFilter,
            UINT                  Mode,
            D3DDISPLAYMODEEX*     pMode);

    HRESULT GetAdapterDisplayModeEx(
            D3DDISPLAYMODEEX*   pMode,
            D3DDISPLAYROTATION* pRotation);

    HRESULT GetAdapterLUID(LUID* pLUID);

    UINT GetOrdinal() { return m_ordinal; }

    Rc<DxvkAdapter> GetDXVKAdapter() { return m_adapter; }

    D3D9_VK_FORMAT_MAPPING GetFormatMapping(D3D9Format Format) const {
      return m_d3d9Formats.GetFormatMapping(Format);
    }

    const DxvkFormatInfo* GetUnsupportedFormatInfo(D3D9Format Format) const {
      return m_d3d9Formats.GetUnsupportedFormatInfo(Format);
    }

  private:

    HRESULT CheckDeviceVkFormat(
          VkFormat        Format,
          DWORD           Usage,
          D3DRESOURCETYPE RType);

    void CacheModes(D3D9Format Format);

    D3D9InterfaceEx*              m_parent;

    Rc<DxvkAdapter>               m_adapter;
    UINT                          m_ordinal;
    UINT                          m_displayIndex;

    std::vector<D3DDISPLAYMODEEX> m_modes;
    D3D9Format                    m_modeCacheFormat;

    const D3D9VkFormatTable       m_d3d9Formats;

  };

}


code:
#include "d3d9_annotation.h"

namespace dxvk {

  ////////////////////////////
  // D3D9GlobalAnnotationList
  ////////////////////////////

  D3D9GlobalAnnotationList::D3D9GlobalAnnotationList()
    : m_shouldAnnotate(false)
    , m_eventDepth(0)
  {}

  D3D9GlobalAnnotationList::~D3D9GlobalAnnotationList()
  {}

  void D3D9GlobalAnnotationList::RegisterAnnotator(IDXVKUserDefinedAnnotation* annotation) {
    auto lock = std::unique_lock(m_mutex);
    m_shouldAnnotate = true;
    m_annotations.push_back(annotation);
  }

  void D3D9GlobalAnnotationList::UnregisterAnnotator(IDXVKUserDefinedAnnotation* annotation) {
    auto lock = std::unique_lock(m_mutex);
    auto iter = std::find(m_annotations.begin(), m_annotations.end(), annotation);
    if (iter != m_annotations.end())
        m_annotations.erase(iter);
  }

  INT D3D9GlobalAnnotationList::BeginEvent(D3DCOLOR color, LPCWSTR name) {
    if (!m_shouldAnnotate)
      return 0;

    auto lock = std::unique_lock(m_mutex);
    for (auto* annotation : m_annotations)
      annotation->BeginEvent(color, name);

    return m_eventDepth++;
  }

  INT D3D9GlobalAnnotationList::EndEvent() {
    if (!m_shouldAnnotate)
      return 0;

    auto lock = std::unique_lock(m_mutex);
    for (auto* annotation : m_annotations)
      annotation->EndEvent();

    return m_eventDepth--;
  }

  void D3D9GlobalAnnotationList::SetMarker(D3DCOLOR color, LPCWSTR name) {
    if (!m_shouldAnnotate)
      return;

    auto lock = std::unique_lock(m_mutex);
    for (auto* annotation : m_annotations)
      annotation->SetMarker(color, name);
  }

  void D3D9GlobalAnnotationList::SetRegion(D3DCOLOR color, LPCWSTR name) {
    // This, by the documentation, does nothing.
  }

  BOOL D3D9GlobalAnnotationList::QueryRepeatFrame() const {
    // This, by the documentation, does nothing.
    // It's meant to return TRUE if the profiler/debugger
    // wants a frame to be repeated, but we never need that.
    return FALSE;
  }

  void D3D9GlobalAnnotationList::SetOptions(DWORD options) {
    // This is used to say that the app should
    // not be debugged/profiled.
  }

  DWORD D3D9GlobalAnnotationList::GetStatus() const {
    // This returns whether the app is being
    // profiled / debugged.
    // Some apps may rely on this to emit
    // debug markers.
    return m_shouldAnnotate ? 1 : 0;
  }

  ////////////////////////////
  // D3D9UserDefinedAnnotation
  ////////////////////////////

  D3D9UserDefinedAnnotation::D3D9UserDefinedAnnotation(D3D9DeviceEx* device)
    : m_container(device) {
    D3D9GlobalAnnotationList::Instance().RegisterAnnotator(this);
  }

  D3D9UserDefinedAnnotation::~D3D9UserDefinedAnnotation() {
    D3D9GlobalAnnotationList::Instance().UnregisterAnnotator(this);
  }

  ULONG STDMETHODCALLTYPE D3D9UserDefinedAnnotation::AddRef() {
    return m_container->AddRef();
  }

  ULONG STDMETHODCALLTYPE D3D9UserDefinedAnnotation::Release() {
    return m_container->Release();
  }

  HRESULT STDMETHODCALLTYPE D3D9UserDefinedAnnotation::QueryInterface(
          REFIID                  riid,
          void**                  ppvObject) {
    return m_container->QueryInterface(riid, ppvObject);
  }

  INT STDMETHODCALLTYPE D3D9UserDefinedAnnotation::BeginEvent(
          D3DCOLOR                Color,
          LPCWSTR                 Name) {
    m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
      VkDebugUtilsLabelEXT label;
      label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
      label.pNext = nullptr;
      label.pLabelName = labelName.c_str();
      DecodeD3DCOLOR(color, label.color);

      ctx->beginDebugLabel(&label);
    });

    // Handled by the global list.
    return 0;
  }

  INT STDMETHODCALLTYPE D3D9UserDefinedAnnotation::EndEvent() {
    m_container->EmitCs([](DxvkContext *ctx) {
      ctx->endDebugLabel();
    });

    // Handled by the global list.
    return 0;
  }

  void STDMETHODCALLTYPE D3D9UserDefinedAnnotation::SetMarker(
          D3DCOLOR                Color,
          LPCWSTR                 Name) {
    m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
      VkDebugUtilsLabelEXT label;
      label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
      label.pNext = nullptr;
      label.pLabelName = labelName.c_str();
      DecodeD3DCOLOR(color, label.color);

      ctx->insertDebugLabel(&label);
    });
  }

  BOOL STDMETHODCALLTYPE D3D9UserDefinedAnnotation::GetStatus() {
    return TRUE;
  }

}


code:
#pragma once

#include "d3d9_device.h"
#include "d3d9_include.h"
#include "../dxvk/dxvk_annotation.h"

#include <atomic>
#include <mutex>
#include <vector>

namespace dxvk {

  class D3D9GlobalAnnotationList {

  public:

    D3D9GlobalAnnotationList();
    ~D3D9GlobalAnnotationList();

    void RegisterAnnotator(IDXVKUserDefinedAnnotation* annotation);
    void UnregisterAnnotator(IDXVKUserDefinedAnnotation* annotation);

    INT BeginEvent(D3DCOLOR color, LPCWSTR name);
    INT EndEvent();

    void SetMarker(D3DCOLOR color, LPCWSTR name);

    void SetRegion(D3DCOLOR color, LPCWSTR name);

    BOOL QueryRepeatFrame() const;

    void SetOptions(DWORD options);

    DWORD GetStatus() const;

    static D3D9GlobalAnnotationList& Instance() {
      return s_instance;
    }

  private:

    static D3D9GlobalAnnotationList s_instance;

    std::atomic<bool> m_shouldAnnotate;

    std::mutex m_mutex;
    std::vector<IDXVKUserDefinedAnnotation*> m_annotations;

    // Provide our own event depth as we
    // may have multiple annotators which could get out of sync.
    int32_t m_eventDepth;

  };

  class D3D9UserDefinedAnnotation final : public IDXVKUserDefinedAnnotation {

  public:

    D3D9UserDefinedAnnotation(D3D9DeviceEx* device);
    ~D3D9UserDefinedAnnotation();

    ULONG STDMETHODCALLTYPE AddRef();

    ULONG STDMETHODCALLTYPE Release();

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

    INT STDMETHODCALLTYPE BeginEvent(
            D3DCOLOR                Color,
            LPCWSTR                 Name);

    INT STDMETHODCALLTYPE EndEvent();

    void STDMETHODCALLTYPE SetMarker(
            D3DCOLOR                Color,
            LPCWSTR                 Name);

    BOOL STDMETHODCALLTYPE GetStatus();

  private:

    D3D9DeviceEx* m_container;

  };

}


code:
#include "d3d9_buffer.h"

namespace dxvk {

  ////////////////////////
  // D3D9VertexBuffer
  ////////////////////////

  D3D9VertexBuffer::D3D9VertexBuffer(
          D3D9DeviceEx*      pDevice,
    const D3D9_BUFFER_DESC*  pDesc)
  : D3D9VertexBufferBase(pDevice, pDesc) {

  }

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

    *ppvObject = nullptr;

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

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

  D3DRESOURCETYPE STDMETHODCALLTYPE D3D9VertexBuffer::GetType() {
    return D3DRTYPE_VERTEXBUFFER;
  }

  HRESULT STDMETHODCALLTYPE D3D9VertexBuffer::GetDesc(
          D3DVERTEXBUFFER_DESC* pDesc) {
    if (pDesc == nullptr)
      return D3DERR_INVALIDCALL;

    const D3D9_BUFFER_DESC* desc = m_buffer.Desc();

    pDesc->Format = static_cast<D3DFORMAT>(desc->Format);
    pDesc->Type   = desc->Type;
    pDesc->Usage  = desc->Usage;
    pDesc->Pool   = desc->Pool;
    pDesc->Size   = desc->Size;
    pDesc->FVF    = desc->FVF;

    return D3D_OK;
  }

  //////////////////////
  // D3D9IndexBuffer
  //////////////////////

  D3D9IndexBuffer::D3D9IndexBuffer(
          D3D9DeviceEx*      pDevice,
    const D3D9_BUFFER_DESC*  pDesc)
  : D3D9IndexBufferBase(pDevice, pDesc) {

  }

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

    *ppvObject = nullptr;

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

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

  D3DRESOURCETYPE STDMETHODCALLTYPE D3D9IndexBuffer::GetType() {
    return D3DRTYPE_INDEXBUFFER;
  }

  HRESULT STDMETHODCALLTYPE D3D9IndexBuffer::GetDesc(
          D3DINDEXBUFFER_DESC* pDesc) {
    if (pDesc == nullptr)
      return D3DERR_INVALIDCALL;

    const D3D9_BUFFER_DESC* desc = m_buffer.Desc();

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

    return D3D_OK;
  }

}


code:
#pragma once

#include "d3d9_resource.h"

#include "d3d9_common_buffer.h"

namespace dxvk {

  template <typename... Type>
  class D3D9Buffer : public D3D9Resource<Type...> {

  public:

    D3D9Buffer(
            D3D9DeviceEx*      pDevice,
      const D3D9_BUFFER_DESC*  pDesc)
    : D3D9Resource<Type...> (pDevice),
      m_buffer              (pDevice, pDesc) {

    }

    HRESULT STDMETHODCALLTYPE Lock(
            UINT   OffsetToLock,
            UINT   SizeToLock,
            void** ppbData,
            DWORD  Flags) final {
      return m_buffer.Lock(
        OffsetToLock,
        SizeToLock,
        ppbData,
        Flags);
    }

    HRESULT STDMETHODCALLTYPE Unlock() final {
      return m_buffer.Unlock();
    }

    void STDMETHODCALLTYPE PreLoad() final {
      m_buffer.PreLoad();
    }

    D3D9CommonBuffer* GetCommonBuffer() {
      return &m_buffer;
    }

  protected:

    D3D9CommonBuffer m_buffer;

  };

  using D3D9VertexBufferBase = D3D9Buffer<IDirect3DVertexBuffer9>;
  class D3D9VertexBuffer final : public D3D9VertexBufferBase {

  public:

    D3D9VertexBuffer(
            D3D9DeviceEx*      pDevice,
      const D3D9_BUFFER_DESC*  pDesc);

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

    D3DRESOURCETYPE STDMETHODCALLTYPE GetType();

    HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc);

  };

  using D3D9IndexBufferBase = D3D9Buffer<IDirect3DIndexBuffer9>;
  class D3D9IndexBuffer final : public D3D9IndexBufferBase {

  public:

    D3D9IndexBuffer(
            D3D9DeviceEx*      pDevice,
      const D3D9_BUFFER_DESC*  pDesc);

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

    D3DRESOURCETYPE STDMETHODCALLTYPE GetType();

    HRESULT STDMETHODCALLTYPE GetDesc(D3DINDEXBUFFER_DESC* pDesc);

  };

  template <typename T>
  inline D3D9CommonBuffer* GetCommonBuffer(const T& pResource) {
    return pResource != nullptr ? pResource->GetCommonBuffer() : nullptr;
  }

}