code:
#pragma once

#include "d3d9_include.h"

#include "d3d9_caps.h"

#include "../dxvk/dxvk_shader.h"

#include "../dxso/dxso_isgn.h"

#include <unordered_map>
#include <bitset>

namespace dxvk {

  class D3D9DeviceEx;
  class SpirvModule;

  struct D3D9Options;

  struct D3D9FogContext {
    // General inputs...
    bool     IsPixel;
    bool     RangeFog;
    uint32_t RenderState;
    uint32_t vPos;
    uint32_t vFog;

    uint32_t oColor;

    bool     HasFogInput;

    bool     IsFixedFunction;
    bool     IsPositionT;
    bool     HasSpecular;
    uint32_t Specular;
  };

  struct D3D9FixedFunctionOptions {
    D3D9FixedFunctionOptions(const D3D9Options* options);

    bool invariantPosition;
  };

  // Returns new oFog if VS
  // Returns new oColor if PS
  uint32_t DoFixedFunctionFog(SpirvModule& spvModule, const D3D9FogContext& fogCtx);

  // Returns a render state block
  uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count);

  struct D3D9PointSizeInfoVS {
    uint32_t defaultValue;
    uint32_t min;
    uint32_t max;
  };

  // Default point size and point scale magic!
  D3D9PointSizeInfoVS GetPointSizeInfoVS(SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock, bool isFixedFunction);

  struct D3D9PointSizeInfoPS {
    uint32_t isSprite;
  };

  D3D9PointSizeInfoPS GetPointSizeInfoPS(SpirvModule& spvModule, uint32_t rsBlock);

  uint32_t GetPointCoord(SpirvModule& spvModule, std::vector<uint32_t>& entryPointInterfaces);

  uint32_t GetSharedConstants(SpirvModule& spvModule);

  constexpr uint32_t TCIOffset = 16;
  constexpr uint32_t TCIMask   = 0b111 << TCIOffset;

  enum D3D9FF_VertexBlendMode {
    D3D9FF_VertexBlendMode_Disabled,
    D3D9FF_VertexBlendMode_Normal,
    D3D9FF_VertexBlendMode_Tween,
  };

  struct D3D9FFShaderKeyVSData {
    union {
      struct {
        uint32_t TexcoordIndices : 24;

        uint32_t HasPositionT : 1;

        uint32_t HasColor0 : 1; // Diffuse
        uint32_t HasColor1 : 1; // Specular

        uint32_t HasPointSize : 1;

        uint32_t UseLighting : 1;

        uint32_t NormalizeNormals : 1;
        uint32_t LocalViewer : 1;
        uint32_t RangeFog : 1;

        uint32_t TexcoordFlags : 24;

        uint32_t DiffuseSource : 2;
        uint32_t AmbientSource : 2;
        uint32_t SpecularSource : 2;
        uint32_t EmissiveSource : 2;

        uint32_t TransformFlags : 24;

        uint32_t LightCount : 4;

        uint32_t TexcoordDeclMask : 24;
        uint32_t HasFog : 1;

        uint32_t VertexBlendMode    : 2;
        uint32_t VertexBlendIndexed : 1;
        uint32_t VertexBlendCount   : 3;

        uint32_t VertexClipping     : 1;
      } Contents;

      uint32_t Primitive[4];
    };
  };

  struct D3D9FFShaderKeyVS {
    D3D9FFShaderKeyVS() {
      // memcmp safety
      std::memset(&Data, 0, sizeof(Data));
    }

    D3D9FFShaderKeyVSData Data;
  };

  constexpr uint32_t TextureArgCount = 3;

  struct D3D9FFShaderStage {
    union {
      struct {
        uint32_t     ColorOp   : 5;
        uint32_t     ColorArg0 : 6;
        uint32_t     ColorArg1 : 6;
        uint32_t     ColorArg2 : 6;

        uint32_t     AlphaOp   : 5;
        uint32_t     AlphaArg0 : 6;
        uint32_t     AlphaArg1 : 6;
        uint32_t     AlphaArg2 : 6;

        uint32_t     Type         : 2;
        uint32_t     ResultIsTemp : 1;
        uint32_t     Projected    : 1;

        uint32_t     ProjectedCount : 3;

        // Included in here, read from Stage 0 for packing reasons
        // Affects all stages.
        uint32_t     GlobalSpecularEnable : 1;
        uint32_t     GlobalFlatShade      : 1;
      } Contents;

      uint32_t Primitive[2];
    };
  };

  struct D3D9FFShaderKeyFS {
    D3D9FFShaderKeyFS() {
      // memcmp safety
      std::memset(Stages, 0, sizeof(Stages));

      // Normalize this. DISABLE != 0.
      for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
        Stages[i].Contents.ColorOp = D3DTOP_DISABLE;
        Stages[i].Contents.AlphaOp = D3DTOP_DISABLE;
      }
    }

    D3D9FFShaderStage Stages[caps::TextureStageCount];
  };

  struct D3D9FFShaderKeyHash {
    size_t operator () (const D3D9FFShaderKeyVS& key) const;
    size_t operator () (const D3D9FFShaderKeyFS& key) const;
  };

  bool operator == (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b);
  bool operator != (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b);
  bool operator == (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b);
  bool operator != (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b);

  struct D3D9FFShaderKeyEq {
    bool operator () (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b) const;
    bool operator () (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b) const;
  };

  class D3D9FFShader {

  public:

    D3D9FFShader(
            D3D9DeviceEx*         pDevice,
      const D3D9FFShaderKeyVS&    Key);

    D3D9FFShader(
            D3D9DeviceEx*         pDevice,
      const D3D9FFShaderKeyFS&    Key);

    template <typename T>
    void Dump(const T& Key, const std::string& Name);

    Rc<DxvkShader> GetShader() const {
      return m_shader;
    }

  private:

    Rc<DxvkShader> m_shader;

    DxsoIsgn       m_isgn;

  };

  class D3D9FFShaderModuleSet : public RcObject {

  public:

    D3D9FFShader GetShaderModule(
            D3D9DeviceEx*         pDevice,
      const D3D9FFShaderKeyVS&    ShaderKey);

    D3D9FFShader GetShaderModule(
            D3D9DeviceEx*         pDevice,
      const D3D9FFShaderKeyFS&    ShaderKey);

  private:

    std::unordered_map<
      D3D9FFShaderKeyVS,
      D3D9FFShader,
      D3D9FFShaderKeyHash, D3D9FFShaderKeyEq> m_vsModules;

    std::unordered_map<
      D3D9FFShaderKeyFS,
      D3D9FFShader,
      D3D9FFShaderKeyHash, D3D9FFShaderKeyEq> m_fsModules;

  };

  inline const DxsoIsgn& GetFixedFunctionIsgn() {
    extern DxsoIsgn g_ffIsgn;

    return g_ffIsgn;
  }

}

repo_name: orochi/dxvk


code:
#include "d3d9_format.h"

namespace dxvk {

  // It is also worth noting that the msb/lsb-ness is flipped between VK and D3D9.
  D3D9_VK_FORMAT_MAPPING ConvertFormatUnfixed(D3D9Format Format) {
    switch (Format) {
      case D3D9Format::Unknown: return {};

      case D3D9Format::R8G8B8: return {}; // Unsupported

      case D3D9Format::A8R8G8B8: return {
        VK_FORMAT_B8G8R8A8_UNORM,
        VK_FORMAT_B8G8R8A8_SRGB,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::X8R8G8B8: return {
        VK_FORMAT_B8G8R8A8_UNORM,
        VK_FORMAT_B8G8R8A8_SRGB,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::R5G6B5: return {
        VK_FORMAT_R5G6B5_UNORM_PACK16,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT};

      case D3D9Format::X1R5G5B5: return {
        VK_FORMAT_A1R5G5B5_UNORM_PACK16,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::A1R5G5B5: return {
        VK_FORMAT_A1R5G5B5_UNORM_PACK16,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::A4R4G4B4: return {
        VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::R3G3B2: return {}; // Unsupported

      case D3D9Format::A8: return {
        VK_FORMAT_R8_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO,
          VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R }};

      case D3D9Format::A8R3G3B2: return {}; // Unsupported

      case D3D9Format::X4R4G4B4: return {
        VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::A2B10G10R10: return {
        VK_FORMAT_A2B10G10R10_UNORM_PACK32, // The A2 is out of place here. This should be investigated.
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::A8B8G8R8: return {
        VK_FORMAT_R8G8B8A8_UNORM,
        VK_FORMAT_R8G8B8A8_SRGB,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::X8B8G8R8: return {
        VK_FORMAT_R8G8B8A8_UNORM,
        VK_FORMAT_R8G8B8A8_SRGB,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::G16R16: return {
        VK_FORMAT_R16G16_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R,   VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::A2R10G10B10: return {
        VK_FORMAT_A2R10G10B10_UNORM_PACK32,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::A16B16G16R16: return {
        VK_FORMAT_R16G16B16A16_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::A8P8: return {}; // Unsupported

      case D3D9Format::P8: return {}; // Unsupported

      case D3D9Format::L8: return {
        VK_FORMAT_R8_UNORM,
        VK_FORMAT_R8_SRGB,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
          VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::A8L8: return {
        VK_FORMAT_R8G8_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
          VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G }};

      case D3D9Format::A4L4: return {
        VK_FORMAT_R4G4_UNORM_PACK8,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R }};

      case D3D9Format::V8U8: return {
        VK_FORMAT_R8G8_SNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R,   VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::L6V5U5: return {
        // Any PACK16 format will do...
        VK_FORMAT_B5G6R5_UNORM_PACK16,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A },
        { D3D9ConversionFormat_L6V5U5, 1u,
        // Convert -> float (this is a mixed snorm and unorm type)
          VK_FORMAT_R16G16B16A16_SFLOAT } };

      case D3D9Format::X8L8V8U8: return {
        VK_FORMAT_B8G8R8A8_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE },
        { D3D9ConversionFormat_X8L8V8U8, 1u,
        // Convert -> float (this is a mixed snorm and unorm type)
          VK_FORMAT_R16G16B16A16_SFLOAT } };

      case D3D9Format::Q8W8V8U8: return {
        VK_FORMAT_R8G8B8A8_SNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::V16U16: return {
        VK_FORMAT_R16G16_SNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R,   VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::A2W10V10U10: return {
        VK_FORMAT_A2B10G10R10_UNORM_PACK32,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A },
        { D3D9ConversionFormat_A2W10V10U10, 1u,
        // Convert -> float (this is a mixed snorm and unorm type)
          VK_FORMAT_R16G16B16A16_SFLOAT } };

      case D3D9Format::UYVY: return {
        VK_FORMAT_B8G8R8A8_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
          VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
        { D3D9ConversionFormat_UYVY, 1u }
      };

      case D3D9Format::R8G8_B8G8: return {
        VK_FORMAT_G8B8G8R8_422_UNORM, // This format may have been _SCALED in DX9.
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::YUY2: return {
        VK_FORMAT_B8G8R8A8_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
          VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
        { D3D9ConversionFormat_YUY2, 1u }
      };

      case D3D9Format::G8R8_G8B8: return {
        VK_FORMAT_B8G8R8G8_422_UNORM, // This format may have been _SCALED in DX9.
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::DXT1: return {
        VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
        VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::DXT2: return {
        VK_FORMAT_BC2_UNORM_BLOCK,
        VK_FORMAT_BC2_SRGB_BLOCK,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::DXT3: return {
        VK_FORMAT_BC2_UNORM_BLOCK,
        VK_FORMAT_BC2_SRGB_BLOCK,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::DXT4: return {
        VK_FORMAT_BC3_UNORM_BLOCK,
        VK_FORMAT_BC3_SRGB_BLOCK,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::DXT5: return {
        VK_FORMAT_BC3_UNORM_BLOCK,
        VK_FORMAT_BC3_SRGB_BLOCK,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::D16_LOCKABLE: return {
        VK_FORMAT_D16_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT };

      case D3D9Format::D32: return {}; // Unsupported (everywhere)

      case D3D9Format::D15S1: return {}; // Unsupported (everywhere)

      case D3D9Format::D24S8: return {
        VK_FORMAT_D24_UNORM_S8_UINT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT };

      case D3D9Format::D24X8: return {
        VK_FORMAT_D24_UNORM_S8_UINT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT };

      case D3D9Format::D24X4S4: return {}; // Unsupported (everywhere)

      case D3D9Format::D16: return {
        VK_FORMAT_D16_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT };

      case D3D9Format::D32F_LOCKABLE: return {
        VK_FORMAT_D32_SFLOAT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT };

      case D3D9Format::D24FS8: return {
        VK_FORMAT_D24_UNORM_S8_UINT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT };

      case D3D9Format::D32_LOCKABLE: return {
        VK_FORMAT_D32_SFLOAT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT };

      case D3D9Format::S8_LOCKABLE: return {
        VK_FORMAT_S8_UINT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_STENCIL_BIT };

      case D3D9Format::L16: return {
        VK_FORMAT_R16_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
          VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::VERTEXDATA: return {
        VK_FORMAT_R8_UINT,
        VK_FORMAT_UNDEFINED,
        0 };

      case D3D9Format::INDEX16: return {
        VK_FORMAT_R16_UINT,
        VK_FORMAT_UNDEFINED,
        0 };

      case D3D9Format::INDEX32: return {
        VK_FORMAT_R32_UINT,
        VK_FORMAT_UNDEFINED,
        0 };

      case D3D9Format::Q16W16V16U16: return {
        VK_FORMAT_R16G16B16A16_SNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::MULTI2_ARGB8: return {}; // Unsupported

      case D3D9Format::R16F: return {
        VK_FORMAT_R16_SFLOAT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R,   VK_COMPONENT_SWIZZLE_ONE,
          VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::G16R16F: return {
        VK_FORMAT_R16G16_SFLOAT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R,   VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::A16B16G16R16F: return {
        VK_FORMAT_R16G16B16A16_SFLOAT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::R32F: return {
        VK_FORMAT_R32_SFLOAT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R,   VK_COMPONENT_SWIZZLE_ONE,
          VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::G32R32F: return {
        VK_FORMAT_R32G32_SFLOAT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R,   VK_COMPONENT_SWIZZLE_G,
          VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::A32B32G32R32F: return {
        VK_FORMAT_R32G32B32A32_SFLOAT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::CxV8U8: return {}; // Unsupported

      case D3D9Format::A1: return {}; // Unsupported

      case D3D9Format::A2B10G10R10_XR_BIAS: return {
        VK_FORMAT_A2B10G10R10_SNORM_PACK32,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT };

      case D3D9Format::BINARYBUFFER: return {
        VK_FORMAT_R8_UINT,
        VK_FORMAT_UNDEFINED,
        0 };

      case D3D9Format::ATI1: return {
        VK_FORMAT_BC4_UNORM_BLOCK,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_R,    VK_COMPONENT_SWIZZLE_ZERO,
          VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::ATI2: return {
        VK_FORMAT_BC5_UNORM_BLOCK,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_G,   VK_COMPONENT_SWIZZLE_R,
          VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::INST: return {}; // Driver hack, handled elsewhere

      case D3D9Format::DF24: return {
        VK_FORMAT_D24_UNORM_S8_UINT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT,
        { VK_COMPONENT_SWIZZLE_R,    VK_COMPONENT_SWIZZLE_ZERO,
          VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::DF16: return {
        VK_FORMAT_D16_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT,
        { VK_COMPONENT_SWIZZLE_R,    VK_COMPONENT_SWIZZLE_ZERO,
          VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }};

      case D3D9Format::NULL_FORMAT: return {}; // Driver hack, handled elsewhere

      case D3D9Format::GET4: return {}; // Unsupported

      case D3D9Format::GET1: return {}; // Unsupported

      case D3D9Format::NVDB: return {}; // Driver hack, handled elsewhere

      case D3D9Format::A2M1: return {}; // Driver hack, handled elsewhere

      case D3D9Format::A2M0: return {}; // Driver hack, handled elsewhere

      case D3D9Format::ATOC: return {}; // Driver hack, handled elsewhere

      case D3D9Format::INTZ: return {
        VK_FORMAT_D24_UNORM_S8_UINT,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
        { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
          VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R }};

      case D3D9Format::NV12: return {
        VK_FORMAT_R8_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
          VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
        { D3D9ConversionFormat_NV12, 2u, VK_FORMAT_B8G8R8A8_UNORM }
      };

      case D3D9Format::YV12: return {
        VK_FORMAT_R8_UNORM,
        VK_FORMAT_UNDEFINED,
        VK_IMAGE_ASPECT_COLOR_BIT,
        { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
          VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
        { D3D9ConversionFormat_YV12, 3u, VK_FORMAT_B8G8R8A8_UNORM }
      };

      case D3D9Format::RAWZ: return {}; // Unsupported

      default:
        Logger::warn(str::format("ConvertFormat: Unknown format encountered: ", Format));
        return {}; // Unsupported
    }
  }

  D3D9VkFormatTable::D3D9VkFormatTable(
    const Rc<DxvkAdapter>& adapter,
    const D3D9Options&     options) {
    m_dfSupport = options.supportDFFormats;
    m_x4r4g4b4Support = options.supportX4R4G4B4;
    m_d32supportFinal = options.supportD32;

    // AMD do not support 24-bit depth buffers on Vulkan,
    // so we have to fall back to a 32-bit depth format.
    m_d24s8Support = CheckImageFormatSupport(adapter, VK_FORMAT_D24_UNORM_S8_UINT,
      VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
      VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);

    // NVIDIA do not support 16-bit depth buffers with stencil on Vulkan,
    // so we have to fall back to a 32-bit depth format.
    m_d16s8Support = CheckImageFormatSupport(adapter, VK_FORMAT_D16_UNORM_S8_UINT,
      VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
      VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);

    // VK_EXT_4444_formats
    m_a4r4g4b4Support = CheckImageFormatSupport(adapter, VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,
      VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);

    if (!m_d24s8Support)
      Logger::info("D3D9: VK_FORMAT_D24_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT");

    if (!m_d16s8Support) {
      if (m_d24s8Support)
        Logger::info("D3D9: VK_FORMAT_D16_UNORM_S8_UINT -> VK_FORMAT_D24_UNORM_S8_UINT");
      else
        Logger::info("D3D9: VK_FORMAT_D16_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT");
    }

    if (!m_a4r4g4b4Support)
      Logger::warn("D3D9: VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT -> VK_FORMAT_B4G4R4A4_UNORM_PACK16");
  }

  D3D9_VK_FORMAT_MAPPING D3D9VkFormatTable::GetFormatMapping(
          D3D9Format          Format) const {
    D3D9_VK_FORMAT_MAPPING mapping = ConvertFormatUnfixed(Format);

    if (Format == D3D9Format::X4R4G4B4 && !m_x4r4g4b4Support)
      return D3D9_VK_FORMAT_MAPPING();

    if (Format == D3D9Format::DF16 && !m_dfSupport)
      return D3D9_VK_FORMAT_MAPPING();

    if (Format == D3D9Format::DF24 && !m_dfSupport)
      return D3D9_VK_FORMAT_MAPPING();

    if (Format == D3D9Format::D32 && !m_d32supportFinal)
      return D3D9_VK_FORMAT_MAPPING();

    if (!m_d24s8Support && mapping.FormatColor == VK_FORMAT_D24_UNORM_S8_UINT)
      mapping.FormatColor = VK_FORMAT_D32_SFLOAT_S8_UINT;

    if (!m_d16s8Support && mapping.FormatColor == VK_FORMAT_D16_UNORM_S8_UINT)
      mapping.FormatColor = m_d24s8Support ? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT;

    if (!m_a4r4g4b4Support && mapping.FormatColor == VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT) {
      VkComponentSwizzle alphaSwizzle = Format == D3D9Format::A4R4G4B4
        ? VK_COMPONENT_SWIZZLE_B
        : VK_COMPONENT_SWIZZLE_ONE;

      mapping.FormatColor = VK_FORMAT_B4G4R4A4_UNORM_PACK16;
      mapping.Swizzle     = {
        VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R,
        VK_COMPONENT_SWIZZLE_A, alphaSwizzle };
    }

    return mapping;
  }

  const DxvkFormatInfo* D3D9VkFormatTable::GetUnsupportedFormatInfo(
    D3D9Format            Format) const {
    static const DxvkFormatInfo r8b8g8      = { 3, VK_IMAGE_ASPECT_COLOR_BIT };
    static const DxvkFormatInfo r3g3b2      = { 1, VK_IMAGE_ASPECT_COLOR_BIT };
    static const DxvkFormatInfo a8r3g3b2    = { 2, VK_IMAGE_ASPECT_COLOR_BIT };
    static const DxvkFormatInfo a8p8        = { 2, VK_IMAGE_ASPECT_COLOR_BIT };
    static const DxvkFormatInfo p8          = { 1, VK_IMAGE_ASPECT_COLOR_BIT };
    static const DxvkFormatInfo l6v5u5      = { 2, VK_IMAGE_ASPECT_COLOR_BIT };
    static const DxvkFormatInfo x8l8v8u8    = { 4, VK_IMAGE_ASPECT_COLOR_BIT };
    static const DxvkFormatInfo a2w10v10u10 = { 4, VK_IMAGE_ASPECT_COLOR_BIT };
    static const DxvkFormatInfo cxv8u8      = { 2, VK_IMAGE_ASPECT_COLOR_BIT };
    static const DxvkFormatInfo unknown     = {};

    switch (Format) {
      case D3D9Format::R8G8B8:
        return &r8b8g8;

      case D3D9Format::R3G3B2:
        return &r3g3b2;

      case D3D9Format::A8R3G3B2:
        return &a8r3g3b2;

      case D3D9Format::A8P8:
        return &a8p8;

      case D3D9Format::P8:
        return &p8;

      case D3D9Format::L6V5U5:
        return &l6v5u5;

      case D3D9Format::X8L8V8U8:
        return &x8l8v8u8;

      case D3D9Format::A2W10V10U10:
        return &a2w10v10u10;

      // MULTI2_ARGB8 -> Don't have a clue what this is.

      case D3D9Format::CxV8U8:
        return &cxv8u8;

      // A1 -> Doesn't map nicely here cause it's not byte aligned.
      // Gonna just pretend that doesn't exist until something
      // depends on that.

      default:
        return &unknown;
    }
  }

  bool D3D9VkFormatTable::CheckImageFormatSupport(
    const Rc<DxvkAdapter>&      Adapter,
          VkFormat              Format,
          VkFormatFeatureFlags  Features) const {
    VkFormatProperties supported = Adapter->formatProperties(Format);

    return (supported.linearTilingFeatures  & Features) == Features
        || (supported.optimalTilingFeatures & Features) == Features;
  }

}


code:
#include "d3d9_format_helpers.h"

#include <d3d9_convert_yuy2_uyvy.h>
#include <d3d9_convert_l6v5u5.h>
#include <d3d9_convert_x8l8v8u8.h>
#include <d3d9_convert_a2w10v10u10.h>
#include <d3d9_convert_nv12.h>
#include <d3d9_convert_yv12.h>

namespace dxvk {

  D3D9FormatHelper::D3D9FormatHelper(const Rc<DxvkDevice>& device)
    : m_device(device), m_context(m_device->createContext()) {
    m_context->beginRecording(
      m_device->createCommandList());

    InitShaders();
  }

  void D3D9FormatHelper::Flush() {
    if (m_transferCommands != 0)
      FlushInternal();
  }

  void D3D9FormatHelper::ConvertFormat(
          D3D9_CONVERSION_FORMAT_INFO   conversionFormat,
    const Rc<DxvkImage>&                dstImage,
          VkImageSubresourceLayers      dstSubresource,
    const DxvkBufferSlice&              srcSlice) {
    switch (conversionFormat.FormatType) {
      case D3D9ConversionFormat_YUY2:
      case D3D9ConversionFormat_UYVY: {
        uint32_t specConstant = conversionFormat.FormatType == D3D9ConversionFormat_UYVY ? 1 : 0;
        ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, specConstant, { 2u, 1u });
        break;
      }

      case D3D9ConversionFormat_NV12:
        ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R16_UINT, 0, { 2u, 1u });
        break;

      case D3D9ConversionFormat_YV12:
        ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R8_UINT, 0, { 1u, 1u });
        break;

      case D3D9ConversionFormat_L6V5U5:
        ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R16_UINT, 0, { 1u, 1u });
        break;

      case D3D9ConversionFormat_X8L8V8U8:
        ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, 0, { 1u, 1u });
        break;

      case D3D9ConversionFormat_A2W10V10U10:
        ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, 0, { 1u, 1u });
        break;

      default:
        Logger::warn("Unimplemented format conversion");
    }
  }

  void D3D9FormatHelper::ConvertGenericFormat(
          D3D9_CONVERSION_FORMAT_INFO   videoFormat,
    const Rc<DxvkImage>&                dstImage,
          VkImageSubresourceLayers      dstSubresource,
    const DxvkBufferSlice&              srcSlice,
          VkFormat                      bufferFormat,
          uint32_t                      specConstantValue,
          VkExtent2D                    macroPixelRun) {
    DxvkImageViewCreateInfo imageViewInfo;
    imageViewInfo.type      = VK_IMAGE_VIEW_TYPE_2D;
    imageViewInfo.format    = dstImage->info().format;
    imageViewInfo.usage     = VK_IMAGE_USAGE_STORAGE_BIT;
    imageViewInfo.aspect    = dstSubresource.aspectMask;
    imageViewInfo.minLevel  = dstSubresource.mipLevel;
    imageViewInfo.numLevels = 1;
    imageViewInfo.minLayer  = dstSubresource.baseArrayLayer;
    imageViewInfo.numLayers = dstSubresource.layerCount;
    auto tmpImageView = m_device->createImageView(dstImage, imageViewInfo);

    VkExtent3D imageExtent = dstImage->mipLevelExtent(dstSubresource.mipLevel);
    imageExtent = VkExtent3D{ imageExtent.width  / macroPixelRun.width,
                              imageExtent.height / macroPixelRun.height,
                              1 };

    DxvkBufferViewCreateInfo bufferViewInfo;
    bufferViewInfo.format      = bufferFormat;
    bufferViewInfo.rangeOffset = srcSlice.offset();
    bufferViewInfo.rangeLength = srcSlice.length();
    auto tmpBufferView = m_device->createBufferView(srcSlice.buffer(), bufferViewInfo);

    if (specConstantValue)
      m_context->setSpecConstant(VK_PIPELINE_BIND_POINT_COMPUTE, 0, specConstantValue);

    m_context->bindResourceView(BindingIds::Image,  tmpImageView, nullptr);
    m_context->bindResourceView(BindingIds::Buffer, nullptr,     tmpBufferView);
    m_context->bindShader(VK_SHADER_STAGE_COMPUTE_BIT, m_shaders[videoFormat.FormatType]);
    m_context->pushConstants(0, sizeof(VkExtent2D), &imageExtent);
    m_context->dispatch(
      (imageExtent.width  / 8) + (imageExtent.width  % 8),
      (imageExtent.height / 8) + (imageExtent.height % 8),
      1);

    // Reset the spec constants used...
    if (specConstantValue)
      m_context->setSpecConstant(VK_PIPELINE_BIND_POINT_COMPUTE, 0, 0);

    m_transferCommands += 1;
  }

  void D3D9FormatHelper::InitShaders() {
    m_shaders[D3D9ConversionFormat_YUY2] = InitShader(d3d9_convert_yuy2_uyvy);
    m_shaders[D3D9ConversionFormat_UYVY] = m_shaders[D3D9ConversionFormat_YUY2];
    m_shaders[D3D9ConversionFormat_L6V5U5] = InitShader(d3d9_convert_l6v5u5);
    m_shaders[D3D9ConversionFormat_X8L8V8U8] = InitShader(d3d9_convert_x8l8v8u8);
    m_shaders[D3D9ConversionFormat_A2W10V10U10] = InitShader(d3d9_convert_a2w10v10u10);
    m_shaders[D3D9ConversionFormat_NV12] = InitShader(d3d9_convert_nv12);
    m_shaders[D3D9ConversionFormat_YV12] = InitShader(d3d9_convert_yv12);
  }

  Rc<DxvkShader> D3D9FormatHelper::InitShader(SpirvCodeBuffer code) {
    const std::array<DxvkResourceSlot, 2> resourceSlots = { {
      { BindingIds::Image,  VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,        VK_IMAGE_VIEW_TYPE_2D },
      { BindingIds::Buffer, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_IMAGE_VIEW_TYPE_1D },
    } };

    DxvkShaderCreateInfo info;
    info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
    info.resourceSlotCount = resourceSlots.size();
    info.resourceSlots = resourceSlots.data();
    info.pushConstOffset = 0;
    info.pushConstSize = sizeof(VkExtent2D);

    return new DxvkShader(info, std::move(code));
  }

  void D3D9FormatHelper::FlushInternal() {
    m_context->flushCommandList();

    m_transferCommands = 0;
  }

}


code:
#pragma once

#include "d3d9_include.h"
#include "d3d9_format.h"
#include "../dxvk/dxvk_device.h"
#include "../dxvk/dxvk_context.h"

namespace dxvk {

  class D3D9FormatHelper {

  public:

    D3D9FormatHelper(const Rc<DxvkDevice>& device);

    void Flush();

    void ConvertFormat(
            D3D9_CONVERSION_FORMAT_INFO   conversionFormat,
      const Rc<DxvkImage>&                dstImage,
            VkImageSubresourceLayers      dstSubresource,
      const DxvkBufferSlice&              srcSlice);

  private:

    void ConvertGenericFormat(
            D3D9_CONVERSION_FORMAT_INFO   videoFormat,
      const Rc<DxvkImage>&                dstImage,
            VkImageSubresourceLayers      dstSubresource,
      const DxvkBufferSlice&              srcSlice,
            VkFormat                      bufferFormat,
            uint32_t                      specConstantValue,
            VkExtent2D                    macroPixelRun);

    enum BindingIds : uint32_t {
      Image  = 0,
      Buffer = 1,
    };

    void InitShaders();

    Rc<DxvkShader> InitShader(SpirvCodeBuffer code);

    void FlushInternal();

    Rc<DxvkDevice>    m_device;
    Rc<DxvkContext>   m_context;

    size_t            m_transferCommands = 0;

    std::array<Rc<DxvkShader>, D3D9ConversionFormat_Count> m_shaders;

  };

}


code:
#include "d3d9_hud.h"

namespace dxvk::hud {

  HudSamplerCount::HudSamplerCount(D3D9DeviceEx* device)
    : m_device       (device)
    , m_samplerCount ("0"){

  }

  void HudSamplerCount::update(dxvk::high_resolution_clock::time_point time) {
    m_samplerCount = str::format(m_device->GetSamplerCount());
  }

  HudPos HudSamplerCount::render(
          HudRenderer&      renderer,
          HudPos            position) {
    position.y += 16.0f;

    renderer.drawText(16.0f,
      { position.x, position.y },
      { 0.0f, 1.0f, 0.75f, 1.0f },
      "Samplers:");

    renderer.drawText(16.0f,
      { position.x + 120.0f, position.y },
      { 1.0f, 1.0f, 1.0f, 1.0f },
      m_samplerCount);

    position.y += 8.0f;
    return position;
  }

}


code:
#pragma once

#include "d3d9_device.h"
#include "../dxvk/hud/dxvk_hud_item.h"

namespace dxvk::hud {

  /**
   * \brief HUD item to display DXVK version
   */
  class HudSamplerCount : public HudItem {

  public:

    HudSamplerCount(D3D9DeviceEx* device);

    void update(dxvk::high_resolution_clock::time_point time);

    HudPos render(
            HudRenderer&      renderer,
            HudPos            position);

  private:

    D3D9DeviceEx* m_device;

    std::string m_samplerCount;

  };

}


code:
#pragma once

#ifndef _MSC_VER
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0A00
#endif

#include <stdint.h>
#include <d3d9.h>

//for some reason we need to specify __declspec(dllexport) for MinGW
#if defined(__WINE__)
#define DLLEXPORT __attribute__((visibility("default")))
#else
#define DLLEXPORT
#endif

#include "../util/com/com_guid.h"
#include "../util/com/com_object.h"
#include "../util/com/com_pointer.h"

#include "../util/log/log.h"
#include "../util/log/log_debug.h"

#include "../util/rc/util_rc.h"
#include "../util/rc/util_rc_ptr.h"

#include "../util/sync/sync_recursive.h"

#include "../util/util_env.h"
#include "../util/util_enum.h"
#include "../util/util_error.h"
#include "../util/util_flags.h"
#include "../util/util_likely.h"
#include "../util/util_math.h"
#include "../util/util_monitor.h"
#include "../util/util_string.h"

// Missed definitions in Wine/MinGW.

#ifndef D3DPRESENT_BACK_BUFFERS_MAX_EX
#define D3DPRESENT_BACK_BUFFERS_MAX_EX 30
#endif

#ifndef D3DSI_OPCODE_MASK
#define D3DSI_OPCODE_MASK 0x0000FFFF
#endif

#ifndef D3DSP_TEXTURETYPE_MASK
#define D3DSP_TEXTURETYPE_MASK 0x78000000
#endif

#ifndef D3DUSAGE_AUTOGENMIPMAP
#define D3DUSAGE_AUTOGENMIPMAP 0x00000400L
#endif

#ifndef D3DSP_DCL_USAGE_MASK
#define D3DSP_DCL_USAGE_MASK 0x0000000f
#endif

#ifndef D3DSP_OPCODESPECIFICCONTROL_MASK
#define D3DSP_OPCODESPECIFICCONTROL_MASK 0x00ff0000
#endif

#ifndef D3DSP_OPCODESPECIFICCONTROL_SHIFT
#define D3DSP_OPCODESPECIFICCONTROL_SHIFT 16
#endif

#ifndef D3DCURSOR_IMMEDIATE_UPDATE
#define D3DCURSOR_IMMEDIATE_UPDATE             0x00000001L
#endif

#ifndef D3DPRESENT_FORCEIMMEDIATE
#define D3DPRESENT_FORCEIMMEDIATE              0x00000100L
#endif

// MinGW headers are broken. Who'dve guessed?
#ifndef _MSC_VER
typedef struct _D3DDEVINFO_RESOURCEMANAGER
{
  char dummy;
} D3DDEVINFO_RESOURCEMANAGER, * LPD3DDEVINFO_RESOURCEMANAGER;

#ifndef __WINE__
extern "C" WINUSERAPI WINBOOL WINAPI SetProcessDPIAware(VOID);
#endif
#endif

// This is the managed pool on D3D9Ex, it's just hidden!
#define D3DPOOL_MANAGED_EX D3DPOOL(6)

using D3D9VertexElements = std::vector<D3DVERTEXELEMENT9>;


code:
#include <cstring>

#include "d3d9_initializer.h"

namespace dxvk {

  D3D9Initializer::D3D9Initializer(
    const Rc<DxvkDevice>&             Device)
  : m_device(Device), m_context(m_device->createContext()) {
    m_context->beginRecording(
      m_device->createCommandList());
  }

  D3D9Initializer::~D3D9Initializer() {

  }

  void D3D9Initializer::Flush() {
    std::lock_guard<dxvk::mutex> lock(m_mutex);

    if (m_transferCommands != 0)
      FlushInternal();
  }

  void D3D9Initializer::InitBuffer(
          D3D9CommonBuffer*  pBuffer) {
    VkMemoryPropertyFlags memFlags = pBuffer->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>()->memFlags();

    (memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
      ? InitHostVisibleBuffer(pBuffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>())
      : InitDeviceLocalBuffer(pBuffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>());

    if (pBuffer->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
      InitHostVisibleBuffer(pBuffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_STAGING>());
  }

  void D3D9Initializer::InitTexture(
          D3D9CommonTexture* pTexture,
          void*              pInitialData) {
    if (pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_NONE)
      return;

    (pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED)
      ? InitDeviceLocalTexture(pTexture)
      : InitHostVisibleTexture(pTexture, pInitialData);
  }

  void D3D9Initializer::InitDeviceLocalBuffer(
          DxvkBufferSlice    Slice) {
    std::lock_guard<dxvk::mutex> lock(m_mutex);

    m_transferCommands += 1;

    m_context->initBuffer(
      Slice.buffer());

    FlushImplicit();
  }

  void D3D9Initializer::InitHostVisibleBuffer(
          DxvkBufferSlice    Slice) {
    // If the buffer is mapped, we can write data directly
    // to the mapped memory region instead of doing it on
    // the GPU. Same goes for zero-initialization.
    std::memset(
      Slice.mapPtr(0), 0,
      Slice.length());
  }

  void D3D9Initializer::InitDeviceLocalTexture(
          D3D9CommonTexture* pTexture) {
    std::lock_guard<dxvk::mutex> lock(m_mutex);

    auto InitImage = [&](Rc<DxvkImage> image) {
      if (image == nullptr)
        return;

      auto formatInfo = imageFormatInfo(image->info().format);

      m_transferCommands += 1;

      // While the Microsoft docs state that resource contents are
      // undefined if no initial data is provided, some applications
      // expect a resource to be pre-cleared.
      VkImageSubresourceRange subresources;
      subresources.aspectMask     = formatInfo->aspectMask;
      subresources.baseMipLevel   = 0;
      subresources.levelCount     = image->info().mipLevels;
      subresources.baseArrayLayer = 0;
      subresources.layerCount     = image->info().numLayers;

      m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_UNDEFINED);
    };

    InitImage(pTexture->GetImage());

    FlushImplicit();
  }

  void D3D9Initializer::InitHostVisibleTexture(
          D3D9CommonTexture* pTexture,
          void*              pInitialData) {
    // If the buffer is mapped, we can write data directly
    // to the mapped memory region instead of doing it on
    // the GPU. Same goes for zero-initialization.
    const D3D9_COMMON_TEXTURE_DESC* desc = pTexture->Desc();
    for (uint32_t a = 0; a < desc->ArraySize; a++) {
      for (uint32_t m = 0; m < desc->MipLevels; m++) {
        uint32_t subresource = pTexture->CalcSubresource(a, m);
        DxvkBufferSliceHandle mapSlice  = pTexture->GetBuffer(subresource)->getSliceHandle();

        if (pInitialData != nullptr) {
          VkExtent3D mipExtent = pTexture->GetExtentMip(m);
          const DxvkFormatInfo* formatInfo = imageFormatInfo(pTexture->GetFormatMapping().FormatColor);
          VkExtent3D blockCount = util::computeBlockCount(mipExtent, formatInfo->blockSize);
          uint32_t pitch = blockCount.width * formatInfo->elementSize;
          uint32_t alignedPitch = align(pitch, 4);

          util::packImageData(
            mapSlice.mapPtr,
            pInitialData,
            pitch,
            pitch * blockCount.height,
            alignedPitch,
            alignedPitch * blockCount.height,
            D3D9CommonTexture::GetImageTypeFromResourceType(pTexture->GetType()),
            mipExtent,
            pTexture->Desc()->ArraySize,
            formatInfo,
            VK_IMAGE_ASPECT_COLOR_BIT);
        } else {
          std::memset(
            mapSlice.mapPtr, 0,
            mapSlice.length);
        }
      }
    }
  }

  void D3D9Initializer::FlushImplicit() {
    if (m_transferCommands > MaxTransferCommands
     || m_transferMemory   > MaxTransferMemory)
      FlushInternal();
  }

  void D3D9Initializer::FlushInternal() {
    m_context->flushCommandList();

    m_transferCommands = 0;
    m_transferMemory   = 0;
  }

}


code:
#pragma once

#include "d3d9_common_buffer.h"
#include "d3d9_common_texture.h"

namespace dxvk {

  /**
   * \brief Resource initialization context
   *
   * Manages a context which is used for resource
   * initialization. This includes
   * zero-initialization for buffers and images.
   */
  class D3D9Initializer {
    constexpr static size_t MaxTransferMemory    = 32 * 1024 * 1024;
    constexpr static size_t MaxTransferCommands  = 512;
  public:

    D3D9Initializer(
      const Rc<DxvkDevice>&             Device);

    ~D3D9Initializer();

    void Flush();

    void InitBuffer(
            D3D9CommonBuffer*  pBuffer);

    void InitTexture(
            D3D9CommonTexture* pTexture,
            void*              pInitialData = nullptr);

  private:

    dxvk::mutex       m_mutex;

    Rc<DxvkDevice>    m_device;
    Rc<DxvkContext>   m_context;

    size_t            m_transferCommands  = 0;
    size_t            m_transferMemory    = 0;

    void InitDeviceLocalBuffer(
            DxvkBufferSlice    Slice);

    void InitHostVisibleBuffer(
            DxvkBufferSlice    Slice);

    void InitDeviceLocalTexture(
            D3D9CommonTexture* pTexture);

    void InitHostVisibleTexture(
            D3D9CommonTexture* pTexture,
            void*              pInitialData);

    void FlushImplicit();
    void FlushInternal();

  };

}


code:
#include "d3d9_interface.h"

#include "d3d9_monitor.h"
#include "d3d9_caps.h"
#include "d3d9_device.h"

#include <algorithm>

namespace dxvk {

  D3D9InterfaceEx::D3D9InterfaceEx(bool bExtended)
    : m_instance    ( new DxvkInstance() )
    , m_extended    ( bExtended )
    , m_d3d9Options ( nullptr, m_instance->config() ) {
    // D3D9 doesn't enumerate adapters like physical adapters...
    // only as connected displays.

    // Let's create some "adapters" for the amount of displays we have.
    // We'll go through and match up displays -> our adapters in order.
    // If we run out of adapters, then we'll just make repeats of the first one.
    // We can't match up by names on Linux/Wine as they don't match at all
    // like on Windows, so this is our best option.
    if (m_d3d9Options.enumerateByDisplays) {
      DISPLAY_DEVICEA device = { };
      device.cb = sizeof(device);

      uint32_t adapterOrdinal = 0;
      uint32_t i = 0;
      while (::EnumDisplayDevicesA(nullptr, i++, &device, 0)) {
        // If we aren't attached, skip over.
        if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
          continue;

        // If we are a mirror, skip over this device.
        if (device.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
          continue;

        Rc<DxvkAdapter> adapter = adapterOrdinal >= m_instance->adapterCount()
          ? m_instance->enumAdapters(0)
          : m_instance->enumAdapters(adapterOrdinal);

        if (adapter != nullptr)
          m_adapters.emplace_back(this, adapter, adapterOrdinal++, i - 1);
      }
    }
    else
    {
      const uint32_t adapterCount = m_instance->adapterCount();
      m_adapters.reserve(adapterCount);

      for (uint32_t i = 0; i < adapterCount; i++)
        m_adapters.emplace_back(this, m_instance->enumAdapters(i), i, 0);
    }

    if (m_d3d9Options.dpiAware) {
      Logger::info("Process set as DPI aware");
      SetProcessDPIAware();
    }
  }

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

    *ppvObject = nullptr;

    if (riid == __uuidof(IUnknown)
     || riid == __uuidof(IDirect3D9)
     || (m_extended && riid == __uuidof(IDirect3D9Ex))) {
      *ppvObject = ref(this);
      return S_OK;
    }

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

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::RegisterSoftwareDevice(void* pInitializeFunction) {
    Logger::warn("D3D9InterfaceEx::RegisterSoftwareDevice: Stub");
    return D3D_OK;
  }

  UINT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterCount() {
    return UINT(m_adapters.size());
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterIdentifier(
          UINT                    Adapter,
          DWORD                   Flags,
          D3DADAPTER_IDENTIFIER9* pIdentifier) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->GetAdapterIdentifier(Flags, pIdentifier);

    return D3DERR_INVALIDCALL;
  }

  UINT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) {
    D3DDISPLAYMODEFILTER filter;
    filter.Size             = sizeof(D3DDISPLAYMODEFILTER);
    filter.Format           = Format;
    filter.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;

    return this->GetAdapterModeCountEx(Adapter, &filter);
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) {
    if (auto* adapter = GetAdapter(Adapter)) {
      D3DDISPLAYMODEEX modeEx = { };
      modeEx.Size = sizeof(D3DDISPLAYMODEEX);
      HRESULT hr = adapter->GetAdapterDisplayModeEx(&modeEx, nullptr);

      if (FAILED(hr))
        return hr;

      pMode->Width       = modeEx.Width;
      pMode->Height      = modeEx.Height;
      pMode->RefreshRate = modeEx.RefreshRate;
      pMode->Format      = modeEx.Format;

      return D3D_OK;
    }

    return D3DERR_INVALIDCALL;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceType(
          UINT       Adapter,
          D3DDEVTYPE DevType,
          D3DFORMAT  AdapterFormat,
          D3DFORMAT  BackBufferFormat,
          BOOL       bWindowed) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->CheckDeviceType(
        DevType, EnumerateFormat(AdapterFormat),
        EnumerateFormat(BackBufferFormat), bWindowed);

    return D3DERR_INVALIDCALL;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceFormat(
          UINT            Adapter,
          D3DDEVTYPE      DeviceType,
          D3DFORMAT       AdapterFormat,
          DWORD           Usage,
          D3DRESOURCETYPE RType,
          D3DFORMAT       CheckFormat) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->CheckDeviceFormat(
        DeviceType, EnumerateFormat(AdapterFormat),
        Usage, RType,
        EnumerateFormat(CheckFormat));

    return D3DERR_INVALIDCALL;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceMultiSampleType(
          UINT                Adapter,
          D3DDEVTYPE          DeviceType,
          D3DFORMAT           SurfaceFormat,
          BOOL                Windowed,
          D3DMULTISAMPLE_TYPE MultiSampleType,
          DWORD*              pQualityLevels) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->CheckDeviceMultiSampleType(
        DeviceType, EnumerateFormat(SurfaceFormat),
        Windowed, MultiSampleType,
        pQualityLevels);

    return D3DERR_INVALIDCALL;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDepthStencilMatch(
          UINT       Adapter,
          D3DDEVTYPE DeviceType,
          D3DFORMAT  AdapterFormat,
          D3DFORMAT  RenderTargetFormat,
          D3DFORMAT  DepthStencilFormat) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->CheckDepthStencilMatch(
        DeviceType, EnumerateFormat(AdapterFormat),
        EnumerateFormat(RenderTargetFormat),
        EnumerateFormat(DepthStencilFormat));

    return D3DERR_INVALIDCALL;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceFormatConversion(
          UINT       Adapter,
          D3DDEVTYPE DeviceType,
          D3DFORMAT  SourceFormat,
          D3DFORMAT  TargetFormat) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->CheckDeviceFormatConversion(
        DeviceType, EnumerateFormat(SourceFormat),
        EnumerateFormat(TargetFormat));

    return D3DERR_INVALIDCALL;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetDeviceCaps(
          UINT       Adapter,
          D3DDEVTYPE DeviceType,
          D3DCAPS9*  pCaps) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->GetDeviceCaps(
        DeviceType, pCaps);

    return D3DERR_INVALIDCALL;
  }

  HMONITOR STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterMonitor(UINT Adapter) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->GetMonitor();

    return nullptr;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CreateDevice(
          UINT                   Adapter,
          D3DDEVTYPE             DeviceType,
          HWND                   hFocusWindow,
          DWORD                  BehaviorFlags,
          D3DPRESENT_PARAMETERS* pPresentationParameters,
          IDirect3DDevice9**     ppReturnedDeviceInterface) {
    return this->CreateDeviceEx(
      Adapter,
      DeviceType,
      hFocusWindow,
      BehaviorFlags,
      pPresentationParameters,
      nullptr, // <-- pFullscreenDisplayMode
      reinterpret_cast<IDirect3DDevice9Ex**>(ppReturnedDeviceInterface));
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::EnumAdapterModes(
          UINT            Adapter,
          D3DFORMAT       Format,
          UINT            Mode,
          D3DDISPLAYMODE* pMode) {
    if (pMode == nullptr)
      return D3DERR_INVALIDCALL;

    D3DDISPLAYMODEFILTER filter;
    filter.Format           = Format;
    filter.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
    filter.Size             = sizeof(D3DDISPLAYMODEFILTER);

    D3DDISPLAYMODEEX modeEx = { };
    modeEx.Size = sizeof(D3DDISPLAYMODEEX);
    HRESULT hr = this->EnumAdapterModesEx(Adapter, &filter, Mode, &modeEx);

    if (FAILED(hr))
      return hr;

    pMode->Width       = modeEx.Width;
    pMode->Height      = modeEx.Height;
    pMode->RefreshRate = modeEx.RefreshRate;
    pMode->Format      = modeEx.Format;

    return D3D_OK;
  }

  // Ex Methods

  UINT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterModeCountEx(UINT Adapter, CONST D3DDISPLAYMODEFILTER* pFilter) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->GetAdapterModeCountEx(pFilter);

    return 0;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::EnumAdapterModesEx(
          UINT                  Adapter,
    const D3DDISPLAYMODEFILTER* pFilter,
          UINT                  Mode,
          D3DDISPLAYMODEEX*     pMode) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->EnumAdapterModesEx(pFilter, Mode, pMode);

    return D3DERR_INVALIDCALL;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterDisplayModeEx(
          UINT                Adapter,
          D3DDISPLAYMODEEX*   pMode,
          D3DDISPLAYROTATION* pRotation) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->GetAdapterDisplayModeEx(pMode, pRotation);

    return D3DERR_INVALIDCALL;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CreateDeviceEx(
          UINT                   Adapter,
          D3DDEVTYPE             DeviceType,
          HWND                   hFocusWindow,
          DWORD                  BehaviorFlags,
          D3DPRESENT_PARAMETERS* pPresentationParameters,
          D3DDISPLAYMODEEX*      pFullscreenDisplayMode,
          IDirect3DDevice9Ex**   ppReturnedDeviceInterface) {
    InitReturnPtr(ppReturnedDeviceInterface);

    if (ppReturnedDeviceInterface == nullptr
    || pPresentationParameters    == nullptr)
      return D3DERR_INVALIDCALL;

    auto* adapter = GetAdapter(Adapter);

    if (adapter == nullptr)
      return D3DERR_INVALIDCALL;

    auto dxvkAdapter = adapter->GetDXVKAdapter();

    try {
      auto dxvkDevice = dxvkAdapter->createDevice(m_instance, D3D9DeviceEx::GetDeviceFeatures(dxvkAdapter));

      auto* device = new D3D9DeviceEx(
        this,
        adapter,
        DeviceType,
        hFocusWindow,
        BehaviorFlags,
        dxvkDevice);

      HRESULT hr = device->InitialReset(pPresentationParameters, pFullscreenDisplayMode);

      if (FAILED(hr))
        return hr;

      *ppReturnedDeviceInterface = ref(device);
    }
    catch (const DxvkError& e) {
      Logger::err(e.message());
      return D3DERR_NOTAVAILABLE;
    }

    return D3D_OK;
  }

  HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterLUID(UINT Adapter, LUID* pLUID) {
    if (auto* adapter = GetAdapter(Adapter))
      return adapter->GetAdapterLUID(pLUID);

    return D3DERR_INVALIDCALL;
  }

}


code:
#pragma once

#include "d3d9_adapter.h"

#include "../dxvk/dxvk_instance.h"

namespace dxvk {

  /**
  * \brief D3D9 interface implementation
  *
  * Implements the IDirect3DDevice9Ex interfaces
  * which provides the way to get adapters and create other objects such as \ref IDirect3DDevice9Ex.
  * similar to \ref DxgiFactory but for D3D9.
  */
  class D3D9InterfaceEx final : public ComObjectClamp<IDirect3D9Ex> {

  public:

    D3D9InterfaceEx(bool bExtended);

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

    HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void* pInitializeFunction);

    UINT STDMETHODCALLTYPE GetAdapterCount();

    HRESULT STDMETHODCALLTYPE GetAdapterIdentifier(
            UINT                    Adapter,
            DWORD                   Flags,
            D3DADAPTER_IDENTIFIER9* pIdentifier);

    UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter, D3DFORMAT Format);

    HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode);

    HRESULT STDMETHODCALLTYPE CheckDeviceType(
            UINT       Adapter,
            D3DDEVTYPE DevType,
            D3DFORMAT  AdapterFormat,
            D3DFORMAT  BackBufferFormat,
            BOOL       bWindowed);

    HRESULT STDMETHODCALLTYPE CheckDeviceFormat(
            UINT            Adapter,
            D3DDEVTYPE      DeviceType,
            D3DFORMAT       AdapterFormat,
            DWORD           Usage,
            D3DRESOURCETYPE RType,
            D3DFORMAT       CheckFormat);

    HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType(
            UINT                Adapter,
            D3DDEVTYPE          DeviceType,
            D3DFORMAT           SurfaceFormat,
            BOOL                Windowed,
            D3DMULTISAMPLE_TYPE MultiSampleType,
            DWORD*              pQualityLevels);

    HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch(
            UINT       Adapter,
            D3DDEVTYPE DeviceType,
            D3DFORMAT  AdapterFormat,
            D3DFORMAT  RenderTargetFormat,
            D3DFORMAT  DepthStencilFormat);

    HRESULT STDMETHODCALLTYPE CheckDeviceFormatConversion(
            UINT       Adapter,
            D3DDEVTYPE DeviceType,
            D3DFORMAT  SourceFormat,
            D3DFORMAT  TargetFormat);

    HRESULT STDMETHODCALLTYPE GetDeviceCaps(
            UINT       Adapter,
            D3DDEVTYPE DeviceType,
            D3DCAPS9*  pCaps);

    HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter);

    HRESULT STDMETHODCALLTYPE CreateDevice(
            UINT                   Adapter,
            D3DDEVTYPE             DeviceType,
            HWND                   hFocusWindow,
            DWORD                  BehaviorFlags,
            D3DPRESENT_PARAMETERS* pPresentationParameters,
            IDirect3DDevice9**     ppReturnedDeviceInterface);

    HRESULT STDMETHODCALLTYPE EnumAdapterModes(
            UINT            Adapter,
            D3DFORMAT       Format,
            UINT            Mode,
            D3DDISPLAYMODE* pMode);

    // Ex Methods

    UINT STDMETHODCALLTYPE GetAdapterModeCountEx(UINT Adapter, CONST D3DDISPLAYMODEFILTER* pFilter);

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

    HRESULT STDMETHODCALLTYPE GetAdapterDisplayModeEx(
            UINT                Adapter,
            D3DDISPLAYMODEEX*   pMode,
            D3DDISPLAYROTATION* pRotation);

    HRESULT STDMETHODCALLTYPE CreateDeviceEx(
            UINT                   Adapter,
            D3DDEVTYPE             DeviceType,
            HWND                   hFocusWindow,
            DWORD                  BehaviorFlags,
            D3DPRESENT_PARAMETERS* pPresentationParameters,
            D3DDISPLAYMODEEX*      pFullscreenDisplayMode,
            IDirect3DDevice9Ex**   ppReturnedDeviceInterface);

    HRESULT STDMETHODCALLTYPE GetAdapterLUID(UINT Adapter, LUID* pLUID);

    const D3D9Options& GetOptions() { return m_d3d9Options; }

    D3D9Adapter* GetAdapter(UINT Ordinal) {
      return Ordinal < m_adapters.size()
        ? &m_adapters[Ordinal]
        : nullptr;
    }

    bool IsExtended() { return m_extended; }

    Rc<DxvkInstance> GetInstance() { return m_instance; }

  private:

    void CacheModes(D3D9Format Format);

    static const char* GetDriverDllName(DxvkGpuVendor vendor);

    Rc<DxvkInstance>              m_instance;

    bool                          m_extended;

    D3D9Options                   m_d3d9Options;

    std::vector<D3D9Adapter>      m_adapters;

  };

}


code:
#include "../dxvk/dxvk_instance.h"

#include "d3d9_interface.h"
#include "d3d9_shader_validator.h"

#include "d3d9_annotation.h"

class D3DFE_PROCESSVERTICES;
using PSGPERRORID = UINT;

namespace dxvk {
  Logger Logger::s_instance("d3d9.log");
  D3D9GlobalAnnotationList D3D9GlobalAnnotationList::s_instance;

  HRESULT CreateD3D9(
          bool           Extended,
          IDirect3D9Ex** ppDirect3D9Ex) {
    if (!ppDirect3D9Ex)
      return D3DERR_INVALIDCALL;

    *ppDirect3D9Ex = ref(new D3D9InterfaceEx( Extended ));
    return D3D_OK;
  }
}

extern "C" {

  DLLEXPORT IDirect3D9* __stdcall Direct3DCreate9(UINT nSDKVersion) {
    IDirect3D9Ex* pDirect3D = nullptr;
    dxvk::CreateD3D9(false, &pDirect3D);

    return pDirect3D;
  }

  DLLEXPORT HRESULT __stdcall Direct3DCreate9Ex(UINT nSDKVersion, IDirect3D9Ex** ppDirect3D9Ex) {
    return dxvk::CreateD3D9(true, ppDirect3D9Ex);
  }

  DLLEXPORT int __stdcall D3DPERF_BeginEvent(D3DCOLOR col, LPCWSTR wszName) {
    return dxvk::D3D9GlobalAnnotationList::Instance().BeginEvent(col, wszName);
  }

  DLLEXPORT int __stdcall D3DPERF_EndEvent(void) {
    return dxvk::D3D9GlobalAnnotationList::Instance().EndEvent();
  }

  DLLEXPORT void __stdcall D3DPERF_SetMarker(D3DCOLOR col, LPCWSTR wszName) {
    dxvk::D3D9GlobalAnnotationList::Instance().SetMarker(col, wszName);
  }

  DLLEXPORT void __stdcall D3DPERF_SetRegion(D3DCOLOR col, LPCWSTR wszName) {
    dxvk::D3D9GlobalAnnotationList::Instance().SetRegion(col, wszName);
  }

  DLLEXPORT BOOL __stdcall D3DPERF_QueryRepeatFrame(void) {
    return dxvk::D3D9GlobalAnnotationList::Instance().QueryRepeatFrame();
  }

  DLLEXPORT void __stdcall D3DPERF_SetOptions(DWORD dwOptions) {
    dxvk::D3D9GlobalAnnotationList::Instance().SetOptions(dwOptions);
  }

  DLLEXPORT DWORD __stdcall D3DPERF_GetStatus(void) {
    return dxvk::D3D9GlobalAnnotationList::Instance().GetStatus();
  }

  DLLEXPORT void __stdcall DebugSetMute(void) {
  }

  DLLEXPORT int __stdcall DebugSetLevel(void) {
    return 0;
  }

  // Processor Specific Geometry Pipeline
  // for P3 SIMD/AMD 3DNow.

  DLLEXPORT void __stdcall PSGPError(D3DFE_PROCESSVERTICES* a, PSGPERRORID b, UINT c) {
  }

  DLLEXPORT void __stdcall PSGPSampleTexture(D3DFE_PROCESSVERTICES* a, UINT b, float(*const c)[4], UINT d, float(*const e)[4]) {
  }

  DLLEXPORT dxvk::D3D9ShaderValidator* __stdcall Direct3DShaderValidatorCreate9(void) {
    return ref(new dxvk::D3D9ShaderValidator());
  }

  DLLEXPORT int __stdcall Direct3D9EnableMaximizedWindowedModeShim(UINT a) {
    return 0;
  }

  DLLEXPORT void __stdcall DXVK_RegisterAnnotation(IDXVKUserDefinedAnnotation* annotation) {
    dxvk::D3D9GlobalAnnotationList::Instance().RegisterAnnotator(annotation);
  }

  DLLEXPORT void __stdcall DXVK_UnRegisterAnnotation(IDXVKUserDefinedAnnotation* annotation) {
    dxvk::D3D9GlobalAnnotationList::Instance().UnregisterAnnotator(annotation);
  }

  DLLEXPORT void __stdcall Direct3D9ForceHybridEnumeration(UINT uHybrid) {
  }

}


code:
#include "d3d9_monitor.h"

#include "d3d9_format.h"

namespace dxvk {

  uint32_t GetMonitorFormatBpp(D3D9Format Format) {
    switch (Format) {
    case D3D9Format::A8R8G8B8:
    case D3D9Format::X8R8G8B8: // This is still 32 bit even though the alpha is unspecified.
    case D3D9Format::A2R10G10B10:
      return 32;

    case D3D9Format::A1R5G5B5:
    case D3D9Format::X1R5G5B5:
    case D3D9Format::R5G6B5:
      return 16;

    default:
      Logger::warn(str::format(
        "GetMonitorFormatBpp: Unknown format: ",
        Format));
      return 32;
    }
  }

  bool IsSupportedAdapterFormat(
          D3D9Format Format) {
    return Format == D3D9Format::A2R10G10B10
        || Format == D3D9Format::X8R8G8B8
        || Format == D3D9Format::X1R5G5B5
        || Format == D3D9Format::R5G6B5;
  }

  bool IsSupportedBackBufferFormat(
          D3D9Format AdapterFormat,
          D3D9Format BackBufferFormat,
          BOOL       Windowed) {
    if (!Windowed) {
      return (AdapterFormat == D3D9Format::A2R10G10B10 && BackBufferFormat == D3D9Format::A2R10G10B10) ||
             (AdapterFormat == D3D9Format::X8R8G8B8    && BackBufferFormat == D3D9Format::X8R8G8B8) ||
             (AdapterFormat == D3D9Format::X8R8G8B8    && BackBufferFormat == D3D9Format::A8R8G8B8) ||
             (AdapterFormat == D3D9Format::X1R5G5B5    && BackBufferFormat == D3D9Format::X1R5G5B5) ||
             (AdapterFormat == D3D9Format::X1R5G5B5    && BackBufferFormat == D3D9Format::A1R5G5B5) ||
             (AdapterFormat == D3D9Format::R5G6B5      && BackBufferFormat == D3D9Format::R5G6B5);
    }

    return IsSupportedBackBufferFormat(BackBufferFormat);
  }

  bool IsSupportedBackBufferFormat(
        D3D9Format BackBufferFormat) {
    return BackBufferFormat == D3D9Format::A2R10G10B10
        || BackBufferFormat == D3D9Format::A8R8G8B8
        || BackBufferFormat == D3D9Format::X8R8G8B8
        || BackBufferFormat == D3D9Format::A1R5G5B5
        || BackBufferFormat == D3D9Format::X1R5G5B5
        || BackBufferFormat == D3D9Format::R5G6B5
        || BackBufferFormat == D3D9Format::Unknown;
  }

}


code:
#pragma once

#include "d3d9_include.h"

#include "d3d9_format.h"

namespace dxvk {

  /**
  * \brief Queries bits per pixel for a format
  *
  * The format must be a valid swap chain format.
  * \param [in] Format The D3D9 format to query
  * \returns Bits per pixel for this format
  */
  uint32_t GetMonitorFormatBpp(
    D3D9Format             Format);

  /**
  * \brief Returns if a format is supported for a backbuffer/swapchain.
  *
  * \param [in] Format The D3D9 format to query
  * \returns If it is supported as a swapchain/backbuffer format.
  */
  bool IsSupportedAdapterFormat(
          D3D9Format Format);

  bool IsSupportedBackBufferFormat(
          D3D9Format AdapterFormat,
          D3D9Format BackBufferFormat,
          BOOL       Windowed);

  bool IsSupportedBackBufferFormat(
          D3D9Format BackBufferFormat);
}


code:
#include "d3d9_device.h"

namespace dxvk {

  D3D9Multithread::D3D9Multithread(
          BOOL                  Protected)
    : m_protected( Protected ) { }

}


code:
#pragma once

#include "d3d9_include.h"

namespace dxvk {

  /**
   * \brief Device lock
   *
   * Lightweight RAII wrapper that implements
   * a subset of the functionality provided by
   * \c std::unique_lock, with the goal of being
   * cheaper to construct and destroy.
   */
  class D3D9DeviceLock {

  public:

    D3D9DeviceLock()
      : m_mutex(nullptr) { }

    D3D9DeviceLock(sync::RecursiveSpinlock& mutex)
      : m_mutex(&mutex) {
      mutex.lock();
    }

    D3D9DeviceLock(D3D9DeviceLock&& other)
      : m_mutex(other.m_mutex) {
      other.m_mutex = nullptr;
    }

    D3D9DeviceLock& operator = (D3D9DeviceLock&& other) {
      if (m_mutex)
        m_mutex->unlock();

      m_mutex = other.m_mutex;
      other.m_mutex = nullptr;
      return *this;
    }

    ~D3D9DeviceLock() {
      if (m_mutex != nullptr)
        m_mutex->unlock();
    }

  private:

    sync::RecursiveSpinlock* m_mutex;

  };

  /**
   * \brief D3D9 context lock
   */
  class D3D9Multithread {

  public:

    D3D9Multithread(
      BOOL                  Protected);

    D3D9DeviceLock AcquireLock() {
      return m_protected
        ? D3D9DeviceLock(m_mutex)
        : D3D9DeviceLock();
    }

  private:

    BOOL            m_protected;

    sync::RecursiveSpinlock m_mutex;

  };

}


code:
#include "d3d9_format.h"

namespace dxvk {

  std::ostream& operator << (std::ostream& os, D3D9Format e) {
    switch (e) {
      ENUM_NAME(D3D9Format::Unknown);

      ENUM_NAME(D3D9Format::R8G8B8);
      ENUM_NAME(D3D9Format::A8R8G8B8);
      ENUM_NAME(D3D9Format::X8R8G8B8);
      ENUM_NAME(D3D9Format::R5G6B5);
      ENUM_NAME(D3D9Format::X1R5G5B5);
      ENUM_NAME(D3D9Format::A1R5G5B5);
      ENUM_NAME(D3D9Format::A4R4G4B4);
      ENUM_NAME(D3D9Format::R3G3B2);
      ENUM_NAME(D3D9Format::A8);
      ENUM_NAME(D3D9Format::A8R3G3B2);
      ENUM_NAME(D3D9Format::X4R4G4B4);
      ENUM_NAME(D3D9Format::A2B10G10R10);
      ENUM_NAME(D3D9Format::A8B8G8R8);
      ENUM_NAME(D3D9Format::X8B8G8R8);
      ENUM_NAME(D3D9Format::G16R16);
      ENUM_NAME(D3D9Format::A2R10G10B10);
      ENUM_NAME(D3D9Format::A16B16G16R16);
      ENUM_NAME(D3D9Format::A8P8);
      ENUM_NAME(D3D9Format::P8);
      ENUM_NAME(D3D9Format::L8);
      ENUM_NAME(D3D9Format::A8L8);
      ENUM_NAME(D3D9Format::A4L4);
      ENUM_NAME(D3D9Format::V8U8);
      ENUM_NAME(D3D9Format::L6V5U5);
      ENUM_NAME(D3D9Format::X8L8V8U8);
      ENUM_NAME(D3D9Format::Q8W8V8U8);
      ENUM_NAME(D3D9Format::V16U16);
      ENUM_NAME(D3D9Format::A2W10V10U10);
      ENUM_NAME(D3D9Format::UYVY);
      ENUM_NAME(D3D9Format::R8G8_B8G8);
      ENUM_NAME(D3D9Format::YUY2);
      ENUM_NAME(D3D9Format::G8R8_G8B8);
      ENUM_NAME(D3D9Format::DXT1);
      ENUM_NAME(D3D9Format::DXT2);
      ENUM_NAME(D3D9Format::DXT3);
      ENUM_NAME(D3D9Format::DXT4);
      ENUM_NAME(D3D9Format::DXT5);
      ENUM_NAME(D3D9Format::D16_LOCKABLE);
      ENUM_NAME(D3D9Format::D32);
      ENUM_NAME(D3D9Format::D15S1);
      ENUM_NAME(D3D9Format::D24S8);
      ENUM_NAME(D3D9Format::D24X8);
      ENUM_NAME(D3D9Format::D24X4S4);
      ENUM_NAME(D3D9Format::D16);
      ENUM_NAME(D3D9Format::D32F_LOCKABLE);
      ENUM_NAME(D3D9Format::D24FS8);
      ENUM_NAME(D3D9Format::D32_LOCKABLE);
      ENUM_NAME(D3D9Format::S8_LOCKABLE);
      ENUM_NAME(D3D9Format::L16);
      ENUM_NAME(D3D9Format::VERTEXDATA);
      ENUM_NAME(D3D9Format::INDEX16);
      ENUM_NAME(D3D9Format::INDEX32);
      ENUM_NAME(D3D9Format::Q16W16V16U16);
      ENUM_NAME(D3D9Format::MULTI2_ARGB8);
      ENUM_NAME(D3D9Format::R16F);
      ENUM_NAME(D3D9Format::G16R16F);
      ENUM_NAME(D3D9Format::A16B16G16R16F);
      ENUM_NAME(D3D9Format::R32F);
      ENUM_NAME(D3D9Format::G32R32F);
      ENUM_NAME(D3D9Format::A32B32G32R32F);
      ENUM_NAME(D3D9Format::CxV8U8);
      ENUM_NAME(D3D9Format::A1);
      ENUM_NAME(D3D9Format::A2B10G10R10_XR_BIAS);
      ENUM_NAME(D3D9Format::BINARYBUFFER);

      // Driver Hacks / Unofficial Formats
      ENUM_NAME(D3D9Format::ATI1);
      ENUM_NAME(D3D9Format::ATI2);
      ENUM_NAME(D3D9Format::INST);
      ENUM_NAME(D3D9Format::DF24);
      ENUM_NAME(D3D9Format::DF16);
      ENUM_NAME(D3D9Format::NULL_FORMAT);
      ENUM_NAME(D3D9Format::GET4);
      ENUM_NAME(D3D9Format::GET1);
      ENUM_NAME(D3D9Format::NVDB);
      ENUM_NAME(D3D9Format::A2M1);
      ENUM_NAME(D3D9Format::A2M0);
      ENUM_NAME(D3D9Format::ATOC);
      ENUM_NAME(D3D9Format::INTZ);
      ENUM_NAME(D3D9Format::RAWZ);
      ENUM_NAME(D3D9Format::RESZ);

      ENUM_NAME(D3D9Format::NV11);
      ENUM_NAME(D3D9Format::NV12);
      ENUM_NAME(D3D9Format::P010);
      ENUM_NAME(D3D9Format::P016);
      ENUM_NAME(D3D9Format::Y210);
      ENUM_NAME(D3D9Format::Y216);
      ENUM_NAME(D3D9Format::Y410);
      ENUM_NAME(D3D9Format::AYUV);
      ENUM_NAME(D3D9Format::YV12);
      ENUM_NAME(D3D9Format::OPAQUE_420);

      ENUM_NAME(D3D9Format::AI44);
      ENUM_NAME(D3D9Format::IA44);
      ENUM_NAME(D3D9Format::R2VB);
      ENUM_NAME(D3D9Format::COPM);
      ENUM_NAME(D3D9Format::SSAA);
      ENUM_NAME(D3D9Format::AL16);
      ENUM_NAME(D3D9Format::R16);

      ENUM_NAME(D3D9Format::EXT1);
      ENUM_NAME(D3D9Format::FXT1);
      ENUM_NAME(D3D9Format::GXT1);
      ENUM_NAME(D3D9Format::HXT1);

      ENUM_DEFAULT(e);
    }
  }

  std::ostream& operator << (std::ostream& os, D3DRENDERSTATETYPE e) {
    switch (e) {
      ENUM_NAME(D3DRS_ZENABLE);
      ENUM_NAME(D3DRS_FILLMODE);
      ENUM_NAME(D3DRS_SHADEMODE);
      ENUM_NAME(D3DRS_ZWRITEENABLE);
      ENUM_NAME(D3DRS_ALPHATESTENABLE);
      ENUM_NAME(D3DRS_LASTPIXEL);
      ENUM_NAME(D3DRS_SRCBLEND);
      ENUM_NAME(D3DRS_DESTBLEND);
      ENUM_NAME(D3DRS_CULLMODE);
      ENUM_NAME(D3DRS_ZFUNC);
      ENUM_NAME(D3DRS_ALPHAREF);
      ENUM_NAME(D3DRS_ALPHAFUNC);
      ENUM_NAME(D3DRS_DITHERENABLE);
      ENUM_NAME(D3DRS_ALPHABLENDENABLE);
      ENUM_NAME(D3DRS_FOGENABLE);
      ENUM_NAME(D3DRS_SPECULARENABLE);
      ENUM_NAME(D3DRS_FOGCOLOR);
      ENUM_NAME(D3DRS_FOGTABLEMODE);
      ENUM_NAME(D3DRS_FOGSTART);
      ENUM_NAME(D3DRS_FOGEND);
      ENUM_NAME(D3DRS_FOGDENSITY);
      ENUM_NAME(D3DRS_RANGEFOGENABLE);
      ENUM_NAME(D3DRS_STENCILENABLE);
      ENUM_NAME(D3DRS_STENCILFAIL);
      ENUM_NAME(D3DRS_STENCILZFAIL);
      ENUM_NAME(D3DRS_STENCILPASS);
      ENUM_NAME(D3DRS_STENCILFUNC);
      ENUM_NAME(D3DRS_STENCILREF);
      ENUM_NAME(D3DRS_STENCILMASK);
      ENUM_NAME(D3DRS_STENCILWRITEMASK);
      ENUM_NAME(D3DRS_TEXTUREFACTOR);
      ENUM_NAME(D3DRS_WRAP0);
      ENUM_NAME(D3DRS_WRAP1);
      ENUM_NAME(D3DRS_WRAP2);
      ENUM_NAME(D3DRS_WRAP3);
      ENUM_NAME(D3DRS_WRAP4);
      ENUM_NAME(D3DRS_WRAP5);
      ENUM_NAME(D3DRS_WRAP6);
      ENUM_NAME(D3DRS_WRAP7);
      ENUM_NAME(D3DRS_CLIPPING);
      ENUM_NAME(D3DRS_LIGHTING);
      ENUM_NAME(D3DRS_AMBIENT);
      ENUM_NAME(D3DRS_FOGVERTEXMODE);
      ENUM_NAME(D3DRS_COLORVERTEX);
      ENUM_NAME(D3DRS_LOCALVIEWER);
      ENUM_NAME(D3DRS_NORMALIZENORMALS);
      ENUM_NAME(D3DRS_DIFFUSEMATERIALSOURCE);
      ENUM_NAME(D3DRS_SPECULARMATERIALSOURCE);
      ENUM_NAME(D3DRS_AMBIENTMATERIALSOURCE);
      ENUM_NAME(D3DRS_EMISSIVEMATERIALSOURCE);
      ENUM_NAME(D3DRS_VERTEXBLEND);
      ENUM_NAME(D3DRS_CLIPPLANEENABLE);
      ENUM_NAME(D3DRS_POINTSIZE);
      ENUM_NAME(D3DRS_POINTSIZE_MIN);
      ENUM_NAME(D3DRS_POINTSPRITEENABLE);
      ENUM_NAME(D3DRS_POINTSCALEENABLE);
      ENUM_NAME(D3DRS_POINTSCALE_A);
      ENUM_NAME(D3DRS_POINTSCALE_B);
      ENUM_NAME(D3DRS_POINTSCALE_C);
      ENUM_NAME(D3DRS_MULTISAMPLEANTIALIAS);
      ENUM_NAME(D3DRS_MULTISAMPLEMASK);
      ENUM_NAME(D3DRS_PATCHEDGESTYLE);
      ENUM_NAME(D3DRS_DEBUGMONITORTOKEN);
      ENUM_NAME(D3DRS_POINTSIZE_MAX);
      ENUM_NAME(D3DRS_INDEXEDVERTEXBLENDENABLE);
      ENUM_NAME(D3DRS_COLORWRITEENABLE);
      ENUM_NAME(D3DRS_TWEENFACTOR);
      ENUM_NAME(D3DRS_BLENDOP);
      ENUM_NAME(D3DRS_POSITIONDEGREE);
      ENUM_NAME(D3DRS_NORMALDEGREE);
      ENUM_NAME(D3DRS_SCISSORTESTENABLE);
      ENUM_NAME(D3DRS_SLOPESCALEDEPTHBIAS);
      ENUM_NAME(D3DRS_ANTIALIASEDLINEENABLE);
      ENUM_NAME(D3DRS_MINTESSELLATIONLEVEL);
      ENUM_NAME(D3DRS_MAXTESSELLATIONLEVEL);
      ENUM_NAME(D3DRS_ADAPTIVETESS_X);
      ENUM_NAME(D3DRS_ADAPTIVETESS_Y);
      ENUM_NAME(D3DRS_ADAPTIVETESS_Z);
      ENUM_NAME(D3DRS_ADAPTIVETESS_W);
      ENUM_NAME(D3DRS_ENABLEADAPTIVETESSELLATION);
      ENUM_NAME(D3DRS_TWOSIDEDSTENCILMODE);
      ENUM_NAME(D3DRS_CCW_STENCILFAIL);
      ENUM_NAME(D3DRS_CCW_STENCILZFAIL);
      ENUM_NAME(D3DRS_CCW_STENCILPASS);
      ENUM_NAME(D3DRS_CCW_STENCILFUNC);
      ENUM_NAME(D3DRS_COLORWRITEENABLE1);
      ENUM_NAME(D3DRS_COLORWRITEENABLE2);
      ENUM_NAME(D3DRS_COLORWRITEENABLE3);
      ENUM_NAME(D3DRS_BLENDFACTOR);
      ENUM_NAME(D3DRS_SRGBWRITEENABLE);
      ENUM_NAME(D3DRS_DEPTHBIAS);
      ENUM_NAME(D3DRS_WRAP8);
      ENUM_NAME(D3DRS_WRAP9);
      ENUM_NAME(D3DRS_WRAP10);
      ENUM_NAME(D3DRS_WRAP11);
      ENUM_NAME(D3DRS_WRAP12);
      ENUM_NAME(D3DRS_WRAP13);
      ENUM_NAME(D3DRS_WRAP14);
      ENUM_NAME(D3DRS_WRAP15);
      ENUM_NAME(D3DRS_SEPARATEALPHABLENDENABLE);
      ENUM_NAME(D3DRS_SRCBLENDALPHA);
      ENUM_NAME(D3DRS_DESTBLENDALPHA);
      ENUM_NAME(D3DRS_BLENDOPALPHA);

      ENUM_DEFAULT(e);
    }
  }

}


code:
#include "d3d9_include.h"

namespace dxvk {

  std::ostream& operator << (std::ostream& os, D3DRENDERSTATETYPE e);

}


code:
#include "d3d9_options.h"

#include "d3d9_caps.h"

namespace dxvk {

  static int32_t parsePciId(const std::string& str) {
    if (str.size() != 4)
      return -1;

    int32_t id = 0;

    for (size_t i = 0; i < str.size(); i++) {
      id *= 16;

      if (str[i] >= '0' && str[i] <= '9')
        id += str[i] - '0';
      else if (str[i] >= 'A' && str[i] <= 'F')
        id += str[i] - 'A' + 10;
      else if (str[i] >= 'a' && str[i] <= 'f')
        id += str[i] - 'a' + 10;
      else
        return -1;
    }

    return id;
  }

  D3D9Options::D3D9Options(const Rc<DxvkDevice>& device, const Config& config) {
    const Rc<DxvkAdapter> adapter = device != nullptr ? device->adapter() : nullptr;

    // Fetch these as a string representing a hexadecimal number and parse it.
    this->customVendorId        = parsePciId(config.getOption<std::string>("d3d9.customVendorId"));
    this->customDeviceId        = parsePciId(config.getOption<std::string>("d3d9.customDeviceId"));
    this->customDeviceDesc      =            config.getOption<std::string>("d3d9.customDeviceDesc");

    const int32_t vendorId = this->customDeviceId != -1
      ? this->customDeviceId
      : (adapter != nullptr ? adapter->deviceProperties().vendorID : 0);

    this->maxFrameLatency               = config.getOption<int32_t>     ("d3d9.maxFrameLatency",               0);
    this->maxFrameRate                  = config.getOption<int32_t>     ("d3d9.maxFrameRate",                  0);
    this->presentInterval               = config.getOption<int32_t>     ("d3d9.presentInterval",               -1);
    this->shaderModel                   = config.getOption<int32_t>     ("d3d9.shaderModel",                   3);
    this->evictManagedOnUnlock          = config.getOption<bool>        ("d3d9.evictManagedOnUnlock",          false);
    this->dpiAware                      = config.getOption<bool>        ("d3d9.dpiAware",                      true);
    this->strictConstantCopies          = config.getOption<bool>        ("d3d9.strictConstantCopies",          false);
    this->strictPow                     = config.getOption<bool>        ("d3d9.strictPow",                     true);
    this->lenientClear                  = config.getOption<bool>        ("d3d9.lenientClear",                  false);
    this->numBackBuffers                = config.getOption<int32_t>     ("d3d9.numBackBuffers",                0);
    this->noExplicitFrontBuffer         = config.getOption<bool>        ("d3d9.noExplicitFrontBuffer",         false);
    this->deferSurfaceCreation          = config.getOption<bool>        ("d3d9.deferSurfaceCreation",          false);
    this->samplerAnisotropy             = config.getOption<int32_t>     ("d3d9.samplerAnisotropy",             -1);
    this->maxAvailableMemory            = config.getOption<int32_t>     ("d3d9.maxAvailableMemory",            4096);
    this->supportDFFormats              = config.getOption<bool>        ("d3d9.supportDFFormats",              true);
    this->supportX4R4G4B4               = config.getOption<bool>        ("d3d9.supportX4R4G4B4",               true);
    this->supportD32                    = config.getOption<bool>        ("d3d9.supportD32",                    true);
    this->disableA8RT                   = config.getOption<bool>        ("d3d9.disableA8RT",                   false);
    this->invariantPosition             = config.getOption<bool>        ("d3d9.invariantPosition",             true);
    this->memoryTrackTest               = config.getOption<bool>        ("d3d9.memoryTrackTest",               false);
    this->supportVCache                 = config.getOption<bool>        ("d3d9.supportVCache",                 vendorId == 0x10de);
    this->enableDialogMode              = config.getOption<bool>        ("d3d9.enableDialogMode",              false);
    this->forceSamplerTypeSpecConstants = config.getOption<bool>        ("d3d9.forceSamplerTypeSpecConstants", false);
    this->forceSwapchainMSAA            = config.getOption<int32_t>     ("d3d9.forceSwapchainMSAA",            -1);
    this->forceAspectRatio              = config.getOption<std::string> ("d3d9.forceAspectRatio",              "");
    this->allowDoNotWait                = config.getOption<bool>        ("d3d9.allowDoNotWait",                true);
    this->allowDiscard                  = config.getOption<bool>        ("d3d9.allowDiscard",                  true);
    this->enumerateByDisplays           = config.getOption<bool>        ("d3d9.enumerateByDisplays",           true);
    this->longMad                       = config.getOption<bool>        ("d3d9.longMad",                       false);
    this->tearFree                      = config.getOption<Tristate>    ("d3d9.tearFree",                      Tristate::Auto);
    this->alphaTestWiggleRoom           = config.getOption<bool>        ("d3d9.alphaTestWiggleRoom",           false);
    this->apitraceMode                  = config.getOption<bool>        ("d3d9.apitraceMode",                  false);
    this->deviceLocalConstantBuffers    = config.getOption<bool>        ("d3d9.deviceLocalConstantBuffers",    false);
    this->allowDirectBufferMapping      = config.getOption<bool>        ("d3d9.allowDirectBufferMapping",      true);
    this->seamlessCubes                 = config.getOption<bool>        ("d3d9.seamlessCubes",                 false);

    // If we are not Nvidia, enable general hazards.
    this->generalHazards = adapter != nullptr
                        && !adapter->matchesDriver(
                            DxvkGpuVendor::Nvidia,
                            VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR,
                            0, 0);
    applyTristate(this->generalHazards, config.getOption<Tristate>("d3d9.generalHazards", Tristate::Auto));

    std::string floatEmulation = Config::toLower(config.getOption<std::string>("d3d9.floatEmulation", "auto"));
    if (floatEmulation == "strict") {
      d3d9FloatEmulation = D3D9FloatEmulation::Strict;
    } else if (floatEmulation == "false") {
      d3d9FloatEmulation = D3D9FloatEmulation::Disabled;
    } else if (floatEmulation == "true") {
      d3d9FloatEmulation = D3D9FloatEmulation::Enabled;
    } else {
      bool hasMulz = adapter != nullptr
                  && adapter->matchesDriver(DxvkGpuVendor::Amd,
                                            VK_DRIVER_ID_MESA_RADV,
                                            VK_MAKE_VERSION(21, 99, 99),
                                            0);
      d3d9FloatEmulation = hasMulz ? D3D9FloatEmulation::Strict : D3D9FloatEmulation::Enabled;
    }
  }

}


code:
#pragma once

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

namespace dxvk {

  enum class D3D9FloatEmulation {
    Disabled,
    Enabled,
    Strict
  };

  struct D3D9Options {

    D3D9Options(const Rc<DxvkDevice>& device, const Config& config);

    /// Override PCI vendor and device IDs reported to the
    /// application. This may make apps think they are running
    /// on a different GPU than they do and behave differently.
    int32_t customVendorId;
    int32_t customDeviceId;
    std::string customDeviceDesc;

    /// Present interval. Overrides the value
    /// in D3DPRESENT_PARAMS used in swapchain present.
    int32_t presentInterval;

    /// Override maximum frame latency if the app specifies
    /// a higher value. May help with frame timing issues.
    int32_t maxFrameLatency;

    /// Limit frame rate
    int32_t maxFrameRate;

    /// Set the max shader model the device can support in the caps.
    int32_t shaderModel;

    /// Whether or not managed resources should stay in memory until unlock, or until manually evicted.
    bool evictManagedOnUnlock;

    /// Whether or not to set the process as DPI aware in Windows when the API interface is created.
    bool dpiAware;

    /// True:  Copy our constant set into UBO if we are relative indexing ever.
    /// False: Copy our constant set into UBO if we are relative indexing at the start of a defined constant
    /// Why?:  In theory, FXC should never generate code where this would be an issue.
    bool strictConstantCopies;

    /// Whether or not we should care about pow(0, 0) = 1
    bool strictPow;

    /// Whether or not to do a fast path clear if we're close enough to the whole render target.
    bool lenientClear;

    /// Back buffer count for the Vulkan swap chain.
    /// Overrides buffer count in present parameters.
    int32_t numBackBuffers;

    /// Don't create an explicit front buffer in our own swapchain. The Vulkan swapchain is unaffected.
    /// Some games don't handle front/backbuffer flipping very well because they don't always redraw
    /// each frame completely, and rely on old pixel data from the previous frame to still be there.
    /// When this option is set and a game only requests one backbuffer, there will be no flipping in
    /// our own swapchain, so the game will always draw to the same buffer and can rely on old pixel
    /// data to still be there after a Present call.
    /// This means that D3D9SwapChainEx::GetFrontBufferData returns data from the backbuffer of the
    /// previous frame, which is the same as the current backbuffer if only 1 backbuffer was requested.
    bool noExplicitFrontBuffer;

    /// Defer surface creation
    bool deferSurfaceCreation;

    /// Whether to transition to general
    /// for rendering hazards
    bool generalHazards;

    /// Anisotropic filter override
    ///
    /// Enforces anisotropic filtering with the
    /// given anisotropy value for all samplers.
    int32_t samplerAnisotropy;

    /// Max available memory override
    ///
    /// Changes the max initial value used in
    /// tracking and GetAvailableTextureMem
    uint32_t maxAvailableMemory;

    /// D3D9 Floating Point Emulation (anything * 0 = 0)
    D3D9FloatEmulation d3d9FloatEmulation;

    /// Support the DF16 & DF24 texture format
    bool supportDFFormats;

    /// Support X4R4G4B4
    bool supportX4R4G4B4;

    /// Support D32
    bool supportD32;

    /// Disable D3DFMT_A8 for render targets.
    /// Specifically to work around a game
    /// bug in The Sims 2 that happens on native too!
    bool disableA8RT;

    /// Work around a NV driver quirk
    /// Fixes flickering/z-fighting in some games.
    bool invariantPosition;

    /// Whether or not to respect memory tracking for
    /// failing resource allocation.
    bool memoryTrackTest;

    /// Support VCACHE query
    bool supportVCache;

    /// Forced aspect ratio, disable other modes
    std::string forceAspectRatio;

    /// Enable dialog mode (ie. no exclusive fullscreen)
    bool enableDialogMode;

    /// Always use a spec constant to determine sampler type (instead of just in PS 1.x)
    /// Works around a game bug in Halo CE where it gives cube textures to 2d/volume samplers
    bool forceSamplerTypeSpecConstants;

    /// Forces an MSAA level on the swapchain
    int32_t forceSwapchainMSAA;

    /// Allow D3DLOCK_DONOTWAIT
    bool allowDoNotWait;

    /// Allow D3DLOCK_DISCARD
    bool allowDiscard;

    /// Enumerate adapters by displays
    bool enumerateByDisplays;

    /// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
    /// This solves some rendering bugs in games that have z-pass shaders which
    /// don't match entirely to the regular vertex shader in this way.
    bool longMad;

    /// Tear-free mode if vsync is disabled
    /// Tearing mode if vsync is enabled
    Tristate tearFree;

    /// Workaround for games using alpha test == 1.0, etc due to wonky interpolation or
    /// misc. imprecision on some vendors
    bool alphaTestWiggleRoom;

    /// Apitrace mode: Maps all buffers in cached memory.
    bool apitraceMode;

    /// Use device local memory for constant buffers.
    bool deviceLocalConstantBuffers;

    /// Disable direct buffer mapping
    bool allowDirectBufferMapping;

    /// Don't use non seamless cube maps
    bool seamlessCubes;
  };

}


code:
#include "d3d9_query.h"

#include "d3d9_device.h"

namespace dxvk {

  D3D9Query::D3D9Query(
        D3D9DeviceEx*      pDevice,
        D3DQUERYTYPE       QueryType)
    : D3D9DeviceChild<IDirect3DQuery9>(pDevice)
    , m_queryType                          (QueryType)
    , m_state                              (D3D9_VK_QUERY_INITIAL) {
    Rc<DxvkDevice> dxvkDevice = m_parent->GetDXVKDevice();

    switch (m_queryType) {
      case D3DQUERYTYPE_VCACHE:
        break;

      case D3DQUERYTYPE_EVENT:
        m_event[0] = dxvkDevice->createGpuEvent();
        break;

      case D3DQUERYTYPE_OCCLUSION:
        m_query[0] = dxvkDevice->createGpuQuery(
          VK_QUERY_TYPE_OCCLUSION,
          VK_QUERY_CONTROL_PRECISE_BIT, 0);
        break;

      case D3DQUERYTYPE_TIMESTAMP:
        m_query[0] = dxvkDevice->createGpuQuery(
          VK_QUERY_TYPE_TIMESTAMP, 0, 0);
        break;

      case D3DQUERYTYPE_TIMESTAMPDISJOINT:
        for (uint32_t i = 0; i < 2; i++) {
          m_query[i] = dxvkDevice->createGpuQuery(
            VK_QUERY_TYPE_TIMESTAMP, 0, 0);
        }
        break;

      case D3DQUERYTYPE_TIMESTAMPFREQ:
        break;

      case D3DQUERYTYPE_VERTEXSTATS:
        m_query[0] = dxvkDevice->createGpuQuery(
          VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
        break;

      default:
        throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType));
    }
  }

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

    *ppvObject = nullptr;

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

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

  D3DQUERYTYPE STDMETHODCALLTYPE D3D9Query::GetType() {
    return m_queryType;
  }

  DWORD STDMETHODCALLTYPE D3D9Query::GetDataSize() {
    switch (m_queryType) {
      case D3DQUERYTYPE_VCACHE:               return sizeof(D3DDEVINFO_VCACHE);
      case D3DQUERYTYPE_RESOURCEMANAGER:      return sizeof(D3DDEVINFO_RESOURCEMANAGER);
      case D3DQUERYTYPE_VERTEXSTATS:          return sizeof(D3DDEVINFO_D3DVERTEXSTATS);
      case D3DQUERYTYPE_EVENT:                return sizeof(BOOL);
      case D3DQUERYTYPE_OCCLUSION:            return sizeof(DWORD);
      case D3DQUERYTYPE_TIMESTAMP:            return sizeof(UINT64);
      case D3DQUERYTYPE_TIMESTAMPDISJOINT:    return sizeof(BOOL);
      case D3DQUERYTYPE_TIMESTAMPFREQ:        return sizeof(UINT64);
      case D3DQUERYTYPE_PIPELINETIMINGS:      return sizeof(D3DDEVINFO_D3D9PIPELINETIMINGS);
      case D3DQUERYTYPE_INTERFACETIMINGS:     return sizeof(D3DDEVINFO_D3D9INTERFACETIMINGS);
      case D3DQUERYTYPE_VERTEXTIMINGS:        return sizeof(D3DDEVINFO_D3D9STAGETIMINGS);
      case D3DQUERYTYPE_PIXELTIMINGS:         return sizeof(D3DDEVINFO_D3D9PIPELINETIMINGS);
      case D3DQUERYTYPE_BANDWIDTHTIMINGS:     return sizeof(D3DDEVINFO_D3D9BANDWIDTHTIMINGS);
      case D3DQUERYTYPE_CACHEUTILIZATION:     return sizeof(D3DDEVINFO_D3D9CACHEUTILIZATION);
      default:                                return 0;
    }
  }

  HRESULT STDMETHODCALLTYPE D3D9Query::Issue(DWORD dwIssueFlags) {
    // Note: No need to submit to CS if we don't do anything!

    if (dwIssueFlags == D3DISSUE_BEGIN) {
      if (QueryBeginnable(m_queryType)) {
        if (m_state == D3D9_VK_QUERY_BEGUN && QueryEndable(m_queryType)) {
          m_resetCtr.fetch_add(1, std::memory_order_acquire);
          m_parent->End(this);
        }

        m_parent->Begin(this);

        m_state = D3D9_VK_QUERY_BEGUN;
      }
    }
    else {
      if (QueryEndable(m_queryType)) {
        if (m_state != D3D9_VK_QUERY_BEGUN && QueryBeginnable(m_queryType))
          m_parent->Begin(this);

        m_resetCtr.fetch_add(1, std::memory_order_acquire);

        m_parent->End(this);

      }
      m_state = D3D9_VK_QUERY_ENDED;
    }

    return D3D_OK;
  }

  HRESULT STDMETHODCALLTYPE D3D9Query::GetData(void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
    if (m_state == D3D9_VK_QUERY_CACHED) {
      // Query data was already retrieved once.
      // Use cached query data to prevent having to check the VK event
      // and having to iterate over the VK queries again
      if (likely(pData && dwSize)) {
        if (m_queryType != D3DQUERYTYPE_EVENT) {
          memcpy(pData, &m_dataCache, dwSize);
        } else {
          *static_cast<bool*>(pData) = true;
        }
      }
      return D3D_OK;
    }

    HRESULT hr = this->GetQueryData(pData, dwSize);

    bool flush = dwGetDataFlags & D3DGETDATA_FLUSH;

    // If we get S_FALSE and it's not from the fact
    // they didn't call end, do some flushy stuff...
    if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) {
      this->NotifyStall();
      m_parent->FlushImplicit(FALSE);
    }

    return hr;
  }

  HRESULT D3D9Query::GetQueryData(void* pData, DWORD dwSize) {
    // Let the game know that calling end might be a good idea...
    if (m_state == D3D9_VK_QUERY_BEGUN)
      return S_FALSE;

    if (unlikely(!pData && dwSize))
      return D3DERR_INVALIDCALL;

    // The game forgot to even issue the query!
    // Let's do it for them...
    // This will issue both the begin, and the end.
    if (m_state == D3D9_VK_QUERY_INITIAL)
      this->Issue(D3DISSUE_END);

    if (m_resetCtr != 0u)
      return S_FALSE;

    if (m_queryType == D3DQUERYTYPE_EVENT) {
      DxvkGpuEventStatus status = m_event[0]->test();

      if (status == DxvkGpuEventStatus::Invalid)
        return D3DERR_INVALIDCALL;

      bool signaled = status == DxvkGpuEventStatus::Signaled;

      if (pData != nullptr)
        *static_cast<BOOL*>(pData) = signaled;

      if (signaled) {
        m_state = D3D9_VK_QUERY_CACHED;
        return D3D_OK;
      } else {
        return S_FALSE;
      }
    }
    else {
      std::array<DxvkQueryData, MaxGpuQueries> queryData = { };

      for (uint32_t i = 0; i < MaxGpuQueries && m_query[i] != nullptr; i++) {
        DxvkGpuQueryStatus status = m_query[i]->getData(queryData[i]);

        if (status == DxvkGpuQueryStatus::Invalid
         || status == DxvkGpuQueryStatus::Failed)
          return D3DERR_INVALIDCALL;

        if (status == DxvkGpuQueryStatus::Pending)
          return S_FALSE;
      }

      if (pData == nullptr)
        return D3D_OK;

      switch (m_queryType) {
        case D3DQUERYTYPE_VCACHE:
          // Don't know what the hell any of this means.
          // Nor do I care. This just makes games work.
          m_dataCache.VCache.Pattern     = MAKEFOURCC('H', 'C', 'A', 'C');
          m_dataCache.VCache.OptMethod   = 1;
          m_dataCache.VCache.CacheSize   = 24;
          m_dataCache.VCache.MagicNumber = 20;
          break;

        case D3DQUERYTYPE_OCCLUSION:
          m_dataCache.Occlusion = DWORD(queryData[0].occlusion.samplesPassed);
          break;

        case D3DQUERYTYPE_TIMESTAMP:
          m_dataCache.Timestamp = queryData[0].timestamp.time;
          break;

        case D3DQUERYTYPE_TIMESTAMPDISJOINT:
          m_dataCache.TimestampDisjoint = queryData[0].timestamp.time < queryData[1].timestamp.time;
          break;

        case D3DQUERYTYPE_TIMESTAMPFREQ:
          m_dataCache.TimestampFreq = GetTimestampQueryFrequency();
          break;

        case D3DQUERYTYPE_VERTEXSTATS:
          m_dataCache.VertexStats.NumRenderedTriangles      = queryData[0].statistic.iaPrimitives;
          m_dataCache.VertexStats.NumExtraClippingTriangles = queryData[0].statistic.clipPrimitives;
          break;

        default:
          break;
      }

      if (likely(pData && dwSize))
        memcpy(pData, &m_dataCache, dwSize);

      m_state = D3D9_VK_QUERY_CACHED;
      return D3D_OK;
    }
  }

  UINT64 D3D9Query::GetTimestampQueryFrequency() const {
    Rc<DxvkDevice>  device  = m_parent->GetDXVKDevice();
    Rc<DxvkAdapter> adapter = device->adapter();

    VkPhysicalDeviceLimits limits = adapter->deviceProperties().limits;
    return uint64_t(1'000'000'000.0f / limits.timestampPeriod);
  }

  void D3D9Query::Begin(DxvkContext* ctx) {
    switch (m_queryType) {
      case D3DQUERYTYPE_OCCLUSION:
      case D3DQUERYTYPE_VERTEXSTATS:
        ctx->beginQuery(m_query[0]);
        break;

      case D3DQUERYTYPE_TIMESTAMPDISJOINT:
        ctx->writeTimestamp(m_query[1]);
        break;

      default: break;
    }
  }

  void D3D9Query::End(DxvkContext* ctx) {
    switch (m_queryType) {
      case D3DQUERYTYPE_TIMESTAMP:
      case D3DQUERYTYPE_TIMESTAMPDISJOINT:
        ctx->writeTimestamp(m_query[0]);
        break;

      case D3DQUERYTYPE_VERTEXSTATS:
      case D3DQUERYTYPE_OCCLUSION:
        ctx->endQuery(m_query[0]);
        break;

      case D3DQUERYTYPE_EVENT:
        ctx->signalGpuEvent(m_event[0]);
        break;

      default: break;
    }

    m_resetCtr.fetch_sub(1, std::memory_order_release);
  }

  bool D3D9Query::QueryBeginnable(D3DQUERYTYPE QueryType) {
    return QueryType == D3DQUERYTYPE_OCCLUSION
        || QueryType == D3DQUERYTYPE_VERTEXSTATS
        || QueryType == D3DQUERYTYPE_TIMESTAMPDISJOINT;
  }

  bool D3D9Query::QueryEndable(D3DQUERYTYPE QueryType) {
    return QueryBeginnable(QueryType)
        || QueryType == D3DQUERYTYPE_TIMESTAMP
        || QueryType == D3DQUERYTYPE_EVENT;
  }

  HRESULT D3D9Query::QuerySupported(D3D9DeviceEx* pDevice, D3DQUERYTYPE QueryType) {
    switch (QueryType) {
      case D3DQUERYTYPE_VCACHE:
        if (!pDevice->GetOptions()->supportVCache)
          return D3DERR_NOTAVAILABLE;

        return D3D_OK;
      case D3DQUERYTYPE_EVENT:
      case D3DQUERYTYPE_OCCLUSION:
      case D3DQUERYTYPE_TIMESTAMP:
      case D3DQUERYTYPE_TIMESTAMPDISJOINT:
      case D3DQUERYTYPE_TIMESTAMPFREQ:
      case D3DQUERYTYPE_VERTEXSTATS:
        return D3D_OK;

      default:
        return D3DERR_NOTAVAILABLE;
    }
  }

}


code:
#pragma once

#include "d3d9_device_child.h"

#include "../dxvk/dxvk_context.h"

namespace dxvk {

  enum D3D9_VK_QUERY_STATE : uint32_t {
    D3D9_VK_QUERY_INITIAL,
    D3D9_VK_QUERY_BEGUN,
    D3D9_VK_QUERY_ENDED,
    D3D9_VK_QUERY_CACHED
  };

  union D3D9_QUERY_DATA {
    D3DDEVINFO_VCACHE         VCache;
    DWORD                     Occlusion;
    UINT64                    Timestamp;
    BOOL                      TimestampDisjoint;
    UINT64                    TimestampFreq;
    D3DDEVINFO_D3DVERTEXSTATS VertexStats;
  };

  class D3D9Query : public D3D9DeviceChild<IDirect3DQuery9> {
    constexpr static uint32_t MaxGpuQueries = 2;
    constexpr static uint32_t MaxGpuEvents  = 1;
  public:

    D3D9Query(
            D3D9DeviceEx*      pDevice,
            D3DQUERYTYPE       QueryType);

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

    D3DQUERYTYPE STDMETHODCALLTYPE GetType() final;

    DWORD STDMETHODCALLTYPE GetDataSize() final;

    HRESULT STDMETHODCALLTYPE Issue(DWORD dwIssueFlags) final;

    HRESULT STDMETHODCALLTYPE GetData(void* pData, DWORD dwSize, DWORD dwGetDataFlags) final;

    HRESULT GetQueryData(void* pData, DWORD dwSize);

    void Begin(DxvkContext* ctx);
    void End(DxvkContext* ctx);

    static bool QueryBeginnable(D3DQUERYTYPE QueryType);
    static bool QueryEndable(D3DQUERYTYPE QueryType);

    static HRESULT QuerySupported(D3D9DeviceEx* pDevice, D3DQUERYTYPE QueryType);

    bool IsEvent() const {
      return m_queryType == D3DQUERYTYPE_EVENT;
    }

    bool IsStalling() const {
      return m_stallFlag;
    }

    void NotifyEnd() {
      m_stallMask <<= 1;
    }

    void NotifyStall() {
      m_stallMask |= 1;
      m_stallFlag |= bit::popcnt(m_stallMask) >= 16;
    }

  private:

    D3DQUERYTYPE      m_queryType;

    D3D9_VK_QUERY_STATE m_state;

    std::array<Rc<DxvkGpuQuery>, MaxGpuQueries> m_query;
    std::array<Rc<DxvkGpuEvent>, MaxGpuEvents>  m_event;

    uint32_t m_stallMask = 0;
    bool     m_stallFlag = false;

    std::atomic<uint32_t> m_resetCtr = { 0u };

    D3D9_QUERY_DATA m_dataCache;

    UINT64 GetTimestampQueryFrequency() const;

  };

}


code:
#pragma once

#include "d3d9_device_child.h"

#include "../util/com/com_private_data.h"

namespace dxvk {

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

  public:

    D3D9Resource(D3D9DeviceEx* pDevice)
      : D3D9DeviceChild<Type...>(pDevice)
      , m_priority              ( 0 ) { }

    HRESULT STDMETHODCALLTYPE SetPrivateData(
            REFGUID     refguid,
      const void*       pData,
            DWORD       SizeOfData,
            DWORD       Flags) final {
      HRESULT hr;
      if (Flags & D3DSPD_IUNKNOWN) {
        IUnknown* unknown =
          const_cast<IUnknown*>(
            reinterpret_cast<const IUnknown*>(pData));
        hr = m_privateData.setInterface(
          refguid, unknown);
      }
      else
        hr = m_privateData.setData(
          refguid, SizeOfData, pData);

      if (FAILED(hr))
        return D3DERR_INVALIDCALL;

      return D3D_OK;
    }

    HRESULT STDMETHODCALLTYPE GetPrivateData(
            REFGUID     refguid,
            void*       pData,
            DWORD*      pSizeOfData) final {
      HRESULT hr = m_privateData.getData(
        refguid, reinterpret_cast<UINT*>(pSizeOfData), pData);

      if (FAILED(hr))
        return D3DERR_INVALIDCALL;

      return D3D_OK;
    }

    HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) final {
      HRESULT hr = m_privateData.setData(refguid, 0, nullptr);

      if (FAILED(hr))
        return D3DERR_INVALIDCALL;

      return D3D_OK;
    }

    DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) {
      DWORD oldPriority = m_priority;
      m_priority = PriorityNew;
      return oldPriority;
    }

    DWORD STDMETHODCALLTYPE GetPriority() {
      return m_priority;
    }

  protected:

    DWORD m_priority;

  private:

    ComPrivateData m_privateData;

  };

}