code:
#pragma once

#include <unordered_set>

#include "spirv_code_buffer.h"

namespace dxvk {

  struct SpirvPhiLabel {
    uint32_t varId         = 0;
    uint32_t labelId       = 0;
  };

  struct SpirvSwitchCaseLabel {
    uint32_t literal       = 0;
    uint32_t labelId       = 0;
  };

  struct SpirvImageOperands {
    uint32_t flags         = 0;
    uint32_t sLodBias      = 0;
    uint32_t sLod          = 0;
    uint32_t sConstOffset  = 0;
    uint32_t sGradX        = 0;
    uint32_t sGradY        = 0;
    uint32_t gOffset       = 0;
    uint32_t gConstOffsets = 0;
    uint32_t sSampleId     = 0;
    uint32_t sMinLod       = 0;
  };

  constexpr uint32_t spvVersion(uint32_t major, uint32_t minor) {
    return (major << 16) | (minor << 8);
  }

  /**
   * \brief SPIR-V module
   *
   * This class generates a code buffer containing a full
   * SPIR-V shader module. Ensures that the module layout
   * is valid, as defined in the SPIR-V 1.0 specification,
   * section 2.4 "Logical Layout of a Module".
   */
  class SpirvModule {

  public:

    explicit SpirvModule(uint32_t version);

    ~SpirvModule();

    SpirvCodeBuffer compile() const;

    size_t getInsertionPtr() {
      return m_code.getInsertionPtr();
    }

    void beginInsertion(size_t ptr) {
      m_code.beginInsertion(ptr);
    }

    void endInsertion() {
      m_code.endInsertion();
    }

    uint32_t allocateId();

    bool hasCapability(
            spv::Capability         capability);

    void enableCapability(
            spv::Capability         capability);

    void enableExtension(
      const char*                   extensionName);

    void addEntryPoint(
            uint32_t                entryPointId,
            spv::ExecutionModel     executionModel,
      const char*                   name,
            uint32_t                interfaceCount,
      const uint32_t*               interfaceIds);

    void setMemoryModel(
            spv::AddressingModel    addressModel,
            spv::MemoryModel        memoryModel);

    void setExecutionMode(
            uint32_t                entryPointId,
            spv::ExecutionMode      executionMode);

    void setExecutionMode(
            uint32_t                entryPointId,
            spv::ExecutionMode      executionMode,
            uint32_t                argCount,
      const uint32_t*               args);

    void setInvocations(
            uint32_t                entryPointId,
            uint32_t                invocations);

    void setLocalSize(
            uint32_t                entryPointId,
            uint32_t                x,
            uint32_t                y,
            uint32_t                z);

    void setOutputVertices(
            uint32_t                entryPointId,
            uint32_t                vertexCount);

    uint32_t addDebugString(
      const char*                   string);

    void setDebugSource(
            spv::SourceLanguage     language,
            uint32_t                version,
            uint32_t                file,
      const char*                   source);

    void setDebugName(
            uint32_t                expressionId,
      const char*                   debugName);

    void setDebugMemberName(
            uint32_t                structId,
            uint32_t                memberId,
      const char*                   debugName);

    uint32_t constBool(
            bool                    v);

    uint32_t consti32(
            int32_t                 v);

    uint32_t consti64(
            int64_t                 v);

    uint32_t constu32(
            uint32_t                v);

    uint32_t constu64(
            uint64_t                v);

    uint32_t constf32(
            float                   v);

    uint32_t constf64(
            double                  v);

    uint32_t constvec4i32(
            int32_t                 x,
            int32_t                 y,
            int32_t                 z,
            int32_t                 w);

    uint32_t constvec4b32(
            bool                    x,
            bool                    y,
            bool                    z,
            bool                    w);

    uint32_t constvec4u32(
            uint32_t                x,
            uint32_t                y,
            uint32_t                z,
            uint32_t                w);

    uint32_t constvec2f32(
            float                   x,
            float                   y);

    uint32_t constvec3f32(
            float                   x,
            float                   y,
            float                   z);

    uint32_t constvec4f32(
            float                   x,
            float                   y,
            float                   z,
            float                   w);

    uint32_t constfReplicant(
            float                   replicant,
            uint32_t                count);

    uint32_t constbReplicant(
            bool                    replicant,
            uint32_t                count);

    uint32_t constiReplicant(
            int32_t                 replicant,
            uint32_t                count);

    uint32_t constuReplicant(
            int32_t                 replicant,
            uint32_t                count);

    uint32_t constComposite(
            uint32_t                typeId,
            uint32_t                constCount,
      const uint32_t*               constIds);

    uint32_t constUndef(
            uint32_t                typeId);

    uint32_t lateConst32(
            uint32_t                typeId);

    void setLateConst(
            uint32_t                constId,
      const uint32_t*               argIds);

    uint32_t specConstBool(
            bool                    v);

    uint32_t specConst32(
            uint32_t                typeId,
            uint32_t                value);

    void decorate(
            uint32_t                object,
            spv::Decoration         decoration);

    void decorateArrayStride(
            uint32_t                object,
            uint32_t                stride);

    void decorateBinding(
            uint32_t                object,
            uint32_t                binding);

    void decorateBlock(
            uint32_t                object);

    void decorateBuiltIn(
            uint32_t                object,
            spv::BuiltIn            builtIn);

    void decorateComponent(
            uint32_t                object,
            uint32_t                location);

    void decorateDescriptorSet(
            uint32_t                object,
            uint32_t                set);

    void decorateIndex(
            uint32_t                object,
            uint32_t                index);

    void decorateLocation(
            uint32_t                object,
            uint32_t                location);

    void decorateSpecId(
            uint32_t                object,
            uint32_t                specId);

    void decorateXfb(
            uint32_t                object,
            uint32_t                streamId,
            uint32_t                bufferId,
            uint32_t                offset,
            uint32_t                stride);

    void memberDecorateBuiltIn(
            uint32_t                structId,
            uint32_t                memberId,
            spv::BuiltIn            builtIn);

    void memberDecorate(
            uint32_t                structId,
            uint32_t                memberId,
            spv::Decoration         decoration);

    void memberDecorateMatrixStride(
            uint32_t                structId,
            uint32_t                memberId,
            uint32_t                stride);

    void memberDecorateOffset(
            uint32_t                structId,
            uint32_t                memberId,
            uint32_t                offset);

    uint32_t defVoidType();

    uint32_t defBoolType();

    uint32_t defIntType(
            uint32_t                width,
            uint32_t                isSigned);

    uint32_t defFloatType(
            uint32_t                width);

    uint32_t defVectorType(
            uint32_t                elementType,
            uint32_t                elementCount);

    uint32_t defMatrixType(
            uint32_t                columnType,
            uint32_t                columnCount);

    uint32_t defArrayType(
            uint32_t                typeId,
            uint32_t                length);

    uint32_t defArrayTypeUnique(
            uint32_t                typeId,
            uint32_t                length);

    uint32_t defRuntimeArrayType(
            uint32_t                typeId);

    uint32_t defRuntimeArrayTypeUnique(
            uint32_t                typeId);

    uint32_t defFunctionType(
            uint32_t                returnType,
            uint32_t                argCount,
      const uint32_t*               argTypes);

    uint32_t defStructType(
            uint32_t                memberCount,
      const uint32_t*               memberTypes);

    uint32_t defStructTypeUnique(
            uint32_t                memberCount,
      const uint32_t*               memberTypes);

    uint32_t defPointerType(
            uint32_t                variableType,
            spv::StorageClass       storageClass);

    uint32_t defSamplerType();

    uint32_t defImageType(
            uint32_t                sampledType,
            spv::Dim                dimensionality,
            uint32_t                depth,
            uint32_t                arrayed,
            uint32_t                multisample,
            uint32_t                sampled,
            spv::ImageFormat        format);

    uint32_t defSampledImageType(
            uint32_t                imageType);

    uint32_t newVar(
            uint32_t                pointerType,
            spv::StorageClass       storageClass);

    uint32_t newVarInit(
            uint32_t                pointerType,
            spv::StorageClass       storageClass,
            uint32_t                initialValue);

    void functionBegin(
            uint32_t                returnType,
            uint32_t                functionId,
            uint32_t                functionType,
      spv::FunctionControlMask      functionControl);

    uint32_t functionParameter(
            uint32_t                parameterType);

    void functionEnd();

    uint32_t opAccessChain(
            uint32_t                resultType,
            uint32_t                composite,
            uint32_t                indexCount,
      const uint32_t*               indexArray);

    uint32_t opArrayLength(
            uint32_t                resultType,
            uint32_t                structure,
            uint32_t                memberId);

    uint32_t opAny(
            uint32_t                resultType,
            uint32_t                vector);

    uint32_t opAll(
            uint32_t                resultType,
            uint32_t                vector);

    uint32_t opAtomicLoad(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics);

    void opAtomicStore(
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicExchange(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicCompareExchange(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                equal,
            uint32_t                unequal,
            uint32_t                value,
            uint32_t                comparator);

    uint32_t opAtomicIIncrement(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics);

    uint32_t opAtomicIDecrement(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics);

    uint32_t opAtomicIAdd(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicISub(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicSMin(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicSMax(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicUMin(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicUMax(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicAnd(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicOr(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opAtomicXor(
            uint32_t                resultType,
            uint32_t                pointer,
            uint32_t                scope,
            uint32_t                semantics,
            uint32_t                value);

    uint32_t opBitcast(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opBitCount(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opBitReverse(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFindILsb(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFindUMsb(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFindSMsb(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opBitFieldInsert(
            uint32_t                resultType,
            uint32_t                base,
            uint32_t                insert,
            uint32_t                offset,
            uint32_t                count);

    uint32_t opBitFieldSExtract(
            uint32_t                resultType,
            uint32_t                base,
            uint32_t                offset,
            uint32_t                count);

    uint32_t opBitFieldUExtract(
            uint32_t                resultType,
            uint32_t                base,
            uint32_t                offset,
            uint32_t                count);

    uint32_t opBitwiseAnd(
            uint32_t                resultType,
            uint32_t                operand1,
            uint32_t                operand2);

    uint32_t opBitwiseOr(
            uint32_t                resultType,
            uint32_t                operand1,
            uint32_t                operand2);

    uint32_t opBitwiseXor(
            uint32_t                resultType,
            uint32_t                operand1,
            uint32_t                operand2);

    uint32_t opNot(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opShiftLeftLogical(
            uint32_t                resultType,
            uint32_t                base,
            uint32_t                shift);

    uint32_t opShiftRightArithmetic(
            uint32_t                resultType,
            uint32_t                base,
            uint32_t                shift);

    uint32_t opShiftRightLogical(
            uint32_t                resultType,
            uint32_t                base,
            uint32_t                shift);

    uint32_t opConvertFtoS(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opConvertFtoU(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opConvertStoF(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opConvertUtoF(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opCompositeConstruct(
            uint32_t                resultType,
            uint32_t                valueCount,
      const uint32_t*               valueArray);

    uint32_t opCompositeExtract(
            uint32_t                resultType,
            uint32_t                composite,
            uint32_t                indexCount,
      const uint32_t*               indexArray);

    uint32_t opCompositeInsert(
            uint32_t                resultType,
            uint32_t                object,
            uint32_t                composite,
            uint32_t                indexCount,
      const uint32_t*               indexArray);

    uint32_t opDpdx(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opDpdy(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opDpdxCoarse(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opDpdyCoarse(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opDpdxFine(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opDpdyFine(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opVectorExtractDynamic(
            uint32_t                resultType,
            uint32_t                vector,
            uint32_t                index);

    uint32_t opVectorShuffle(
            uint32_t                resultType,
            uint32_t                vectorLeft,
            uint32_t                vectorRight,
            uint32_t                indexCount,
      const uint32_t*               indexArray);

    uint32_t opSNegate(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFNegate(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opSAbs(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFAbs(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFSign(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFMix(
            uint32_t                resultType,
            uint32_t                x,
            uint32_t                y,
            uint32_t                a);

  uint32_t opCross(
            uint32_t                resultType,
            uint32_t                x,
            uint32_t                y);

    uint32_t opIAdd(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opISub(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opFAdd(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opFSub(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opSDiv(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opUDiv(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opSRem(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opUMod(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opFDiv(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opIMul(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opFMul(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opVectorTimesScalar(
            uint32_t                resultType,
            uint32_t                vector,
            uint32_t                scalar);

    uint32_t opMatrixTimesMatrix(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opMatrixTimesVector(
            uint32_t                resultType,
            uint32_t                matrix,
            uint32_t                vector);

    uint32_t opVectorTimesMatrix(
            uint32_t                resultType,
            uint32_t                vector,
            uint32_t                matrix);

    uint32_t opTranspose(
            uint32_t                resultType,
            uint32_t                matrix);

    uint32_t opInverse(
            uint32_t                resultType,
            uint32_t                matrix);

    uint32_t opFFma(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b,
            uint32_t                c);

    uint32_t opFMax(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opFMin(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opNMax(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opNMin(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opSMax(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opSMin(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opUMax(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opUMin(
            uint32_t                resultType,
            uint32_t                a,
            uint32_t                b);

    uint32_t opFClamp(
            uint32_t                resultType,
            uint32_t                x,
            uint32_t                minVal,
            uint32_t                maxVal);

    uint32_t opNClamp(
            uint32_t                resultType,
            uint32_t                x,
            uint32_t                minVal,
            uint32_t                maxVal);

    uint32_t opIEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opINotEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opSLessThan(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opSLessThanEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opSGreaterThan(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opSGreaterThanEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opULessThan(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opULessThanEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opUGreaterThan(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opUGreaterThanEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opFOrdEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opFOrdNotEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opFOrdLessThan(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opFOrdLessThanEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opFOrdGreaterThan(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opFOrdGreaterThanEqual(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opLogicalEqual(
            uint32_t                resultType,
            uint32_t                operand1,
            uint32_t                operand2);

    uint32_t opLogicalNotEqual(
            uint32_t                resultType,
            uint32_t                operand1,
            uint32_t                operand2);

    uint32_t opLogicalAnd(
            uint32_t                resultType,
            uint32_t                operand1,
            uint32_t                operand2);

    uint32_t opLogicalOr(
            uint32_t                resultType,
            uint32_t                operand1,
            uint32_t                operand2);

    uint32_t opLogicalNot(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opDot(
            uint32_t                resultType,
            uint32_t                vector1,
            uint32_t                vector2);

    uint32_t opSin(
            uint32_t                resultType,
            uint32_t                vector);

    uint32_t opCos(
            uint32_t                resultType,
            uint32_t                vector);

    uint32_t opSqrt(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opInverseSqrt(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opNormalize(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opReflect(
            uint32_t                resultType,
            uint32_t                incident,
            uint32_t                normal);

    uint32_t opLength(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opExp2(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opExp(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opLog2(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opPow(
            uint32_t                resultType,
            uint32_t                base,
            uint32_t                exponent);

    uint32_t opFract(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opCeil(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFloor(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opRound(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opRoundEven(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opTrunc(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFConvert(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opPackHalf2x16(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opUnpackHalf2x16(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opSelect(
            uint32_t                resultType,
            uint32_t                condition,
            uint32_t                operand1,
            uint32_t                operand2);

    uint32_t opIsNan(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opIsInf(
            uint32_t                resultType,
            uint32_t                operand);

    uint32_t opFunctionCall(
            uint32_t                resultType,
            uint32_t                functionId,
            uint32_t                argCount,
      const uint32_t*               argIds);

    void opLabel(
            uint32_t                labelId);

    uint32_t opLoad(
            uint32_t                typeId,
            uint32_t                pointerId);

    void opStore(
            uint32_t                pointerId,
            uint32_t                valueId);

    uint32_t opInterpolateAtCentroid(
            uint32_t                resultType,
            uint32_t                interpolant);

    uint32_t opInterpolateAtSample(
            uint32_t                resultType,
            uint32_t                interpolant,
            uint32_t                sample);

    uint32_t opInterpolateAtOffset(
            uint32_t                resultType,
            uint32_t                interpolant,
            uint32_t                offset);

    uint32_t opImage(
            uint32_t                resultType,
            uint32_t                sampledImage);

    uint32_t opImageRead(
            uint32_t                resultType,
            uint32_t                image,
            uint32_t                coordinates,
      const SpirvImageOperands&     operands);

    void opImageWrite(
            uint32_t                image,
            uint32_t                coordinates,
            uint32_t                texel,
      const SpirvImageOperands&     operands);

    uint32_t opImageTexelPointer(
            uint32_t                resultType,
            uint32_t                image,
            uint32_t                coordinates,
            uint32_t                sample);

    uint32_t opSampledImage(
            uint32_t                resultType,
            uint32_t                image,
            uint32_t                sampler);

    uint32_t opImageQuerySizeLod(
            uint32_t                resultType,
            uint32_t                image,
            uint32_t                lod);

    uint32_t opImageQuerySize(
            uint32_t                resultType,
            uint32_t                image);

    uint32_t opImageQueryLevels(
            uint32_t                resultType,
            uint32_t                image);

    uint32_t opImageQueryLod(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates);

    uint32_t opImageQuerySamples(
            uint32_t                resultType,
            uint32_t                image);

    uint32_t opImageFetch(
            uint32_t                resultType,
            uint32_t                image,
            uint32_t                coordinates,
      const SpirvImageOperands&     operands);

    uint32_t opImageGather(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
            uint32_t                component,
      const SpirvImageOperands&     operands);

    uint32_t opImageDrefGather(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
            uint32_t                reference,
      const SpirvImageOperands&     operands);

    uint32_t opImageSampleImplicitLod(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
      const SpirvImageOperands&     operands);

    uint32_t opImageSampleExplicitLod(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
      const SpirvImageOperands&     operands);

    uint32_t opImageSampleProjImplicitLod(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
      const SpirvImageOperands&     operands);

    uint32_t opImageSampleProjExplicitLod(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
      const SpirvImageOperands&     operands);

    uint32_t opImageSampleDrefImplicitLod(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
            uint32_t                reference,
      const SpirvImageOperands&     operands);

    uint32_t opImageSampleDrefExplicitLod(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
            uint32_t                reference,
      const SpirvImageOperands&     operands);

    uint32_t opImageSampleProjDrefImplicitLod(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
            uint32_t                reference,
      const SpirvImageOperands&     operands);

    uint32_t opImageSampleProjDrefExplicitLod(
            uint32_t                resultType,
            uint32_t                sampledImage,
            uint32_t                coordinates,
            uint32_t                reference,
      const SpirvImageOperands&     operands);

    uint32_t opGroupNonUniformBallot(
            uint32_t                resultType,
            uint32_t                execution,
            uint32_t                predicate);

    uint32_t opGroupNonUniformBallotBitCount(
            uint32_t                resultType,
            uint32_t                execution,
            uint32_t                operation,
            uint32_t                ballot);

    uint32_t opGroupNonUniformElect(
            uint32_t                resultType,
            uint32_t                execution);

    uint32_t opGroupNonUniformBroadcastFirst(
            uint32_t                resultType,
            uint32_t                execution,
            uint32_t                value);

    void opControlBarrier(
            uint32_t                execution,
            uint32_t                memory,
            uint32_t                semantics);

    void opMemoryBarrier(
            uint32_t                memory,
            uint32_t                semantics);

    void opLoopMerge(
            uint32_t                mergeBlock,
            uint32_t                continueTarget,
            uint32_t                loopControl);

    void opSelectionMerge(
            uint32_t                mergeBlock,
            uint32_t                selectionControl);

    void opBranch(
            uint32_t                label);

    void opBranchConditional(
            uint32_t                condition,
            uint32_t                trueLabel,
            uint32_t                falseLabel);

    void opSwitch(
            uint32_t                selector,
            uint32_t                jumpDefault,
            uint32_t                caseCount,
      const SpirvSwitchCaseLabel*   caseLabels);

    uint32_t opPhi(
            uint32_t                resultType,
            uint32_t                sourceCount,
      const SpirvPhiLabel*          sourceLabels);

    void opReturn();

    void opKill();

    void opDemoteToHelperInvocation();

    void opEmitVertex(
            uint32_t                streamId);

    void opEndPrimitive(
            uint32_t                streamId);

  private:

    uint32_t m_version;
    uint32_t m_id             = 1;
    uint32_t m_instExtGlsl450 = 0;

    SpirvCodeBuffer m_capabilities;
    SpirvCodeBuffer m_extensions;
    SpirvCodeBuffer m_instExt;
    SpirvCodeBuffer m_memoryModel;
    SpirvCodeBuffer m_entryPoints;
    SpirvCodeBuffer m_execModeInfo;
    SpirvCodeBuffer m_debugNames;
    SpirvCodeBuffer m_annotations;
    SpirvCodeBuffer m_typeConstDefs;
    SpirvCodeBuffer m_variables;
    SpirvCodeBuffer m_code;

    std::unordered_set<uint32_t> m_lateConsts;

    uint32_t defType(
            spv::Op                 op,
            uint32_t                argCount,
      const uint32_t*               argIds);

    uint32_t defConst(
            spv::Op                 op,
            uint32_t                typeId,
            uint32_t                argCount,
      const uint32_t*               argIds);

    void instImportGlsl450();

    uint32_t getImageOperandWordCount(
      const SpirvImageOperands&     op) const;

    void putImageOperands(
      const SpirvImageOperands&     op);

  };

}

repo_name: orochi/dxvk


code:
#include "com_guid.h"

#include "../../d3d11/d3d11_interfaces.h"

#include "../../dxgi/dxgi_interfaces.h"

std::ostream& operator << (std::ostream& os, REFIID guid) {
  os << std::hex << std::setfill('0')
     << std::setw(8) << guid.Data1 << '-';

  os << std::hex << std::setfill('0')
     << std::setw(4) << guid.Data2 << '-';

  os << std::hex << std::setfill('0')
     << std::setw(4) << guid.Data3 << '-';

  os << std::hex << std::setfill('0')
     << std::setw(2) << static_cast<short>(guid.Data4[0])
     << std::setw(2) << static_cast<short>(guid.Data4[1])
     << '-'
     << std::setw(2) << static_cast<short>(guid.Data4[2])
     << std::setw(2) << static_cast<short>(guid.Data4[3])
     << std::setw(2) << static_cast<short>(guid.Data4[4])
     << std::setw(2) << static_cast<short>(guid.Data4[5])
     << std::setw(2) << static_cast<short>(guid.Data4[6])
     << std::setw(2) << static_cast<short>(guid.Data4[7]);
  return os;
}


code:
#pragma once

#include <ostream>
#include <iomanip>

#include "com_include.h"

std::ostream& operator << (std::ostream& os, REFIID guid);


code:
#pragma once

// GCC complains about the COM interfaces
// not having virtual destructors
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif // __GNUC__

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <unknwn.h>

// GCC: -std options disable certain keywords
// https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html
#if defined(__WINE__) && !defined(typeof)
#define typeof __typeof
#endif


code:
#pragma once

#include <atomic>

#include "com_include.h"

#include "../util_likely.h"

namespace dxvk {

  template<typename T>
  class NoWrapper : public T {

  public:

    virtual ~NoWrapper() { }

  };

  /**
   * \brief Reference-counted COM object
   *
   * This can serve as a templated base class for most
   * COM objects. It implements AddRef and Release from
   * \c IUnknown, and provides methods to increment and
   * decrement private references which are not visible
   * to the application.
   *
   * Having two reference counters is sadly necessary
   * in order to not break games which steal internal
   * references if the refefence count of an object is
   + greater than they expect. DXVK sometimes requires
   * holding on to objects which the application wants
   * to delete.
   */
  template<typename Base>
  class ComObject : public Base {

  public:

    virtual ~ComObject() { }

    ULONG STDMETHODCALLTYPE AddRef() {
      uint32_t refCount = m_refCount++;
      if (unlikely(!refCount))
        AddRefPrivate();
      return refCount + 1;
    }

    ULONG STDMETHODCALLTYPE Release() {
      uint32_t refCount = --m_refCount;
      if (unlikely(!refCount))
        ReleasePrivate();
      return refCount;
    }

    void AddRefPrivate() {
      ++m_refPrivate;
    }

    void ReleasePrivate() {
      uint32_t refPrivate = --m_refPrivate;
      if (unlikely(!refPrivate)) {
        m_refPrivate += 0x80000000;
        delete this;
      }
    }

    ULONG GetPrivateRefCount() {
      return m_refPrivate.load();
    }

  protected:

    std::atomic<uint32_t> m_refCount   = { 0ul };
    std::atomic<uint32_t> m_refPrivate = { 0ul };

  };

  /**
   * \brief Clamped, reference-counted COM object
   *
   * This version of ComObject ensures that the reference
   * count does not wrap around if a release happens at zero.
   * eg. [m_refCount = 0]
   *     Release()
   *     [m_refCount = 0]
   * This is a notable quirk of D3D9's COM implementation
   * and is relied upon by some games.
   */
  template<typename Base>
  class ComObjectClamp : public ComObject<Base> {

  public:

    ULONG STDMETHODCALLTYPE Release() {
      ULONG refCount = this->m_refCount;
      if (likely(refCount != 0ul)) {
        this->m_refCount--;
        refCount--;

        if (refCount == 0ul)
          this->ReleasePrivate();
      }

      return refCount;
    }

  };

  template<typename T>
  inline void InitReturnPtr(T** ptr) {
    if (ptr != nullptr)
      *ptr = nullptr;
  }

}


code:
#pragma once

#include "com_include.h"

namespace dxvk {

  /**
   * \brief Increment public ref count
   *
   * If the pointer is not \c nullptr, this
   * calls \c AddRef for the given object.
   * \returns Pointer to the object
   */
  template<typename T>
  T* ref(T* object) {
    if (object != nullptr)
      object->AddRef();
    return object;
  }

  /**
   * \brief Ref count methods for public references
   */
  template<typename T, bool Public>
  struct ComRef_ {
    static void incRef(T* ptr) { ptr->AddRef(); }
    static void decRef(T* ptr) { ptr->Release(); }
  };

  /**
   * \brief Ref count methods for private references
   */
  template<typename T>
  struct ComRef_<T, false> {
    static void incRef(T* ptr) { ptr->AddRefPrivate(); }
    static void decRef(T* ptr) { ptr->ReleasePrivate(); }
  };

  /**
   * \brief COM pointer
   *
   * Implements automatic reference
   * counting for COM objects.
   */
  template<typename T, bool Public = true>
  class Com {
    using ComRef = ComRef_<T, Public>;
  public:

    Com() { }
    Com(std::nullptr_t) { }
    Com(T* object)
    : m_ptr(object) {
      this->incRef();
    }

    Com(const Com& other)
    : m_ptr(other.m_ptr) {
      this->incRef();
    }

    Com(Com&& other)
    : m_ptr(other.m_ptr) {
      other.m_ptr = nullptr;
    }

    Com& operator = (T* object) {
      this->decRef();
      m_ptr = object;
      this->incRef();
      return *this;
    }

    Com& operator = (const Com& other) {
      other.incRef();
      this->decRef();
      m_ptr = other.m_ptr;
      return *this;
    }

    Com& operator = (Com&& other) {
      this->decRef();
      this->m_ptr = other.m_ptr;
      other.m_ptr = nullptr;
      return *this;
    }

    Com& operator = (std::nullptr_t) {
      this->decRef();
      m_ptr = nullptr;
      return *this;
    }

    ~Com() {
      this->decRef();
    }

    T* operator -> () const {
      return m_ptr;
    }

    T**       operator & ()       { return &m_ptr; }
    T* const* operator & () const { return &m_ptr; }

    template<bool Public_>
    bool operator == (const Com<T, Public_>& other) const { return m_ptr == other.m_ptr; }
    template<bool Public_>
    bool operator != (const Com<T, Public_>& other) const { return m_ptr != other.m_ptr; }

    bool operator == (const T* other) const { return m_ptr == other; }
    bool operator != (const T* other) const { return m_ptr != other; }

    bool operator == (std::nullptr_t) const { return m_ptr == nullptr; }
    bool operator != (std::nullptr_t) const { return m_ptr != nullptr; }

    T* ref() const {
      return dxvk::ref(m_ptr);
    }

    T* ptr() const {
      return m_ptr;
    }

    Com<T, true>  pubRef() const { return m_ptr; }
    Com<T, false> prvRef() const { return m_ptr; }

  private:

    T* m_ptr = nullptr;

    void incRef() const {
      if (m_ptr != nullptr)
        ComRef::incRef(m_ptr);
    }

    void decRef() const {
      if (m_ptr != nullptr)
        ComRef::decRef(m_ptr);
    }

  };

}


code:
#include <cmath>
#include <cstring>
#include <cstdlib>

#include "com_private_data.h"

namespace dxvk {

  ComPrivateDataEntry::ComPrivateDataEntry() { }
  ComPrivateDataEntry::ComPrivateDataEntry(
          REFGUID   guid,
          UINT      size,
    const void*     data)
  : m_guid(guid),
    m_type(ComPrivateDataType::Data),
    m_size(size),
    m_data(std::malloc(size)) {
    std::memcpy(m_data, data, size);
  }

  ComPrivateDataEntry::ComPrivateDataEntry(
          REFGUID   guid,
    const IUnknown* iface)
  : m_guid  (guid),
    m_type(ComPrivateDataType::Iface),
    m_iface (const_cast<IUnknown*>(iface)) {
    if (m_iface)
      m_iface->AddRef();
  }

  ComPrivateDataEntry::~ComPrivateDataEntry() {
    this->destroy();
  }

  ComPrivateDataEntry::ComPrivateDataEntry(ComPrivateDataEntry&& other)
  : m_guid  (other.m_guid),
    m_type  (other.m_type),
    m_size  (other.m_size),
    m_data  (other.m_data),
    m_iface (other.m_iface) {
    other.m_guid  = __uuidof(IUnknown);
    other.m_type  = ComPrivateDataType::None;
    other.m_size  = 0;
    other.m_data  = nullptr;
    other.m_iface = nullptr;
  }

  ComPrivateDataEntry& ComPrivateDataEntry::operator = (ComPrivateDataEntry&& other) {
    this->destroy();
    this->m_guid  = other.m_guid;
    this->m_type  = other.m_type;
    this->m_size  = other.m_size;
    this->m_data  = other.m_data;
    this->m_iface = other.m_iface;

    other.m_guid  = __uuidof(IUnknown);
    other.m_type  = ComPrivateDataType::None;
    other.m_size  = 0;
    other.m_data  = nullptr;
    other.m_iface = nullptr;
    return *this;
  }

  HRESULT ComPrivateDataEntry::get(UINT& size, void* data) const {
    UINT minSize = 0;

    if (m_type == ComPrivateDataType::Iface) minSize = sizeof(IUnknown*);
    if (m_type == ComPrivateDataType::Data)  minSize = m_size;

    if (!data) {
      size = minSize;
      return S_OK;
    }

    HRESULT result = size < minSize
      ? DXGI_ERROR_MORE_DATA
      : S_OK;

    if (size >= minSize) {
      if (m_type == ComPrivateDataType::Iface) {
        if (m_iface)
          m_iface->AddRef();
        std::memcpy(data, &m_iface, minSize);
      } else {
        std::memcpy(data, m_data, minSize);
      }
    }

    size = minSize;
    return result;
  }

  void ComPrivateDataEntry::destroy() {
    if (m_data)
      std::free(m_data);
    if (m_iface)
      m_iface->Release();
  }

  HRESULT ComPrivateData::setData(
          REFGUID   guid,
          UINT      size,
    const void*     data) {
    if (!data) {
      for (auto it = m_entries.begin(); it != m_entries.end(); ++it) {
        if (it->hasGuid(guid)) {
          m_entries.erase(it);
          return S_OK;
        }
      }
      return S_FALSE;
    }
    this->insertEntry(ComPrivateDataEntry(guid, size, data));
    return S_OK;
  }

  HRESULT ComPrivateData::setInterface(
          REFGUID   guid,
    const IUnknown* iface) {
    this->insertEntry(ComPrivateDataEntry(guid, iface));
    return S_OK;
  }

  HRESULT ComPrivateData::getData(
          REFGUID   guid,
          UINT*     size,
          void*     data) {
    if (!size)
      return E_INVALIDARG;

    auto entry = this->findEntry(guid);

    if (!entry) {
      *size = 0;
      return DXGI_ERROR_NOT_FOUND;
    }

    return entry->get(*size, data);
  }

  ComPrivateDataEntry* ComPrivateData::findEntry(REFGUID guid) {
    for (ComPrivateDataEntry& e : m_entries) {
      if (e.hasGuid(guid))
        return &e;
    }

    return nullptr;
  }

  void ComPrivateData::insertEntry(ComPrivateDataEntry&& entry) {
    ComPrivateDataEntry  srcEntry = std::move(entry);
    ComPrivateDataEntry* dstEntry = this->findEntry(srcEntry.guid());

    if (dstEntry)
      *dstEntry = std::move(srcEntry);
    else
      m_entries.push_back(std::move(srcEntry));
  }

}


code:
#pragma once

#include <vector>

#include "com_include.h"

namespace dxvk {

  /**
   * \brief COM private data entry type
   */
  enum ComPrivateDataType {
    None,
    Data,
    Iface,
  };

  /**
   * \brief Data entry for private storage
   * Stores a single private storage item.
   */
  class ComPrivateDataEntry {

  public:

    ComPrivateDataEntry();
    ComPrivateDataEntry(
            REFGUID   guid,
            UINT      size,
      const void*     data);
    ComPrivateDataEntry(
            REFGUID   guid,
      const IUnknown* iface);
    ~ComPrivateDataEntry();

    ComPrivateDataEntry             (ComPrivateDataEntry&& other);
    ComPrivateDataEntry& operator = (ComPrivateDataEntry&& other);

    /**
     * \brief The entry's GUID
     * \returns The GUID
     */
    REFGUID guid() const {
      return m_guid;
    }

    /**
     * \brief Checks whether the GUID matches another one
     *
     * GUIDs are used to identify private data entries.
     * \param [in] guid The GUID to compare to
     * \returns \c true if this entry holds the same GUID
     */
    bool hasGuid(REFGUID guid) const {
      return m_guid == guid;
    }

    /**
     * \brief Retrieves stored data
     *
     * \param [in,out] size Destination buffer size
     * \param [in] data Appliaction-provided buffer
     * \returns \c S_OK on success, or \c DXGI_ERROR_MORE_DATA
     *          if the destination buffer is too small
     */
    HRESULT get(UINT& size, void* data) const;

  private:

    GUID                m_guid  = __uuidof(IUnknown);
    ComPrivateDataType  m_type  = ComPrivateDataType::None;
    UINT                m_size  = 0;
    void*               m_data  = nullptr;
    IUnknown*           m_iface = nullptr;

    void destroy();

  };

  /**
   * \brief Private storage for DXGI objects
   *
   * Provides storage for application-defined
   * byte arrays or COM interfaces that can be
   * retrieved using GUIDs.
   */
  class ComPrivateData {

  public:

    HRESULT setData(
            REFGUID   guid,
            UINT      size,
      const void*     data);

    HRESULT setInterface(
            REFGUID   guid,
      const IUnknown* iface);

    HRESULT getData(
            REFGUID   guid,
            UINT*     size,
            void*     data);

  private:

    std::vector<ComPrivateDataEntry> m_entries;

    ComPrivateDataEntry* findEntry(REFGUID guid);
    void insertEntry(ComPrivateDataEntry&& entry);

  };

}


code:
#include <array>
#include <fstream>
#include <sstream>
#include <iostream>
#include <regex>
#include <utility>

#include "config.h"

#include "../log/log.h"

#include "../util_env.h"

namespace dxvk {

  const static std::vector<std::pair<const char*, Config>> g_appDefaults = {{
    /* Assassin's Creed Syndicate: amdags issues  */
    { R"(\\ACS\.exe$)", {{
      { "dxgi.customVendorId",              "10de" },
    }} },
    /* Dissidia Final Fantasy NT Free Edition */
    { R"(\\dffnt\.exe$)", {{
      { "dxgi.deferSurfaceCreation",        "True" },
    }} },
    /* Elite Dangerous: Compiles weird shaders    *
     * when running on AMD hardware               */
    { R"(\\EliteDangerous64\.exe$)", {{
      { "dxgi.customVendorId",              "10de" },
    }} },
    /* The Vanishing of Ethan Carter Redux        */
    { R"(\\EthanCarter-Win64-Shipping\.exe$)", {{
      { "dxgi.customVendorId",              "10de" },
    }} },
     /* EVE Online: Needs this to expose D3D12     *
     * otherwise D3D12 option on launcher is      *
     * greyed out                                 */
    { R"(\\evelauncher\.exe$)", {{
      { "d3d11.maxFeatureLevel",            "12_1" },
    }} },
    /* The Evil Within: Submits command lists     *
     * multiple times                             */
    { R"(\\EvilWithin(Demo)?\.exe$)", {{
      { "d3d11.dcSingleUseMode",            "False" },
      { "d3d11.cachedDynamicResources",     "vi"   },
    }} },
    /* Far Cry 3: Assumes clear(0.5) on an UNORM  *
     * format to result in 128 on AMD and 127 on  *
     * Nvidia. We assume that the Vulkan drivers  *
     * match the clear behaviour of D3D11.        */
    { R"(\\(farcry3|fc3_blooddragon)_d3d11\.exe$)", {{
      { "dxgi.nvapiHack",                   "False" },
    }} },
    /* Far Cry 4: Same as Far Cry 3               */
    { R"(\\FarCry4\.exe$)", {{
      { "dxgi.nvapiHack",                   "False" },
    }} },
    /* Frostpunk: Renders one frame with D3D9     *
     * after creating the DXGI swap chain         */
    { R"(\\Frostpunk\.exe$)", {{
      { "dxgi.deferSurfaceCreation",        "True" },
      { "d3d11.cachedDynamicResources",     "c" },
    }} },
    /* Nioh: See Frostpunk, apparently?           */
    { R"(\\nioh\.exe$)", {{
      { "dxgi.deferSurfaceCreation",        "True" },
    }} },
    /* Quantum Break: Mever initializes shared    *
     * memory in one of its compute shaders.      *
     * Also loves using MAP_WRITE on the same     *
     * set of resources multiple times per frame. */
    { R"(\\QuantumBreak\.exe$)", {{
      { "d3d11.zeroInitWorkgroupMemory",    "True" },
      { "d3d11.maxImplicitDiscardSize",     "-1"   },
    }} },
    /* Anno 2205: Random crashes with state cache */
    { R"(\\anno2205\.exe$)", {{
      { "dxvk.enableStateCache",            "False" },
    }} },
    /* Anno 1800: Poor performance without this   */
    { R"(\\Anno1800\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "c"    },
    }} },
    /* Fifa '19+: Binds typed buffer SRV to shader *
     * that expects raw/structured buffer SRV     */
    { R"(\\FIFA(19|[2-9][0-9])(_demo)?\.exe$)", {{
      { "dxvk.useRawSsbo",                  "True" },
    }} },
    /* Resident Evil 2/3: Ignore WaW hazards      */
    { R"(\\re(2|3|3demo)\.exe$)", {{
      { "d3d11.relaxedBarriers",            "True" },
    }} },
    /* Devil May Cry 5                            */
    { R"(\\DevilMayCry5\.exe$)", {{
      { "d3d11.relaxedBarriers",            "True" },
    }} },
    /* Call of Duty WW2                           */
    { R"(\\s2_sp64_ship\.exe$)", {{
      { "dxgi.nvapiHack",                   "False" },
    }} },
    /* Need for Speed 2015                        */
    { R"(\\NFS16\.exe$)", {{
      { "dxgi.nvapiHack",                   "False" },
    }} },
    /* Mass Effect Andromeda                      */
    { R"(\\MassEffectAndromeda\.exe$)", {{
      { "dxgi.nvapiHack",                   "False" },
    }} },
    /* Mirror`s Edge Catalyst: Crashes on AMD     */
    { R"(\\MirrorsEdgeCatalyst(Trial)?\.exe$)", {{
      { "dxgi.customVendorId",              "10de" },
    }} },
    /* Star Wars Battlefront (2015)               */
    { R"(\\starwarsbattlefront(trial)?\.exe$)", {{
      { "dxgi.nvapiHack",                   "False" },
    }} },
    /* Dark Souls Remastered                      */
    { R"(\\DarkSoulsRemastered\.exe$)", {{
      { "d3d11.constantBufferRangeCheck",   "True" },
    }} },
    /* Grim Dawn                                  */
    { R"(\\Grim Dawn\.exe$)", {{
      { "d3d11.constantBufferRangeCheck",   "True" },
    }} },
    /* NieR:Automata                              */
    { R"(\\NieRAutomata\.exe$)", {{
      { "d3d11.constantBufferRangeCheck",   "True" },
    }} },
    /* NieR Replicant                             */
    { R"(\\NieR Replicant ver\.1\.22474487139\.exe)", {{
      { "dxgi.syncInterval",                "1"    },
      { "dxgi.maxFrameRate",                "60"   },
      { "d3d11.cachedDynamicResources",     "vi"   },
    }} },
    /* SteamVR performance test                   */
    { R"(\\vr\.exe$)", {{
      { "d3d11.dcSingleUseMode",            "False" },
    }} },
    /* Hitman 2 and 3 - requires AGS library      */
    { R"(\\HITMAN(2|3)\.exe$)", {{
      { "dxgi.customVendorId",              "10de" },
    }} },
    /* Modern Warfare Remastered                  */
    { R"(\\h1(_[ms]p64_ship|-mod)\.exe$)", {{
      { "dxgi.customVendorId",              "10de" },
    }} },
    /* Titan Quest                                */
    { R"(\\TQ\.exe$)", {{
      { "d3d11.constantBufferRangeCheck",   "True" },
    }} },
    /* Saints Row IV                              */
    { R"(\\SaintsRowIV\.exe$)", {{
      { "d3d11.constantBufferRangeCheck",   "True" },
    }} },
    /* Saints Row: The Third                      */
    { R"(\\SaintsRowTheThird_DX11\.exe$)", {{
      { "d3d11.constantBufferRangeCheck",   "True" },
    }} },
    /* Crysis 3 - slower if it notices AMD card     *
     * Apitrace mode helps massively in cpu bound   *
     * game parts                                   */
    { R"(\\Crysis3\.exe$)", {{
      { "dxgi.customVendorId",              "10de" },
      { "d3d11.cachedDynamicResources",     "a"    },
    }} },
    /* Crysis 3 Remastered                          *
     * Apitrace mode helps massively in cpu bound   *
     * game parts                                   */
    { R"(\\Crysis3Remastered\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "a"    },
    }} },
    /* Atelier series - games try to render video *
     * with a D3D9 swap chain over the DXGI swap  *
     * chain, which breaks D3D11 presentation     */
    { R"(\\Atelier_(Ayesha|Escha_and_Logy|Shallie)(_EN)?\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* Atelier Firis                              */
    { R"(\\A18\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* Atelier Rorona/Totori/Meruru               */
    { R"(\\A(11R|12V|13V)_x64_Release(_en)?\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* Just how many of these games are there?    */
    { R"(\\Atelier_(Lulua|Lydie_and_Suelle|Ryza(_2)?|Sophie_2)\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* ...                                        */
    { R"(\\Atelier_(Lydie_and_Suelle|Firis|Sophie)_DX\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* Fairy Tail                                 */
    { R"(\\FAIRY_TAIL\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* Nights of Azure                            */
    { R"(\\CNN\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* Star Wars Battlefront II: amdags issues    */
    { R"(\\starwarsbattlefrontii\.exe$)", {{
      { "dxgi.customVendorId",              "10de" },
    }} },
    /* F1 games - do not synchronize TGSM access  *
     * in a compute shader, causing artifacts     */
    { R"(\\F1_20(1[89]|[2-9][0-9])\.exe$)", {{
      { "d3d11.forceTgsmBarriers",          "True" },
    }} },
    /* Blue Reflection                            */
    { R"(\\BLUE_REFLECTION\.exe$)", {{
      { "d3d11.constantBufferRangeCheck",   "True" },
    }} },
    /* Secret World Legends                       */
    { R"(\\SecretWorldLegendsDX11\.exe$)", {{
      { "d3d11.constantBufferRangeCheck",   "True" },
    }} },
    /* Darksiders Warmastered - apparently reads  *
     * from write-only mapped buffers             */
    { R"(\\darksiders1\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "a"    },
    }} },
    /* Monster Hunter World                       */
    { R"(\\MonsterHunterWorld\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "a"    },
    }} },
    /* Kingdome Come: Deliverance                 */
    { R"(\\KingdomCome\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "a"    },
    }} },
    /* Homefront: The Revolution                  */
    { R"(\\Homefront2_Release\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "a"    },
    }} },
    /* Sniper Ghost Warrior Contracts             */
    { R"(\\SGWContracts\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "a"    },
    }} },
    /* Armored Warfare             */
    { R"(\\armoredwarfare\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "c"    },
    }} },
    /* Shadow of the Tomb Raider - invariant      *
     * position breaks character rendering on NV  */
    { R"(\\SOTTR\.exe$)", {{
      { "d3d11.invariantPosition",          "False" },
      { "d3d11.floatControls",              "False" },
    }} },
    /* Nioh 2                                     */
    { R"(\\nioh2\.exe$)", {{
      { "dxgi.deferSurfaceCreation",        "True" },
    }} },
    /* DIRT 5 - uses amd_ags_x64.dll when it      *
     * detects an AMD GPU                         */
    { R"(\\DIRT5\.exe$)", {{
      { "dxgi.customVendorId",              "10de" },
    }} },
    /* Crazy Machines 3 - crashes on long device  *
     * descriptions                               */
    { R"(\\cm3\.exe$)", {{
      { "dxgi.customDeviceDesc",            "DXVK Adapter" },
    }} },
    /* World of Final Fantasy: Broken and useless *
     * use of 4x MSAA throughout the renderer     */
    { R"(\\WOFF\.exe$)", {{
      { "d3d11.disableMsaa",                "True" },
    }} },
     /* Mary Skelter 2 - Broken MSAA              */
    { R"(\\MarySkelter2\.exe$)", {{
      { "d3d11.disableMsaa",                "True" },
    }} },
    /* Final Fantasy XIV - Stuttering on NV       */
    { R"(\\ffxiv_dx11\.exe$)", {{
      { "dxvk.shrinkNvidiaHvvHeap",         "True" },
      { "d3d11.cachedDynamicResources",     "vi"   },
    }} },
    /* God of War - relies on NVAPI/AMDAGS for    *
     * barrier stuff, needs nvapi for DLSS        */
    { R"(\\GoW\.exe$)", {{
      { "d3d11.ignoreGraphicsBarriers",     "True" },
      { "d3d11.relaxedBarriers",            "True" },
      { "dxgi.nvapiHack",                   "False" },
      { "dxgi.maxFrameLatency",             "1"    },
    }} },
    /* AoE 2 DE - runs poorly for some users      */
    { R"(\\AoE2DE_s\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "a"    },
    }} },
    /* Total War: Warhammer III                   */
    { R"(\\Warhammer3\.exe$)", {{
      { "d3d11.maxDynamicImageBufferSize",  "4096" },
    }} },
    /* Assassin's Creed 3 and 4                   */
    { R"(\\ac(3|4bf)[sm]p\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "a"    },
    }} },
    /* Stranger of Paradise - FF Origin           */
    { R"(\\SOPFFO\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    /* Small Radios Big Televisions               */
    }} },
    { R"(\\SRBT\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* A Way Out: fix for stuttering and low fps  */
    { R"(\\AWayOut(_friend)?\.exe$)", {{
      { "dxgi.maxFrameLatency",                "1" },
    }} },
    /* Garden Warfare 2
       Won't start on amd Id without atiadlxx     */
    { R"(\\GW2.Main_Win64_Retail\.exe$)", {{
      { "dxgi.customVendorId",           "10de"   },
    }} },
    /* DayZ */
    { R"(\\DayZ_x64\.exe$)", {{
      { "d3d11.cachedDynamicResources",     "cr" },
    }} },
    /* Stray - writes to the same UAV every draw, *
     * presumably for culling, which doesn't play *
     * nicely with D3D11 without vendor libraries */
    { R"(\\Stray-Win64-Shipping\.exe$)", {{
      { "d3d11.ignoreGraphicsBarriers",     "True" },
    }} },
    /* Metal Gear Solid V: Ground Zeroes          *
     * Texture quality can break at high vram     */
    { R"(\\MgsGroundZeroes\.exe$)", {{
      { "dxgi.maxDeviceMemory",     "4095" },
    }} },
    /* Shantae and the Pirate's Curse             *
     * Game speeds up above 60 fps                */
    { R"(\\ShantaeCurse\.exe$)", {{
      { "dxgi.maxFrameRate",                 "60" },
    }} },
    /* Mighty Switch Force! Collection            *
     * Games speed up above 60 fps                */
    { R"(\\MSFC\.exe$)", {{
      { "dxgi.maxFrameRate",                 "60" },
    }} },
    /* Cardfight!! Vanguard Dear Days:            *
     * Submits command lists multiple times       */
    { R"(\\VG2\.exe$)", {{
      { "d3d11.dcSingleUseMode",             "False" },
    }} },
    /* Battlefield: Bad Company 2                 *
     * Gets rid of black flickering               */
    { R"(\\BFBC2Game\.exe$)", {{
      { "d3d11.floatControls",            "False" },
    }} },
    /* Sonic Frontiers - flickering shadows and   *
     * vegetation when GPU-bound                  */
    { R"(\\SonicFrontiers\.exe$)", {{
      { "dxgi.maxFrameLatency",             "1" },
    }} },
    /* TRAHA Global                               *
     * Shadow issues when it sees AMD/Nvidia      */
    { R"(\\RapaNui-Win64-Shipping\.exe$)", {{
      { "dxgi.customVendorId",              "8086" },
    }} },

    /**********************************************/
    /* D3D9 GAMES                                 */
    /**********************************************/

    /* A Hat in Time                              */
    { R"(\\HatinTimeGame\.exe$)", {{
      { "d3d9.strictPow",                   "False" },
      { "d3d9.lenientClear",                "True" },
    }} },
    /* Anarchy Online                             */
    { R"(\\anarchyonline\.exe$)", {{
      { "d3d9.memoryTrackTest",             "True" },
    }} },
    /* Borderlands 2 and The Pre Sequel!           */
    { R"(\\Borderlands(2|PreSequel)\.exe$)", {{
      { "d3d9.lenientClear",                "True" },
      { "d3d9.supportDFFormats",            "False" },
    }} },
    /* Borderlands                                */
    { R"(\\Borderlands\.exe$)", {{
      { "d3d9.lenientClear",                "True" },
    }} },
    /* Gothic 3                                   */
    { R"(\\Gothic(3|3Final| III Forsaken Gods)\.exe$)", {{
      { "d3d9.supportDFFormats",            "False" },
    }} },
    /* Sonic Adventure 2                          */
    { R"(\\Sonic Adventure 2\\(launcher|sonic2app)\.exe$)", {{
      { "d3d9.floatEmulation",              "Strict" },
      { "d3d9.maxFrameRate",                "60" },
    }} },
    /* The Sims 2,
       Body Shop,
       The Sims Life Stories,
       The Sims Pet Stories,
       and The Sims Castaway Stories             */
    { R"(\\(Sims2.*|TS2BodyShop|SimsLS|SimsPS|SimsCS)\.exe$)", {{
      { "d3d9.customVendorId",              "10de" },
      { "d3d9.customDeviceId",              "0091" },
      { "d3d9.customDeviceDesc",            "GeForce 7800 GTX" },
      { "d3d9.disableA8RT",                 "True" },
      { "d3d9.supportX4R4G4B4",             "False" },
      { "d3d9.maxAvailableMemory",          "2048" },
      { "d3d9.memoryTrackTest",             "True" },
    }} },
    /* Dead Space uses the a NULL render target instead
       of a 1x1 one if DF24 is NOT supported
       Mouse and physics issues above 60 FPS
       Built-in Vsync Locks the game to 30 FPS    */
    { R"(\\Dead Space\.exe$)", {{
      { "d3d9.supportDFFormats",                 "False" },
      { "d3d9.maxFrameRate",                     "60" },
      { "d3d9.presentInterval",                  "1" },
    }} },
    /* Halo CE/HaloPC                             */
    { R"(\\halo(ce)?\.exe$)", {{
      // Game enables minor decal layering fixes
      // specifically when it detects AMD.
      // Avoids chip being detected as unsupported
      // when on intel. Avoids possible path towards
      // invalid texture addressing methods.
      { "d3d9.customVendorId",              "1002" },
      // Avoids card not recognized error.
      // Keeps game's rendering methods consistent
      // for optimal compatibility.
      { "d3d9.customDeviceId",              "4172" },
      // The game uses incorrect sampler types in
      // the shaders for glass rendering which
      // breaks it on native + us if we don't
      // spec-constantly chose the sampler type
      // automagically.
      { "d3d9.forceSamplerTypeSpecConstants", "True" },
    }} },
    /* Counter Strike: Global Offensive
       Needs NVAPI to avoid a forced AO + Smoke
       exploit so we must force AMD vendor ID.    */
    { R"(\\csgo\.exe$)", {{
      { "d3d9.customVendorId",              "1002" },
    }} },
    /* Vampire - The Masquerade Bloodlines        */
    { R"(\\vampire\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
      { "d3d9.memoryTrackTest",             "True" },
      { "d3d9.maxAvailableMemory",          "1024" },
    }} },
    /* Senran Kagura Shinovi Versus               */
    { R"(\\SKShinoviVersus\.exe$)", {{
      { "d3d9.forceAspectRatio",            "16:9" },
    }} },
    /* Metal Slug X                               */
    { R"(\\mslugx\.exe$)", {{
      { "d3d9.supportD32",                  "False" },
    }} },
    /* Skyrim (NVAPI)                             */
    { R"(\\TESV\.exe$)", {{
      { "d3d9.customVendorId",              "1002" },
    }} },
    /* RTHDRIBL Demo
       Uses DONOTWAIT after GetRenderTargetData
       then goes into an infinite loop if it gets
       D3DERR_WASSTILLDRAWING.
       This is a better solution than penalizing
       other apps that use this properly.         */
    { R"(\\rthdribl\.exe$)", {{
      { "d3d9.allowDoNotWait",              "False" },
    }} },
    /* Hyperdimension Neptunia U: Action Unleashed */
    { R"(\\Neptunia\.exe$)", {{
      { "d3d9.forceAspectRatio",            "16:9" },
    }} },
    /* D&D - The Temple Of Elemental Evil          */
    { R"(\\ToEE\.exe$)", {{
      { "d3d9.allowDiscard",                "False" },
    }} },
    /* ZUSI 3 - Aerosoft Edition                  */
    { R"(\\ZusiSim\.exe$)", {{
      { "d3d9.noExplicitFrontBuffer",       "True" },
    }} },
    /* GTA IV (NVAPI)                             */
    /* Also thinks we're always on Intel          *
     * and will report/use bad amounts of VRAM.
     * Disabling support for DF texture formats
     * makes the game use a better looking render
     * path for mirrors                           */
    { R"(\\(GTAIV|EFLC)\.exe$)", {{
      { "d3d9.customVendorId",              "1002" },
      { "dxgi.emulateUMA",                  "True" },
      { "d3d9.supportDFFormats",            "False" },
    }} },
    /* Battlefield 2 (bad z-pass)                 */
    { R"(\\BF2\.exe$)", {{
      { "d3d9.longMad",                     "True" },
    }} },
    /* SpellForce 2 Series                        */
    { R"(\\SpellForce2.*\.exe$)", {{
      { "d3d9.forceSamplerTypeSpecConstants", "True" },
    }} },
    /* Everquest 2                                */
    { R"(\\EverQuest2.*\.exe$)", {{
      { "d3d9.alphaTestWiggleRoom", "True" },
    }} },
    /* Tomb Raider: Legend                       */
    { R"(\\trl\.exe$)", {{
      { "d3d9.apitraceMode",                "True" },
    }} },
    /* Everquest                                 */
    { R"(\\eqgame\.exe$)", {{
      { "d3d9.apitraceMode",                "True" },
    }} },
    /* Dark Messiah of Might & Magic             */
    { R"(\\mm\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
      { "d3d9.memoryTrackTest",             "True" },
    }} },
    /* Mafia 2                                   */
    { R"(\\mafia2\.exe$)", {{
      { "d3d9.customVendorId",              "10de" },
      { "d3d9.customDeviceId",              "0402" },
    }} },
    /* Warhammer: Online                         */
    { R"(\\WAR(-64)?\.exe$)", {{
      { "d3d9.customVendorId",              "1002" },
    }} },
    /* Dragon Nest                               */
    { R"(\\DragonNest_x64\.exe$)", {{
      { "d3d9.memoryTrackTest ",            "True" },
    }} },
    /* Dal Segno                                 */
    { R"(\\DST\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* Kohan II                                  */
    { R"(\\k2\.exe$)", {{
      { "d3d9.memoryTrackTest",             "True" },
    }} },
    /* Ninja Gaiden Sigma 1/2                    */
    { R"(\\NINJA GAIDEN SIGMA(2)?\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* Demon Stone breaks at frame rates > 60fps */
    { R"(\\Demonstone\.exe$)", {{
      { "d3d9.maxFrameRate",                "60" },
    }} },
    /* Far Cry 1 has worse water rendering when it detects AMD GPUs */
    { R"(\\FarCry\.exe$)", {{
      { "d3d9.customVendorId",              "10de" },
    }} },
    /* Earth Defense Force 5 */
    { R"(\\EDF5\.exe$)", {{
      { "dxgi.tearFree",                    "False" },
      { "dxgi.syncInterval",                "1"     },
    }} },
    /* Sine Mora EX */
    { R"(\\SineMoraEX\.exe$)", {{
      { "d3d9.maxFrameRate",                "60" },
    }} },
    /* Fantasy Grounds                           */
    { R"(\\FantasyGrounds\.exe$)", {{
      { "d3d9.noExplicitFrontBuffer",       "True" },
    }} },
    /* Red Orchestra 2                           */
    { R"(\\ROGame\.exe$)", {{
      { "d3d9.floatEmulation",              "Strict" },
    }} },
    /* Dark Souls II                            */
    { R"(\\DarkSoulsII\.exe$)", {{
      { "d3d9.floatEmulation",              "Strict" },
    }} },
    /* Dogfight 1942                            */
    { R"(\\Dogfight1942\.exe$)", {{
      { "d3d9.floatEmulation",              "Strict" },
    }} },
    /* Bayonetta                                */
    { R"(\\Bayonetta\.exe$)", {{
      { "d3d9.floatEmulation",              "Strict" },
    }} },
    /* Rayman Origins                           */
    { R"(\\Rayman Origins\.exe$)", {{
      { "d3d9.floatEmulation",              "Strict" },
    }} },
    /* Guilty Gear Xrd -Relevator-              */
    { R"(\\GuiltyGearXrd\.exe$)", {{
      { "d3d9.floatEmulation",              "Strict" },
    }} },
    /* Richard Burns Rally                      */
    { R"(\\RichardBurnsRally_SSE\.exe$)", {{
      { "d3d9.floatEmulation",              "Strict" },
    }} },
    /* BlazBlue Centralfiction                  */
    { R"(\\BBCF\.exe$)", {{
      { "d3d9.floatEmulation",              "Strict" },
    }} },
    /* Resident Evil games                      */
    { R"(\\(rerev|rerev2|re0hd|bhd|re5dx9|BH6)\.exe$)", {{
      { "d3d9.allowDirectBufferMapping",                "False" },
    }} },
    /* Limbo                                    */
    { R"(\\limbo\.exe$)", {{
      { "d3d9.maxFrameRate",                "60" },
    }} },
    /* Warhammer: Return of Reckoning Launcher
       Forcing SM1 fixes a black window otherwise caused by
       the lack of support for partial presentation */
    { R"(\\RoRLauncher\.exe$)", {{
      { "d3d9.shaderModel",                 "1" },
    }} },
    /* Halo CE SPV3 launcher
       Same issue as Warhammer: RoR above       */
    { R"(\\spv3\.exe$)", {{
      { "d3d9.shaderModel",                 "1" },
    }} },
    /* Escape from Tarkov launcher
       Same issue as Warhammer: RoR above       */
    { R"(\\BsgLauncher\.exe$)", {{
      { "d3d9.shaderModel",                 "1" },
    }} },
    /* Star Wars The Force Unleashed 2          *
     * Black particles because it tries to bind *
     * a 2D texture for a shader that           *
     * declares a 3d texture.                   */
    { R"(\\SWTFU2\.exe$)", {{
      { "d3d9.forceSamplerTypeSpecConstants",  "True" },
    }} },
    /* Scrapland (Remastered)                   */
    { R"(\\Scrap\.exe$)", {{
      { "d3d9.deferSurfaceCreation",        "True" },
    }} },
    /* Majesty 2 (Collection)                   *
     * Crashes on UMA without a memory limit,   *
     * since the game(s) will allocate all      *
     * available VRAM on startup.               */
    { R"(\\Majesty2\.exe$)", {{
      { "d3d9.memoryTrackTest",             "True" },
      { "d3d9.maxAvailableMemory",          "2048" },
    }} },
    /* Myst V End of Ages
       Game has white textures on amd radv.
       Expects Nvidia, Intel or ATI VendorId.
       "Radeon" in gpu description also works   */
    { R"(\\eoa\.exe$)", {{
      { "d3d9.customVendorId",              "10de" },
    }} },
    /* Beyond Good And Evil                     *
     * Fixes missing sun and light shafts       *
     * UI breaks at high fps                    */
    { R"(\\BGE\.exe$)", {{
      { "d3d9.allowDoNotWait",             "False" },
      { "d3d9.maxFrameRate",                  "60" },
    }} },
    /* Supreme Commander & Forged Alliance Forever */
    { R"(\\(SupremeCommander|ForgedAlliance)\.exe$)", {{
      { "d3d9.floatEmulation",            "Strict" },
    }} },
    /* Star Wars The Old Republic */
    { R"(\\swtor\.exe$)", {{
      { "d3d9.forceSamplerTypeSpecConstants", "True" },
    }} },
    /* Bionic Commando
       Physics break at high fps               */
    { R"(\\bionic_commando\.exe$)", {{
      { "d3d9.maxFrameRate",                "60" },
    }} },
    /* Port Royale 3                            *
     * Fixes infinite loading screens           */
    { R"(\\PortRoyale3\.exe$)", {{
      { "d3d9.allowDoNotWait",           "False" },
    }} },
    /* Need For Speed 3 modern patch            */
    { R"(\\nfs3\.exe$)", {{
      { "d3d9.enableDialogMode",          "True" },
    }} },
    /* Ninja Blade                              *
     * Transparent main character on Nvidia     */
    { R"(\\NinjaBlade\.exe$)", {{
      { "d3d9.alphaTestWiggleRoom",       "True" },
    }} },
    /* King Of Fighters XIII                     *
     * In-game speed increases on high FPS       */
    { R"(\\kofxiii\.exe$)", {{
      { "d3d9.maxFrameRate",                "60" },
    }} },
    /* YS Origin                                *
     * Helps very bad frametimes in some areas  */
    { R"(\\yso_win\.exe$)", {{
      { "d3d9.maxFrameLatency",              "1" },
    }} },
    /* Heroes of Annihilated Empires            *
     * Has issues with texture rendering and    *
     * video memory detection otherwise.        */
    { R"(\\Heroes (o|O)f Annihilated Empires.*\\engine\.exe$)", {{
      { "d3d9.memoryTrackTest",             "True" },
      { "d3d9.maxAvailableMemory",          "2048" },
    }} },
    /* The Ship (2004)                          */
    { R"(\\ship\.exe$)", {{
      { "d3d9.memoryTrackTest",             "True" },
    }} },
    /* SiN Episodes Emergence                   */
    { R"(\\SinEpisodes\.exe$)", {{
      { "d3d9.memoryTrackTest",             "True" },
    }} },
    /* Witcher 1: Very long loading times       */
    { R"(\\witcher\.exe$)", {{
      { "d3d9.apitraceMode",              "True" },
    }} },
    /* Hammer World Editor                      */
    { R"(\\(hammer(plusplus)?|mallet|wc)\.exe$)", {{
      { "d3d9.apitraceMode",                "True" },
    }} },
    /* Fallout 3 - Doesn't like Intel Id       */
    { R"(\\Fallout3\.exe$)", {{
      { "d3d9.customVendorId",              "10de" },
    }} },
    /* Sonic & All-Stars Racing Transformed    *
     * Helps performance when Resizable BAR    *
     * is enabled                              */
    { R"(\\ASN_App_PcDx9_Final\.exe$)", {{
      { "d3d9.apitraceMode",                "True" },
    }} },
    /* Black Mesa                              *
     * Artifacts & broken flashlight on Intel  */
    { R"(\\bms\.exe$)", {{
      { "d3d9.customVendorId",              "10de" },
    }} },
    /* Secret World Legends launcher           *
     * Invisible UI                            */
    { R"(\\Secret World Legends\\ClientPatcher\.exe$)", {{
      { "d3d9.shaderModel",                 "2" },
    }} },
    /* Alien Rage                              *
     * GTX 295 & disable Hack to fix shadows   */
    { R"(\\(ShippingPC-AFEARGame|ARageMP)\.exe$)", {{
      { "d3d9.customVendorId",              "10de" },
      { "d3d9.customDeviceId",              "05E0" },
      { "dxgi.nvapiHack",                   "False" },
    }} },
  }};

  static bool isWhitespace(char ch) {
    return ch == ' ' || ch == '\x9' || ch == '\r';
  }

  static bool isValidKeyChar(char ch) {
    return (ch >= '0' && ch <= '9')
        || (ch >= 'A' && ch <= 'Z')
        || (ch >= 'a' && ch <= 'z')
        || (ch == '.' || ch == '_');
  }

  static size_t skipWhitespace(const std::string& line, size_t n) {
    while (n < line.size() && isWhitespace(line[n]))
      n += 1;
    return n;
  }

  struct ConfigContext {
    bool active;
  };

  static void parseUserConfigLine(Config& config, ConfigContext& ctx, const std::string& line) {
    std::stringstream key;
    std::stringstream value;

    // Extract the key
    size_t n = skipWhitespace(line, 0);

    if (n < line.size() && line[n] == '[') {
      n += 1;

      size_t e = line.size() - 1;
      while (e > n && line[e] != ']')
        e -= 1;

      while (n < e)
        key << line[n++];

      ctx.active = key.str() == env::getExeName();
    } else {
      while (n < line.size() && isValidKeyChar(line[n]))
        key << line[n++];

      // Check whether the next char is a '='
      n = skipWhitespace(line, n);
      if (n >= line.size() || line[n] != '=')
        return;

      // Extract the value
      bool insideString = false;
      n = skipWhitespace(line, n + 1);

      while (n < line.size()) {
        if (!insideString && isWhitespace(line[n]))
          break;

        if (line[n] == '"') {
          insideString = !insideString;
          n++;
        } else
          value << line[n++];
      }

      if (ctx.active)
        config.setOption(key.str(), value.str());
    }
  }

  Config::Config() { }
  Config::~Config() { }

  Config::Config(OptionMap&& options)
  : m_options(std::move(options)) { }

  void Config::merge(const Config& other) {
    for (auto& pair : other.m_options)
      m_options.insert(pair);
  }

  void Config::setOption(const std::string& key, const std::string& value) {
    m_options.insert_or_assign(key, value);
  }

  std::string Config::getOptionValue(const char* option) const {
    auto iter = m_options.find(option);

    return iter != m_options.end()
      ? iter->second : std::string();
  }

  bool Config::parseOptionValue(
    const std::string&  value,
          std::string&  result) {
    result = value;
    return true;
  }

  bool Config::parseOptionValue(
    const std::string&  value,
          bool&         result) {
    static const std::array<std::pair<const char*, bool>, 2> s_lookup = {{
      { "true",  true  },
      { "false", false },
    }};

    return parseStringOption(value,
      s_lookup.begin(), s_lookup.end(), result);
  }

  bool Config::parseOptionValue(
    const std::string&  value,
          int32_t&      result) {
    if (value.size() == 0)
      return false;

    // Parse sign, don't allow '+'
    int32_t sign = 1;
    size_t start = 0;

    if (value[0] == '-') {
      sign = -1;
      start = 1;
    }

    // Parse absolute number
    int32_t intval = 0;

    for (size_t i = start; i < value.size(); i++) {
      if (value[i] < '0' || value[i] > '9')
        return false;

      intval *= 10;
      intval += value[i] - '0';
    }

    // Apply sign and return
    result = sign * intval;
    return true;
  }

  bool Config::parseOptionValue(
    const std::string&  value,
          Tristate&     result) {
    static const std::array<std::pair<const char*, Tristate>, 3> s_lookup = {{
      { "true",  Tristate::True  },
      { "false", Tristate::False },
      { "auto",  Tristate::Auto  },
    }};

    return parseStringOption(value,
      s_lookup.begin(), s_lookup.end(), result);
  }

  template<typename I, typename V>
  bool Config::parseStringOption(
          std::string   str,
          I             begin,
          I             end,
          V&            value) {
    str = Config::toLower(str);

    for (auto i = begin; i != end; i++) {
      if (str == i->first) {
        value = i->second;
        return true;
      }
    }

    return false;
  }

  Config Config::getAppConfig(const std::string& appName) {
    auto appConfig = std::find_if(g_appDefaults.begin(), g_appDefaults.end(),
      [&appName] (const std::pair<const char*, Config>& pair) {
        std::regex expr(pair.first, std::regex::extended | std::regex::icase);
        return std::regex_search(appName, expr);
      });

    if (appConfig != g_appDefaults.end()) {
      // Inform the user that we loaded a default config
      Logger::info(str::format("Found built-in config:"));

      for (auto& pair : appConfig->second.m_options)
        Logger::info(str::format("  ", pair.first, " = ", pair.second));

      return appConfig->second;
    }

    return Config();
  }

  Config Config::getUserConfig() {
    Config config;

    // Load either $DXVK_CONFIG_FILE or $PWD/dxvk.conf
    std::string filePath = env::getEnvVar("DXVK_CONFIG_FILE");

    if (filePath == "")
      filePath = "dxvk.conf";

    // Open the file if it exists
    std::ifstream stream(str::tows(filePath.c_str()).c_str());

    if (!stream)
      return config;

    // Inform the user that we loaded a file, might
    // help when debugging configuration issues
    Logger::info(str::format("Found config file: ", filePath));

    // Initialize parser context
    ConfigContext ctx;
    ctx.active = true;

    // Parse the file line by line
    std::string line;

    while (std::getline(stream, line))
      parseUserConfigLine(config, ctx, line);

    return config;
  }

  void Config::logOptions() const {
    if (!m_options.empty()) {
      Logger::info("Effective configuration:");

      for (auto& pair : m_options)
        Logger::info(str::format("  ", pair.first, " = ", pair.second));
    }
  }

  std::string Config::toLower(std::string str) {
    std::transform(str.begin(), str.end(), str.begin(),
      [] (unsigned char c) { return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c; });
    return str;
  }

}


code:
#pragma once

#include <string>
#include <unordered_map>

namespace dxvk {

  /**
   * \brief Tri-state
   *
   * Used to conditionally override
   * booleans if desired.
   */
  enum class Tristate : int32_t {
    Auto  = -1,
    False =  0,
    True  =  1,
  };

  /**
   * \brief Config option set
   *
   * Stores configuration options
   * as a set of key-value pairs.
   */
  class Config {
    using OptionMap = std::unordered_map<std::string, std::string>;
  public:

    Config();
    Config(OptionMap&& options);
    ~Config();

    /**
     * \brief Merges two configuration sets
     *
     * Options specified in this config object will
     * not be overridden if they are specified in
     * the second config object.
     * \param [in] other Config set to merge.
     */
    void merge(const Config& other);

    /**
     * \brief Sets an option
     *
     * \param [in] key Option name
     * \param [in] value Option value
     */
    void setOption(
      const std::string& key,
      const std::string& value);

    /**
     * \brief Parses an option value
     *
     * Retrieves the option value as a string, and then
     * tries to convert that string to the given type.
     * If parsing the string fails because it is either
     * invalid or if the option is not defined, this
     * method will return a fallback value.
     *
     * Currently, this supports the types \c bool,
     * \c int32_t, and \c std::string.
     * \tparam T Return value type
     * \param [in] option Option name
     * \param [in] fallback Fallback value
     * \returns Parsed option value
     * \returns The parsed option value
     */
    template<typename T>
    T getOption(const char* option, T fallback = T()) const {
      const std::string& value = getOptionValue(option);

      T result = fallback;
      parseOptionValue(value, result);
      return result;
    }

    /**
     * \brief Logs option values
     *
     * Prints the effective configuration
     * to the log for debugging purposes.
     */
    void logOptions() const;

    /**
     * \brief Retrieves default options for an app
     *
     * \param [in] appName Name of the application
     * \returns Default options for the application
     */
    static Config getAppConfig(const std::string& appName);

    /**
     * \brief Retrieves user configuration
     *
     * Reads options from the configuration file,
     * if it can be found, or an empty option set.
     * \returns User-defined configuration options
     */
    static Config getUserConfig();

    static std::string toLower(std::string str);

  private:

    OptionMap m_options;

    std::string getOptionValue(
      const char*         option) const;

    static bool parseOptionValue(
      const std::string&  value,
            std::string&  result);

    static bool parseOptionValue(
      const std::string&  value,
            bool&         result);

    static bool parseOptionValue(
      const std::string&  value,
            int32_t&      result);

    static bool parseOptionValue(
      const std::string&  value,
            Tristate&     result);

    template<typename I, typename V>
    static bool parseStringOption(
            std::string   str,
            I             begin,
            I             end,
            V&            value);

  };

  /**
   * \brief Applies tristate option
   *
   * Overrides the given value if \c state is
   * \c True or \c False, and leaves it intact
   * otherwise.
   * \param [out] option The value to override
   * \param [in] state Tristate to apply
   */
  inline void applyTristate(bool& option, Tristate state) {
    option &= state != Tristate::False;
    option |= state == Tristate::True;
  }

}


code:
#include "log.h"

#include "../util_env.h"

namespace dxvk {

  Logger::Logger(const std::string& file_name)
  : m_minLevel(getMinLogLevel()) {
    if (m_minLevel != LogLevel::None) {
      auto path = getFileName(file_name);

      if (!path.empty())
        m_fileStream = std::ofstream(str::tows(path.c_str()).c_str());
    }
  }

  Logger::~Logger() { }

  void Logger::trace(const std::string& message) {
    s_instance.emitMsg(LogLevel::Trace, message);
  }

  void Logger::debug(const std::string& message) {
    s_instance.emitMsg(LogLevel::Debug, message);
  }

  void Logger::info(const std::string& message) {
    s_instance.emitMsg(LogLevel::Info, message);
  }

  void Logger::warn(const std::string& message) {
    s_instance.emitMsg(LogLevel::Warn, message);
  }

  void Logger::err(const std::string& message) {
    s_instance.emitMsg(LogLevel::Error, message);
  }

  void Logger::log(LogLevel level, const std::string& message) {
    s_instance.emitMsg(level, message);
  }

  void Logger::emitMsg(LogLevel level, const std::string& message) {
    if (level >= m_minLevel) {
      std::lock_guard<dxvk::mutex> lock(m_mutex);

      static std::array<const char*, 5> s_prefixes
        = {{ "trace: ", "debug: ", "info:  ", "warn:  ", "err:   " }};

      const char* prefix = s_prefixes.at(static_cast<uint32_t>(level));

      std::stringstream stream(message);
      std::string       line;

      while (std::getline(stream, line, '\n')) {
        std::cerr << prefix << line << std::endl;

        if (m_fileStream)
          m_fileStream << prefix << line << std::endl;
      }
    }
  }

  LogLevel Logger::getMinLogLevel() {
    const std::array<std::pair<const char*, LogLevel>, 6> logLevels = {{
      { "trace", LogLevel::Trace },
      { "debug", LogLevel::Debug },
      { "info",  LogLevel::Info  },
      { "warn",  LogLevel::Warn  },
      { "error", LogLevel::Error },
      { "none",  LogLevel::None  },
    }};

    const std::string logLevelStr = env::getEnvVar("DXVK_LOG_LEVEL");

    for (const auto& pair : logLevels) {
      if (logLevelStr == pair.first)
        return pair.second;
    }

    return LogLevel::Info;
  }

  std::string Logger::getFileName(const std::string& base) {
    std::string path = env::getEnvVar("DXVK_LOG_PATH");

    if (path == "none")
      return "";

    if (!path.empty() && *path.rbegin() != '/')
      path += '/';

    std::string exeName = env::getExeBaseName();
    path += exeName + "_" + base;
    return path;
  }

}


code:
#pragma once

#include <array>
#include <fstream>
#include <iostream>
#include <string>

#include "../thread.h"

namespace dxvk {

  enum class LogLevel : uint32_t {
    Trace = 0,
    Debug = 1,
    Info  = 2,
    Warn  = 3,
    Error = 4,
    None  = 5,
  };

  /**
   * \brief Logger
   *
   * Logger for one DLL. Creates a text file and
   * writes all log messages to that file.
   */
  class Logger {

  public:

    Logger(const std::string& file_name);
    ~Logger();

    static void trace(const std::string& message);
    static void debug(const std::string& message);
    static void info (const std::string& message);
    static void warn (const std::string& message);
    static void err  (const std::string& message);
    static void log  (LogLevel level, const std::string& message);

    static LogLevel logLevel() {
      return s_instance.m_minLevel;
    }

  private:

    static Logger s_instance;

    const LogLevel m_minLevel;

    dxvk::mutex   m_mutex;
    std::ofstream m_fileStream;

    void emitMsg(LogLevel level, const std::string& message);

    static LogLevel getMinLogLevel();

    static std::string getFileName(
      const std::string& base);

  };

}


code:
#include "log_debug.h"

namespace dxvk::debug {

  std::string methodName(const std::string& prettyName) {
    size_t end = prettyName.find("(");
    size_t begin = prettyName.substr(0, end).rfind(" ") + 1;
    return prettyName.substr(begin,end - begin);
  }

}


code:
#pragma once

#include <sstream>

#include "log.h"

#ifdef _MSC_VER
#define METHOD_NAME __FUNCSIG__
#else
#define METHOD_NAME __PRETTY_FUNCTION__
#endif

#define TRACE_ENABLED

#ifdef TRACE_ENABLED
#define TRACE(...) \
  do { dxvk::debug::trace(METHOD_NAME, ##__VA_ARGS__); } while (0)
#else
#define TRACE(...) \
  do { } while (0)
#endif

namespace dxvk::debug {

  std::string methodName(const std::string& prettyName);

  inline void traceArgs(std::stringstream& stream) { }

  template<typename Arg1>
  void traceArgs(std::stringstream& stream, const Arg1& arg1) {
    stream << arg1;
  }

  template<typename Arg1, typename Arg2, typename... Args>
  void traceArgs(std::stringstream& stream, const Arg1& arg1, const Arg2& arg2, const Args&... args) {
    stream << arg1 << ",";
    traceArgs(stream, arg2, args...);
  }

  template<typename... Args>
  void trace(const std::string& funcName, const Args&... args) {
    std::stringstream stream;
    stream << methodName(funcName) << "(";
    traceArgs(stream, args...);
    stream << ")";
    Logger::trace(stream.str());
  }

}


code:
util_src = files([
  'util_env.cpp',
  'util_string.cpp',
  'util_fps_limiter.cpp',
  'util_gdi.cpp',
  'util_luid.cpp',
  'util_matrix.cpp',
  'util_monitor.cpp',
  'util_shared_res.cpp',

  'thread.cpp',

  'com/com_guid.cpp',
  'com/com_private_data.cpp',

  'config/config.cpp',

  'log/log.cpp',
  'log/log_debug.cpp',

  'sha1/sha1.c',
  'sha1/sha1_util.cpp',

  'sync/sync_recursive.cpp',
])

util_lib = static_library('util', util_src,
  include_directories : [ dxvk_include_path ],
)

util_dep = declare_dependency(
  link_with           : [ util_lib ],
)


code:
#pragma once

#include <atomic>

namespace dxvk {

  /**
   * \brief Reference-counted object
   */
  class RcObject {

  public:

    /**
     * \brief Increments reference count
     * \returns New reference count
     */
    uint32_t incRef() {
      return ++m_refCount;
    }

    /**
     * \brief Decrements reference count
     * \returns New reference count
     */
    uint32_t decRef() {
      return --m_refCount;
    }

  private:

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

  };

}